Drag physic object in corona sdk - lua

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."

Related

lua eventListener is calling method four times instead of just once

In my game (using Corona SDK) I want to spawn an enemy every 3 seconds. My spawnBlob creates only 1 blob at a time but four are appearing on screen at once every 3 seconds. I'm new at lua and corona and am having trouble tracing this code and figuring how things are being called four times when they shouldn't be. I am also having this problem with collision detection where i print the position where two objects collide. When two objects collide however, 4 lines of the print statement get printed and I don't know what is going on.
Is there an event.phase for this timer I should be utilizing similar to the began for touch events?
local allBlobs = {} -- global variable
function spawnBlob( event )
allBlobs[#allBlobs + 1] = display.newSprite ( mainGroup, mySheet3,
sequenceDataBlob)
local blob = allBlobs[#allBlobs]
physics.addBody( blob, { density=0.3, friction=0.6 })
blob.x = math.random(0, display.contentWidth)
blob.y = -80
blob.myName = "blob" .. #allBlobs
physics.addBody(blob, "dynamic", {density=0.1, bounce=0, friction=.2,
radius=128})
blob:play()
end
--scene:create( event ) contains mainGroup, spriteSheets and buttons
timer.performWithDelay( 3000, spawnBlob, 0) --in scene:show(event)
--scene:hide (event ) is empty
--scene:destroy ( event ) is empty
scene:addEventListener("create", scene)
scene:addEventListener("show", scene)
scene:addEventListener("hide", scene)
scene:addEventListener("destroy", scene)
return scene
In the scene:show function you can use
local phase = event.phase
if (phase == "will") then
--call your listeners
elseif (phase == "did") then
end

Can someone test my Corona project and identify the issue with my jump function?

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.

Corona SDK - Resize a moving physics body

I've been trying to create a simple game where the player controls a physics body that increases in size when it collides with other objects. From what I understand it's not possible to scale the actual physics body directly, instead I'm trying to create a new one using the parameters of the original one. However, when created a new physics body of the appropriate size has been created, I lose the ability to move it around. Any form of input would be highly appriciated, as I can't figure out what to do (I'm still very new to this).
Here's what I've got so far:
function movePlayer(event)
if "began" == event.phase then
player.isFocus = true
player.x0 = event.x - player.x
player.y0 = event.y - player.y
elseif player.isFocus == true then
if "moved" == event.phase then
player.x = event.x - player.x0
player.y = event.y - player.y0
stayOnScreen( player )
elseif "ended" == phase or "cancelled" == phase then
player.isFocus = false
end
end
return true
end
function checks()
if player.resize == true then
local player2 = createPlayer(player.x, player.y, player.xScale, player.yScale, player.rotation)
if player.isFocus == true then
player2.isFocus = player.isFocus
player2.x0 = player.x0
player2.y0 = player.y0
end
player2.resize = false
player:removeSelf()
player = player2
end
end
player:addEventListener("touch", movePlayer)
Runtime:addEventListener( "enterFrame", checks)
Thanks in advance!
Edit:
Here's the code that generates a new player and adds a physics body:
function createPlayer( x, y, xScale, yScale, rotation)
local player = display.newImageRect("images/p1.png", 71, 71)
player.x = x
player.y = y
player.xScale = xScale
player.yScale = yScale
local playerCollisionFilter = { categoryBits = 2, maskBits = 5 }
local playerBodyElement = { filter=playerCollisionFilter, radius = (player.xScale * (player.width *0.5)) }
player.objectType = "player"
physics.addBody ( player, "dynamic", playerBodyElement )
player.isBullet = true
player.isSleepingAllowed = false
player.rotation = rotation
player.resize = false
return player
end
It looks like a problem with your "touch" event handler to me. Specifically, this line:
player:addEventListener("touch", movePlayer)
is only executed once, when the main Lua file is load. That handler needs to be removed from player and added to player2 when you're making the change to player2 in the checks() function.
After you do player:removeSelf(), the physics engine will no longer have a reference to player (because the removeSelf also unregisters from physics). So you have to make player (player2) a physics body:
physics.addBody(player2, ...)
where ... represents same parameters as used when you added player the first time.
Update:
OK so you've already taken care of addBody. I can't see any obvious problem with your code, but you are using the same var name "player" in a few places so its hard to be sure. Try using event.target instead of player in handler, see if that helps. For maintainability consider naming the locals like newPlayer, a give unique name for the global like rocket or person whatever your player actually is.

Update the target coordinates while transitioning

I am making a game in corona and I am facing a problem. I have a circle on screen and I want it to follow the touch coordinates continuously. I am using transition.to function to do so but the thing is, whenever this function get a coordinate, it completes the transition even if the coordinates are updated during the transition.
if event.phase == "began" or event.phase == "moved" then
follow = true
touchX = event.x; touchY = event.y
elseif event.phase == "ended" then
follow = false
end
And in another function, I am doing this
if follow == true then
transition.to(circle, {time = 500, x = touchX, y = touchY, transition = easing.inOutQuad})
end
The code works fine for simple touch but I want the circle to follow the touch even when it's moving.
There are some examples which may solve your problem.
Refer:
1) Flight Path posted by carlos in corona Community.
2) Move Object through a path by renvis
Sample:
local circle = display.newCircle(10,10,20)
circle.x = 160
circle.y = 160
local olderTransition
local function moveCircle(e)
if olderTransition ~= nil then
transition.cancel( olderTransition )
end
olderTransition = transition.to(circle,{time=100,x=e.x,y=e.y})
end
Runtime:addEventListener("touch",moveCircle)
Keep Coding.......... :)
You cant add a new transition to an object, which already in a transition. Thats why you should cancel the older transition first. You can try :
local olderTransition -- This should be visible outside of your function
local function blabla()
if follow == true then
if olderTransition ~= nil then
transition.cancel( olderTransition )
end
olderTransition = transition.to(circle, {time = 500, x = touchX, y = touchY, transition = easing.inOutQuad, onComplete = function() olderTransition = nil end })
end
end
Btw If you want to drag and drop objects, transitions are bad in performance way

