The code below is my Bollinger bands strategy for commodity. I add a position limit and want to optimize this strategy through parameter maxpos. For the function add.distribution, it asks for a component.label, but the function addPosLimit does not have a variable called "label". I wonder how to optimize maxpos at this case.
symbol <- 'C1'
currency("USD")
#stock(symbol, currency="USD", multiplier=1)
portfName <- 'RSI_Strategy'
acctName <- portfName
suppressWarnings(rm.strat(stratName))
initPortf(name = portfName, symbols = symbol, initDate = initDate,
currency = 'USD')
initAcct(name = acctName, portfolios = portfName,
initDate=initDate, initEq=initEq)
initOrders(portfolio = portfName, initDate = initDate)
stratName <- portfName
strategy(name = stratName, store=TRUE)
SD = 2
N = 20
add.indicator(strategy = stratName, name = "BBands",
arguments = list(HLC = quote(HLC(mktdata)), maType='SMA',
n=N, sd=SD),
label='BBands')
add.signal(strategy = stratName, name="sigCrossover",
arguments=list(columns=c("Close","up"),relationship="gt"),
label="Cl.gt.UpperBand")
add.signal(strategy = stratName, name="sigCrossover",
arguments=list(columns=c("Close","dn"),relationship="lt"),
label="Cl.lt.LowerBand")
add.signal(strategy = stratName, name="sigCrossover",
arguments=list(columns=c("High","mavg"),relationship="gt"),
label="Hi.Cross.Mid")
add.signal(strategy = stratName, name="sigCrossover",
arguments=list(columns=c("Low","mavg"),relationship="lt"),
label="Lo.Cross.Mid")
add.rule(strategy = stratName, name='ruleSignal',
arguments=list(sigcol="Cl.gt.UpperBand",sigval=TRUE, orderqty=-nShs,
ordertype='market', orderside=NULL, osFUN=osMaxPos
),type='enter',
label = "Enter.Short")
add.rule(strategy = stratName, name='ruleSignal',
arguments=list(sigcol="Cl.lt.LowerBand",sigval=TRUE, orderqty=nShs,
ordertype='market', orderside=NULL, osFUN=osMaxPos
),type='enter',
label = "Enter.Long")
add.rule(strategy = stratName, name='ruleSignal',
arguments=list(sigcol="Hi.Cross.Mid",sigval=TRUE, orderqty= 'all',
ordertype='market', orderside=NULL),type='exit',
label = "Exit.All")
add.rule(strategy = stratName, name='ruleSignal',
arguments=list(sigcol="Lo.Cross.Mid",sigval=TRUE, orderqty= 'all',
ordertype='market', orderside=NULL),type='exit',
label = "Exit.All")
addPosLimit(portfName, symbol, timestamp=initDate, maxpos=maxpos, minpos=0)
.maxpos = seq(3000,8000,1000)
add.distribution(stratName,
paramset.label = 'PosOpt',
component.type = 'order',
component.label = 'addPosLimit',
variable = list(maxpos = .maxpos),
label = 'MaxPos')
suppose i have simple composable fun which has Canvas.
Canvas(modifier = Modifier
.padding(start = 60.dp, end = 60.dp)
.fillMaxSize(),
onDraw = {
val w = size.width
val h = size.height
val s1LineOffset = w / 4 - 10
val s2LineOffset = w * 3 / 8 - 10
drawImage(
image = ImageBitmap.imageResource(
res = resources,
id = R.drawable.bttn
),
topLeft = Offset(
x = b1StartOffset,
y = 0f
)
)
}
)
I want to define the state of animation using the canvas sizes for initial and target value but i cant do so because i can't use this inside draw scope thats why i have to use it above the Canvas block, hence cant access Canvas size what should i do
val anim by ballAnim.animateFloat(
initialValue = ,
targetValue =,
animationSpec =
)
It is more of a simple job. Just create and remember a MutableState<T> value, then update it inside Canvas. For example,
var canvasSize by remember { mutableStateOf(IntSize()) }
Canvas(modifier = Modifier
.padding(start = 60.dp, end = 60.dp)
.fillMaxSize(),
onDraw = {
canvasSize = size //Assign it here
val w = size.width
val h = size.height
val s1LineOffset = w / 4 - 10
val s2LineOffset = w * 3 / 8 - 10
drawImage(
image = ImageBitmap.imageResource(
res = resources,
id = R.drawable.bttn
),
topLeft = Offset(
x = b1StartOffset,
y = 0f
)
)
}
)
val anim by ballAnim.animateFloat(
initialValue = canvasSize.width,
targetValue = canvasSize.height, //whatever
animationSpec = spring()
)
One of the options is animating some normalized value and denormalizing it using size inside onDraw, e.g.:
val animNormalized by ballAnim.animateFloat(
initialValue = 0.5,
targetValue = 0.8,
animationSpec =
)
Canvas(modifier = Modifier
.padding(start = 60.dp, end = 60.dp)
.fillMaxSize(),
onDraw = {
val w = size.width
val h = size.height
val anim = animNormalized * w
...
}
)
I'm hoping somebody experienced can point out where/if I am missing some crucial syntax.
My program works fine (because 95% of it was created by a CS50 professor), with one exception - I cannot seem to get the player and flag files/classes to reference each other to show that my Mario character has reached the final flag.
Specifically, the function "Flag:victory(player)" does not appear to be pulling information from the player file/class, while player has a similar function that is able to access Flag, although I don't see any difference between the two files as to why Flag is not behaving properly.
Flag = Class{}
function Flag:init(map)
-- reference to map for checking tiles
self.texture = map.spritesheet
-- animation frames
self.frames = {}
-- current animation frame
self.currentFrame = nil
self.player = Player(map)
-- used to determine behavior and animations
self.state = 'waving'
-- x and y velocity
self.dy = 0
-- position on top of map tiles
self.y = map.tileHeight * ((map.mapHeight / 2) - 4)
self.x = (map.mapWidth - 3) * map.tileWidth
-- initialize all player animations
self.animations = {
['waving'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(0, 48, 16, 16, self.texture:getDimensions()),
love.graphics.newQuad(16, 48, 16, 16, self.texture:getDimensions()),
love.graphics.newQuad(0, 48, 16, 16, self.texture:getDimensions()),
},
interval = 0.30
}),
['falling'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(32, 48, 16, 16, self.texture:getDimensions())
}
})
}
-- initialize animation and current frame we should render
self.animation = self.animations['waving']
self.currentFrame = self.animation:getCurrentFrame()
end
function Flag:update(dt)
self.animation:update(dt)
self.currentFrame = self.animation:getCurrentFrame()
self:victory()
end
function Flag:render()
local scaleX = - 1
-- draw sprite with scale factor and offsets
love.graphics.draw(self.texture, self.currentFrame, math.floor(self.x + 8 / 2),
math.floor(self.y + 8 / 2), 0, scaleX, 1, 8 / 2, 8 / 2)
end
function Flag:victory(player)
if self.player.victory == true then -- when player reaches flag
self.state = 'falling' -- change flag animation to down sprite
self.animation = self.animations['falling']
self.y = self.y + 2 -- descend the flag
end
end
--[[
Represents our player in the game, with its own sprite.
]]
Player = Class{}
local WALKING_SPEED = 140
local JUMP_VELOCITY = 400
function Player:init(map)
self.x = 0
self.y = 0
self.width = 16
self.height = 20
-- offset from top left to center to support sprite flipping
self.xOffset = 8
self.yOffset = 10
-- reference to map for checking tiles
self.map = map -- just a convenience because map comes in as a param/arg so the self should be dropped
self.texture = love.graphics.newImage('graphics/blue_alien.png')
-- sound effects
self.sounds = {
['jump'] = love.audio.newSource('sounds/jump.wav', 'static'),
['hit'] = love.audio.newSource('sounds/hit.wav', 'static'),
['coin'] = love.audio.newSource('sounds/coin.wav', 'static'),
}
-- variable for playing sound just once when game ends
self.musicplayed = false
-- animation frames
self.frames = {}
-- current animation frame
self.currentFrame = nil
-- used to determine behavior and animations
self.state = 'idle'
-- determines sprite flipping
self.direction = 'left'
-- x and y velocity
self.dx = 0
self.dy = 0
-- position on top of map tiles
self.y = map.tileHeight * ((map.mapHeight - 2) / 2) - self.height
self.x = map.tileWidth * 10
self.xmax = self.x -- farthest that mario has ever gone to the right
self.xmin = 1 -- farthest mario may go to the left, based on xmax and left border of map
-- initialize all player animations
self.animations = {
['idle'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions())
}
}),
['walking'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(128, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(144, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(160, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(144, 0, 16, 20, self.texture:getDimensions()),
},
interval = 0.15
}),
['jumping'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(32, 0, 16, 20, self.texture:getDimensions())
}
}),
['victory'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(48, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(160, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions()),
},
interval = .25
})
}
-- initialize animation and current frame we should render
self.animation = self.animations['idle']
self.currentFrame = self.animation:getCurrentFrame()
-- behavior map we can call based on player state
self.behaviors = {
['idle'] = function(dt)
-- add spacebar functionality to trigger jump state
if love.keyboard.wasPressed('space') then
self.dy = -JUMP_VELOCITY
self.state = 'jumping'
self.animation = self.animations['jumping']
self.sounds['jump']:play()
elseif love.keyboard.isDown('left') then
self.direction = 'left'
self.dx = -WALKING_SPEED
self.state = 'walking'
self.animations['walking']:restart()
self.animation = self.animations['walking']
self:checkLeftBoundary()
elseif love.keyboard.isDown('right') then
self.direction = 'right'
self.dx = WALKING_SPEED
self.state = 'walking'
self.animations['walking']:restart()
self.animation = self.animations['walking']
else
self.dx = 0
end
self:checkLeftBoundary()
self:checkRightBoundary()
end,
['walking'] = function(dt)
-- keep track of input to switch movement while walking, or reset
-- to idle if we're not moving
if love.keyboard.wasPressed('space') then
self.dy = -JUMP_VELOCITY
self.state = 'jumping'
self.animation = self.animations['jumping']
self.sounds['jump']:play()
elseif love.keyboard.isDown('left') then
self.direction = 'left'
self.dx = -WALKING_SPEED
elseif love.keyboard.isDown('right') then
self.direction = 'right'
self.dx = WALKING_SPEED
else
self.dx = 0
self.state = 'idle'
self.animation = self.animations['idle']
end
self:checkLeftBoundary()
self:checkRightBoundary()
-- check for collisions moving left and right
self:checkRightCollision()
self:checkLeftCollision()
-- check if there's a tile directly beneath us
if not self.map:collides(self.map:tileAt(self.x, self.y + self.height)) and
not self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.state = 'jumping'
self.animation = self.animations['jumping']
end
end,
['jumping'] = function(dt)
if love.keyboard.isDown('left') then
self.direction = 'left'
self.dx = -WALKING_SPEED
elseif love.keyboard.isDown('right') then
self.direction = 'right'
self.dx = WALKING_SPEED
end
-- apply map's gravity before y velocity
self.dy = self.dy + self.map.gravity
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x, self.y + self.height)) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.dy = 0
self.state = 'idle'
self.animation = self.animations['idle']
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
self:checkLeftBoundary()
self:checkRightBoundary()
-- check for collisions moving left and right
self:checkRightCollision()
self:checkLeftCollision()
end,
['victory'] = function(dt)
self.dx = 0
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x, self.y + self.height)) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.dy = 0
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
end
}
end
function Player:update(dt)
self.behaviors[self.state](dt)
self.animation:update(dt)
self.currentFrame = self.animation:getCurrentFrame()
self.x = self.x + self.dx * dt
self.xmax = math.max(self.x, self.xmax) -- tester to update xmax if player moves further to right than ever before
self.xmin = math.max(1, math.min(self.xmax - VIRTUAL_WIDTH / 2, map.mapWidthPixels - VIRTUAL_WIDTH)) -- farthest mario may go to the left, based on xmax and left border of map
self:calculateJumps()
self:gameover()
self:reachflag()
if self.map:victory() == true then
self.victory = true
end
-- apply velocity
self.y = self.y + self.dy * dt
end
function Player:gameover()
if self.y > 300 then
self.game_over = true
end
end
function Player:reachflag(Flag)
if self.x >= flag.x then
self.victory = true
end
end
-- jumping and block hitting logic
function Player:calculateJumps()
-- if we have negative y velocity (jumping), check if we collide
-- with any blocks above us
if self.dy < 0 then
if self.map:tileAt(self.x, self.y).id ~= TILE_EMPTY or
self.map:tileAt(self.x + self.width - 1, self.y).id ~= TILE_EMPTY then
-- reset y velocity
self.dy = 0
-- change block to different block
local playCoin = false
local playHit = false
if self.map:tileAt(self.x, self.y).id == JUMP_BLOCK then
self.map:setTile(math.floor(self.x / self.map.tileWidth) + 1,
math.floor(self.y / self.map.tileHeight) + 1, JUMP_BLOCK_HIT)
playCoin = true
else
playHit = true
end
if self.map:tileAt(self.x + self.width - 1, self.y).id == JUMP_BLOCK then
self.map:setTile(math.floor((self.x + self.width - 1) / self.map.tileWidth) + 1,
math.floor(self.y / self.map.tileHeight) + 1, JUMP_BLOCK_HIT)
playCoin = true
else
playHit = true
end
if playCoin then
self.sounds['coin']:play()
elseif playHit then
self.sounds['hit']:play()
end
end
end
end
-- checks two tiles to our left to see if a collision occurred
function Player:checkLeftCollision()
if self.dx < 0 then
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x - 1, self.y)) or
self.map:collides(self.map:tileAt(self.x - 1, self.y + self.height - 1)) then
-- if so, reset velocity and position and change state
self.dx = 0
self.x = self.map:tileAt(self.x - 1, self.y).x * self.map.tileWidth
end
end
end
-- checks two tiles to our right to see if a collision occurred
function Player:checkRightCollision()
if self.dx > 0 then
-- check if there's a tile directly beneath us
if self.map:collides(map:tileAt(self.x + self.width, self.y)) or
self.map:collides(map:tileAt(self.x + self.width, self.y + self.height - 1)) then
-- if so, reset velocity and position and change state
self.dx = 0
self.x = (self.map:tileAt(self.x + self.width, self.y).x - 1) * map.tileWidth - self.width
end
end
end
function Player:checkLeftBoundary()
if self.x <= self.xmin then -- went too far left
self.x = self.xmin
if self.direction == 'left'then
self.dx = 0 -- set speed to zero but keep state, ie walking, jumping/falling
end
end
end
function Player:checkRightBoundary()
if self.x >= map.mapWidthPixels - 16 then -- went too far right
self.x = map.mapWidthPixels - 16
if self.direction == 'right'then
self.dx = 0 -- set speed to zero but keep state, ie walking, jumping/falling
end
end
end
function Player:render()
local scaleX
-- set negative x scale factor if facing left, which will flip the sprite
-- when applied
if self.direction == 'right' then
scaleX = 1
else
scaleX = -1
end
-- draw sprite with scale factor and offsets
love.graphics.draw(self.texture, self.currentFrame, math.floor(self.x + self.xOffset),
math.floor(self.y + self.yOffset), 0, scaleX, 1, self.xOffset, self.yOffset)
if self.game_over == true then
self.state = 'idle'
self.dy = 0
self.dx = 0
map.music:stop()
if self.musicplayed == false then
love.audio.newSource('sounds/Laser_Shoot2.wav', 'static'):play()
self.musicplayed = true
end
love.graphics.print('Oh Snap! Try again? (y/n)', self.xmin + 40, 40)
if love.keyboard.isDown('y') then
self.map:init()
self.map:render()
elseif love.keyboard.isDown('n')then
love.event.quit()
end
end
if self.victory == true then
self.state = 'victory'
self.animation = self.animations['victory']
if self.musicplayed == false then
love.audio.newSource('sounds/Powerup23.wav', 'static'):play()
self.musicplayed = true
end
love.graphics.print('Congratulations! Play again? (y/n)', self.xmin + 35, 40)
if love.keyboard.isDown('y') then
self.map:init()
self.map:render()
map.music:stop()
elseif love.keyboard.isDown('n')then
love.event.quit()
end
end
end
--[[
Super Mario Bros. Demo
Author: Colton Ogden
Original Credit: Nintendo
Demonstrates rendering a screen of tiles.
]]
Class = require 'class'
push = require 'push'
require 'Animation'
require 'Map'
require 'Player'
require 'Flag'
-- close resolution to NES but 16:9
VIRTUAL_WIDTH = 432
VIRTUAL_HEIGHT = 243
-- actual window resolution
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
-- seed RNG
math.randomseed(os.time())
-- makes upscaling look pixel-y instead of blurry
love.graphics.setDefaultFilter('nearest', 'nearest')
-- an object to contain our map data
map = Map()
flag = Flag(map)
player = Player(map)
-- performs initialization of all objects and data needed by program
function love.load()
-- sets up a different, better-looking retro font as our default
love.graphics.setFont(love.graphics.newFont('fonts/font.ttf', 16))
-- sets up virtual screen resolution for an authentic retro feel
push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, {
fullscreen = false,
resizable = true
})
love.window.setTitle('Super Mario 50')
love.keyboard.keysPressed = {}
love.keyboard.keysReleased = {}
end
-- called whenever window is resized
function love.resize(w, h)
push:resize(w, h)
end
-- global key pressed function
function love.keyboard.wasPressed(key)
if (love.keyboard.keysPressed[key]) then
return true
else
return false
end
end
-- global key released function
function love.keyboard.wasReleased(key)
if (love.keyboard.keysReleased[key]) then
return true
else
return false
end
end
-- called whenever a key is pressed
function love.keypressed(key)
if key == 'escape' then
love.event.quit()
end
love.keyboard.keysPressed[key] = true
end
-- called whenever a key is released
function love.keyreleased(key)
love.keyboard.keysReleased[key] = true
end
-- called every frame, with dt passed in as delta in time since last frame
function love.update(dt)
map:update(dt)
-- reset all keys pressed and released this frame
love.keyboard.keysPressed = {}
love.keyboard.keysReleased = {}
end
-- called each frame, used to render to the screen
function love.draw()
-- begin virtual resolution drawing
push:apply('start')
-- clear screen using Mario background blue
love.graphics.clear(108/255, 140/255, 255/255, 255/255)
-- renders our map object onto the screen
love.graphics.translate(math.floor(-map.camX + 0.5), math.floor(-map.camY + 0.5))
map:render()
-- end virtual resolution
push:apply('end')
end
--[[
Contains tile data and necessary code for rendering a tile map to the
screen.
]]
require 'Util'
Map = Class{}
TILE_BRICK = 1
TILE_EMPTY = -1
-- cloud tiles
CLOUD_LEFT = 6
CLOUD_RIGHT = 7
-- bush tiles
BUSH_LEFT = 2
BUSH_RIGHT = 3
-- mushroom tiles
MUSHROOM_TOP = 10
MUSHROOM_BOTTOM = 11
-- jump block
JUMP_BLOCK = 5
JUMP_BLOCK_HIT = 9
-- flagpole
FLAGPOLE_TOP = 8
FLAGPOLE_MIDDLE = 12
FLAGPOLE_BOTTOM = 16
PYRAMID_BLOCK = 17
-- a speed to multiply delta time to scroll map; smooth value
local SCROLL_SPEED = 62
-- constructor for our map object
function Map:init()
self.spritesheet = love.graphics.newImage('graphics/spritesheet.png')
self.sprites = generateQuads(self.spritesheet, 16, 16)
self.music = love.audio.newSource('sounds/music.wav', 'static')
self.pyramid_block = love.graphics.newImage('graphics/pyramidblock.png')
self.tileWidth = 16
self.tileHeight = 16
self.mapWidth = 300
self.mapHeight = 28
self.tiles = {}
-- applies positive Y influence on anything affected
self.gravity = 15
-- associate player with map
self.player = Player(self)
self.flag = Flag(self)
-- camera offsets
self.camX = 0
self.camY = -3
-- cache width and height of map in pixels
self.mapWidthPixels = self.mapWidth * self.tileWidth
self.mapHeightPixels = self.mapHeight * self.tileHeight
-- first, fill map with empty tiles
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
-- support for multiple sheets per tile; storing tiles as tables
self:setTile(x, y, TILE_EMPTY)
end
end
-- begin generating the terrain using vertical scan lines
local x = 1
while x < self.mapWidth - 20 do
-- 2% chance to generate a cloud
-- make sure we're 2 tiles from edge at least
if x < self.mapWidth - 2 then
if math.random(20) == 1 then
-- choose a random vertical spot above where blocks/pipes generate
local cloudStart = math.random(self.mapHeight / 2 - 6)
self:setTile(x, cloudStart, CLOUD_LEFT)
self:setTile(x + 1, cloudStart, CLOUD_RIGHT)
end
end
-- 5% chance to generate a mushroom
if math.random(20) == 1 then
-- left side of pipe
self:setTile(x, self.mapHeight / 2 - 2, MUSHROOM_TOP)
self:setTile(x, self.mapHeight / 2 - 1, MUSHROOM_BOTTOM)
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
-- next vertical scan line
x = x + 1
-- 10% chance to generate a bush, being sure to generate away from edge
elseif math.random(10) == 1 and x < self.mapWidth - 3 then
local bushLevel = self.mapHeight / 2 - 1
-- place bush component and then column of bricks
self:setTile(x, bushLevel, BUSH_LEFT)
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
x = x + 1
self:setTile(x, bushLevel, BUSH_RIGHT)
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
x = x + 1
-- 10% chance to not generate anything, creating a gap
elseif math.random(10) ~= 1 then
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
-- chance to create a block for Mario to hit
if math.random(15) == 1 then
self:setTile(x, self.mapHeight / 2 - 4, JUMP_BLOCK)
end
-- next vertical scan line
x = x + 1
else
-- increment X so we skip two scanlines, creating a 2-tile gap
x = x + 2
end
end
while x <= self.mapWidth do
-- draw in pyramid
if x == self.mapWidth - 13 then
local row = 1 -- how wide pyramid to be
while row < 7 do
local column = 1 -- might need to not say local everytime
while column <= row do
self:setTile(x, self.mapHeight / 2 - column, PYRAMID_BLOCK)
column = column + 1
end
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
row = row + 1
x = x + 1
end
end
-- draw in flagpole
if x == self.mapWidth - 2 then
self:setTile(x, self.mapHeight / 2 - 3, FLAGPOLE_TOP)
self:setTile(x, self.mapHeight / 2 - 2, FLAGPOLE_MIDDLE)
self:setTile(x, self.mapHeight / 2 - 1, FLAGPOLE_BOTTOM)
end
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
-- next vertical scan line
x = x + 1
end
-- start the background music
self.music:setLooping(true)
self.music:play()
end
-- return whether a given tile is collidable
function Map:collides(tile)
-- define our collidable tiles
local collidables = {
TILE_BRICK, JUMP_BLOCK, JUMP_BLOCK_HIT,
MUSHROOM_TOP, MUSHROOM_BOTTOM, PYRAMID_BLOCK
}
-- iterate and return true if our tile type matches
for _, v in ipairs(collidables) do
if tile.id == v then
return true
end
end
return false
end
-- this function doesn't appear to be doing anything...
function Map:victory(player, flag)
if self.player.x >= self.flag.x * map.tileWidth then
return true
else
return false
end
end
-- function to update camera offset with delta time
function Map:update(dt)
self.player:update(dt)
self.flag:update(dt)
-- keep camera's X coordinate following the player, preventing camera from
-- scrolling past 0 to the left and the map's width
self.camX = math.min(self.mapWidthPixels - VIRTUAL_WIDTH, math.max(self.camX, math.min(self.player.x - VIRTUAL_WIDTH / 2,
math.min(self.mapWidthPixels - VIRTUAL_WIDTH, self.player.x))))
end
-- gets the tile type at a given pixel coordinate
function Map:tileAt(x, y)
return {
x = math.floor(x / self.tileWidth) + 1,
y = math.floor(y / self.tileHeight) + 1,
id = self:getTile(math.floor(x / self.tileWidth) + 1, math.floor(y / self.tileHeight) + 1)
}
end
-- returns an integer value for the tile at a given x-y coordinate
function Map:getTile(x, y)
return self.tiles[(y - 1) * self.mapWidth + x]
end
-- sets a tile at a given x-y coordinate to an integer value
function Map:setTile(x, y, id)
self.tiles[(y - 1) * self.mapWidth + x] = id
end
-- renders our map to the screen, to be called by main's render
function Map:render()
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
local tile = self:getTile(x, y)
if tile ~= TILE_EMPTY then
if tile > 16 then
love.graphics.draw(self.pyramid_block,
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
else
love.graphics.draw(self.spritesheet, self.sprites[tile],
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
end
end
end
end
self.player:render()
self.flag:render()
end
You're using 'self.player' which is a brand new player at the init() (which is a different player than the one you want)
You need to use 'player' that you passed as an argument to check if player.victory is true.
local binser = require "binser"
local log, floor, ceil, min, random = math.log, math.floor, math.ceil, math.min, math.random
local makeNode = function(value,size)
return {
value=value,
next={},
width={},
size=size
}
end
local End ={}
local NIL = makeNode(End,0)
local insert = function(self,value)
local node, chain, stepsAtLevel = self.head, {}, {}
for i=1, self.maxLevel do stepsAtLevel[i]=0 end
for level = self.maxLevel, 1, -1 do
while node.next[level] ~= NIL and node.next[level].value <= value do
stepsAtLevel[level] = ( stepsAtLevel[level] or 0 ) + node.width[level]
node = node.next[level]
--print(level, stepsAtLevel[level],value)
end
chain[level]=node
end
local nodeLevel = min( self.maxLevel, - floor(log(random()) / log(2) ) )
local newNode = makeNode( value, nodeLevel)
local steps, prevNode = 0
for level= 1, nodeLevel do
prevNode = chain[level]
newNode.next[level] = prevNode.next[level]
prevNode.next[level] = newNode
newNode.width[level] = prevNode.width[level] - steps
prevNode.width[level] = steps + 1
steps = steps + stepsAtLevel[level]
end
for level = nodeLevel + 1, self.maxLevel do
chain[level].width[level] = chain[level].width[level] +1
end
self.size = self.size + 1
end
local first = function(self)
return self.head.next[1].value
end
local tostring = function (self)
local t = {}
for k,v in self:ipairs() do table.insert(t,v) end
return "( "..table.concat(t,", ").. " )"
end
local islMT = {
__index = function(self,i)
if type(i) ~= "number" then return end
if i > self.size then return end
local node = self.head
for level=self.maxLevel, 1, -1 do
while node.width[level] <= i do
i = i - node.width[level]
node = node.next[level]
end
end
return node.value
end,
__tostring=tostring
}
local ipairs = function (self)
local node, size = self.head.next[1] , self.size
count = 0
return function()
value=node.value
node = node.next[1]
count = count+1
return count <= size and count or nil, value
end
end
math.randomseed(os.time())
local size = expected_size or 16
if not expected_size then
expected_size = 16
end
local maxLevel = floor( log(expected_size) / log(2) )
local head = makeNode("HEAD",maxLevel)
for i=1,maxLevel do
head.next[i] = NIL
head.width[i] = 1
end
local insdel = setmetatable( {
size = 0,
head = head,
maxLevel = maxLevel,
insert = insert,
tostring = tostring,
ipairs=ipairs,
}, islMT
)
insdel:insert('foo')
print(insdel)
-- how to serialize metatable insdel? this fail
local ser = binser.serialize(insdel)
insdel = binser.deserialize(ser)
insdel:insert('bar')
print(insdel)
I have tried countless serialization module (serpent, json, pluto) and none works with metatable, does someone know how to serialize metatables? Which module to use to serialize/deserialize metatable and how?
The full code is included, the binser module is from luarocks :
https://luarocks.org/modules/bakpakin/binser