05-01-2024, 02:30 PM
This is not meant to be a proper simulation (as you will see if you run it ), but just an experiment with the terrific circle-line functions that Marcus provided a while back. I've used the functions as they were originally written by Marcus, with one small alteration to the polygon function, where I have added a fifth argument to allow me to specify a point around which the polygon is rotated, rather than the center point of the polygon (I needed this for the 2 flippers).
There a few values that can be altered in the code to change the way that the ball reacts to certain lines - I've marked some of these as "arbitrary values", and I'm sure changing these will make for a smoother game, but I've decided to move on to a new project.
Control the flippers with the A and D keys, and launch the ball using the UP arrow.
There a few values that can be altered in the code to change the way that the ball reacts to certain lines - I've marked some of these as "arbitrary values", and I'm sure changing these will make for a smoother game, but I've decided to move on to a new project.
Control the flippers with the A and D keys, and launch the ball using the UP arrow.
Code:
' Experiment.
set window "PINBALL", 480, 640
set redraw off
#win32
visible score = 0
' List of lines that objects can collide with.
left_flipper = []
right_flipper = []
l_flipper = Polygon([0,0,10,-10,60,30,60,40], 140,580, true,[0,0])
r_flipper = Polygon([0,0,-10,-10,-60,30,-60,40], 300,580, true,[0,0])
'=============================================================================
'Note -added fifth argument to Polygon - 0 rotates around center point, or
'use a 2 part table to rotate around any point in the polygon - i.e. [32,34]
' to rotate around the fourth point in the polygon array here : -
'l_flipper = Polygon([0,0,10,0,32,24,32,34,22,34,0,10], 320, 240, true,[32,34])
'==============================================================================
l_flipper.AddTo(left_flipper)
left_flipper_timer = 0
left_ang = 0
r_flipper.AddTo(right_flipper)
right_flipper_timer = 0
right_ang = 0
bouncers = []
lines = []
circles = []
table1 = Polygon([180,0,300,0,360,20,420,60,460,120,480,180,480,640,
0,640,0,180,20,120,60,60,120,20,180,0],0,0,false,0)
table1.AddTo(lines)
visible circle_hit = unset
circle1 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],100,230,true,0)
circle1.AddTo(circles)
circle2 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],225,230,true,0)
circle2.AddTo(circles)
circle3 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],350,230,true,0)
circle3.AddTo(circles)
circle4 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],162,180,true,0)
circle4.AddTo(circles)
circle5 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],287,180,true,0)
circle5.AddTo(circles)
circle6 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],130,440,true,0)
circle6.AddTo(circles)
circle7 = Polygon([0,0,9,3,13,8,15,15,13,23,9,27,0,30,-9,27,-13,23,-15,15,-13,8,-9,3],310,440,true,0)
circle7.AddTo(circles)
'additional parts of table
'lines - no bouncing
lines[sizeof(lines)] = Line(440,640,440,180)
lines[sizeof(lines)] = Line(360,640,440,590)
lines[sizeof(lines)] = Line(0,590,80,640)
'left upper curve (inner) - no bouncing
lines[sizeof(lines)] = Line(65,330,40,290)
lines[sizeof(lines)] = Line(40,290,40,200)
lines[sizeof(lines)] = Line(40,200,55,150)
lines[sizeof(lines)] = Line(55,150,95,95)
lines[sizeof(lines)] = Line(95,95,150,60)
lines[sizeof(lines)] = Line(150,60,200,45)
'right upper curve (inner) - no bouncing
lines[sizeof(lines)] = Line(300,85,315,90)
lines[sizeof(lines)] = Line(315,90,360,120)
lines[sizeof(lines)] = Line(360,120,385,160)
lines[sizeof(lines)] = Line(385,160,400,200)
lines[sizeof(lines)] = Line(40,490,40,430)
lines[sizeof(lines)] = Line(400,430,400,490)
'triangles sticking out of side - not bouncing
lines[sizeof(lines)] = Line(0,380,40,380)
lines[sizeof(lines)] = Line(0,310,40,380)
lines[sizeof(lines)] = Line(440,380,400,380)
lines[sizeof(lines)] = Line(400,380,440,310)
'bouncers
bouncers[sizeof(bouncers)] = Line(40,490,130,550)
bouncers[sizeof(bouncers)] = Line(400,490,310,550)
bouncers[sizeof(bouncers)] = Line(40,430,70,435)
bouncers[sizeof(bouncers)] = Line(400,430,370,435)
' Player.
visible obj = Object(472, 632, 16)
obj.dx = 0
obj.dy = 0
############ to calculate FPS ##########################
visible framecount,lasttime = 999,fps,frametime = 0,starttime = 0,endtime = 0,min_fps = 99999,max_fps = 0
##########################################################
while not keydown(KEY_ESCAPE)
### for FPS calc #########
framecount = framecount + 1
starttime = clock()
###########################
' Rotate obstacles.
circle1.SetAngle(circle1.Angle() + rad(3))
circle2.SetAngle(circle2.Angle() + rad(3))
circle3.SetAngle(circle3.Angle() + rad(3))
circle4.SetAngle(circle4.Angle() + rad(3))
circle5.SetAngle(circle5.Angle() + rad(3))
circle6.SetAngle(circle5.Angle() + rad(3))
circle7.SetAngle(circle5.Angle() + rad(3))
set mouse off
if obj.y >= 624 and obj.x < 440 then game_over()
obj.x = obj.x + obj.dx
obj.y = obj.y + obj.dy
'------- left flipper ------------
if keydown(KEY_A,true) and left_flipper_timer <= 0
left_flipper_timer = 16
endif
if left_flipper_timer > 0
left_flipper_timer = left_flipper_timer - 1
l_flipper.SetAngle(max(l_flipper.Angle() - rad(4),-1.2))
elseif left_flipper_timer <= 0
l_flipper.SetAngle(0)
endif
PushOut(obj, left_flipper)
if obj.pdy < 0
if l_flipper.Angle() <> 0
obj.dy = - 10
left_ang = angle_rad(l_flipper.trans[1][0],l_flipper.trans[1][1],l_flipper.trans[2][0],l_flipper.trans[2][1])
left_vecs = get_vecs(left_ang)
obj.dx = obj.dx + left_vecs[0] * 16'arbitrary figure
endif
endif
'==================================
'------- right flipper ------------
if keydown(KEY_D,true) and right_flipper_timer <= 0
right_flipper_timer = 16
endif
if right_flipper_timer > 0
right_flipper_timer = right_flipper_timer - 1
r_flipper.SetAngle(max(r_flipper.Angle() + rad(4),-1.2))
elseif right_flipper_timer <= 0
r_flipper.SetAngle(0)
endif
PushOut(obj, right_flipper)
if obj.pdy < 0
if r_flipper.Angle() <> 0
obj.dy = - 10
right_ang = angle_rad(r_flipper.trans[2][0],r_flipper.trans[2][1],r_flipper.trans[1][0],r_flipper.trans[1][1])
right_vecs = get_vecs(right_ang)
obj.dx = obj.dx + right_vecs[0] * 32'arbitrary figure
endif
endif
'==================================
PushOut(obj, bouncers)' make them bounce a little
if obj.pdx <> 0 or obj.pdy <> 0
obj.dx = obj.dx + obj.pdx*12'arbitrary figure
obj.dy = obj.dy + obj.pdy*12 'arbitrary figure
endif
PushOut(obj, lines)
'
if obj.y < 180 and obj.x > 240 and obj.dx < 0' help with initial lauch of ball
if obj.pdx <> 0 or obj.pdy <> 0
obj.dx = obj.dx + obj.pdx*4'arbitrary figure
endif
endif
if obj.y < 180 and obj.x < 240 ' help with initial lauch of ball
if obj.pdx <> 0 or obj.pdy <> 0
obj.dx = obj.dx + obj.pdx*0.3'arbitrary figure
obj.dy = obj.dy + obj.pdy*1
endif
endif
' obj.pdx and obj.pdy has now been set to the average "push direction" caused by all lines
' pushing the object around.
' Push direction y < 0 means the object is being pushed UP. In that case, set dy to 0.
if obj.pdy < 0
' If push direction y < -0.25, let the player jump.
if obj.pdy < -0.25 and keydown(KEY_UP, true) and obj.x >= 455
obj.dy = -14
endif
endif
' Apply gravity.
obj.dy = min(obj.dy + 0.1, 6)
' So ... stuff to dx.
obj.dx = obj.dx + obj.pdx*0.25 ' I have no idea
obj.dx = obj.dx*0.95
PushOut(obj, circles)
if obj.pdx <> 0 or obj.pdy <> 0
score = score + 10
obj.dx = obj.pdx * 8'arbitrary
obj.dy = obj.pdy * 8'arbitrary
endif
set color 0, 0, 0
cls
set color 255, 255, 255
DrawLines(lines)
DrawLines(circles)
DrawLines(bouncers)
DrawLines(left_flipper)
DrawLines(right_flipper)
obj.Draw()
set caret 20,10
set justification left
write "SCORE : " + score;wln
' set caret 460,10
' set justification right
' write "FPS = " + str(fps);wln
' write "MIN_FPS = " + str(min_fps);wln
' write "MAX_FPS = " + str(max_fps);wln
redraw
fwait 60
####### FPS calc ############################
endtime = clock()
frametime = frametime + endtime - starttime
if frametime > 1000 # 1 second
fps = framecount
framecount = 0
frametime = 0
if fps < min_fps then min_fps = fps
if fps > max_fps then max_fps = fps
endif
################################################
wend
function DrawLines(lines)
foreach ln in lines draw line ln[0], ln[1], ln[2], ln[3]
endfunc
function Object(x, y, r)
return [x: x, y: y, r: r, rsqr: r*r, pdx: 0, pdy: 0,
Draw: function(); draw ellipse .x, .y, .r, .r, false; endfunc]
endfunc
' Pushout
' -------
function PushOut(obj, lines)
tests = 4
obj.pdx = 0
obj.pdy = 0
for i = 1 to tests
col = false
foreach ln in lines
dp = max(0, min(ln[6], (obj.x - ln[0])*ln[4] + (obj.y - ln[1])*ln[5]))
px = ln[0] + dp*ln[4]; py = ln[1] + dp*ln[5]
dx = obj.x - px; dy = obj.y - py
d = dx*dx + dy*dy
if d < obj.rsqr
k = 1/sqr(d)
obj.x = px + dx*k*obj.r
obj.y = py + dy*k*obj.r
obj.pdx = obj.pdx + dx*k
obj.pdy = obj.pdy + dy*k
col = true
endif
next
if not col break
next
if obj.pdx or obj.pdy
k = 1/sqr(obj.pdx*obj.pdx + obj.pdy*obj.pdy)
obj.pdx = obj.pdx*k
obj.pdy = obj.pdy*k
endif
endfunc
' Polygon
' -------
' Return polygon at position x, y.
' Polygon
' -------
' Return polygon at position x, y.
'function Polygon(points, x, y, closed,rotation_point_x,rotation_point_y)
function Polygon(points, x, y, closed,rotation_point)
'========================================================================
'Note - added fifth argument to Polygon - 0 rotates around center point, or
'use a 2 part table to rotate around any point in the polygon - i.e. [32,34]
' to rotate around the fourth point in the polygon array here :-
'l_flipper = Polygon([0,0,10,0,32,24,32,34,22,34,0,10], 320, 240, true,[32,34])
'========================================================================
p = [trans: unset, org: [], x: x, y: y, a: 0, cx:0, cy: 0]
pcount = sizeof(points)/2
centerX = 0
centerY = 0
if closed n = pcount - 1
else n = pcount - 2
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
if rotation_point = 0
p.cx = p.cx + points[i*2]; p.cy = p.cy + points[i*2 + 1]
else
p.cx = rotation_point[0] * pcount 'rotation_point_x
p.cy = rotation_point[1] * pcount ' rotation_point_y
endif
next
p.cx = p.cx/pcount; p.cy = p.cy/pcount
p.trans = copy(p.org)
' AddTo
' -----
' Add to list of lines.
p.AddTo = function(lines)
foreach ln in .trans lines[sizeof(lines)] = ln
endfunc
' X
' -
' Return x coordinate.
p.X = function()
return .x
endfunc
' Y
' -
' Return y coordinate.
p.Y = function()
return .y
endfunc
' Angle
' -----
' Return angle.
p.Angle = function()
return .a
endfunc
' SetTransform
' ------------
' Set position and angle and apply.
p.SetTransform = function(x, y, angle)
.x = x
.y = y
.a = angle
.Transform()
endfunc
' SetPosition
' -----------
' Set position and apply.
p.SetPosition = function(x, y)
.x = x
.y = y
.Transform()
endfunc
' SetAngle
' --------
' Set angle and apply.
p.SetAngle = function(angle)
.a = angle
.Transform()
endfunc
' Transform
' ---------
' Update transformed polygon.
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.Transform()
return p
' RotateLines
' -----------
' Helper.
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
' Rectangle
' ---------
function Rectangle(x, y, w, h)
w = w - 1
h = h - 1
return Polygon([0, 0, w, 0, w, h, 0, h], x, y, true,0)
endfunc
' Line
' ----
' Return a new line.
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 angle_rad(x0,y0,x1,y1)
dx = x1 - x0
dy = y1 - y0
angle_r = atan2(dx,dy)
return angle_r
endfunc
'-----------------------
function get_vecs(angle_r)
vector_x = -cos(angle_r - PI)
vector_y = sin(angle_r - PI)
return [vector_x,vector_y]
endfunc
'-----------------------
function game_over()
set caret 240,320
set justification center
write "GAME OVER"
'pln "GAME OVER"
redraw
wait 4000
obj.x = 472
obj.y = 632
score = 0
endfunc