I started this ages ago and just now dug it up and threw in scoring. It was for a little challenge a while ago to make a game with only ovals, lines, and text.
I did it finally!
Basically, it's Pong in a circle. The paddles looked a bit better on my old and dark screen, but they'll probably look fine on most people's screens anyway.
There are up to 5 players in the game. The first two are controlled using W,A,S,D and the arrow keys.
Scoring is simple: Hit the ball out of the ring without hitting the rectangle in the center. (I came up with that while coding, because I realized that the other method I devised would be absurd).
I've noticed that it's kind of interesting trying to play both players at once... That may make an interesting gameplay element eventually.
Um... It's not finished, but it will be a while until I dig in and and add networking for the other 3 players, powerups, and/or AI.
Yes, I know the source code is a mess and the only clean part (the circle and line bouncing functions) is not mine.
I did it finally!
Basically, it's Pong in a circle. The paddles looked a bit better on my old and dark screen, but they'll probably look fine on most people's screens anyway.
There are up to 5 players in the game. The first two are controlled using W,A,S,D and the arrow keys.
Scoring is simple: Hit the ball out of the ring without hitting the rectangle in the center. (I came up with that while coding, because I realized that the other method I devised would be absurd).
I've noticed that it's kind of interesting trying to play both players at once... That may make an interesting gameplay element eventually.
Um... It's not finished, but it will be a while until I dig in and and add networking for the other 3 players, powerups, and/or AI.
;Ping. (Pong? Hah! PING!!) ;By Dylan McCall ;Name explanation: Ping is based off of Pong, but rather than build a Pong clone I did something quite crazy. ;I realized that Pong is probably named after Ping-Pong, and so rather than have the name Pong again, ;why not borrow the other word? Thus, it is called Ping. AppTitle "Ping. By Dylan McCall" SeedRnd(MilliSecs()) Type Person End Type Type Player Field name$ Field Number Field Angle[1] Field Hit Field Score Field Lane[1] Field Paddles End Type Global playercount = Input("Input Player Count: (1-6) ") ;Global playercount = 2 Dim pl.player(playercount - 1) Dim plMarkers.cline(playercount-1,1) angleInc = 360/(playercount*2) Angle = 0 ;I should have commented... For n = 0 To playercount - 1 pl.player(n) = New player pl(n)\Number=n b = n + 1 pl(n)\name$= "Player " + b pl(n)\Paddles=2 For pa = 0 To pl(n)\Paddles-1 plMarkers(n,pa) = LineNew(0,0,0,0) plMarkers(n,pa)\Owner = pl.player(n) Select b Case 1 plMarkers(n,pa)\r = 150 : plMarkers(n,pa)\g = 150 : plMarkers(n,pa)\b = 255 Case 2 plMarkers(n,pa)\r = 255 : plMarkers(n,pa)\g = 150 : plMarkers(n,pa)\b = 150 Case 3 plMarkers(n,pa)\r = 150 : plMarkers(n,pa)\g = 255 : plMarkers(n,pa)\b = 150 Case 4 plMarkers(n,pa)\r = 255 : plMarkers(n,pa)\g = 255 : plMarkers(n,pa)\b = 150 Case 5 plMarkers(n,pa)\r = 150 : plMarkers(n,pa)\g = 255 : plMarkers(n,pa)\b = 255 Case 6 plMarkers(n,pa)\r = 255 : plMarkers(n,pa)\g = 255 : plMarkers(n,pa)\b = 255 End Select pl(n)\angle[pa] = angle Angle = Angle + angleInc Next Next Global CRectX,CRectY,CRectW,CRectH ;Draw the rectangle in the center centerRect(325,250,150,100) Const RingX = 5 Const RingY = 5 Const RingW = 790 Const RingH = 590 Global ballCount = 1 For t = 1 To ballCount BallStart() Next DefFont = LoadFont("Arial",10) Graphics 800,600,False,2 SetBuffer BackBuffer() ; Create the timer to track speed frameTimer=CreateTimer(100) ;main loop While Not KeyDown(1) WaitTimer(frameTimer) ; Pause until the timer reaches 60 UpdateHumanMovement() drawWorld() UpdateText() Flip Cls Wend End Function UpdateHumanMovement() If KeyDown(205) If Not PaddleCollides(0,0,1) pl(0)\angle[0] = pl(0)\angle[0] + 1 If pl(0)\angle[0] > 360 Then pl(0)\angle[0] = 0 If pl(0)\angle[0] < 0 Then pl(0)\angle[0] = 359 EndIf EndIf If KeyDown(203) If Not PaddleCollides(0,0,-1) pl(0)\angle[0] = pl(0)\angle[0] - 1 If pl(0)\angle[0] > 360 Then pl(0)\angle[0] = 0 If pl(0)\angle[0] < 0 Then pl(0)\angle[0] = 359 EndIf EndIf If KeyHit(200) If Not PaddleCollides(0,0,10,True) If pl(0)\lane[0] < 30 pl(0)\lane[0] = pl(0)\lane[0] + 10 EndIf EndIf EndIf If KeyHit(208) If Not PaddleCollides(0,0,-10,True) If pl(0)\lane[0] > 0 pl(0)\lane[0] = pl(0)\lane[0] - 10 EndIf EndIf EndIf If KeyDown(30) If Not PaddleCollides(0,1,1) pl(0)\angle[1] = pl(0)\angle[1] + 1 If pl(0)\angle[1] > 360 Then pl(0)\angle[1] = 0 If pl(0)\angle[1] < 0 Then pl(0)\angle[1] = 359 EndIf EndIf If KeyDown(32) If Not PaddleCollides(0,1,-1) pl(0)\angle[1] = pl(0)\angle[1] - 1 If pl(0)\angle[1] > 360 Then pl(0)\angle[1] = 0 If pl(0)\angle[1] < 0 Then pl(0)\angle[1] = 359 EndIf EndIf If KeyHit(17) If Not PaddleCollides(0,1,10,True) If pl(0)\lane[1] < 30 pl(0)\lane[1] = pl(0)\lane[1] + 10 EndIf EndIf EndIf If KeyHit(31) If Not PaddleCollides(0,1,-10,True) If pl(0)\lane[1] > 0 pl(0)\lane[1] = pl(0)\lane[1] - 10 EndIf EndIf EndIf End Function Function PaddleCollides(p,pa,dir,LaneChanging=False) Local DirC,DirB If LaneChanging Then DirC = dir Else DirC = 0 If LaneChanging Then DirB = 0 Else DirB = dir For n = 0 To PlayerCount-1 If Not n = p For pad = 0 To pl(n)\Paddles-1 If pl(n)\lane[pad] => pl(p)\lane[pa]+dirC And pl(n)\lane[pad] =< pl(p)\lane[pa]+dirC If pl(n)\angle[pad]=> pl(p)\angle[pa]-10+DirB And pl(n)\angle[pad] =< pl(p)\angle[pa]+10+DirB Then Return True EndIf Next EndIf Next Return False End Function Global ScoringPlayer Global MiddleTxtTimer Function CenterRect(x,y,w,h) l.cline = linenew(x,y,x+w,y);Top line l\b = 255 l.cline = linenew(x+w,y,x+w,y+h);Right line l\b = 255 l.cline = linenew(x,y+h,x+w,y+h);Bottom line l\b = 255 l.cline = linenew(x,y+h,x,y);Left line l\b = 255 CRectX=x:CRectY=y:CRectW=w:CRectH=h End Function Function UpdateText() If MilliSecs() < MiddleTxtTimer + 3000 Color 200,200,200 ElseIf MilliSecs() < MiddleTxtTimer + 4000 colourChange=(MilliSecs() - MiddleTxtTimer - 3000)/5 ;I doubt that this fader works as it should Color 200-colourChange,200-colourChange,200-colourChange Else Return EndIf n=ScoringPlayer Local Points$ If Abs(pl(n)\Score) = 1 Then Points$ = " Point." Else Points$ = " Points." ;If pl(n)\Score > 0 Text 330,270,pl(n)\Name$ Text 330,300,"Has "+pl(n)\Score+Points$ ;ElseIf pl(n)\Score < 0 ; Text 300,300,pl(n)\Name$ ; Text 330,300,"Has "+pl(n)\Score+Points$ ;EndIf ;n=ScoringPlayer ;Text 330,260,pl(n)\Name$+" Scores" ;If pl(n)\Score > 1 Then Text 330,300,"Has "+pl(n)\Score+" Points." ElseIf pl(n)\Score = 1 Then Text 330,300,"Has "+pl(n)\Score+" Point." End Function Function Score(plN) pl(plN)\Score = pl(plN)\Score+1 ScoringPlayer = plN MiddleTxtTimer = MilliSecs() End Function Function NegScore(plN) pl(plN)\Score = pl(plN)\Score-1 ScoringPlayer = plN MiddleTxtTimer = MilliSecs() End Function Function BallStart() .retry BallX = Rand(325,475) BallY = Rand(125,275) If RectsOverlap(BallX,BallY,2,2,CRectX,CRectY,CRectW,CRectH) Then Goto retry BallAngle# = Rnd(0,259) ball.Circle = CircleNew(BallX,BallY,2,Sin(ballangle) * 2,Cos(ballangle) * 2) End Function Function drawWorld() ;Draw the ring Color 0,0,255 Oval RingX,RingY,RingW,RingH,False ;draw the ball(s) circleupdate() circledraw() ;draw paddles for each player For p.player = Each player For pa = 0 To pl(n)\Paddles-1 RX = ringW/2 - 5 RY = ringH/2 - 5 a = p\angle[pa] - 5 xA = Sin(a) * (RX-p\Lane[pa]) yA = Cos(a) * (RY-p\Lane[pa]) a = p\angle[pa] + 5 xB = Sin(a) * (RX-p\Lane[pa]) yB = Cos(a) * (RY-p\Lane[pa]) linerecalc(plMarkers(n,pa),xA + 400,yA + 300,xB + 400,yB + 300) Next n = n + 1 Next linedraw() End Function Type cline Field x1#,y1#,x2#,y2#,nx#,ny#,ux#,uy# Field r,g,b Field Owner.player End Type Function LineNew.cline(x1#,y1#,x2#,y2#) l.cline=New cline LineRecalc(l,x1#,y1#,x2#,y2#) Return l End Function Function LineRecalc(l.cline,x1#,y1#,x2#,y2#) l\x1=x1 l\y1=y1 l\x2=x2 l\y2=y2 dx#=l\x2-l\x1 dy#=l\y2-l\y1 d#=Sqr(dx*dx+dy*dy) If d#<0.0001 d#=0.0001 EndIf l\ux=dx/d l\uy=dy/d l\nx#=l\uy l\ny#=-l\ux End Function Function LineDraw() For l.cline=Each cline Color l\r,l\g,l\b Line l\x1,l\y1,l\x2,l\y2 ; Color 255,255,0 ; ;Draw normal ; xm#=(l\x1+l\x2)/2.0 ; ym#=(l\y1+l\y2)/2.0 ; Line xm,ym,xm+l\nx*10,ym+l\ny*10 ; n = n + 1 Next End Function ;Global LineCollisionX# ;Global LineCollisionY# ;Returns the shortest distance from a point to a line ;Use LineCollisionX and LineCollisionY to get the collision point. Function LineDistance#(l.cline,x#,y#) dx#=l\x2-l\x1 dy#=l\y2-l\y1 d#=Sqr(dx*dx+dy*dy) px#=l\x1-x# py#=l\y1-y# dist#=(dx*py-px*dy) / d LineCollisionX=x#-l\nx*dist# LineCollisionY=y#-l\ny*dist# Return Abs(dist#) End Function ;Returns true if a point collides with a line within range r Function LineCollide(l.cline,x#,y#,r#) dx1#=x-(l\x1-l\ux*r) dy1#=y-(l\y1-l\uy*r) d#=Sqr(dx1*dx1+dy1*dy1) dx1=dx1/d dy1=dy1/d dx2#=x-(l\x2+l\ux*r) dy2#=y-(l\y2+l\uy*r) d#=Sqr(dx2*dx2+dy2*dy2) dx2=dx2/d dy2=dy2/d dot1#=dx1*l\ux+dy1*l\uy dot2#=dx2*l\ux+dy2*l\uy Return ((dot1#>=0 And dot2#<=0) Or (dot1#<=0 And dot2#>=0)) And (LineDistance(l,x,y)<=r) End Function Type Circle Field x#,y#,vx#,vy# Field vel# field veladd# Field r# Field LastHit.cline,LastLastHit.cline End Type Function CircleNew.Circle(x#,y#,r#=50,vx#=0,vy#=0) c.Circle=New Circle c\x=x c\y=y c\r=r c\vx=vx c\vy=vy c\veladd# = 1 ;CirclePlace(c) Return c End Function ;draw circles Function CircleDraw() Color 255,255,255 For c.Circle=Each Circle rh#=c\r*2 Oval c\x-c\r,c\y-c\r,rh,rh Next End Function Function CircleUpdate() For c.Circle=Each Circle ;Calculate total velocity c\vel#=Sqr(c\vx*c\vx+c\vy*c\vy#) ;+ c\veladd ;collision against other circles For cc.Circle=Each Circle ;do not test against itself If cc<>c ;vector from one circle to another dx#=cc\x-c\x dy#=cc\y-c\y d#=Sqr(dx*dx+dy*dy) ;check of distance is smaller than the two circle´s radii together If d<(c\r+cc\r) ;make the vector a unit vector (length=1), multiply it with the circle´s ;total velocity, to get the new motion vector c\vx=(-dx#/d) * c\vel c\vy=(-dy#/d) * c\vel EndIf EndIf Next ;collision against lines For l.cline=Each cline for veladd# = 1 to c\veladd# step 0.1 x=c\x+c\vx * veladd# y=c\y+c\vy * c\veladd# ;Check if circle collides with a line If LineCollide(l,x,y,c\r) if c\veladd# < 2 then c\veladd# = c\veladd# + 0.1 ;boost speed of the ball with each bounce ;debuglog "Velocity: " + c\vel debuglog "Added to speed: " + c\veladd ;Get the dot product between the circles motion vector and the line´s normal vector dot#=c\vx*l\nx+c\vy*l\ny ;Calculate the circle´s new motion vector c\vx=c\vx-2.0*l\nx*dot c\vy=c\vy-2.0*l\ny*dot ;Make note of the last collision If Not c\lasthit = Null If c\LastHit\Owner = Null If Not c\LastLastHit = Null If Not c\LastLastHit\Owner=l\Owner ;Score(l.cline\Owner\Number) NegScore(c\LastLastHit\Owner\Number) EndIf EndIf EndIf EndIf c\LastLastHit = c\LastHit.cline c\LastHit = l.cline exit EndIf next Next ;add velocity to position c\x=c\x+c\vx * c\veladd# c\y=c\y+c\vy * c\veladd# ;Wrap to screen boundaries If c\x>GraphicsWidth() c\x=0 EndIf If c\y>GraphicsHeight() c\y=0 EndIf If c\x<0 c\x=GraphicsWidth() EndIf If c\y<0 c\y=GraphicsHeight() EndIf If c\y = 0 Or c\y = GraphicsHeight() Or c\x = 0 Or c\x = GraphicsWidth() If Not c\LastHit = Null If Not c\LastHit\Owner = Null Score(c\LastHit\Owner\Number) EndIf EndIf Delete c If ballCount = 1 BallStart() Else ballCount = ballCount - 1 EndIf EndIf Next End Function
Yes, I know the source code is a mess and the only clean part (the circle and line bouncing functions) is not mine.