Aaditya Parashar
Junior Member
Just somebody with an abnormal coding routine.
Posts: 95
|
Post by Aaditya Parashar on Feb 24, 2024 9:26:54 GMT
Air Hockey (Made in an hour!). I Challenge you to beat AI with a score of 50. Screen _NewImage(480, 640, 32) _Title "Air Hockey" Type Vec2 As Single X, Y End Type Dim As Vec2 NULLVECTOR
Dim As _Unsigned Integer ScoreAI, ScorePlayer Dim As Vec2 Ball_Position, Ball_Velocity, Mouse, AI Ball_Position.X = _Width / 2: Ball_Position.Y = _Height / 2 AI.X = _Width / 2: AI.Y = _Height / 4 Const Ball_Radius = 5 Const Mouse_Radius = 20 Const AI_Radius = 10 Const AIMaxSpeed = 5
_MouseMove _Width / 2, _Height * 0.75 Const FPS = 60 Do Cls , _RGB32(0, 63, 127) _Limit FPS If _WindowHasFocus = 0 Then _Continue While _MouseInput Mouse.X = _MouseX: Mouse.Y = _MouseY If Mouse.Y < _Height / 2 Then Mouse.Y = _Height / 2 CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 25, Ball_Velocity Wend Line (0, _Height / 2 - 2)-(_Width, _Height / 2 + 2), _RGB32(255), BF If inBox(Ball_Position.X, Ball_Position.Y, _Width / 4, 0, _Width * 0.75, _Height / 10) Then C& = _RGB32(127, 0, 0) ScorePlayer = ScorePlayer + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.4 Ball_Velocity = NULLVECTOR Else C& = _RGB32(0, 127, 0) End If Line (_Width / 4, 0)-(_Width * 0.75, _Height / 10), C&, B If inBox(Ball_Position.X, Ball_Position.Y, _Width / 4, _Height * 0.9, _Width * 0.75, _Height) Then C& = _RGB32(127, 0, 0) ScoreAI = ScoreAI + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.6 Ball_Velocity = NULLVECTOR Else C& = _RGB32(0, 127, 0) End If Line (_Width / 4, _Height * 0.9)-(_Width * 0.75, _Height), C&, B CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 25, Ball_Velocity
AI.X = AI.X + Sgn(Ball_Position.X - AI.X) * Min(Abs(Ball_Position.X - AI.X), AIMaxSpeed) If Ball_Position.Y >= _Height / 2 Then AI.Y = AI.Y + Sgn(_Height / 4 - AI.Y) Else AI.Y = AI.Y + Sgn(Ball_Position.Y - Ball_Radius * 0.75 - AI.Y) * Min(Abs(Ball_Position.Y - Ball_Radius * 0.75 - AI.Y), AIMaxSpeed) End If CircleCollision Ball_Position, Ball_Radius, 1, AI, AI_Radius, 25, Ball_Velocity
Ball_Position.X = Ball_Position.X + Ball_Velocity.X / FPS Ball_Position.Y = Ball_Position.Y + Ball_Velocity.Y / FPS If Ball_Position.X < Ball_Radius Then Ball_Position.X = Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.X > _Width - Ball_Radius Then Ball_Position.X = _Width - Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.Y < Ball_Radius Then Ball_Position.Y = Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 If Ball_Position.Y > _Height - Ball_Radius Then Ball_Position.Y = _Height - Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 Ball_Velocity.X = Round(Ball_Velocity.X * 0.99) Ball_Velocity.Y = Round(Ball_Velocity.Y * 0.99) FillCircle Ball_Position.X, Ball_Position.Y, 0, Ball_Radius, _RGB32(255, 0, 0) FillCircle Mouse.X, Mouse.Y, Mouse_Radius - 5, Mouse_Radius, _RGB32(0, 255, 127) FillCircle AI.X, AI.Y, AI_Radius - 2, AI_Radius, _RGB32(0, 127, 255) _PrintString (0, _Height / 4), Str$(ScoreAI) _PrintString (0, _Height * 0.75), Str$(ScorePlayer) _Display Loop Until Inp(&H60) = 1 System Sub CircleCollision (P1 As Vec2, R1, M1, P2 As Vec2, R2, M2, V1 As Vec2) d = R1 + R2 - distance2(P1.X, P1.Y, P2.X, P2.Y) If d < 0 Then Exit Sub d = d * M2 / M1 r = _Atan2(P1.Y - P2.Y, P1.X - P2.X) V1.X = V1.X + d * Cos(r) V1.Y = V1.Y + d * Sin(r) End Sub Function distance2 (X1, Y1, X2, Y2) distance2 = _Hypot(Abs(X1 - X2), Abs(Y1 - Y2)) End Function Sub FillCircle (X, Y, R1, R2, C&) For I = R1 To R2 Circle (X, Y), I, C& Next I End Sub Function Round (X) If Abs(X) < 5 Then Round = 0 Else Round = X End Function Function inRange (A, B, C) If A <= B And B <= C Then inRange = -1 End Function Function inBox (x, y, x1, y1, x2, y2) If inRange(x1, x, x2) And inRange(y1, y, y2) Then inBox = -1 End Function Function Min (A, B) If A < B Then Min = A Else Min = B End Function Function Max (A, B) If A < B Then Max = B Else Max = A End Function Finally a century
|
|
ubi44
New Member
Posts: 32
|
Post by ubi44 on Feb 25, 2024 0:10:22 GMT
A good game... I was over 50 but I didn't win... Missing an ending. I think it's a shame that the ball goes through the sides of the cage... and the AI has a smaller puck! Otherwise, the sensations are good, you feel like you're on ice... Maybe a larger game board and larger puck would improve accuracy !
|
|
Aaditya Parashar
Junior Member
Just somebody with an abnormal coding routine.
Posts: 95
|
Post by Aaditya Parashar on Feb 25, 2024 2:06:15 GMT
I was thinking about the sensitivity and accuracy of the puck(s), if you see it closely, ball goes through the puck if they have a lot of speed, which is the main reason I could win against AI. But talking about the AI, it looks so good while playing. And I do need to update the cage though, ball just go through the sides.
|
|
Aaditya Parashar
Junior Member
Just somebody with an abnormal coding routine.
Posts: 95
|
Post by Aaditya Parashar on Feb 25, 2024 8:28:38 GMT
New Update, Improving Accuracy and UI (a little)
Screen _NewImage(480, 640, 32) _PrintMode _KeepBackground Color _RGB32(255) _Title "Air Hockey" Type Vec2 As Single X, Y End Type Dim As Vec2 NULLVECTOR
Dim As _Unsigned Integer ScoreAI, ScorePlayer Dim As Vec2 Ball_Position, Ball_Velocity, Mouse, AI Ball_Position.X = _Width / 2: Ball_Position.Y = _Height / 2 AI.X = _Width / 2: AI.Y = _Height / 4 Const Ball_Radius = 5 Const Mouse_Radius = 20 Const AI_Radius = 10 Const AIMaxSpeed = 300
_MouseMove _Width / 2, _Height * 0.75 Const FPS = 60 * 4 Do _Limit FPS If _WindowHasFocus = 0 Then _Continue While _MouseInput Mouse.X = _MouseX: Mouse.Y = _MouseY If Mouse.Y < _Height / 2 Then Mouse.Y = _Height / 2 CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 25, Ball_Velocity Wend If CircleTouchBox(Ball_Position, Ball_Radius, _Width / 4, 0, _Width * 0.75, 5) Then C1& = _RGB32(127, 0, 0) ScorePlayer = ScorePlayer + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.4 Ball_Velocity = NULLVECTOR Else C1& = _RGB32(0, 127, 0) End If If CircleTouchBox(Ball_Position, Ball_Radius, _Width / 4, _Height - 5, _Width * 0.75, _Height) Then C2& = _RGB32(127, 0, 0) ScoreAI = ScoreAI + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.6 Ball_Velocity = NULLVECTOR Else C2& = _RGB32(0, 127, 0) End If CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 25, Ball_Velocity
AI.X = AI.X + Sgn(Ball_Position.X - AI.X) * Min(Abs(Ball_Position.X - AI.X) * FPS, AIMaxSpeed) / FPS If Ball_Position.Y >= _Height / 2 Then AI.Y = AI.Y + Sgn(_Height / 4 - AI.Y) Else AI.Y = AI.Y + Sgn(Ball_Position.Y - Ball_Radius * 0.75 - AI.Y) * Min(Abs(Ball_Position.Y - Ball_Radius * 0.75 - AI.Y) * FPS, AIMaxSpeed) / FPS End If CircleCollision Ball_Position, Ball_Radius, 1, AI, AI_Radius, 25, Ball_Velocity
Ball_Position.X = Ball_Position.X + Ball_Velocity.X / FPS Ball_Position.Y = Ball_Position.Y + Ball_Velocity.Y / FPS If Ball_Position.X < Ball_Radius Then Ball_Position.X = Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.X > _Width - Ball_Radius Then Ball_Position.X = _Width - Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.Y < Ball_Radius Then Ball_Position.Y = Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 If Ball_Position.Y > _Height - Ball_Radius Then Ball_Position.Y = _Height - Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 Ball_Velocity.X = Round(Ball_Velocity.X * 0.995) Ball_Velocity.Y = Round(Ball_Velocity.Y * 0.995) If DISPLAY Mod 4 = 0 Then Cls , _RGB32(0, 63, 127) Line (0, _Height / 2 - 2)-(_Width, _Height / 2 + 2), _RGB32(255), BF
Line (_Width / 4, 0)-(_Width * 0.75, 5), C1&, BF Line (_Width / 4, _Height - 5)-(_Width * 0.75, _Height), C2&, BF
FillCircle Ball_Position.X, Ball_Position.Y, 0, Ball_Radius, _RGB32(255, 0, 0)
FillCircle Mouse.X, Mouse.Y, Mouse_Radius - 4, Mouse_Radius, _RGB32(0, 255, 127) FillCircle AI.X, AI.Y, AI_Radius - 2, AI_Radius, _RGB32(0, 127, 255)
_PrintString (0, _Height / 4), Str$(ScoreAI) _PrintString (0, _Height * 0.75), Str$(ScorePlayer) _Display DISPLAY = 0 End If DISPLAY = DISPLAY + 1 Loop Until Inp(&H60) = 1 System Sub CircleCollision (P1 As Vec2, R1, M1, P2 As Vec2, R2, M2, V1 As Vec2) d = R1 + R2 - distance2(P1.X, P1.Y, P2.X, P2.Y) If d < 0 Then Exit Sub d = d * M2 / M1 r = _Atan2(P1.Y - P2.Y, P1.X - P2.X) V1.X = V1.X + d * Cos(r) V1.Y = V1.Y + d * Sin(r) End Sub Function distance2 (X1, Y1, X2, Y2) distance2 = _Hypot(Abs(X1 - X2), Abs(Y1 - Y2)) End Function Sub FillCircle (X, Y, R1, R2, C&) For I = R1 To R2 Circle (X, Y), I, C& Next I End Sub Function Round (X) If Abs(X) < 5 Then Round = 0 Else Round = X End Function Function inRange (A, B, C) If A <= B And B <= C Then inRange = -1 End Function Function inBox (x, y, x1, y1, x2, y2) If inRange(x1, x, x2) And inRange(y1, y, y2) Then inBox = -1 End Function Function Min (A, B) If A < B Then Min = A Else Min = B End Function Function Max (A, B) If A < B Then Max = B Else Max = A End Function Function CircleTouchBox (C As Vec2, R As Single, X1, Y1, X2, Y2) t = _Atan2((Y1 + Y2) / 2 - C.Y, (X1 + X2) / 2 - C.X) CircleTouchBox = inBox(C.X + R * Cos(t), C.Y + R * Sin(t), X1, Y1, X2, Y2) End Function
|
|
|
Post by bplus on Feb 25, 2024 16:32:51 GMT
I am hesitant to comment here as I have my own air hockey game that i like quite a bit, not fair to AP to compare to it.
I will say AP's game is like playing a machine, it is too fast and puck too little for this human to track and keep up with. It's not fun trying to play against a god.
|
|
Aaditya Parashar
Junior Member
Just somebody with an abnormal coding routine.
Posts: 95
|
Post by Aaditya Parashar on Feb 27, 2024 15:20:13 GMT
New Update: I have decreased mouse sensitivity for more accuracy, and some values are changed. This game is playable, it's not like we are playing against a god, we just need to be accurate and fast, then we may roast this god . Screen _NewImage(480, 640, 32) _PrintMode _KeepBackground Color _RGB32(255) _Title "Air Hockey" Type Vec2 As Single X, Y End Type Dim As Vec2 NULLVECTOR
Dim As _Unsigned Integer ScoreAI, ScorePlayer Dim As Vec2 Ball_Position, Ball_Velocity, Mouse, AI Ball_Position.X = _Width / 2: Ball_Position.Y = _Height / 2 AI.X = _Width / 2: AI.Y = _Height / 4 Mouse.X = _Width / 2: Mouse.Y = _Height * 0.75 Const Ball_Radius = 5 Const Mouse_Radius = 20 Const AI_Radius = 10
onst AIMaxSpeed = 300 Dim Mouse_Goal_Width, AI_Goal_Width Mouse_Goal_Width = _Width / 2 AI_Goal_Width = _Width / 2
_MouseMove _Width / 2, _Height * 0.75 _MouseHide Const FPS = 60 * 4 Do _Limit FPS If _WindowHasFocus = 0 Then _Continue While _MouseInput Mouse.X = Mouse.X + _MouseMovementX * 2 / 3: Mouse.Y = Mouse.Y + _MouseMovementY * 2 / 3 Mouse.X = Bound(0, Mouse.X, _Width) Mouse.Y = Bound(_Height / 2, Mouse.Y, _Height) If Mouse.Y < _Height / 2 Then Mouse.Y = _Height / 2 _MouseMove _Width / 2, _Height * 0.75 CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 10, Ball_Velocity Wend If CircleTouchBox(Ball_Position, Ball_Radius, (_Width - AI_Goal_Width) / 2, 0, (_Width + AI_Goal_Width) / 2, 5) Then C1& = _RGB32(127, 0, 0) ScorePlayer = ScorePlayer + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.4 Ball_Velocity = NULLVECTOR AI_Goal_Width = Max(_Width * 0.25, AI_Goal_Width - 5) Mouse_Goal_Width = Min(_Width * 0.75, Mouse_Goal_Width + 5) Else C1& = _RGB32(0, 127, 0) End If If CircleTouchBox(Ball_Position, Ball_Radius, (_Width - Mouse_Goal_Width) / 2, _Height - 5, (_Width + Mouse_Goal_Width) / 2, _Height) Then C2& = _RGB32(127, 0, 0) ScoreAI = ScoreAI + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.6 Ball_Velocity = NULLVECTOR Mouse_Goal_Width = Max(_Width * 0.25, Mouse_Goal_Width - 5) AI_Goal_Width = Min(_Width * 0.75, AI_Goal_Width + 5) Else C2& = _RGB32(0, 127, 0) End If CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 10, Ball_Velocity
AI.X = AI.X + Sgn(Ball_Position.X - AI.X) * Min(Abs(Ball_Position.X - AI.X) * FPS, AIMaxSpeed) / FPS If Ball_Position.Y >= _Height / 2 Then AI.Y = AI.Y + Sgn(_Height / 4 - AI.Y) Else AI.Y = AI.Y + Sgn(Ball_Position.Y - Ball_Radius * 0.75 - AI.Y) * Min(Abs(Ball_Position.Y - Ball_Radius * 0.75 - AI.Y) * FPS, AIMaxSpeed) / FPS End If CircleCollision Ball_Position, Ball_Radius, 1, AI, AI_Radius, 25, Ball_Velocity
Ball_Position.X = Ball_Position.X + Ball_Velocity.X / FPS Ball_Position.Y = Ball_Position.Y + Ball_Velocity.Y / FPS If Ball_Position.X < Ball_Radius Then Ball_Position.X = Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.X > _Width - Ball_Radius Then Ball_Position.X = _Width - Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.Y < Ball_Radius Then Ball_Position.Y = Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 If Ball_Position.Y > _Height - Ball_Radius Then Ball_Position.Y = _Height - Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 Ball_Velocity.X = Round(Ball_Velocity.X * 0.995) Ball_Velocity.Y = Round(Ball_Velocity.Y * 0.995) If DISPLAY Mod 4 = 0 Then Cls , _RGB32(0, 63, 127) Line (0, _Height / 2 - 2)-(_Width, _Height / 2 + 2), _RGB32(255), BF
Line ((_Width - AI_Goal_Width) / 2, 0)-((_Width + AI_Goal_Width) / 2, 5), C1&, BF Line ((_Width - Mouse_Goal_Width) / 2, _Height - 5)-((_Width + Mouse_Goal_Width) / 2, _Height), C2&, BF
FillCircle Ball_Position.X, Ball_Position.Y, 0, Ball_Radius, _RGB32(255, 0, 0)
FillCircle Mouse.X, Mouse.Y, Mouse_Radius - 4, Mouse_Radius, _RGB32(0, 255, 127) FillCircle AI.X, AI.Y, AI_Radius - 2, AI_Radius, _RGB32(0, 127, 255)
_PrintString (0, _Height / 4), Str$(ScoreAI) _PrintString (0, _Height * 0.75), Str$(ScorePlayer) _Display DISPLAY = 0 End If DISPLAY = DISPLAY + 1 Loop Until Inp(&H60) = 1 System Sub CircleCollision (P1 As Vec2, R1, M1, P2 As Vec2, R2, M2, V1 As Vec2) d = R1 + R2 - distance2(P1.X, P1.Y, P2.X, P2.Y) If d < 0 Then Exit Sub d = d * M2 / M1 r = _Atan2(P1.Y - P2.Y, P1.X - P2.X) V1.X = V1.X + d * Cos(r) V1.Y = V1.Y + d * Sin(r) End Sub Function distance2 (X1, Y1, X2, Y2) distance2 = _Hypot(Abs(X1 - X2), Abs(Y1 - Y2)) End Function Sub FillCircle (X, Y, R1, R2, C&) For I = R1 To R2 Circle (X, Y), I, C& Next I End Sub Function Bound (A, X, B) Bound = X If X < A Then Bound = A If X > B Then Bound = B End Function Function Round (X) If Abs(X) < 5 Then Round = 0 Else Round = X End Function Function inRange (A, B, C) If A <= B And B <= C Then inRange = -1 End Function Function inBox (x, y, x1, y1, x2, y2) If inRange(x1, x, x2) And inRange(y1, y, y2) Then inBox = -1 End Function Function Min (A, B) If A < B Then Min = A Else Min = B End Function Function Max (A, B) If A < B Then Max = B Else Max = A End Function Function CircleTouchBox (C As Vec2, R As Single, X1, Y1, X2, Y2) CircleTouchBox = inBox(C.X, C.Y, X1 - R, Y1 - R, X2 + R, Y2 + R) End Function And bplus , there is no comparison, about how our games are, you can share your version so we could even play that and maybe learn something new from it. Sorry if my language is rude, I am not too good in English .
|
|
|
Post by bplus on Feb 27, 2024 19:18:03 GMT
AP i am glad you welcome alternate game versions and learning from others. You are not seen as rude by me at all! I hope the same goes for you with me, it is an important thing as it does help learning from others. It does seem to play a little better? Still fast as heck! AI may be tracking too closely to the x component of the puck ie always hitting it straight parallel to the left and right walls.
I had to add this to your code so I dont have to move the game by dragging title bar because I can't as your code wont let me move my mouse up there.
_ScreenMove 400, 60 Your code without that screen move command starts with the bottom quarter off screen.
Ok Here is my version of this game:
Option _Explicit 'Air Hockey v2-1.bas for QB64 ' Started in QB64 Walter fork version (B+=MGA) 2017-09-05 ' The first version was a direct translation from SmallBASIC, ' Now v2.0 add some more graphic image handling, try new things. ' 2020-03-11 v2-1 (QB64 v1.4 now) cleanup some code: ' Fix _MOUSEINPUT block too newbie ;) ' Fix flat spots on strikers how long have they been there? ' Increase frames per sec and slow puck speed for less double images. ' Oh that sped up the AI player! Nice. ' Do start shots to the side instead of directly at goal. MUCH BETTER! ' Update opening screen with this info. Now pause the puck at start. ' Ran OPTION _EXPLICIT and found a type-O that has been 0 all this time! ' 2022-05-14 fixes for Linux
Randomize Timer Const xmax = 1200, ymax = 690 'screen dimensions Screen _NewImage(xmax, ymax, 32) _Title "Air Hockey 2-1" _ScreenMove 90, 0
Const pr = 16 ' puck radius Const pr2 = 2 * pr ' puck diameter = bumper width = radius of strikers Const tl = xmax ' table length Const tw = tl / 2 ' table width Const tw13 = .3333 * tw \ 1 'goal end point Const tw23 = .6667 * tw \ 1 'goal end point Const speed = 15 ' puck speed also see _limit in main loop Const midC = 316 ' (tl - 2 * pr2) \ 4 + pr2 'mid line of computer's sin field Const rangeC = 252 ' 316 - 252 = 64 (bumper + pr2) 316 + 252 = 568 (mid screen - pr2)
Common Shared f&, table&, computer, player, s$, tx, px, py, pa, psx, psy, c1, csx, csy, strkr&
f& = _LoadFont("arial.ttf", 25) ' arial normal style if you have windows _Font f& ' arial is pretty common if you don't have Windows
table& = _NewImage(xmax, tw, 32) _Dest table& drawTable
strkr& = _NewImage(2 * pr2 + 1, 2 * pr2 + 1, 32) ' more space to avoid right and bottom flat edges _Dest strkr& striker pr2, pr2
_Dest 0 ' Opening screen cp 7, "Air Hockey, first to score 21 goals wins!" cp 9, "Player you will be defending the goal on the right (a black slot)." cp 10, "Your goal is on the left, defended by the computer." cp 12, "The puck will be started going up and down in the middle of" cp 13, "the screen at slight angle towards a randomly selected goal." cp 16, "Press any when ready..." Sleep _Delay 1 Cls updateScore _PutImage (0, 0), table&, 0 drawComputerStriker While _MouseInput: Wend psx = _MouseX: psy = _MouseY drawPlayerStriker initball While player < 21 And computer < 21 ' play until someone scores 21 Cls updateScore _PutImage (0, 0), table&, 0 drawComputerStriker While _MouseInput: Wend psx = _MouseX: psy = _MouseY drawPlayerStriker drawPuck _Display _Limit 60 '<<<<<<<<<<<<< slow down, speeed up as needed for good game Wend If computer > player Then ' last report s$ = "Game Won by Computer." tx = 450 Else s$ = "Game Won by Player!" tx = 470 End If Color _RGB(200, 240, 140) _PrintString (tx, tw + 30), s$ _Display _Delay 3
Sub initball 'toss puck out to side slightly angled to one goal or the other Dim pao px = tl / 2: py = tw / 2: pao = _Pi(1 / 10) * Rnd puck px, py _Display _Delay .3 If Rnd < .5 Then pa = _Pi(.5) Else pa = _Pi(1.5) If Rnd < .5 Then pa = pa + pao Else pa = pa - pao End Sub
Sub updateScore Color _RGB(40, 255, 255) s$ = "Computer: " + Str$(computer) + Space$(67) + "Player: " + Str$(player) _PrintString (200, tw + 30), s$ End Sub
Sub drawTable Dim i, shade For i = 0 To pr2 Step 4 shade = 64 + i / pr2 * 100 Color _RGB(shade, shade, shade) Line (i, i)-(tl - i, tw - i), , BF Next Line (pr2, pr2)-(tl - pr2, tw - pr2), _RGB(190, 230, 255), BF 'field Line (pr, tw13)-(pr2, tw23), _RGB(60, 60, 60), BF Line (tl - pr2, tw13)-(tl - pr, tw23), _RGB(60, 60, 60), BF Line (tl \ 2 - 1, pr2)-(tl \ 2 + 1, tw - pr2), _RGB(128, 128, 128), BF End Sub
Sub drawPlayerStriker If psx - pr2 < tl / 2 Then psx = tl / 2 + pr2 If psx + pr2 > tl - pr2 Then psx = tl - 2 * pr2 If psy - pr2 < pr2 Then psy = 2 * pr2 If psy + pr2 > tw - pr2 Then psy = tw - 2 * pr2 _PutImage (psx - pr2, psy - pr2), strkr&, 0 End Sub
Sub drawComputerStriker c1 = c1 + _Pi(1 / 80) csx = midC + rangeC * Sin(c1) If px > csx Then csy = py + pr2 * 1.5 * Sin(c1) If csy - pr2 < pr2 Then csy = 2 * pr2 If csy + pr2 > tw - pr2 Then csy = tw - 2 * pr2 _PutImage (csx - pr2, csy - pr2), strkr&, 0 End Sub
Sub drawPuck 'update ball x, y and see if hit anything Dim i, shade px = px + speed * Cos(pa) py = py + speed * Sin(pa)
If px - pr < pr2 Then If tw13 < py - pr And py + pr < tw23 Then 'through computer slot, player scores player = player + 1 Cls updateScore drawTable striker csx, csy striker psx, psy puck pr, py For i = 0 To pr Step 4 shade = 64 + i / pr2 * 100 Color _RGB(shade, shade, shade) Line (i, tw13)-(pr, tw23), , BF ' wow tw13 has been 0 Next snd 1200, 200 snd 2200, 300 _Display initball _Delay .5 Exit Sub Else snd 2600, 8 pa = _Pi(1) - pa px = pr2 + pr End If End If
If px + pr > tl - pr2 Then If tw13 < py - pr And py + pr < tw23 Then computer = computer + 1 Cls updateScore drawTable striker csx, csy striker psx, psy puck tl - pr, py For i = 0 To pr Step 4 shade = 64 + i / pr2 * 100 Color _RGB(shade, shade, shade) Line (tl - pr, tw13)-(tl - i, tw23), , BF 't13 again! Next snd 2200, 300 snd 1200, 200 _Display initball _Delay .5 Exit Sub Else snd 2600, 5 pa = _Pi(1) - pa px = tl - pr2 - pr End If End If
If py - pr < pr2 Then ' hit top boundry snd 2600, 8 pa = -pa py = pr2 + pr End If
If py + pr > tw - pr2 Then ' hit bottom boundry snd 2600, 8 pa = -pa py = tw - pr2 - pr End If
If Sqr((px - psx) ^ 2 + (py - psy) ^ 2) < (pr + pr2) Then 'contact player striker pa = _Atan2(py - psy, px - psx) 'boost puck away px = px + .5 * speed * Cos(pa) py = py + .5 * speed * Sin(pa) snd 2200, 4 End If If Sqr((px - csx) ^ 2 + (py - csy) ^ 2) < (pr + pr2) Then 'contact computer striker pa = _Atan2(py - csy, px - csx) 'boost puck away px = px + .5 * speed * Cos(pa) py = py + .5 * speed * Sin(pa) snd 2200, 4 End If puck px, py ' here it is! End Sub
Sub puck (x, y) Color _RGB(90, 90, 90) fillcirc x, y, pr Color _RGB(190, 100, 0) fillcirc x, y, pr - 4 End Sub
Sub striker (x, y) Dim i, shade For i = pr2 To pr Step -1 shade = 164 - 90 * Sin(i * _Pi(2) / pr) Color _RGB(shade, shade, shade) fillcirc x, y, i Next For i = pr To 0 Step -1 shade = 185 + 70 * (pr - i) / pr Color _RGB(shade, shade, shade) fillcirc x, y, i Next End Sub
'Steve McNeil's copied from his forum note: Radius is too common a name Sub fillcirc (CX As Long, CY As Long, R As Long) Dim subRadius As Long, RadiusError As Long Dim X As Long, Y As Long
subRadius = Abs(R) RadiusError = -subRadius X = subRadius Y = 0
If subRadius = 0 Then PSet (CX, CY): Exit Sub
' Draw the middle span here so we don't draw it twice in the main loop, ' which would be a problem with blending turned on. Line (CX - X, CY)-(CX + X, CY), , BF
While X > Y RadiusError = RadiusError + Y * 2 + 1 If RadiusError >= 0 Then If X <> Y + 1 Then Line (CX - Y, CY - X)-(CX + Y, CY - X), , BF Line (CX - Y, CY + X)-(CX + Y, CY + X), , BF End If X = X - 1 RadiusError = RadiusError - X * 2 End If Y = Y + 1 Line (CX - X, CY - Y)-(CX + X, CY - Y), , BF Line (CX - X, CY + Y)-(CX + X, CY + Y), , BF Wend End Sub
Sub snd (frq, dur) Sound frq / 2.2, dur * .01 End Sub
Sub cp (lineNum, s$) Dim x, y '1200 pixels / 85 characters = 14.11 pixels/char wide '700 pixels / 28 lines = 18.42 pixels / char high x = (xmax - 11 * Len(s$)) \ 2 y = lineNum * 25 _PrintString (x, y), s$ End Sub
If you have Windows it should find the Arial Font, otherwise use an Arial font that Linux can find? The forum would not take a zip with the font included. It's just a normal Arial.ttf.
|
|
Aaditya Parashar
Junior Member
Just somebody with an abnormal coding routine.
Posts: 95
|
Post by Aaditya Parashar on Feb 28, 2024 15:05:32 GMT
New Update: added the ability of AI to aim at our goal. If someone makes it more accurate, feel free to post the fix.
Screen _NewImage(480, 640, 32) _PrintMode _KeepBackground Color _RGB32(255) _Title "Air Hockey" Type Vec2 As Single X, Y End Type Dim As Vec2 NULLVECTOR
Dim As _Unsigned Integer ScoreAI, ScorePlayer Dim As Vec2 Ball_Position, Ball_Velocity, Mouse, AI, AITarget Ball_Position.X = _Width / 2: Ball_Position.Y = _Height / 2 AI.X = _Width / 2: AI.Y = _Height / 4 Mouse.X = _Width / 2: Mouse.Y = _Height * 0.75 Const Ball_Radius = 5 Const Mouse_Radius = 20 Const AI_Radius = 10 Const AIMaxSpeed = 300 Dim Mouse_Goal_Width, AI_Goal_Width Mouse_Goal_Width = _Width / 2 AI_Goal_Width = _Width / 2
_ScreenMove _DesktopWidth / 2 - _Width / 2, _DesktopHeight / 2 - _Height / 2 _MouseMove _Width / 2, _Height * 0.75 _MouseHide Const FPS = 60 * 4 Do _Limit FPS If _WindowHasFocus = 0 Then _Continue While _MouseInput Mouse.X = Mouse.X + _MouseMovementX * 2 / 3: Mouse.Y = Mouse.Y + _MouseMovementY * 2 / 3 Mouse.X = Bound(0, Mouse.X, _Width) Mouse.Y = Bound(_Height / 2, Mouse.Y, _Height) If Mouse.Y < _Height / 2 Then Mouse.Y = _Height / 2 _MouseMove _Width / 2, _Height * 0.75 CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 10, Ball_Velocity Wend If CircleTouchBox(Ball_Position, Ball_Radius, (_Width - AI_Goal_Width) / 2, 0, (_Width + AI_Goal_Width) / 2, 5) Then C1& = _RGB32(127, 0, 0) ScorePlayer = ScorePlayer + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.4 Ball_Velocity = NULLVECTOR AI_Goal_Width = Max(_Width * 0.25, AI_Goal_Width - 5) Mouse_Goal_Width = Min(_Width * 0.75, Mouse_Goal_Width + 5) Else C1& = _RGB32(0, 127, 0) End If If CircleTouchBox(Ball_Position, Ball_Radius, (_Width - Mouse_Goal_Width) / 2, _Height - 5, (_Width + Mouse_Goal_Width) / 2, _Height) Then C2& = _RGB32(127, 0, 0) ScoreAI = ScoreAI + 1 Ball_Position.X = _Width / 2 Ball_Position.Y = _Height * 0.6 Ball_Velocity = NULLVECTOR Mouse_Goal_Width = Max(_Width * 0.25, Mouse_Goal_Width - 5) AI_Goal_Width = Min(_Width * 0.75, AI_Goal_Width + 5) Else C2& = _RGB32(0, 127, 0) End If CircleCollision Ball_Position, Ball_Radius, 1, Mouse, Mouse_Radius, 10, Ball_Velocity
AITarget.X = Ball_Position.X + Ball_Radius * 0.75 * Cos(_Atan2(Ball_Position.Y - _Height, Ball_Position.X - _Width / 2)) AITarget.Y = Ball_Position.Y + Ball_Radius * 0.75 * Sin(_Atan2(Ball_Position.Y - _Height, Ball_Position.X - _Width / 2)) AI.X = AI.X + Sgn(AITarget.X - AI.X) * Min(Abs(AITarget.X - AI.X) * FPS, AIMaxSpeed) / FPS If Ball_Position.Y >= _Height / 2 Then AI.Y = AI.Y + Sgn(_Height / 4 - AI.Y) Else AI.Y = AI.Y + Sgn(AITarget.Y - AI.Y) * Min(Abs(AITarget.Y - AI.Y) * FPS, AIMaxSpeed) / FPS End If CircleCollision Ball_Position, Ball_Radius, 1, AI, AI_Radius, 25, Ball_Velocity
Ball_Position.X = Ball_Position.X + Ball_Velocity.X / FPS Ball_Position.Y = Ball_Position.Y + Ball_Velocity.Y / FPS If Ball_Position.X < Ball_Radius Then Ball_Position.X = Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.X > _Width - Ball_Radius Then Ball_Position.X = _Width - Ball_Radius: Ball_Velocity.X = Ball_Velocity.X * -0.67 If Ball_Position.Y < Ball_Radius Then Ball_Position.Y = Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 If Ball_Position.Y > _Height - Ball_Radius Then Ball_Position.Y = _Height - Ball_Radius: Ball_Velocity.Y = Ball_Velocity.Y * -0.67 Ball_Velocity.X = Round(Ball_Velocity.X * 0.995) Ball_Velocity.Y = Round(Ball_Velocity.Y * 0.995) If DISPLAY Mod 4 = 0 Then Cls , _RGB32(0, 63, 127) Line (0, _Height / 2 - 2)-(_Width, _Height / 2 + 2), _RGB32(255), BF
Line ((_Width - AI_Goal_Width) / 2, 0)-((_Width + AI_Goal_Width) / 2, 5), C1&, BF Line ((_Width - Mouse_Goal_Width) / 2, _Height - 5)-((_Width + Mouse_Goal_Width) / 2, _Height), C2&, BF
FillCircle Ball_Position.X, Ball_Position.Y, 0, Ball_Radius, _RGB32(255, 0, 0)
FillCircle Mouse.X, Mouse.Y, Mouse_Radius - 4, Mouse_Radius, _RGB32(0, 255, 127) FillCircle AI.X, AI.Y, AI_Radius - 2, AI_Radius, _RGB32(0, 127, 255)
_PrintString (0, _Height / 4), Str$(ScoreAI) _PrintString (0, _Height * 0.75), Str$(ScorePlayer) _Display DISPLAY = 0 End If DISPLAY = DISPLAY + 1 Loop Until Inp(&H60) = 1 System Sub CircleCollision (P1 As Vec2, R1, M1, P2 As Vec2, R2, M2, V1 As Vec2) d = R1 + R2 - distance2(P1.X, P1.Y, P2.X, P2.Y) If d < 0 Then Exit Sub d = d * M2 / M1 r = _Atan2(P1.Y - P2.Y, P1.X - P2.X) V1.X = V1.X + d * Cos(r) V1.Y = V1.Y + d * Sin(r) End Sub Function distance2 (X1, Y1, X2, Y2) distance2 = _Hypot(Abs(X1 - X2), Abs(Y1 - Y2)) End Function Sub FillCircle (X, Y, R1, R2, C&) For I = R1 To R2 Circle (X, Y), I, C& Next I End Sub Function Bound (A, X, B) Bound = X If X < A Then Bound = A If X > B Then Bound = B End Function Function Round (X) If Abs(X) < 5 Then Round = 0 Else Round = X End Function Function inRange (A, B, C) If A <= B And B <= C Then inRange = -1 End Function Function inBox (x, y, x1, y1, x2, y2) If inRange(x1, x, x2) And inRange(y1, y, y2) Then inBox = -1 End Function Function Min (A, B) If A < B Then Min = A Else Min = B End Function Function Max (A, B) If A < B Then Max = B Else Max = A End Function Function CircleTouchBox (C As Vec2, R As Single, X1, Y1, X2, Y2) CircleTouchBox = inBox(C.X, C.Y, X1 - R, Y1 - R, X2 + R, Y2 + R) End Function bplus, you made a very good game, and I really liked those sound effects, which I didn't thought was possible with duration of less than 1/18. But there's a big issue, the AI puck just randomly teleports, otherwise it's a good game. Need to practice aiming a lot for that.
By the way, can there be a qb64 AI algorithm to learn and improve on its own? If we add it to a game, then we may be playing against a god...
|
|
|
Post by bplus on Feb 28, 2024 18:39:20 GMT
Well this game can shoot the puck into goal every shot, who wants to play against THAT?
MiniMax doesn't need learning, it plays out every scenario and picks best. who wants to play against THAT?
What AI might need to learn is how to give it's human opponent a challenging game and lets them win when skill level seems better than average and has them lose when they aren't playing their best.
PS teleporting is a proper criticism of my game, but I don't think it happens often.
I can follow the puck better with your latest AP but still have to _MoveScreen before I test it.
|
|
Aaditya Parashar
Junior Member
Just somebody with an abnormal coding routine.
Posts: 95
|
Post by Aaditya Parashar on Mar 1, 2024 4:24:40 GMT
Isn't there any way to instantaneously get mouse values without using _mouseinput? Because _mouseinput remembers all input, and using a while loop increases system usage.
|
|
|
Post by bplus on Mar 1, 2024 11:05:12 GMT
As I understand it, the While _MouseInput: Wend Polls the system for the latest data on the mouse status, like using Inkey$ in a loop. Except that tends to collect keypresses between polling for keys, hey maybe that's why the loop to get the mouse status at the very instant you hit that line. Remember the mouse wheel data for scrolling DOES work inside that loop, mousemovement too?
|
|