Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Pinball Problems :)
Started by toblotron Aug 17 2019 12:41 PM

12 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

My problem:

 

When the ball moves pretty fast (going downwards), and the flipper is moving, the ball sometimes passes through the flipper altogether.

 

I've implemented the movement of the flipper by having a joint with a motor, and in all other ways this seems to work well, but I can't seem to get around this problem.

 

- If I slow the motor speed down, the flipper doesn't push the ball enough.

- I have set 60 FPS, and that seemed to make the problem less common, but it still occurs pretty often.

- I've fiddled with PositionIterations and VelocityIterations, but those have no noticable effect

 

-Not sure if there's a solution to this, but I thought I'd ask - thanks for making a great tool!

 

  



[TOPIC: post.html]
#2

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 893 posts
  • Corona SDK

You can try adding "isBullet" value to the ball (and then the flippers if just the ball doesn't work).

 

https://docs.coronalabs.com/api/type/Body/isBullet.html

 

Box2D stops monitoring for collisions when an object hasn't been active in a certain period of time and this may result in fast moving objects to pass through idle/sleeping objects because it takes them some time to wake up. Adding "isBullet" to the bodies makes them stay active all the time.



[TOPIC: post.html]
#3

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

Thank you for your reply - I forgot to mention that I already have isBullet set, both on the flippers and the balls.

 

I've been trying to come up with some way to get around this problem, but right now I'm stumped.

 

I'd really like to make a decent 2D pinball game for mobile, in the vein of Pinball Dreams

 

Cheers!



[TOPIC: post.html]
#4

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 893 posts
  • Corona SDK

Can you make a small sample project that demonstrates your problem?



[TOPIC: post.html]
#5

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

I can give you a condensed version of the project - it's a good deal of ugly code, but it's probably needed to replicate the problem, if you have the patience.

 

It occurs sometimes when the bat is moving, and it's supposed to hit a ball travelling at high speed

 

Cheers! :)

 

main.lua

system.activate( "multitouch" )
local physics = require "physics"
physics.setDrawMode( "hybrid" )
physics.start()
physics.setTimeStep( 0 )
physics.setContinuous(enabled) 
physics.setGravity( 0, 44)
physics.setPositionIterations( 48 )
physics.setVelocityIterations( 64 )
 
local flipSpeed = 1000
 
local frameGroup = display.newGroup()
frameGroup.anchorX = 0.5
 
-- walls and stuff
physics.addBody(display.newRect(frameGroup,-5,-1000,2200,20),"static",{ density = 1.0, friction = 0.5, bounce = 0.7})
physics.addBody(display.newRect(frameGroup,-5,-5,20,2000),"static",{ density = 1.0, friction = 0.5, bounce = 0.7})
physics.addBody(display.newRect(frameGroup,1024,-5,20,2024),"static",{ density = 1.0, friction = 0.5, bounce = 0.7})
physics.addBody(display.newRect(frameGroup,-5,1000,2209,20),"static",{ density = 1.0, friction = 0.5, bounce = 0.7})
 
local leftSlide = display.newRect(frameGroup,207,487,270,20)
leftSlide.rotation =20
physics.addBody(leftSlide,"static",wallMaterial)
 
local ldown = display.newRect(frameGroup,80,325,10,250)
physics.addBody(ldown,"static",wallMaterial)
 
local rleftSlide = display.newRect(frameGroup,808,490,270,20)
rleftSlide.rotation =-20
physics.addBody(rleftSlide,"static",wallMaterial)
 
local rldown = display.newRect(frameGroup,945,325,10,250)
physics.addBody(rldown,"static",wallMaterial)
 
local topSlide = display.newRect(frameGroup,800,-480,500,-10)
topSlide.rotation =20
topSlide.x = 500
physics.addBody(topSlide,"static",{ density = 1.0, friction = 0.5, bounce = 0.7})
topSlide.level = 2
 
local topSlide2 = display.newRect(frameGroup,800,-650,400,-10)
topSlide2.rotation =-20
topSlide2.x = 700
physics.addBody(topSlide2,"static",{ density = 1.0, friction = 0.5, bounce = 0.7})
  
--- flippers
local lx = 330
local ly = 532
 
local lfShape = {
-65,-20, 
60,-10, 
60,10, 
-65,20
}
local leftFlipper = display.newPolygon( frameGroup, lx, ly, lfShape )
leftFlipper.x = lx+83
leftFlipper.y = ly+15
local leftPivot = display.newCircle(frameGroup, lx+15, ly+15, 20 )
 
physics.addBody( leftFlipper, "dynamic", { density=10.0, friction=0.8, bounce=0.2, shape=lfShape } )
physics.addBody( leftPivot, "static", { density=2, radius=5, friction=2.5, bounce=0.5} )
leftFlipper.isBullet = true
local leftJoint = physics.newJoint( "pivot", leftPivot, leftFlipper, leftPivot.x, leftPivot.y )
leftJoint.isLimitEnabled = true
leftJoint:setRotationLimits( -20, 15) 
leftJoint.isMotorEnabled = true
leftJoint.maxMotorTorque = 100000
leftJoint.motorTorque = 70000
leftFlipper.isBullet = true
 
