object:applyForce problem

Hi guys, this is my game and when I start to touch the screen, the character will jump off, but currently when I do it, it is jumping countlessly. This is my full code.

-- xxx starts to jump when it is touched function xxxJump(event)      if event.phase == "began" then          xxx.enterFrame = function(self, event) self:applyForce(0, -5, self.x, self.y) end          print("Game Scene: xxxs jumps with -5")          Runtime:addEventListener("enterFrame", xxx)     print("Game Scene: xxx jumps with listener.")        elseif event.phase == "ended" then     Runtime:removeEventListener("enterFrame", xxx)         print("Game Scene: xxx ends with listener.")   end end -- "scene:create()" function scene:create( event )     local sceneGroup = self.view          -- xxx Sprite Sheet Options, width, height and number of frames     xxxImageSheet = graphics.newImageSheet("img/xxx.png", { width = 80, height = 104, numFrames = 6 })     xxx = display.newSprite(xxxImageSheet, { name="xxx", start=1, count=6, time=1000, loopCount=0, loopDirection="bounce" })     xxx.myName = "xxx"     xxx.x = -50     xxx.y = display.contentCenterY + 200     xxx:play() -- Play the animation     physics.addBody(xxx, "static", { density=.1, bounce=0.3, friction=0.1, radius=15 })     transition.to(xxx, {time = 3000, x = 150, onComplete=xxxComeToScene })     sceneGroup:insert(xxx)          -- abc Sprite Sheet Options, width, height and number of frames     abcImageSheet = graphics.newImageSheet("img/abc.png", { width = 73, height = 47, numFrames = 2 })     abc = display.newSprite(abcImageSheet, { name="abc", start=1, count=2, time=800, loopCount=0, loopDirection="bounce" })     abc.myName = "abc"     abc.x = 900     abc.y = display.contentCenterY     abc.speed = math.random(5, 10)     abc.initY = abc.y     abc.amp = math.random(50, 100)     abc.angle = math.random(1, 360)     abc:play() -- Play the animation     physics.addBody(abc, "static", { density=.1, bounce=0.3, friction=0.1, radius=20 })     transition.to(abc, { time = 2000, x = 850, onComplete=abcComeToScene })     sceneGroup:insert(abc)          --[[    -- abc Sprite Sheet Options, width, height and number of frames     abcImageSheet = graphics.newImageSheet("img/abc.png", { width = 73, height = 47, numFrames = 2 })     abc2 = display.newSprite(abcImageSheet, { name="abc2", start=1, count=2, time=800, loopCount=0, loopDirection="bounce" })     abc2.myName = "abc2"     abc2.x = 900     abc2.y = 800     abc2.speed = math.random(5, 10)     abc2.initY = abc.y     abc2.amp = math.random(20, 100)     abc2.angle = math.random(1, 360)     abc2:play() -- Play the animation     physics.addBody(abc2, "static", { density=.1, bounce=0.3, friction=0.1, radius=35 })     transition.to(abc2, { time = 2000, x = 800, onComplete=abcComeToScene })     sceneGroup:insert(abc2)    ]]--          -- bbb Sprite Sheet Options, width, height and number of frames     bbbImageSheet = graphics.newImageSheet("img/bbb.png", { width = 23, height = 20, numFrames = 2 })     bbb = display.newSprite(bbbImageSheet, { name="bbb", start=1, count=2, time=800, loopCount=0, loopDirection="bounce" })     bbb.myName = "bbb"     bbb.x = 900     bbb.y = display.contentCenterY + 100     bbb.speed = math.random(5, 10)     bbb.initY = bbb.y     bbb.amp = math.random(20, 100)     bbb.angle = math.random(1, 360)     bbb:play() -- Play the animation     physics.addBody(bbb, "static", { density=.1, bounce=0.3, friction=0.1, radius=15 })     transition.to(bbb, { time = 2000, x = 800, onComplete=abcComeToScene })     sceneGroup:insert(bbb) end -- "scene:show()" function scene:show( event )     local sceneGroup = self.view          if(event.phase == "will") then              -- hhh is moving from right to left       hhh.enterFrame = transitionFromRightToLeft       Runtime:addEventListener("enterFrame", hhh)              -- uuu is moving from right to left       uuu.enterFrame = moveFromRightToLeft       Runtime:addEventListener("enterFrame", uuu)         -- abc is moving       abc.enterFrame = abcMoves       Runtime:addEventListener("enterFrame", abc)                 bbb.enterFrame = bbbMoves       Runtime:addEventListener("enterFrame", bbb)                   -- It occurs when the screen is touched.       Runtime:addEventListener("touch", xxxJump)              xxx.collision = xxxCollide       xxx:addEventListener("collision", xxx)              abc.collision = xxxCollide       abc:addEventListener("collision", abc)              mushroomRed.collision = xxxCollide       mushroomRed:addEventListener("collision", mushroomRed)              bbb.collision = xxxCollide       bbb:addEventListener("collision", bbb)            elseif(event.phase == "did") then            end               end -- "scene:hide()" function scene:hide( event )     local sceneGroup = self.view          if (event.phase == "will") then              Runtime:removeEventListener("enterFrame", hhh)       Runtime:removeEventListener("enterFrame", uuu)       Runtime:removeEventListener("enterFrame", abc)       Runtime:removeEventListener("enterFrame", bbb)       Runtime:removeEventListener("touch", xxxJump)            xxx:removeEventListener("collision", xxx)       abc:removeEventListener("collision", abc)       mushroomRed:removeEventListener("collision", mushroomRed)            bbb:removeEventListener("collision", bbb)     elseif (event.phase == "did") then       -- Needs to put for did     end      end -- "scene:destroy()" function scene:destroy(event)     local sceneGroup = self.view end -- Listener setup scene:addEventListener("create", scene ) scene:addEventListener("show", scene ) scene:addEventListener("hide", scene ) scene:addEventListener("destroy", scene ) return scene

