I am trying to learn by starting with a drag and drop game. I want to do this using classes. I have objects dragging using info from others in these forums but as you'll see I get errors - attempt to perform arithmetic on field 'x0' (a nil value) - but I am having enough success to be hopeful this can work.
Eventually I want to detect collisions between sprites and labels as per a matching game.
------------
-- main.lua
------------
-- Create multiple blocks.
scene = gideros.class(Sprite)
--on scene initialization
function scene:init()
--create world instance
self.actors = {}
local actors = {}
for i = 0, 5 do
-- The block image.
local blockSprite = Bitmap.new(Texture.new("_tanker.png"))
-- Create new block.
local block = Block.new(blockSprite)
-- Place blocks in the bottom screen side by side.
block:setPosition((i * 50) + 32, 240)
stage:addChild(block)
self.actors[block] = block
end
end
--Input (sprite2): another sprite to check for collision detection
--Return: return true if the rectangles overlap otherwise return false
function Sprite:collision(sprite2)
-- self bottom < other sprite top
if self:getY() + self:getHeight() < sprite2:getY() then
return false
end
-- self top > other sprite bottom
if self:getY() > sprite2:getY() + sprite2:getHeight() then
return false
end
-- self left > other sprite right
if self:getX() > sprite2:getX() + sprite2:getWidth() then
return false
end
-- self right < other sprite left
if self:getX() + self:getWidth() < sprite2:getX() then
return false
end
return true
end
--running the world
function scene:onEnterFrame()
for sprite in pairs(self.actors) do
--get specific sprite
--sprite:setPosition(body:getPosition())
--sprite:setRotation(body:getAngle() * 180 / math.pi)
--sprite:setPosition(body:getPosition())
--sprite:setRotation(body:getAngle() * 180 / math.pi)
end
end
--removing event on exiting scene
--just in case you're using SceneManager
function scene:onExitBegin()
self:removeEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
--add created scene to stage or sceneManager
local mainScene = scene.new()
stage:addChild(mainScene)
----------
Block = Core.class(Sprite)
local sprite
function Block:init(sprite)
self:addChild(sprite)
-- Register touch events.
sprite:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
sprite:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
sprite:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
sprite:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
local dragging=false
--sprit.
end
-- If block is on focus, stop propagation of touch events
function Block:onTouchesBegin(event)
if self.id == nil then
self.id = event.touch.id
print("BEGIN")
if self:hitTestPoint(event.touch.x, event.touch.y) then
dragging = true
-- Get start postion.
self.x0 = event.touch.x
self.y0 = event.touch.y
else
--self.x0 = 1
--self.y0 = 1
end
end
end
-- If block is on focus, stop propagation of touch events.
function Block:onTouchesMove(event)
if self.id == event.touch.id then
if self:hitTestPoint(event.touch.x, event.touch.y) then
if event.touch.x == nil then
event:stopPropagation()
end
print( self.x0)
local dx = event.touch.x - self.x0--get the diff of initial pos and current touch pos
print("MOVE2")
local dy = event.touch.y - self.y0
print("MOVE3")
self:setX(self:getX() + dx) -- add this diff to img's x and y pos
self:setY(self:getY() + dy)
print("MOVE4")
self.x0 = event.touch.x -- change the initial pos with new one
self.y0 = event.touch.y
event:stopPropagation()
end
end
end
-- If block is on focus, stop propagation of touch events.
function Block:onTouchesEnd(event)
if self.id - event.touch.id then
print("END")
self.id = nil
end
end
-- If touches are cancelled, reset the state of the button.
function Block:onTouchesCancel(event)
if self.focus then
self.focus = false;
self:updateVisualState(false)
event:stopPropagation()
end
end
Comments
main.lua:19: attempt to index global 'Block' (a nil value)
This means that at line 19 it doesn't know what "Block" is. Why doesn't it know that? Because you put this at line 77:
Block = Core.class(Sprite)
You may be thinking: "By the time it gets to scene:init(), it will know what Block is, because line 77 is actually executed before line 19!"
But Lua doesn't work that way. It reads the file from top to bottom and so when it gets to line 17 it goes: "Block? WTF is Block? No one told me about Block!" (As you can probably tell, Lua is very dramatic.)
So you need to put this:
Block = Core.class(Sprite)
BEFORE any function that uses "Block".
I would like to help you more, but this will have to do for now as I'm at work.
The next problems you'll run into also have to do with the order of things.
If "function Block:init(sprite)" isn't declared before you create your Block, it won't be called. So you need to move this function so it's above your "function scene:init()".
And the next problem:
Block:init(sprite) calls:
sprite:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
sprite:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
sprite:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
sprite:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
So again, move these four functions (onTouchesBegin, onTouchesMove, onTouchesEnd, onTouchesCancel) up so they come before the function that uses them.