Air Hockey Physics Issues

Here is the link for that tutorial: https://code.tutsplus.com/tutorials/build-an-air-hockey-game-adding-interaction–pre-45273

And here is the GitHub project: https://github.com/cameronluck/Air-Hockey

I noticed that cameronluck’s project uses the exact same dragBody function, yet requires a separate gameUI.lua file for this, while the tutorial does not seem to, and I’m unsure how that is possible.

re: Touch

You might want to take a timeout from the game and focus entirely on learning how touch event listeners are written.  There are many examples included with Corona (samples).

I will say, there is no single ‘best’ way to do this.  Also, the touch joint idea is actually pretty good.  I think that, combined with an enterFrame listener on the paddle that restricts x and y position ranges would be a real winner.

I tell you what.  I’m at work now, but later I’ll post back a mini-example with a draggable paddle, a puck, and a playboard with four sides.  Be warned I will use SSK2, because I NEVER code long-hand anymore.   Still it should be pretty easily understood.  So check back in a few hours.

re: Links

I think part of this discussion is straying into coding practices (modules, project layout, etc.) which I’d like to avoid for now, except…

The ‘cameronluck’ example is very old and uses an old-style module. 

This line in gameUI.lua is the giveaway ==> 

module(..., package.seeall)

It might contain some useful code, but definitely, do not use it as an example of modules.

As for the ‘tutsplus’ tutorial… even older.   So, neither of those is going to be a great example of project layout and module design.  Still, both might contain some applicable code.

    Thank you! I actually managed to find a simple method buried within some tutorial about water physics that completely solved my problem, at least in terms of movement.

    However, I still don’t quite understand how to restrict movement within that, so thank you, that could probably help a lot. I was planning on using sensor objects for the frame that would set the paddle’s velocity to zero upon collision, but wasn’t sure if that would throw an error or not, or just simply not work.

Downloadable mechanics demo:https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2020/03/airHockeyPaddlePuckConcept.zip

airHockeyPaddlePuckConcept.jpg

Code that is important (in main.lua; WARNING SSK CODE NOT SAME AS VANILLA CORONA ):

-- ===================================================== -- DEMO CODE BEGINS HERE -- ===================================================== local physics = require "physics" physics.start() physics.setGravity(0,0) physics.setDrawMode("hybrid") local back = newImageRect( nil, centerX, centerY, "protoBackX.png", { w = 720, h = 1386, rotation = fullw\>fullh and 90 } ) -- Sides of Play Area newImageRect( nil, left, centerY, "fillW.png", { w = 40, h = fullh, anchorX = 0, fill = \_R\_ }, { bodyType = "static", bounce = 0.5 } ) -- left newImageRect( nil, right, centerY, "fillW.png", { w = 40, h = fullh, anchorX = 1, fill = \_G\_ }, { bodyType = "static", bounce = 0.5 } ) -- right newImageRect( nil, centerX, top, "fillW.png", { w = fullw-80, h = 40, anchorY = 0, fill = \_B\_ }, { bodyType = "static", bounce = 0.5 } ) -- top newImageRect( nil, centerX, bottom, "fillW.png", { w = fullw-80, h = 40, anchorY = 1, fill = \_PURPLE\_ }, { bodyType = "static", bounce = 0.5 } ) -- bottom -- Rectangle To Show Limits of Paddle Movement local boundsWidth = fullw \* 0.5 -- we'll use this value later for the limit code local boundsHeight = fullh \* 0.5 -- we'll use this value later for the limit code local boundsRect = newRect( nil, centerX, centerY, { w = boundsWidth, h = boundsHeight, fill = \_T\_, stroke = \_Y\_, strokeWidth = 4 } ) -- Caculate x,y edges of bounds local minX = centerX - boundsWidth/2 local maxX = centerX + boundsWidth/2 local minY = centerY - boundsHeight/2 local maxY = centerY + boundsHeight/2 local paddleRadius = 40 -- Make Paddle and add phyics dragger to it. local paddle = newCircle( nil, centerX, centerY, { radius = paddleRadius, fill = \_O\_, alpha = 0.5 }, { bodyType = "dynamic" } ) -- We could use the SSK2 drag helper to add a touch joint: -- ssk.misc.addPhysicsDrag( paddle, { force = 1e6 } ) -- But that isn't quite right so we do this instead: paddle.touch = function( self, event ) local phase = event.phase local id = event.id if( phase == "began" ) then self.isFocus = true self.tempJoint = physics.newJoint( "touch", self, self.x, self.y ) self.tempJoint.maxForce = 1e6 self.tempJoint.dampingRatio = 0 self.tempJoint.frequency = 2000 display.currentStage:setFocus( self, id ) elseif( self.isFocus ) then self.tempJoint:setTarget( event.x, event.y ) if( phase == "ended" or phase == "cancelled" ) then self.isFocus = false display.currentStage:setFocus( self, nil ) display.remove( self.tempJoint ) end end return false; end; paddle:addEventListener("touch") -- Add and enterFrame Listener to help limit movement function paddle.enterFrame( self ) if (self.x \< minX + paddleRadius) then self.x = minX end if (self.x \> maxX - paddleRadius) then self.x = maxX end if (self.y \< minY) then self.y = minY end if (self.y \> maxY) then self.y = maxY end end; listen( "enterFrame", paddle ) -- Make Puck local puck = newCircle( nil, centerX, minY, { radius = paddleRadius/2, fill = \_C\_, alpha = 1 }, { bodyType = "dynamic", density = 0.1 } )

I noticed a small error and just fixed it.

If you got it, please download again.

Note: Body of paddle ended up needing to be dynamic for touch joint to work.

    I just came across another issue today. I used a somewhat similar function to restrict the movement of the paddle (referred to as “striker” in my code), and it does exactly what I need it to, but throws the error message “attempt to compare number with nil stack traceback”  when I attempt to go back to the app’s main menu (requires a scene changed that worked previously).

  I think the issue is that the event listener keeps continues to check while the scene is closing, but I’m not sure. Here is the code in question, which is within the scene:create function :

< local function limitStriker()
     local x = striker.x
     local y = striker.y

     if(x > 230) then
          striker.x = 230
     elseif(x < 90) then
          striker.x = 90
     end

     if(y > 360) then
          striker.y = 360
     elseif(y < 280) then
          striker.y = 280
     end

  end 

  Runtime:addEventListener( “enterFrame”, limitStriker ) >

Your ‘striker’ object probably isn’t valid (yet) when the code executes.

Add this line at the top of the function.

if( striker == nil or striker.getLinearVelocity == nil ) then return end

I finally have everything more or less working! (at least for one side of the playing field, I still need to duplicate everything for the opponent’s side)

However, I’ve been having trouble on reset. Everything works fine initially, but if I go back to the home scene from the game and then attempt to start a new game, for example, my puck reset function stops working. During the reset, I attempt to stop the puck before returning it to the center by using <puck:setLinearVelocity( 0, 0 )> , and this works fine initially, but results in a nill stack traceback error when attempted after restarting.

I’m assuming this is because I was sloppy during scene cleanup and missed something important, but I am unsure how to proceed. Any advice?

If more code/ a better explanation is needed please let me know, and if this is getting too off-topic I will start a new thread if necessary.