Edited: working code, credit to roaminggamer

function objectJump(event)      if event.phase == "began" then     object.enterFrame =        function(self, event)         -- self:applyForce(0 \* self.mass, -200 \* self.mass, self.x, self.y)             -- object:setLinearVelocity(0, -400) -- object is jumping with -300 to object.y         object:applyLinearImpulse(0, -200, object.x, object.y) -- This is working and it jumps for -200 y position       end          print("Game Scene: objects jumps with -200")             Runtime:addEventListener("enterFrame", object)     print("Game Scene: object jumps with listener.")        elseif event.phase == "ended" then          Runtime:removeEventListener("enterFrame", object)        object:setLinearVelocity(0, 0)     print("Game Scene: object ends with listener.")   end end
  1. Please don’t post all your code like that.  It’s too much to read.  Just post the part that is relevant or provide a link for folks to download it.  (Take this advice with a grain of salt.  I know that it is hard sometimes to know what is relevant.)

  2. Thanks for formatting it  though.  I do appreciate that.

  3.   This problem is about touching and forces…, so the relevant parts seem to be( scroll scroll scroll, look look, scroll… grumble):

  • xxxJump() - Your touch handler

    – xxx starts to jump when it is touched function xxxJump(event) if event.phase == “began” then xxx.enterFrame = function(self, event) self:applyForce(0, -5, self.x, self.y) end print(“Game Scene: xxxs jumps with -5”) Runtime:addEventListener(“enterFrame”, xxx) print(“Game Scene: xxx jumps with listener.”) elseif event.phase == “ended” then Runtime:removeEventListener(“enterFrame”, xxx) print(“Game Scene: xxx ends with listener.”) end end

The problem is you’re applying a force every frame so as long as you hold the touch, the object will accelerate.  Also, you’re not accounting for mass so the amount of acceleration will be goofed up if you later change the size of your object.

I’m also not seeing a damping statement so the object will never slow down.

I’d make these changes:

  1. Add a linearDamping to your player:

    xxx = display.newSprite(xxxImageSheet, { name=“xxx”, start=1, count=6, time=1000, loopCount=0, loopDirection=“bounce” }) … physics.addBody(xxx, “static”, { density=.1, bounce=0.3, friction=0.1, radius=15 }) … x.linearDamping = 1.0 – experiement with values here

  2. Account for mass in your force:

    function xxxJump(event) … xxx.enterFrame = function(self, event) self:applyForce( 0 * self.mass, -5 * self.mass, self.x, self.y) end … end

Note: Even this will continue to accelerate, but with damping you can control that to some degree.

If you need to limit velocity, you’ll need to do some 2D Math.

I mean when the user touches the screen, how to make the character not to go beyond it’s screen x and y? And where to put that function in which function?

-- Not tested, may have typos local function keepOnScreen( obj, buffer ) buffer = buffer or 0 local minX = display.contentCenterX - display.actualContentWidth/2 + obj.contentWidth/2 + buffer local maxX = display.contentCenterX + display.actualContentWidth/2 - obj.contentWidth/2 - buffer local minY = display.contentCenterY - display.actualContentHeight/2 + obj.contentHeight/2 + buffer local maxY = display.contentCenterY + display.actualContentHeight/2 - obj.contentHeight/2 - buffer if( obj.x \< minX ) then obj.x = minX end if( obj.x \> maxX ) then obj.x = maxX end if( obj.y \< minY ) then obj.y = minY end if( obj.y \> maxY ) then obj.y = maxY end end