Corona SDK - change a variable for the duration of a drag event

I have a "seed" object which has an instance method seed:fall() which is called by my update function (which runs every frame). I've got a "touch" event listener on it so the user can drag it around. When it's being dragged, however, it's still trying to fall, which makes the drag interaction glitchy.
I've added an instance variable to my seed "class" called seed.falling. The fall() function now checks that seed.falling is true before moving the seed down the screen. The next step is to set seed.falling to false when the drag starts, and then set it back to true when the drag stops. I can't figure out this last part though.
Any ideas anyone? Is there a "stop dragging" event i could set a listener for, to switch seed.falling back on? Is there a nicer way of achieving what i want?
physics.start()
physics.setGravity(0,1)
local dd = display.newRect(400,100,200,200)
physics.addBody(dd,"dynamic")
dd:addEventListener("touch", function(event)
if event.phase == "began" then
dd.bodyType = "static"
elseif event.phase == "moved" then
dd.x,dd.y = event.x,event.y
elseif event.phase == "ended" then
dd.bodyType = "dynamic"
end
end)
I think this case is what you want?
Just for the record, here's how i solved this.
Basically i have an attribute "seed.falling" which the seed:fall method checks before moving the seed. And i set that attribute to false if we're not at the "ended" phase of the drag event, which stops the seed falling.
function Seed:new(x,y)
print("Seed:new, x = " .. (x or nil) .. ", y = " .. (y or nil) )
local seed = display.newImage("seed_icon.png")
seed.x = x
seed.y = y
seed.name = 'seed'
seed.falling = true
function seed:fall()
if(self.falling) then
self.y = self.y + 1
end
end
function seed:drag(event)
seed.x = event.x
seed.y = event.y
if(event.phase == "ended") then
seed.falling = true
else
seed.falling = false
end
end
seed:addEventListener("touch", drag)
return seed
end
function drag(event)
seed = event.target
seed:drag(event)
end
It's not a very good solution i think as it leaves the seed stranded on the screen sometimes - possibly when you drag a seed over another falling seed.

Resources