Posts: 706
Threads: 92
Joined: Nov 2023
Reputation:
7
I admit I haven't looked much at the discussion, busy days  But if you half the speed on everything, you can compensate it by doing two updates per frame (so that the speed actually doesn't change). And you can divide the speed with 4 but also make 4 updates per frame.
Posts: 459
Threads: 61
Joined: Nov 2023
Reputation:
3
(05-20-2026, 04:35 PM)kevin Wrote: Final update today.....so with the paddle_speed set to rad(1), there were no issues for over 3 hours. I then left it unobserved for a total of 6 hours, and when I checked back, there were 2 balls stuck in the "L" shaped polygon - none anywhere else, including the paddles. So a definite improvement over rad(10), but still with a frustrating issue, albeit minor. I wonder whether it may be necessary to either restrict the paddle_speed further (not sure about this, as no balls got stuck in the paddles), or maybe restrict the top speed of the balls (I have noticed that if the balls bounce off of polygons at particular angles, they can do so pretty fast)?
Incidentally, thanks are due to Johnno. It was his post last week about possible cause being balls moving through single pixels that have set me on this path.
update :
- added outline for each shapes
- added delta time
Code: #win32
set window "Collision", 900, 480
set redraw off
randomize time()
'shapes
v = []
v.square = [-50, -50, 50, -50, 50, 50, -50, 50]
v.star = [0, -100, 25, -25, 100, 0, 25, 25, 0, 100, -25, 25, -100, 0, -25, -25]
v.cross = [-19,-59, -19,-19, -59,-19, -59,20, -19,20, -19,60, 20,60, 20,20, 60,20, 60,-19, 20,-19, 20,-59]
v.rectangle = [-64.5, -15.5, 64.5, -15.5, 64.5, 15.5, -64.5, 15.5]
v.tmp1 = [0, 0, 200, 0, 200, 31, 0, 31]
v.tmp2 = [0, 0, 31, 0, 31, 415, 0, 415]
visible lines = [];filledPolys = []
' MakePoly(verts, x, y, r, g, b, lines, renderList)
square = MakePoly(v.square, 460, 320, 255, 100, 100, lines, filledPolys)
star = MakePoly(v.star, 350, 150, 100, 55, 100, lines, filledPolys)
cross = MakePoly(v.cross, 175, 125, 100, 100, 255, lines, filledPolys)
rectangle = MakePoly(v.rectangle, 180, 280, 255, 50, 0, lines, filledPolys)
rectangle2 = MakePoly(v.rectangle, 550, 150, 255, 50, 0, lines, filledPolys)
rectangle3 = MakePoly(v.rectangle, 370, 430, 55, 100, 0, lines, filledPolys)
rectangle4 = MakePoly(v.rectangle, 550, 430, 55, 100, 0, lines, filledPolys)
tmp1 = MakePoly(v.tmp1, 50, 416, 255, 100, 255, lines, filledPolys)
tmp2 = MakePoly(v.tmp2, 20, 32, 255, 100, 255, lines, filledPolys)
'balls
visible objs = []
ballCount = 0
objs[ballCount] = Object(rnd(50,width()-50), 0, 16)
ballCount = ballCount + 1
'flippers
visible flipper = []
flipper.L = rad(30)
flipper.L2 = rad(-30)
flipper.R = rad(-30)
flipper.R2 = rad(30)
flipper.S = rad(10)
flipper.autoPhase = 0
'simulation
visible simDuration = 60
visible simStartTime = 0
visible simRunning = false
visible durationOptions = [30, 60, 900, 1800,3600]
visible di = 1
'flippers
flipper.Angle3 = flipper.L
flipper.Angle4 = flipper.R
rectangle3.SetAngle(flipper.Angle3)
rectangle4.SetAngle(flipper.Angle4)
'fps count by Kevin
visible framecount,lasttime = 999,fps,frametime = 0,starttime = 0,endtime = 0
'delta time
baseFrameTime = 1000 / 60
lastFrameTime = clock()
deltaTime = 1
'----------
'Main Loop
'----------
while not keydown(KEY_ESCAPE, true)
'delta time
currentTime = clock()
deltaTime = (currentTime - lastFrameTime) / baseFrameTime
if deltaTime > 2 then
deltaTime = 2
endif
lastFrameTime = currentTime
'fps added by Kevin
framecount = framecount + 1
starttime = clock()
set color 0, 0, 0; cls
'grids
set color 100, 100, 100
for gx = 0 to 640 step 30 draw line gx, 0, gx, 480
for gy = 0 to 480 step 30 draw line 0, gy, 640, gy
'shapes rotation
square.SetAngle(square.Angle() + rad(0.5) * deltaTime)
star.SetAngle(star.Angle() + rad(0.5) * deltaTime)
cross.SetAngle(cross.Angle() - rad(0.5) * deltaTime)
rectangle.SetAngle(rectangle.Angle() - rad(0.5) * deltaTime)
rectangle2.SetAngle(rectangle2.Angle() + rad(0.5) * deltaTime)
'flipper
flipper.autoPhase = flipper.autoPhase + 0.05*deltaTime
target3 = flipper.L + (flipper.L2 - flipper.L) * (sin(flipper.autoPhase) * 0.3 )
target4 = flipper.R + (flipper.R2 - flipper.R) * (sin(-flipper.autoPhase + PI) * 0.3 )
flipperStep = flipper.S * deltaTime
if flipper.Angle3 < target3
flipper.Angle3 = flipper.Angle3 + flipperStep
if flipper.Angle3 > target3 then
flipper.Angle3 = target3
endif
elseif flipper.Angle3 > target3
flipper.Angle3 = flipper.Angle3 - flipperStep
if flipper.Angle3 < target3 then
flipper.Angle3 = target3
endif
endif
if flipper.Angle4 < target4
flipper.Angle4 = flipper.Angle4 + flipperStep
if flipper.Angle4 > target4 then
flipper.Angle4 = target4
endif
elseif flipper.Angle4 > target4
flipper.Angle4 = flipper.Angle4 - flipperStep
if flipper.Angle4 < target4 then
flipper.Angle4 = target4
endif
endif
rectangle3.SetAngle(flipper.Angle3)
rectangle4.SetAngle(flipper.Angle4)
'polygon lines
foreach polygn in filledPolys polygn.DrawFilled()
set color 255,255,255; DrawLines(lines)
'coordinate label
set color 255, 255, 255
shapes = [square,star,cross,rectangle,rectangle2,rectangle3,rectangle4]
for i = 0 to sizeof(shapes)-1
DrawCoordLabel(shapes[i])
next
if simRunning then
foreach ball in objs
UpdateObject(ball, deltaTime)
DrawObject(ball)
next
i = 0
while i < ballCount
if objs[i].x > 690 or objs[i].x < -50 or objs[i].y > 530
j = i
while j < ballCount - 1
objs[j] = objs[j + 1]
j = j + 1
wend
ballCount = ballCount - 1
else
i = i + 1
endif
wend
while ballCount < 32
objs[ballCount] = Object(rnd(50,width()-50), 0, 16)
ballCount = ballCount + 1
wend
i = 0
while i < ballCount - 1
j = i + 1
while j < ballCount
ResolveBallCollision(objs[i], objs[j])
j = j + 1
wend
i = i + 1
wend
endif
'control keys
if keydown(KEY_RETURN,true)
if not simRunning then
simRunning = true
simStartTime = clock()
elseif ballCount < 32
objs[ballCount] = Object(rnd(50,width()-50), 0, 16)
ballCount = ballCount + 1
endif
endif
if keydown(KEY_D, true)
di = di - 1
if di < 0 then
di = sizeof(durationOptions) - 1
endif
simDuration = durationOptions[di]
endif
'infobox
set color 30,30,30; draw rect 635,0,260,480,true
set color 255,255,255
set caret 650,10
wln "SIMULATION"
wln "=========="
wln "FPS = " + fps
wln "ballCount is " + ballCount
wln "objs Table size is " + sizeof(objs)
wln
wln "Duration: " + durationOptions[di] + "s"
if simRunning then
elapsed = (clock() - simStartTime) / 1000
wln "Elapsed: " + int(elapsed) + "s"
'progress bar
progress = elapsed / durationOptions[di]
if progress > 1 then
progress = 1
endif
barW = int(progress * 200)
set color 255,255,255; draw rect 650, 200, 200, 10, false
set color 0,255,0; draw rect 650, 200, barW, 10, true
set color 255,255,255
if elapsed >= durationOptions[di] then
wln "COMPLETE"
wln "Press SPACE BAR to continue"
redraw
do
wait 1
until keydown(KEY_SPACE,true)
'reset section
simRunning = false
end
endif
else
wln
wln "D to adjust duration"
wln "ENTER to start"
endif
redraw
fwait 60
'fps count added by Kevin
endtime = clock()
frametime = frametime + endtime - starttime
if frametime > 1000
fps = framecount
framecount = 0
frametime = 0
endif
wend
'-----------
' Functions
'-----------
function Object(x, y, r)
return [x: x, y: y, r: r, rsqr: r*r, dx: 0, dy: 0, pdx: 0, pdy: 0]
endfunc
function DrawObject(obj)
set color 255, 255, 0
draw ellipse obj.x, obj.y, obj.r, obj.r, true
endfunc
function UpdateObject(obj, dt)
obj.dy = obj.dy + 0.1 * dt
if obj.dy > 6.0 then obj.dy = 6.0
obj.x = obj.x + obj.dx * dt
obj.y = obj.y + obj.dy * dt
PushOut(obj, lines)
endfunc
function ResolveBallCollision(b1, b2)
dx = b2.x - b1.x; dy = b2.y - b1.y
distSq = dx*dx + dy*dy
minDist = b1.r + b2.r
minDistSq = minDist * minDist
if distSq >= minDistSq or distSq = 0 then return
dist = sqr(distSq)
overlap = minDist - dist
nx = dx / dist; ny = dy / dist
b1.x = b1.x - nx * overlap * 0.5; b1.y = b1.y - ny * overlap * 0.5
b2.x = b2.x + nx * overlap * 0.5; b2.y = b2.y + ny * overlap * 0.5
dvx = b2.dx - b1.dx; dvy = b2.dy - b1.dy
dvn = dvx*nx + dvy*ny
if dvn < 0
bounce = -(1 + 0.7) * dvn * 0.3
b1.dx = b1.dx - bounce * nx; b1.dy = b1.dy - bounce * ny
b2.dx = b2.dx + bounce * nx; b2.dy = b2.dy + bounce * ny
endif
endfunc
function PushOut(obj, lines)
for iter = 1 to 4
col = false
deepest = 0
nx = 0; ny = 0
foreach ln in lines
t = (obj.x - ln[0])*ln[4] + (obj.y - ln[1])*ln[5]
if t < 0 then t = 0
if t > ln[6] then t = ln[6]
px = ln[0] + t*ln[4]; py = ln[1] + t*ln[5]
dx = obj.x - px; dy = obj.y - py
dSq = dx*dx + dy*dy
if dSq < obj.rsqr and dSq > 0.001
dist = sqr(dSq)
pen = obj.r - dist
if pen > deepest
deepest = pen
nx = dx / dist; ny = dy / dist
col = true
endif
endif
next
if not col break
obj.x = obj.x + nx * (deepest + 0.5)
obj.y = obj.y + ny * (deepest + 0.5)
vn = obj.dx * nx + obj.dy * ny
if vn < 0
obj.dx = obj.dx - 1.7 * vn * nx
obj.dy = obj.dy - 1.7 * vn * ny
endif
obj.dx = obj.dx * 0.98
obj.dy = obj.dy * 0.98
next
endfunc
function Polygon(points, x, y, r, g, b)
p = [trans: unset, org: [], verts: [], x: x, y: y, a: 0, cx: 0, cy: 0, r: r, g: g, b: b]
pcount = sizeof(points)/2
for i = 0 to pcount - 1
p.verts[sizeof(p.verts)] = points[i*2]
p.verts[sizeof(p.verts)] = points[i*2 + 1]
next
n = pcount - 1
for i = 0 to n
j = (i + 1)%pcount
p.org[sizeof(p.org)] = Line(
points[i*2], points[i*2 + 1],
points[j*2], points[j*2 + 1])
next
for i = 0 to pcount - 1
p.cx = p.cx + points[i*2]; p.cy = p.cy + points[i*2 + 1]
next
p.cx = p.cx/pcount; p.cy = p.cy/pcount
p.trans = copy(p.org)
p.AddTo = function(lines)
foreach ln in .trans lines[sizeof(lines)] = ln
endfunc
p.X = function(); return .x ;endfunc
p.Y = function(); return .y ;endfunc
p.Angle = function(); return .a ;endfunc
p.SetTransform = function(x, y, angle)
.x = x; .y = y; .a = angle; .Transform()
endfunc
p.SetPosition = function(x, y)
.x = x; .y = y; .Transform()
endfunc
p.SetAngle = function(angle)
.a = angle; .Transform()
endfunc
p.Transform = function()
RotateLines(.org, .trans, .cx, .cy, .a)
foreach ln in .trans
ln[0] = ln[0] + .x; ln[1] = ln[1] + .y
ln[2] = ln[2] + .x; ln[3] = ln[3] + .y
ln[4] = (ln[2] - ln[0])/ln[6]; ln[5] = (ln[3] - ln[1])/ln[6]
next
endfunc
p.DrawFilled = function()
set color .r, .g, .b
vcount = sizeof(.verts)/2
polyArgs = []
for i = 0 to vcount - 1
vx = .verts[i*2] - .cx; vy = .verts[i*2 + 1] - .cy
rx = vx*cos(.a) - vy*sin(.a)
ry = vx*sin(.a) + vy*cos(.a)
polyArgs[sizeof(polyArgs)] = rx + .cx + .x
polyArgs[sizeof(polyArgs)] = ry + .cy + .y
next
draw poly polyArgs, true
endfunc
p.Transform()
return p
function RotateLines(srcLines, dstLines, aroundX, aroundY, angle)
c = cos(angle); s = sin(angle)
for i = 0 to sizeof(srcLines) - 1
srcLn = srcLines[i]; dstLn = dstLines[i]
x = srcLn[0] - aroundX; y = srcLn[1] - aroundY
dstLn[0] = aroundX + x*c - y*s; dstLn[1] = aroundY + y*c + x*s
x = srcLn[2] - aroundX; y = srcLn[3] - aroundY
dstLn[2] = aroundX + x*c - y*s; dstLn[3] = aroundY + y*c + x*s
next
endfunc
endfunc
function Line(x0, y0, x1, y1)
ln = [x0, y0, x1, y1]
dx = ln[2] - ln[0]; dy = ln[3] - ln[1]
ln[6] = sqr(dx*dx + dy*dy)
ln[4] = dx/ln[6]
ln[5] = dy/ln[6]
return ln
endfunc
function MakePoly(verts, x, y, r, g, b, lines, renderList)
p = Polygon(verts, x, y, r, g, b)
p.AddTo(lines)
renderList[sizeof(renderList)] = p
return p
endfunc
function DrawCoordLabel(p)
set caret p.X(), p.Y()
wln "X"
wln (int(p.X())) + "," + (int(p.Y()))
endfunc
function DrawLines(lines)
foreach ln in lines draw line ln[0], ln[1], ln[2], ln[3]
endfunc
Posts: 755
Threads: 78
Joined: Nov 2023
Reputation:
8
Very nicely done indeed!
Logic is the beginning of wisdom.
Live long and prosper.
Posts: 196
Threads: 15
Joined: Dec 2023
Reputation:
8
Many congratulations.....I can see that you have put a lot of effort into getting this working properly, and I have now been running the code continuously for 21 hours with no issues whatsoever. A great achievement.
Posts: 706
Threads: 92
Joined: Nov 2023
Reputation:
7
Posts: 755
Threads: 78
Joined: Nov 2023
Reputation:
8
Is it my imagination or can I see the potential of a Pinball game in the making? Moo Ha Ha Ha....
Logic is the beginning of wisdom.
Live long and prosper.
Posts: 459
Threads: 61
Joined: Nov 2023
Reputation:
3
(05-23-2026, 09:58 AM)johnno56 Wrote: Is it my imagination or can I see the potential of a Pinball game in the making? Moo Ha Ha Ha....
You may refer to Kevin's work here https://www.naalaa.com/forum/thread-129.html
It's a small pinball game using Marcus' circle-line collision routines
|