keepOnScreen( xxx )

Note: You’re doing great, but I think you could have figured this out on your own.  Everything you need is in the docs:

You should do some reading to buff up on the the basics of Corona display.* and other key modules.

I changed the function with

self:setLinearVelocity(0, -400)

in xxxJump and it is what I was looking for. Thanks :slight_smile:

@Roaminggamer, I mean where to put that function? By just calling it and can use or need to put inside some enterFrame listener to use it? 

If you use setLinearVelocity() be sure to later set the velocity to zero or it will keep moving forever.

i.e.  instead of using a enterFrame() with a force, do the following:

  1. Where you used to ‘attach’ (start listening for) enterFrame, setLinearVelocity(0,-400) like you showed above.
  2. Where you used to ‘detach’ (stop listening for) enterFrame, setLinearVelocity(0,0)

I would add a enterFrame listener to the player (xxx) and have it run forever.  Then, in the enterFrame listener put a derivative of the code I wrote.

It is very brute force, but will keep the object on screen.

Note: For ‘jumping’, applyLinearImpulse() is more suitable than velocity or force.

I write like

local function jumperOnScreen(self, event) &nbsp; print(string.format("Game Scene: X: %d, Y: %d", self.x, self.y)) &nbsp; &nbsp;buffer = buffer or 0 &nbsp; &nbsp;local minX = display.contentCenterX - display.actualContentWidth/2 + self.contentWidth/2 + buffer &nbsp; &nbsp;local maxX = display.contentCenterX + display.actualContentWidth/2 - self.contentWidth/2 - buffer &nbsp; &nbsp;local minY = display.contentCenterY - display.actualContentHeight/2 + self.contentHeight/2 + buffer &nbsp; &nbsp;local maxY = display.contentCenterY + display.actualContentHeight/2 - self.contentHeight/2 - buffer &nbsp; &nbsp;if( self.x \< minX ) then self.x = minX end &nbsp; &nbsp;if( self.x \> maxX ) then self.x = maxX &nbsp;end &nbsp; &nbsp;if( self.y \< minY ) then self.y = minY end &nbsp; &nbsp;if( self.y \> maxY ) then self.y = maxY end end

jumper.enterFrame =&nbsp; &nbsp; &nbsp; &nbsp; function(self, event) &nbsp; &nbsp; &nbsp; &nbsp; -- self:applyForce(0 \* self.mass, -200 \* self.mass, self.x, self.y) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- jumper:setLinearVelocity(0, -400) -- Jumper is jumping with -300 to jumper.y &nbsp; &nbsp; &nbsp; &nbsp; jumper:applyLinearImpulse(0, -200, jumper.x, jumper.y) &nbsp; &nbsp; &nbsp; &nbsp; jumperOnScreen(jumper) &nbsp; &nbsp; &nbsp; end

For every time, it doesn’t go beyond the minY, but for MaxY, it goes beyond the screen. So when I jump, it is not going beyond the roof but it can goes until the bottom and cannot see it anymore

No.  Don’t put an impulse in an enterFrame call.  That isn’t what I suggested.

Give me 10 and I’ll post an example.

** UPDATE ** 10 minutes

This is how I wrote for the function. It is still not working for my project though I think I need to call this function inside some functions or?? :smiley:

 minX = 50 &nbsp; maxX = display.contentWidth &nbsp; minY = 50 &nbsp; maxY = display.contentHeight - 150 &nbsp;&nbsp; &nbsp; -- checks the x = 0 &nbsp; if self.x - self.width \* 0.5 \< minX then &nbsp; &nbsp; self.x = minX &nbsp; &nbsp;&nbsp; &nbsp; elseif self.x - self.width \* 0.5 \> maxX then &nbsp; &nbsp; self.x = maxX &nbsp; &nbsp;&nbsp; &nbsp; elseif self.y - self.height \* 0.5 \< minY then self.y = minY &nbsp; &nbsp;&nbsp; &nbsp; elseif self.y - self.height \* 0.5 \> maxY then &nbsp; &nbsp; self.y = maxY

Gives you 10 bucks or 10 minutes?? :smiley:

Here look at this example:

http://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2016/05/jump.zip

