I am currently making a jumping game where there is an object at the left side of the screen, on a platform. Once the object successfully jumps and lands on the platform on the right, it does the following:
1) the platform on the right moves to the left
2) the platform on the left (that you JUST jumped off from) moves off-screen.
3) a new platform is supposed to appear at the right side of the screen, thus continuing the loop.
I have already made the functions where it allows the object to jump and show if the collision is successful or not. My problem is, the 3 things I have mentioned above happens, but it keeps on going and does not stop for the object to make the next jump. This makes the object go off screen as well, since the platforms keep moving towards the left. After debugging, I feel like the problem lies where the collision happens. This is because, once it touches the platform, the collision keeps on happening until the object is off of the platform. I was wondering if you guys can help me with this!
Here is part of my code that is relevant:
local onPlatform = false
local gameStarted = false
function playerCollision( self, event )
if ( event.phase == "began" ) then
--if hit bottom column, u get points
if event.target.type == "player" and event.other.type == "bottomColumn" then
print ("hit column")
onPlatform = true
else
--if hit anything else, gameOver
--composer.gotoScene( "restart" )
print ("hit ground")
end
end
end
function moveColumns()
for a = elements.numChildren,1,-1 do
--speed of columns moving
--if greater than -100, keep moving it to left
--puts platform at the right and stops
if (elements[a].x > display.contentWidth/1.1) then
elements[a].x = elements[a].x - 12
end
--moves platform to left after it successfully lands
if (onPlatform == true) then
if (elements[a].x > display.contentWidth/3 and elements[a].x < display.contentWidth/1.11) then
elements[a].x = elements[a].x - 12
end
end
--moves left platform to off-screen and deletes after it passes a certain X-axis
if (onPlatform == true) then
if(elements[a].x > -100 and elements[a].x < display.contentWidth/2.99) then
elements[a].x = elements[a].x - 12
--adds score if it goes past a certain X-axis at left side
elseif(elements[a].x < -100) then
mydata.score = mydata.score + 1
tb.text = mydata.score
elements[a].scoreAdded = true
elements:remove(elements[a])
elements[a] = nil
end
end
end
end
When are you calling moveColumns?? Could you just call it from within playerCollision and remove the onPlatform variable? Probably need a bit more code to help properly.
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've been trying to make a game where you're in a square and when you go to the sides, parts come up and block you.
I've gotten far to the point where it's working fine, except for a few problems:
the parts go below the square when not raised, I want them to be visible when they're not raised
the parts go down when you jump, making it easy to escape.
the parts go up too early
This is the code that deals with the wall positioning.
for _, v in pairs(model:GetChildren()) do
if string.sub(v.Name,1,4) == "Wall" then
local walls = {}
walls[v] = {v.CFrame,Vector3.new(1, 1, 1)}
game:GetService("RunService").RenderStepped:connect(function()
if(workspace[game.Players.LocalPlayer.Name]:FindFirstChild("HumanoidRootPart")) then
local mag = (v.Position - workspace[game.Players.LocalPlayer.Name]:FindFirstChild("HumanoidRootPart").Position).magnitude
sizeFactor = math.floor(mag)
v.CFrame = walls[v][1]*CFrame.new(0,-sizeFactor+(walls[v][1].Y*1.8),0)
end
end)
end
end
You can see my game here: https://www.roblox.com/games/400391033/Marble-walls
See commented code.
for _, v in pairs(model:GetChildren()) do
if string.sub(v.Name,1,4) == "Wall" then
local walls = {}
walls[v] = {v.CFrame,Vector3.new(1, 1, 1)}
game:GetService("RunService").RenderStepped:connect(function()
if(workspace[game.Players.LocalPlayer.Name]:FindFirstChild("HumanoidRootPart")) then
local mag = (v.Position - workspace[game.Players.LocalPlayer.Name]:FindFirstChild("HumanoidRootPart").Position).magnitude
if (mag <= 2) then --[[
Currently your issue is that you never actually do ANYTHING regarding magnitude
you essentially change the y-Axis as soon as the player spawns.. hence why it does it too early
kappa
]]
sizeFactor = math.floor(mag)
v.CFrame = walls[v][1]*CFrame.new(0,-sizeFactor+(walls[v][1].Y*1.8),0)
end;
end
end)
end
end
When a user swipes the screen, I need the player to move to specific position. So, if the player is in the center of the screen, and the user swipes left, the x position is -100. If the user swipes right again, the player would move back to center. Another swipe right would put the x position at + 100. A swipe right would do nothing from that point, but a swipe left would move them back to center See below for text visual: Any help would be GREATLY APPRECIATED!
swipe swipe
<----> <---->
X X X
Implementing "swipe" is pretty easy, but you have to understand touch handlers and the different event phases and the data passed to the handler to make a lot of sense for this.
A swipe is nothing more than a touch that moves in a direction and then the app responds to the action. This is similar to dragging, but a drag moves the object with the touch. The basic touch handler is something like this:
local LEFT = 50
local CENTER = display.contentCenterX
local RIGHT = display.contentWidth - 50
local object = display.newCircle( display.contentCenterX, display.contentCenterY, 25 )
local function handleSwipe( event )
if event.phase == "moved" then
local dX = event.x - event.xStart
print(event.x, event.xStart, dX)
if dX > 10 then
-- swipe right
local spot = RIGHT
if event.target.x == LEFT then
spot = CENTER
end
transition.to( event.target, {time=500, x = spot } )
elseif dX < -10 then
-- swipe left
local spot = LEFT
if event.target.x == RIGHT then
spot = CENTER
end
transition.to( event.target, {time=500, x = spot } )
end
end
return true
end
object:addEventListener( "touch", handleSwipe )
Now I used 10 px of touch movement to do this, but I normally use 5px of touch movement, adjust to taste.
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'm using CORONA SDK. I have a set of pages and I would like to slide between them using swipe left -right. The page contains a set of controls (mostly text)
What is the best way to do this slide/swipe in Corona?
Using touch events.
When the phase of event is "began" (The user just touched the screen), allow the three pages to move (the actual, the forwards and the backwards).
if event.phase == "began" then
page1.canMove = true
page2.canMove = true
page3.canMove = true
initial = {}
initial.x = event.x
end
If the pages are allowed to move:
if page1.canMove == true then
Move the three pages according to the x parameter of event.
page1.x = page1.x + event.x - initial.x
page2.x = page2.x + event.x - initial.x
page3.x = page3.x + event.x - initial.x
when the phase of event is "end" (The user release the finger), remove the permission to move.
if event.phase == "end" then
page1.canMove = false
page2.canMove = false
page3.canMove = false
end
and adjust the pages, depending on where they are.
I just invented this solution, if someone can contribute to make it more complete :D.
You can do this by using the transitions of the Storyboard
In storyboard, page is a scene, you can add transitions.
http://www.coronalabs.com/blog/2011/11/14/introducing-the-storyboard-api/