How can I add tables as a EventListener?
I'm working on a breakout game as a hello-world project and i would like to add the effect of "double ball". so basically i want to add balls to balls table then check if one of the balls hit the brick
my code works with
balls["ball"]:addEventListener( "collision", removeBricks )
but if i try the following:
balls:addEventListener( "collision", removeBricks )
i'm getting Runtime error ...\main.lua:753: attempt to call method 'addEventListener' (a nil value)
stack traceback:
what i've tried:
local balls = {}
balls["ball"] = crackSheet:grabSprite("ball_normal.png", true)
balls["ball"].name = "ball"
function removeBricks(event)
if event.other.isBrick == 1 then
remove brick...
end
end
balls.collision = removeBricks
balls:addEventListener( "collision", removeBricks )
You can't add event listener to a table. If you want to check bricks vs. ball collisions you should add event listeners to every ball or every brick
you can try creating each instance of a ball instead of using a table and then try to add collision eventlistener on every ball try to look at the code
local Table = {}
local function generateBall(event)
if "ended" == event.phase then
local ball = crackSheet:grabSprite("ball_normal.png", true)
ball.name = "ball"
local function removeBricks(event)
if "ended" == event.phase then
if event.other.isBrick == 1 then
remove brick...
end
end
end
ball:EventListener("collision", removeBricks)
table.insert(Table, ball)
end
end
Runtime:EventListener("touch",generateBall)
this way you can have different listener on every ball
If you want to add balls in your table you can insert objects in table
local ballsTable = {}
function addBall()
local ball = crackSheet:grabSprite("ball_normal.png", true)
ball.name = "ball"
ball.collision = function(self, event)
if event.other.isBrick == 1 then
event.other:removeSelf()
end
end
ball:addEventListener( "collision" )
table.insert(ballsTable, ball)
end
Related
Circles of variable sizes will be drawn on blank.png (800 X 800) on touch and in run time. On touch, the coordinates (the positions of x-axis and y-axis coordinates in runtime on touch) will be stored in two variables myCoordx and myCoordy in began event. When a user moves his/her fingers on screen, circle will be drawn based on calculated radius and coordinates. Now the error keeps on appearing. Please help me to debug this code.
Runtime error
d:\corona projects\enterframeevent\main.lua:14: attempt to index global 'drawCircle' (a nil value)
stack traceback:
d:\corona projects\enterframeevent\main.lua:14: in main chunk
This is my main.lua file.
local screen = display.newImage( "blank.png")
function drawCircle:touch(event)
if event.phase == "began" then
local myCoordx = event.x
local myCoordy = event.y
elseif event.phase == "moved" then
local rad = (event.x - myCoordx) ^ 2
local myCircle = display.newCircle(event.x, event.y, rad )
myCircle:setFillColor( 1, 0, 1 )
end
end
Runtime:addEventListener( "touch", drawCircle )
Apparently you try to add :touch method to drawCircle, but you don't define it anywhere. You should init it to something at very least an empty table - i.e. {} or use relevant Corona method to create it.
As per my comment, the code posted can't write, or the error message is wrong. I'll assume the error is wrong, because the statement function drawCircle:touch(event) on line 3 attempts to add a method called touch(self) to a drawCircle table; yet the code does not create this table anywhere. You are either missing drawCircle = display.newSomething..., OR you could simply use a function not a method:
function touch(event)
...
end
Runtime:addEventListener( "touch", touch)
The latter works only because your touch function doesn't use the keyword self, which is an implicitly created variable for methods.
I think you could go with something like this:
-- I think you should define these outside the function
-- since they'll be out of scope in the "moved" phase
local myCoordx = 0
local myCoordy = 0
-- Moved this declaration outside the function
-- so it can be reused, and removed
local myCircle
function onTouch(event)
if event.phase == "began" then
myCoordx = event.x
myCoordy = event.y
elseif event.phase == "moved" then
local rad = (event.x - myCoordx) ^ 2
-- Keep in mind that this line will draw a new circle everytime you fall into the "moved" phase, keeping the old one
-- if i understood well, this is not what you want
-- local myCircle = display.newCircle(event.x, event.y, rad )
-- Try this instead, removing the old display object...
if myCircle then
myCircle:removeSelf()
myCircle = nil
end
-- ...and adding it again
myCircle = display.newCircle(event.x, event.y, rad )
myCircle:setFillColor( 1, 0, 1 )
end
end
-- Since "drawCircle" is not defined, point it directly to a function (in this case, "onTouch")
-- Runtime:addEventListener( "touch", drawCircle )
Runtime:addEventListener( "touch", onTouch )
Didn't have the chance to test the code on Simulator, i'll try it later and update the answer if needed.
UPDATE:
Tested it, and it works as i expected.
I'm all very new to this and everything in this project is just placeholders and scrap work. Some of you may recognize some of the graphics used from other Corona tutorials, but it's to help me get better, so don't be too judgemental. Here's a link to the download for the Corona Simulator: http://www.mediafire.com/download/6a78bsewgwsiyp2/GooMan.rar
Anyways, here's my issue. The jump button seems fine at first. If I hold it down, the character constantly jumps. And if I let go, he stops. If I simultaneously hold down jump while pushing one of the arrow buttons, he'll jump in that direction. However, it seems as though if I jump once, then I hit the jump button again RIGHT as the character is making contact with the ground, that he won't jump. There's a sudden lack of responsiveness. I literally have to pause slightly and wait for the character to fully hit the ground before I can make another successful jump. Why?
And here's all the relevant code for you to look at:
I have this at the beginning to help define my goo character's position:
local spriteInAir = false
local yspeed = 0
local oldypos = 0
local holding = false
I then created the jump button.
local bJump = display.newImage("Images/jumpbutton.png")
bJump.x = 445
bJump.y = 265
bJump.xScale = 0.78
bJump.yScale = 0.78
Followed up by creating an enterFrame Runtime Event which will update my goo character's position in the Y. Running the game at 60fps if that's relevant.
function checkSpeed()
yspeed = sprite.y - oldypos
oldypos = sprite.y
if yspeed == 0 then
spriteInAir = false
else
spriteInAir = true
end
end
Runtime:addEventListener( "enterFrame", checkSpeed )
Then the meat of it all. Created a function called hold which tells the game to not only make my goo character jump, but to keep my goo character constantly jumping as long as the bJump button is held down. Works perfectly. The "jumping" function is a touch event that listens for the hold function, and all of it is executed by the bJump button listening to the jumping function.
local function hold()
if holding and spriteInAir == false then
sprite:applyForce( 0, -8, sprite.x, sprite.y )
sprite:setLinearVelocity(0, -350)
spriteInAir = true
return true
end
end
local function jumping( event )
if event.phase == "began" then
display.getCurrentStage():setFocus( event.target )
event.target.isFocus = true
event.target.alpha = 0.6
Runtime:addEventListener( "enterFrame", hold )
holding = true
elseif event.target.isFocus then
if event.phase == "moved" then
elseif event.phase == "ended" then
holding = false
event.target.alpha = 1
Runtime:removeEventListener( "enterFrame", hold )
display.getCurrentStage():setFocus( nil )
event.target.isFocus = false
spriteInAir = false
return true
end
end
return true
end
bJump:addEventListener("touch",jumping)
Anyone who can help me identify this problem, I'd greatly appreciate it!
You're using a velocity check to detect if the character is on the ground. It can take a short while to set it back to zero after colliding with Box2D, so the better way to do it is to use a collision sensor:
sprite.grounded = 0 -- Use a number to detect if the sprite is on the ground; a Boolean fails if the sprite hits two ground tiles at once
function sprite:collision(event)
if "began" == event.phase then
-- If the other object is a ground object and the character is above it...
if event.other.isGround and self.contentBounds.yMax < event.other.contentBounds.yMin + 5 then
sprite.grounded = sprite.grounded + 1 -- ...register a ground collision
end
elseif "ended" == event.phase then
-- If the other object is a ground object and the character is above it...
if event.other.isGround and self.contentBounds.yMax < event.other.contentBounds.yMin + 5 then
sprite.grounded = sprite.grounded - 1 -- ...unregister a ground collision
end
end
end
sprite:addEventListener("collision")
Then, in your jump function, just check to see if sprite.grounded > 0. If it is, the player is grounded.
I have create a simple scrolling game, following closely to Mark Farkland's Game tutorial. I clearly followed his coding pattern but got to the point where I am just lost and don't why mine behaves different that his example. Everything is working fine until after a scene is purged.
I have two lua files: game.lua and gameover.lua. In game.lua exitScene I have removed all the eventlisteners. In gameover.lua enterScene, I have purged game.lua scene. When the user touched the screen it then loads game.lua file. Every objects load and refreshes like new apart from the main object which just shoots upwards.
Game.lua
local storyboard = require("storyboard")
local scene = storyboard.newScene()
local physics = require("physics")
function scene:createScene(event)
physics.start()
....
local jet = display.newImage("images/jet_normal.png")
physics.addBody(jet, "dynamic", {density=.07, bounce=0.1, friction=.2, radius=12})
local activateJets = function(self, event)
self:applyForce(0, -1.5, self.x, self.y)
end
function touchScreen(event)
local phase = event.phase
if phase == "began" then
jet.enterFrame = activateJets
Runtime:addEventListener("enterFrame", jet)
end
if phase == "ended" then
Runtime:removeEventListener("enterFrame", jet)
end
end
Runtime:addEventListener("touch", touchScreen)
end
function scene:exitScene(event)
Runtime:removeEventListener("touch", touchScreen)
Runtime:removeEventListener("enterFrame", enemy1)
Runtime:removeEventListener("collision", onColission)
end
GameOver.lua
function start(event)
if event.phase == "began" then
storyboard.gotoScene("game", "fade", 100)
end
end
function scene:enterScene(event)
storyboard.purgeAll("game")
background:addEventListener("touch", start)
end
function scene:exitScene(event)
background:removeEventListener("touch", start)
end
You need to add the jet to the current group.
function scene:createScene(event)
local group = self.view
--...
local jet = display.newImage("images/jet_normal.png")
--...
group:insert(jet)
Runtime:addEventListener("touch", touchScreen)
end
The proper cleanup will happen to the group when exitScene is triggered.
more info / different implementation:
http://docs.coronalabs.com/guide/graphics/group.html
I'm try to drag a dynamic body with gravity = 0,0 in my scene, I have a square with body type dynamic, and an image with body type static, but when drag the square over the image this have a little force but can exceed the image and pass to the other side like the images:
This is my code to drag the square:
local function dragBody( event )
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()
if "began" == phase then
stage:setFocus( body, event.id )
body.isFocus = true
body.tempJoint = physics.newJoint( "touch", body, event.x, event.y )
elseif body.isFocus then
if "moved" == phase then
body.tempJoint:setTarget( event.x, event.y )
elseif "ended" == phase or "cancelled" == phase then
stage:setFocus( body, nil )
body.isFocus = false
body.tempJoint:removeSelf()
end
end
return true
end
And this is the code to create the objects:
function scene:createScene( event )
local group = self.view
my_square = display.newImage("square.png")
my_square.x = 60
my_square.y = 60
physics.addBody(my_square, "dynamic" )
group:insert(my_square)
floor = display.newImage("piso.png")
floor.x = 160
floor.y = 240
physics.addBody(floor, "static" )
group:insert(floor)
end
thanks for help.
First, I recommed you to try:
physics.setContinuous( false )
If you did that already:
There are 3 different physics type in Physics2D engine. For drag purposes you can use "Kinematic" object type. But if its an obligation to use a Dynamic object as a dragable object, there may be bugs in collisions. But if your static object will be same every time, you can control it in drag function.
I have implemented a little mobile game using same thing that you want to achieve. Here is the link:
https://itunes.apple.com/tr/app/bricks-world/id602065172?mt=8
If you think that you want something similar in this game, just leave a comment^^ I can help further.
P.S : In the game, the controller paddle is dynamic and walls around the screen are static.
Another Solution:
local lastX, lastY
local function dragBody( event )
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()
if "began" == phase then
stage:setFocus( body, event.id )
body.isFocus = true
lastX, lastY = body.x, body.y
elseif body.isFocus then
if "moved" == phase then
-- You can change 1's with another value.
if(event.x > lastX) body.x = body.x + 1
else body.x = body.x - 1
if(event.y > lastY) body.y = body.y + 1
else body.y = body.y - 1
lastX, lastY = body.x, body.y
elseif "ended" == phase or "cancelled" == phase then
stage:setFocus( body, nil )
body.isFocus = false
end
end
return true
end
When you manually move an object you are doing so out of control of Physics and basically you can force the object to move past the static body.
What you can do is setup collision detection that will give you an event when you move the square that will tell you when to stop moving. Of course if you don't honor that in your move code you can keep moving your object.
Try putting
physics.setContinuous( false )
"By default, Box2D performs continuous collision detection, which prevents objects from "tunneling." If it were turned off, an object that moves quickly enough could potentially pass through a thin wall."
I'm working on a simple breakout game and I've problem with ball:addEventListener( "collision", removeBricks ), it works fine until the ball hits two bricks at same time, than the up/down direction (vy) switch twice, making the ball continue moving up or down.
How can do one by one addEventListener collision and disable multiple collides at once?
function removeBricks(event)
if event.other.isBrick == 1 then
vy = vy * (-1)
...
end
end
Instead of changing ball's velocity in the removeBricks function, you can just flip a flag that means "a ball has hit some bricks and should change it's direction", and then in your enterFrame handler just change the ball's speed:
local ballHasCollided = false
local function removeBricks(event)
if event.other.isBrick == 1 then
ballHasCollided = true
end
end
local function updateBallVelocity(event)
if ballHasCollided then
ballHasCollided = false
ball.vy = -ball.vy
-- ...
end
-- your game set up code somewhere
Runtime:addEventListener('enterFrame', updateBallVelocity)