-- ============================================================= -- Your Copyright Statement Goes Here -- ============================================================= -- main.lua -- ============================================================= -- Empty Framework - Generated using 'EAT - Frameworks' -- https://gumroad.com/l/EATFrameOneTime -- ============================================================= io.output():setvbuf("no") display.setStatusBar(display.HiddenStatusBar) local function stayOnScreen( obj ) buffer = buffer or 0 local minX = display.contentCenterX - display.actualContentWidth/2 + obj.contentWidth/2 + buffer local maxX = display.contentCenterX + display.actualContentWidth/2 - obj.contentWidth/2 - buffer local minY = display.contentCenterY - display.actualContentHeight/2 + obj.contentHeight/2 + buffer local maxY = display.contentCenterY + display.actualContentHeight/2 - obj.contentHeight/2 - buffer local correctedX = false local correctedY = false if( obj.x \< minX ) then obj.x = minX; correctedX = true end if( obj.x \> maxX ) then obj.x = maxX; correctedX = true end if( obj.y \< minY ) then obj.y = minY; correctedY = true end if( obj.y \> maxY ) then obj.y = maxY; correctedY = true end local vx,vy = obj:getLinearVelocity() if( correctedX ) then vx = 0 end if( correctedY ) then vy = 0 end if( correctedX or correctedY ) then obj:setLinearVelocity( vx, vy ) end end local physics = require "physics" physics.start() local boy = display.newImageRect( "images/boy.png", 80, 90 ) boy.x = display.contentCenterX boy.y = display.contentCenterY + 300 physics.addBody( boy, "dynamic" ) function boy.enterFrame( self ) stayOnScreen( self ) end Runtime:addEventListener( "enterFrame", boy ) function boy.touch( self, event ) if( event.phase == "ended") then self:applyLinearImpulse( 0, -10 \* self.mass, self.x, self.y ) end return true end Runtime:addEventListener( "touch", boy )

Note: This will be my last answer for the day.  I’ve gotta get back to work.

Ok, thanks, me too. I need to sleep so this post is my last post. :slight_smile: Thanks by the way. :slight_smile:

  1. Please don’t post all your code like that.  It’s too much to read.  Just post the part that is relevant or provide a link for folks to download it.  (Take this advice with a grain of salt.  I know that it is hard sometimes to know what is relevant.)

  2. Thanks for formatting it  though.  I do appreciate that.

  3.   This problem is about touching and forces…, so the relevant parts seem to be( scroll scroll scroll, look look, scroll… grumble):

  • xxxJump() - Your touch handler

    – xxx starts to jump when it is touched function xxxJump(event) if event.phase == “began” then xxx.enterFrame = function(self, event) self:applyForce(0, -5, self.x, self.y) end print(“Game Scene: xxxs jumps with -5”) Runtime:addEventListener(“enterFrame”, xxx) print(“Game Scene: xxx jumps with listener.”) elseif event.phase == “ended” then Runtime:removeEventListener(“enterFrame”, xxx) print(“Game Scene: xxx ends with listener.”) end end

The problem is you’re applying a force every frame so as long as you hold the touch, the object will accelerate.  Also, you’re not accounting for mass so the amount of acceleration will be goofed up if you later change the size of your object.

I’m also not seeing a damping statement so the object will never slow down.

I’d make these changes:

  1. Add a linearDamping to your player:

    xxx = display.newSprite(xxxImageSheet, { name=“xxx”, start=1, count=6, time=1000, loopCount=0, loopDirection=“bounce” }) … physics.addBody(xxx, “static”, { density=.1, bounce=0.3, friction=0.1, radius=15 }) … x.linearDamping = 1.0 – experiement with values here

  2. Account for mass in your force:

    function xxxJump(event) … xxx.enterFrame = function(self, event) self:applyForce( 0 * self.mass, -5 * self.mass, self.x, self.y) end … end

Note: Even this will continue to accelerate, but with damping you can control that to some degree.

If you need to limit velocity, you’ll need to do some 2D Math.

I mean when the user touches the screen, how to make the character not to go beyond it’s screen x and y? And where to put that function in which function?

-- Not tested, may have typos local function keepOnScreen( obj, buffer ) buffer = buffer or 0 local minX = display.contentCenterX - display.actualContentWidth/2 + obj.contentWidth/2 + buffer local maxX = display.contentCenterX + display.actualContentWidth/2 - obj.contentWidth/2 - buffer local minY = display.contentCenterY - display.actualContentHeight/2 + obj.contentHeight/2 + buffer local maxY = display.contentCenterY + display.actualContentHeight/2 - obj.contentHeight/2 - buffer if( obj.x \< minX ) then obj.x = minX end if( obj.x \> maxX ) then obj.x = maxX end if( obj.y \< minY ) then obj.y = minY end if( obj.y \> maxY ) then obj.y = maxY end end

keepOnScreen( xxx )

Note: You’re doing great, but I think you could have figured this out on your own.  Everything you need is in the docs:

You should do some reading to buff up on the the basics of Corona display.* and other key modules.

I changed the function with

self:setLinearVelocity(0, -400)

in xxxJump and it is what I was looking for. Thanks :slight_smile: