When object1 collides with object2, I want object2 to disappear without affecting the position or velocity of object1. Object1 is dynamic and object2 is static. So it would be like a bonus object hitting my main object and the bonus object should disappear without affecting anything.
Here is my code for the collision function:
local function onCollision( self,event )
--if my object hits a bonus object
if(event.object2.name == "bonus")then
--self:setLinearVelocity(0,horizontal)
--I have tried the above method but every so often I receive an error
event.object2:removeSelf()
score = score*2
scoreText.text = score --sets the new score
Runtime:removeEventListener("enterFrame", event.object2)
else
composer.gotoScene( "restart" )
Runtime:removeEventListener("touch", onObjectTouch)
end
end
UPDATE:
Try setting your bonus objects as sensors, either in this area, or when you initialize them.
event.object2.isSensor = true
OR
object2.isSensor = true
This should allow Physics & Collision Detection on object2 without any effect on other objects.
Related
I'm creating a 2D platform game using Corona SDK and I'm stuck with collisions.
Basically there is a character that runs over this ground made of blocks. This is because sometimes there can be holes in the ground.
The game is an endless one, so as the character moves forward new blocks (and holes) are dynamically added - and also removed if they goes off screen.
It works nicely but this approach works against the collision system, let me explain how.
Now that I have the ground in place I want the character to jump but only if it is touching the ground, to avoid jumping while in air.
Whenever a collision is detected between character and ground an event is fired - two times. The first time when the character is entering a ground block and the second time when the character leaves it. So when the character lands on the ground a isGround Boolean is set to true. And when - after a jump - it leaves it the flag is set to false. The problem is that every time it exits a block to enter another - walking along the ground without jumping - the flag get updated. This makes the jump based on the isGround flag less reliable. Sometimes it happens that you can't jump because isGround == false though the character is on the ground.
Ground block creation snippet
-- init() method set the sprite of the ground block and physic to that sprite
function GroundBlock:init()
self.sprite = display.newImageRect(self.path, self.width, self.height)
self.sprite.x = self.x
self.sprite.y = self.y
physics.addBody(self.sprite, 'static', {
density = 0,
friction = 0,
bounce = 0,
box = {
halfWidth = self.width / 2,
halfHeight = self.height / 2,
y = 16,
x = 0
}
})
local collisionObj = {
name = 'ground'
}
self._collision = collisionObj
self.sprite._collision = collisionObj
self.isShow = true
end
Ground placing GroundBlocks snippet
-- init() method initialize the ground with a fixed number of blocks
function Ground:init()
self.offsetX = 0
while self.offsetX < self.camera.borderRight * 2 do
self._createBlock(1)
end
self.lastCameraPos = self.camera.borderRight
end
-- update() is called once per frame
function Ground:update()
if (self.camera.borderRight - self.lastCameraPos > self._blockWidth) then
local rand = math.ceil(math.random() * 10) % 2
if self._skippedBlock >= 2 or rand == 0 then
self._createBlock(1)
self._skippedBlock = 0
else
self._createBlock(0)
self._skippedBlock = self._skippedBlock + 1
end
self.lastCameraPos = self.camera.borderRight
end
for i, block in ipairs(self.blocks) do
if block.sprite.x < self.camera.borderLeft - block.width then
table.remove(self.blocks, i)
self.camera:remove(block.sprite)
block:delete()
end
end
end
Collision detection snippet
function Character:collision(event)
if ( event.phase == "began" ) then
if event.other._collision.name == "ground" then
self.isGround = true
end
elseif ( event.phase == "ended" ) then
if event.other._collision.name == "ground" then
self.isGround = false
print('nope')
end
end
end
A solution would be to make a ground as a single imgRect but how to make holes in it?
You could simplify your code and prevent this issue from ever occurring by tracking if the character can jump instead of tracking if the character is on the ground.
For instance,
function jump( event )
if event.phase == "began" then
if canJump then
canJump = false
-- your code that makes the player jump
end
end
end
You probably use touches to determine whether the player character jumps, right? This way, you'll trigger the jump when the touch starts as long as the character has not already jumped.
You could then reset this value in your collision function by editing it slightly:
function Character:collision(event)
if event.phase == "began" then
if event.other._collision.name == "ground" then
canJump = true
end
end
end
This way, the character's ability to jump is determined by whether or not the player has pressed jump already and if the character has hit the ground since the last jump.
This kind of approach also gives you the ability to pivot towards implementing mechanics like double jump. If instead of using a boolean canJump variable you chose to use a number variable, e.g. jumpsLeft, you could reduce the number of jumps left every time the character jumps and only let the character jump if jumpsLeft is larger than 0. Then you'd simply reset the value back to 1 (or whatever you'd want upon hitting the ground).
I am making a game with a guy that collects things, like coins. I want to detect the collision between these two, so I can remove the coin, but I don't want the coin to interact with the character, because right now it is slowing him down slightly. It should still interact with the ground before the collision though. Thanks for your help!
function createCoin()
for i = 1, 10 do
coin = display.newCircle(0, 0, 16)
coin.x = totallength - 1000 + i * 100
coin.y = totalheight - 200
physics.addBody(coin,
{bounce = 0, friction = 1, density = 0}
)
game:insert(coin)
coin.myName = "coin"
end
end
createCoin()
local function onCollision(event)
if event.phase == "began" then
if (event.object1.myName == "coin" and
event.object2.myName == "wheel") then
event.object1:removeSelf();
end
end
end
You cannot remove objects involved in a collision during the collision handling: see Modifying Objects" at Collision event page. Use timer.performWithDelay() as documented. This should prevent your coin from interacting with player. If that doesn't work, you could create a "ghost" object that follows the coin everywhere (same size placement etc but not visible) and is added to physics as a sensor. A sensor does not cause collision dynamics but the event is fired. You would also need to do a delayed removal of coin if removal is desired.
I'm getting a (a nil value) error when i try to do this :
player = display.newSprite( imageSheet, "sequenceDataPlayer"..math.random(1, 7) )
Looking at a test print :
print ("sequenceDataPlayer"..math.random(1, 7) )
It prints the data oky 'sequenceDataPlayer1'
What Im i doing wrong here ?
Your print statement is just printing the string "sequenceDataPlayer" concatenated with a random number between 1 and 7.
It took me a little while to figure out how to use sprites in Corona, but here's how I do it. I'll use Player for the variables since that's what you're using.
First I create an options variable to get the frames from my Player.lua file:
optionsPlayer =
{
frames = require("player").frames,
}
Then I create a variable for the image sheet:
playerSheet = graphics.newImageSheet( "player.png", optionsPlayer )
After that, I create a variable to set up the name, the sequence of frames, the time it takes to play, and set how many times it will loop:
spriteOptionsPlayer = { name="Player", start=1, count=10, time=500, loopCount = 1}
Finally, I create the new sprite:
spriteInstancePlayer = display.newSprite( playerSheet, spriteOptionsPlayer )
Once I've done all this, I usually set up the x and y positions, xScale and yScale, and other properties along with adding it to a display group.
Last of all, then I play the sprite somewhere:
spriteInstancePlayer:play()
From what it looks like, you want to have 7 different sprites to choose from. Personally, I would just create seven different sprites using all of the steps above and then put them in a table.
sprites = { spriteInstancePlayer, spriteInstancePlayer2, spriteInstancePlayer3, etc.. }
Then when I wanted to play them, I would set the position and visibility and just do:
r = math,random(1, 7)
sprites[r].x = x position
sprites[r].y = y position
sprites[r].isVisible = true
sprites[r]:play()
Of course, then I would want to set listeners to either completely remove the sprite or set the visibility to false when it's done playing, there's a collision(you'd have to add a physics body and set that all up), or whatever else might happen...
There are probably simpler ways to do it, but that's what I do.
Hope this helps.
I am doing my first game in Corona SDK and I've been stuck for a while. I am trying to move two display objects, every object has a position property, after every move I update the position property, the problem is if I click again the object it don't show me the updated position.
I created my objects this way:
while count<=16 do
button[count] = display.newImage(count..".png")
button[count].position = count
count = count+1
end
And in my touch handler listener I want to move object 1 and 2:
local c = 1
while c <= 2 do
--HERE I DO THE MOVEMENT, THIS WORKS
transition.to( button[c], { time=200, delta=true, x=100 } )
--HERE I CHANGE THE POSITION
button[c].position = 1000
c = c+1
end
Then if I click again any of the 2 objects the position property was not updated! Thank you!
I am attempting to add/remove objects from the physics engine (addBody() and removeBody()) in an app I am working on. The app I am working on is modular so the issue is in one of two files.
The objects file (TransmitterObject) or the main file (main):
This is the relevant code for both:
main.lua
local physics = require("physics")
physics.start()
physics.setGravity(0,0)
physics.setDrawMode( "debug" )
local TransmitterObject = require("TransmitterObject")
function updateGame(event)
if(ITERATIONS % 100 == 0) then
tran1:activate() --create new physics object here
end
ITERATIONS = ITERATIONS + 1
--print(ITERATIONS)
end
Runtime:addEventListener("enterFrame", updateGame)
TransmitterObject.lua
function transmitter.new(props) --constructor
Transmitter =
{
x = props.x,
y = props.y,
receivers = props.receivers
}
return setmetatable( Transmitter, transmitter_mt )
end
function transmitter:activate()
local group = math.random(1, #self.receivers)
local receiver = math.random(1,#self.receivers[group])
local x , y = self.receivers[group][receiver][1], self.receivers[group][receiver][2]
local d = math.sqrt(math.pow((self.x-x),2) + math.pow((self.y-y),2))
local dx = math.abs(self.x - x)
local angle = math.deg(math.acos(dx/d))
local beam = display.newRect(self.x,self.y, d, 10)
beam:setReferencePoint(display.TopLeftReferencePoint)
beam.rotation = 180 + angle
beam:setFillColor(0,255,0)
beam.alpha = 0
local function add(event)
physics.addBody(beam, "static")
end
local function delete(event)
physics.removeBody(beam)
end
transition.to( beam, { time=1000, alpha=1.0, onComplete=add } )
transition.to( beam, { time=1000, delay=2500, alpha=0, onComplete=delete})
end
Now let me try to describe the issue a little better. basically every 100th time that 'enterFrame' fires I tell the transmitter object (tran1) to call its function 'activate'
which then preforms some basic math to get coordinates. Then it creates a rectangle (beam) using the calculated information and sets some properties. That is all basic stuff. Next I tell it to transition from not visible (alpha = 0) to visible over the span of 1 second. When does it is to call the function 'add' which adds the object to the physics engine. Likewise with the next line where it removes the objects.
That being said, when i set physics.setDrawMode( "debug" ) the beam object appears as a static body, but does not accept collisions. Does anyone know why the above code would not accept collisions for the beam object?
Keep in mind I have other objects that do work properly within the physics engine.
Wow, I'm answering super late!
On collisions, modifying bodies aren't supported.
What I propose you is to create a new function,
local function addBody ( event )
physics.addBody(ball, "static")
end
and in your collision event you have to add this,
timer.performWithDelay(500, addBody)
The only thing that may cause some problems it's the delay, but as the collision doesn't take too much time it should be ok.
Sorry for this necroposting,
It's just to help other people that may have that problem,
Fannick