local rx = 690
local ry = 532
 
local rfShape = { 60,-20, -60,-10, -60,10, 60,20}
local rightFlipper = display.newPolygon( frameGroup, rx, ry, rfShape )
rightFlipper.x = rx-82
rightFlipper.y = ry+15
local rightPivot = display.newCircle(frameGroup, rx-15, ry+15, 20 )
 
physics.addBody( rightFlipper, "dynamic", { density=10.0, friction=0.8, bounce=0.1, shape=rfShape } )
physics.addBody( rightPivot, "static", { density=2, radius=5, friction=2.5, bounce=0.5} )
 
local rightJoint = physics.newJoint( "pivot", rightPivot, rightFlipper, rightPivot.x, leftPivot.y )
rightJoint.isLimitEnabled = true
rightJoint:setRotationLimits( -15, 20) 
rightJoint.isMotorEnabled = true
rightJoint.maxMotorTorque = 100000
rightJoint.motorTorque = 70000
rightFlipper.isBullet = true
 
 
 
local ball = display.newCircle(frameGroup, 0, 0, 20);
ball.x, ball.y = 90, 222;
 
physics.addBody(ball, "dynamic", {friction = 0.5, density = 2.5, bounce = 0, radius = 20});
ball.isBullet = true;
 
 
local function flipLeft()
if(leftFlipper.active == false) then
leftFlipper.active = true
end
end
 
local function flipRight()
if(rightFlipper.active == false) then
rightFlipper.active = true
end
end
 
local function dropLeft()
leftFlipper.active = false
leftJoint.motorSpeed = flipSpeed
end
 
local function dropRight()
rightFlipper.active = false
rightJoint.motorSpeed = -flipSpeed
end
 
function leftFlipper:enterFrame()
  if self.active then
leftJoint.motorSpeed = -flipSpeed
  end
end
Runtime:addEventListener("enterFrame", leftFlipper);
 
function ball:enterFrame()
  if (ball.y > 900) then
ball.x = 130
ball.y = 0
  end
  frameGroup.y = -ball.y + 400
end
Runtime:addEventListener("enterFrame", ball);
 
function rightFlipper:enterFrame()
  if self.active then
rightJoint.motorSpeed = flipSpeed
  end
end
Runtime:addEventListener("enterFrame", rightFlipper);
 
 
local function listener(event) 
 
if(event.phase == "began" or event.phase == "moved") then
if(event.x > 600) then
flipRight()
else
flipLeft()
end
elseif(event.phase == "ended" or event.phase == "cancelled") then
if(event.x > 600) then
dropRight()
else
dropLeft()
end
end
  
return true 
end 
 
local function onKeyEvent( event )
 
    local phase = event.phase
    local keyName = event.keyName
    local returnValue = false
print(phase)
if(phase == "down") then
 
if(keyName == "right") then
flipRight(event)
end
 
if(keyName == "left") then
flipLeft(event)
end
elseif(event.phase == "up") then
if(keyName == "right") then
dropRight()
end
 
if(keyName == "left") then
dropLeft()
end
 
end
end
 
-- Add the key callback
Runtime:addEventListener( "key", onKeyEvent )
Runtime:addEventListener( "touch", listener )

 

build.settings:

settings =
{
orientation =
    {
        default = "landscapeRight",
supported =
        {
            "landscapeRight"
        }
    }
}

 

config.lua

application =
{
launchPad = false,
    content =
    {
fps = 60,
width = 600,
        height = 1024,
scale = "letterbox",
        antialias = true,
    },
}


[TOPIC: post.html]
#6

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 893 posts
  • Corona SDK

So, this is again one of those cases that would have been nearly impossible to diagnose without seeing your code. Also, it is much easier for others if you just zip the necessary code files and upload them here to the forums. You can do so in the "More Reply Options".

 

Your entire issue has to do with improperly created display objects, for instance,

local topSlide2 = display.newRect(frameGroup,800,-650,400,-10)

You've set the height of the rectangle to minus 10. A rectangle's height cannot be negative! For some reason Corona allows you to draw this abomination, but the physics engine is understandably confused when you give it an object that cannot realistically exist. Take away the minus and those platforms will work.

 

As for your flipper, Corona requires polygon physics bodies to have their vertices defined in clockwise order, but this is counterclockwise:

local rfShape = { 60,-20, -60,-10, -60,10, 60,20}

Fix those issues and your issues will be fixed.

 

I'll take my upvotes and eternal fame now... well, right.. this isn't reddit. Still, it is better to always post your code from the beginning as the issue may be clear there. You'll save yourself some days of waiting next time by doing so.



[TOPIC: post.html]
#7

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

Thanks a big bunch - hope you're right!

 

I have only my own, unofficial  upvote to give, but you have it :)



[TOPIC: post.html]
#8

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

Dang it - the flippers still happily let the ball through, every once in a while :(

 

The only thing that seems to help is if I reduce the speed of the flippers down to 800 (from 1000), but if I do that, the ball will not get enough speed to get to the top of the table.

 

And if I reduce the gravity to make it easier for the ball to get to the top, the game will feel a bit slow 

 

-Thanks for all your help(!), but it seems I still can't get rid of this problem. Maybe Box2D can't handle the speeds required.. 

 

Have a nice weekend!

/TJ



[TOPIC: post.html]
#9

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 893 posts
  • Corona SDK

Can you post the code, again, for how you create the flippers? Their shapes, specifically.



[TOPIC: post.html]
#10

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

Here it is - I think the polygon of the right flipper is correct (clockwise) now

 

local lfShape = {
-65,-20, 
60,-10, 
60,10, 
-65,20
}
 
local leftFlipper = display.newPolygon( frameGroup, lx, ly, lfShape )
leftFlipper.x = lx+83
leftFlipper.y = ly+15
local leftPivot = display.newCircle(frameGroup, lx+15, ly+15, 20 )
leftFlipper.active = false
 
physics.addBody( leftFlipper, "dynamic", { density=10.0, friction=0.8, bounce=0.2, shape=lfShape } )
physics.addBody( leftPivot, "static", { density=2, radius=5, friction=2.5, bounce=0.5} )
leftFlipper.isBullet = true
local leftJoint = physics.newJoint( "pivot", leftPivot, leftFlipper, leftPivot.x, leftPivot.y )
leftJoint.isLimitEnabled = true
 
leftJoint:setRotationLimits( -20, 15) 
leftJoint.isMotorEnabled = true
leftJoint.maxMotorTorque = 100000
leftJoint.motorTorque = 70000
leftFlipper.isBullet = true
 
local rx = 690
local ry = 532
 
 
local rfShape = { 65,20, -60,10, -60,-10,65,-20}
 
local rightFlipper = display.newPolygon( frameGroup, rx, ry, rfShape )
rightFlipper.x = rx-82
rightFlipper.y = ry+15
local rightPivot = display.newCircle(frameGroup, rx-15, ry+15, 20 )
rightFlipper.active = false
 
physics.addBody( rightFlipper, "dynamic", { density=10.0, friction=0.8, bounce=0.1, shape=rfShape } )
physics.addBody( rightPivot, "static", { density=2, radius=5, friction=2.5, bounce=0.5} )
 
 
local rightJoint = physics.newJoint( "pivot", rightPivot, rightFlipper, rightPivot.x, leftPivot.y )
rightJoint.isLimitEnabled = true
rightJoint:setRotationLimits( -15, 20) 
rightJoint.isMotorEnabled = true
rightJoint.maxMotorTorque = 100000
rightJoint.motorTorque = 70000
rightFlipper.isBullet = true


[TOPIC: post.html]
#11

nick_sherman

[GLOBAL: userInfoPane.html]
nick_sherman
  • Corona Geek

  • 1,820 posts
  • Corona SDK

You could try making the physics object of the flipper 'thicker' than it appears on screen, making the ball less likely to slip past it in between physics ticks. Unfortunately this is a thing that you might have to do some ugly hacks to protect against, such as checking if the ball reaches a certain 'impossible' position in relation to the flipper while travelling between certain angles, and artificially propel the ball if so.

 

Or perhaps reduce the flipper speed as you have done and multiply the velocity of the ball by some factor once it leaves the flipper.

 

The twitch streamer Quill18 built a pinball game in Unity for Ludum Dare and had the same issue, even though in Unity you have the ability to increase the number of physics simulations per second and alter various other settings objects related to collisions. He increased it to 100 but it still happened occasionally. 



[TOPIC: post.html]
#12

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,360 posts
  • Corona SDK

for "joint power", often the issue is torque, not speed.  play with the values, see what happens - if you can achieve sufficient power via torque, then perhaps you can then decrease speed to improve stability.



[TOPIC: post.html]
#13

toblotron

[GLOBAL: userInfoPane.html]
toblotron
  • Observer

  • 9 posts
  • Corona SDK

Thanks for replying, guys! 

 

Without an exact and fair flipper, there is no point making a flipper game, so this is kind of my big problem with this project

 

"Manually" adjusting the interaction between the ball and the flipper feels like it could be a can of worms. I wonder how they did it in Pinball Dreams, with only a modest Amiga processor :)

 

I've fiddled around a good bit with torque/speed, but haven't achieved a good result yet. 

 

I've also fiddled with position and velocity-iterations, but when I put them really high, sometimes gameplay feels twitchy.. it seems to reduce the main problem, though.

 

I think my next thing to test will be to measure at what speeds the problem occurs, and then maybe limiting the max speed of the ball. I have  a hunch it will fell a bit strange when playing, though.

 

This being my first physics-based project, I kindof had the idea that Box2D would work a bit differently :) - And I'm surprised that the same problem seems to occur in Unity; I'd actually pondered making the game in Unity instead, in order to not have to deal with this problem.

 

I've had a cursory look at the Defold engine (The one used by King - seems a bit similar to Corona), and they seem to have a thng where you can project "rays" along the path of an object, which I guess is in order to avoid things like this.. maybe that is something I could try in corona, as well




[topic_controls]
[/topic_controls]