Profile Pong Game Development
#12
I should have know about serve, use to play all the time in college but that was 50 years ago!

OK the serve stuff is fixed, but I hated the way that paddle shape was playing so I switched back to a bigger circle, better!
Then I discovered a trick to beat the machine! Player's new color is Green because it ain't easy...
Code: (Select All)
Option _Explicit
_Title "Profile Pong 2-4" ' b+ 2023-02-01 started inspired by Rosy game at RCBasic
'2023-02-02 1.1 fix straight up and down problem that infinitely loops.
' You can hit a ball again so long as the dx is still headed at you or 0.
' To tighten down game to actual Ping Pong Rules added variables TableTouchL and TableTouchR
' Set those to 0 when ball collides with paddle on that side. Check those when scoring points.
' Oh some sound effects would be nice.
'2023-02-02 1-2 Increase paddleR, let paddle go through table 1/2 way, blue background.
' Try nicer font...
'2023-02-03 2-0 change shape of paddle and work out collision code circle and line segment,
' collision with offset for ball radius. Add recticle draw sub for new paddle shape.
' Collision with paddle has 3 parts now:
' 1. Collision with straight part of paddle
' 2. Collision with top circle of paddle
' 3. Collision with bottom corcle part of paddle
' PaddleR was decressed since now circle parts of paddle instead of 1/2 circle.
' Now it seems too easy to beat Computer, will take care of that next!
' Clean up comments.
'2023-02-03 2-2 OK attempt to make the computer a little harder to beat. ParkCompterY will keep
' computers paddle parked until the ball hits it's side of the table, then it will spring to
' action, so no more freebee points if you hit it out of ball park.
' Fix problem when last player to hit ball hits backwards like in a serve, should lose
' a point not get one! Now checking lastToHit variable and assigned Computer and Player
' Constants. Now a problem when player lobs just past table and hits computer paddle.
' Computer needs to really duck or fly! Fixed after ball crosses net computer stays above it
' until it hits table, then it gets in position to return.
'2023-02-04 2-3
' WOW I just made one gross adjustment to ComputerY Paddle height according to ball distance to
' table and made this a very hard game for Player to score!
'2023-02-04 2-4
' Observe the proper rule for legal serve, hit server's side first and then opponent's side.
' Add Const Server and use for scoring. Now get in habit of striking ball with bottom circle
' maybe side?
' New Paddle, back to big circle!!! Ah much better!
' If the ball hasn't touched the table you can hit it more than once.


'                       Rules of Profile Ping Pong (now in effect):
' Ping Pong Legal Service:
' The ball must be struck so the ball first bounces on the server's side and then the
' opponent's side. Version 2-4

' On your return you must clear net and not bounce again on your side of the table.
' Opponent may or may not chooses to wait for bounce.
' Opponent should not attempt to return a ball clearly not going to hit his side of table,
' to win a point. Version 2-2 and above AI will not attempt a return until players serve or
' return hits its side of table.

Const Xmax = 1200, Ymax = 700 '     screen size
Const PaddleR = 30, BallR = 5
Const CircR = 50 '                  radii
Const TableL = 100, TableR = 1100 ' table ends
Const TableY = Ymax - 80 '          table height from top screen
Const NetY = TableY - 40 '          net height from top screen
Const NetL = 598 '                  net left side
Const NetR = 602 '                  net right side
Const Gravity = .1 '                just about right drop
Const BallSpeed = 8 '               for ball speed
Const Player = 1 '                  for scoring properly
Const Computer = 2 '                need to know who hit ball last
Const Server = 3 '                  track serve hits right side first

Dim Shared As Long Table, LPaddle ' images shared so can be made in isolated subs once
Dim Shared ballX, ballY
Screen _NewImage(Xmax, Ymax, 32)
_ScreenMove 60, 20 '               <<< you may want different, for my screen it is almost middle
_PrintMode _KeepBackground '         usebackground color or image for background of text printed

Dim As Long f, mx, my, playerX, playerY, computerX, computerY, parkComputerY ' locating
Dim As Long playerPt, computerPt, tableTouchL, tableTouchR, lastToHit ' scoring and scoring helpers
Dim As Double ballDX, ballDY, a, snd
Dim As Long paddleY1, paddleY2 ' top and bottom line segment ends and centers of circle ends
Dim As String s ' score string fitting _printstring command on one line, one call to _PrintWidth
f = _LoadFont("Arial.ttf", 32) ' everyone has Arial right?
_Font f
_MouseHide
makeTableImg ' background and table, CLS with it
makeLeftPaddle ' Rectircle!

computerX = TableL - PaddleR - 3 ' as of now, ComputerX doesnt ever change x position
parkComputerY = TableY - 6 * PaddleR ' keeping Computer paddle above board out of trouble

Do 'resets for serve
    tableTouchL = 0: tableTouchR = 0: lastToHit = Server ' for serving
    computerY = parkComputerY
    ballY = 550: ballX = TableR - BallR
    ballDX = 0: ballDY = 0
    ' serve follows video of Rosy Demo, just drop ball on human side of table

    Do
        _PutImage , Table, 0 '                                                 background table...
        _PrintString (100, 100), "Computer:" + Str$(computerPt) '                     score update
        s = "Player:" + Str$(playerPt)
        _PrintString (1100 - _PrintWidth(s), 100), s

        '                                                                            Player Paddle
        While _MouseInput: Wend '                   poll mouse status
        mx = _MouseX: my = _MouseY
        If mx > NetR + CircR Then '               keep player on his side of table
            playerX = mx: playerY = my
        Else
            playerY = my ' OK let me move in Y direction
        End If
        fcirc playerX, playerY, CircR, &HFF00BB00
        makeEyes playerX, playerY

        ' Computer x is constant behind table edge y adjusted to ballY             Computer Paddle
        If tableTouchL = 0 Then
            If ballX < NetL Then computerY = ballY - 3 * PaddleR Else computerY = parkComputerY
        Else
            'version 2-3  needs to adjust paddle height to ball height from table
            If ballY > NetY - 3 * PaddleR Then
                computerY = ballY + .5 * PaddleR + 20 '    <<<<<<<< version 2-3 new line unbeatable
            Else
                computerY = ballY + .5 * PaddleR + 5 '         so upper round part hits ball upward
            End If
        End If
        _PutImage (computerX - PaddleR, computerY - 1.5 * PaddleR), LPaddle, 0
        makeEyes computerX, computerY

        '                                                                            ball handling
        ballDY = ballDY + Gravity '                     gravity weighs ball down going up or down
        ballX = ballX + ballDX: ballY = ballY + ballDY

        ' collide player
        If Sqr((playerX - ballX) ^ 2 + (playerY - ballY) ^ 2) < BallR + CircR Then
            Sound 230, 1
            a = _Atan2(ballY - playerY, ballX - playerX)
            ballDX = BallSpeed * Cos(a)
            ballDY = BallSpeed * Sin(a)
            ballX = ballX + 2 * ballDX ' boost
            ballY = ballY + 2 * ballDY
            If lastToHit <> Server Then lastToHit = Player
            tableTouchR = 0
        End If

        'collide with computer paddle
        ' first check if it hit the flat edge of paddle calc the 2 endpoints of that line
        paddleY1 = computerY - .5 * PaddleR ' paddle top circle origin and line segment end
        paddleY2 = computerY + .5 * PaddleR
        If hitLine(ballX, ballY, BallR, computerX + PaddleR, paddleY1, computerX + PaddleR,_
         paddleY2) Then

            ballDX = -ballDX ' the paddle line is straight up and down so x direction is reversed
            ballX = ballX + 2 * ballDX 'boost away
            lastToHit = Computer
            tableTouchL = 0

            ' 2nd check if hit top circle of paddle
        ElseIf Sqr((ballX - computerX) ^ 2 + (ballY - paddleY1) ^ 2) < (BallR + PaddleR) And_
         ballDX <= 0 Then

            Sound 230, 1
            a = _Atan2(ballY - paddleY1, ballX - computerX)
            ballDX = BallSpeed * Cos(a)
            ballDY = BallSpeed * Sin(a)
            ballX = ballX + 2 * ballDX ' boost
            ballY = ballY + 2 * ballDY
            lastToHit = Computer
            tableTouchL = 0

            ' 3rd check if hit bottom circle of paddle
        ElseIf Sqr((ballX - computerX) ^ 2 + (ballY - paddleY2) ^ 2) < (BallR + PaddleR) And_
         ballDX <= 0 Then

            a = _Atan2(ballY - paddleY2, ballX - computerX)
            ballDX = BallSpeed * Cos(a)
            ballDY = BallSpeed * Sin(a)
            ballX = ballX + 2 * ballDX ' boost
            ballY = ballY + 2 * ballDY
            lastToHit = Computer
            tableTouchL = 0
        End If

        ' collide net   vertical part
        If ballY + BallR > NetY Then
            If ballDX > 0 Then ' going towards player
                If ballX > NetL - BallR And ballX < NetR + BallR Then ' collide
                    GoSub player
                    Exit Do
                End If
            ElseIf ballDX < 0 Then ' going towards computer
                If ballX > NetL - BallR And ballX < NetR + BallR Then ' collide
                    GoSub computer
                    Exit Do
                End If
            End If
        End If

        ' collide table   very import to hit table on opponents side on serve and returns
        'If ballY + BallR > TableY And ((ballX > TableL) Or (ballX < TableR)) Then ' why the OR ???
        If (((ballY + BallR) > TableY) And (ballX > TableL)) And (ballX < TableR) Then
            Sound 600, .25
            If (ballX - BallR) < NetL Then ' table left
                If lastToHit = Server Then
                    GoSub computer
                    Exit Do
                End If
                If tableTouchL = 0 And ballDX > 0 Then
                    GoSub player
                    Exit Do
                Else
                    tableTouchL = tableTouchL + 1
                    If tableTouchL > 1 Then
                        GoSub player
                        Exit Do
                    End If
                End If
            ElseIf (ballX - BallR) > NetR Then 'table right
                If tableTouchR = 0 And ballDX < 0 Then ' ball headed left
                    If lastToHit = Server Then ' server struck ball correctly on his side first
                        lastToHit = Player
                    Else
                        GoSub computer ' player hit his side first, not on a serve
                        Exit Do
                    End If
                Else
                    tableTouchR = tableTouchR + 1
                    If tableTouchR > 1 And lastToHit <> Server Then
                        GoSub computer
                        Exit Do
                    End If
                End If
            End If
            ballY = TableY - BallR
            ballDY = -ballDY
        End If

        ' collide floor ?   I doubt this ever happens
        If ballY + BallR > Ymax Then
            If lastToHit = Server Then
                GoSub computer
                Exit Do
            End If
            If ballX + BallR < TableL Then
                If (tableTouchL > 0 And lastToHit = Player) Or (lastToHit = Computer) Then
                    GoSub player
                Else
                    GoSub computer
                End If
            ElseIf ballX - BallR > TableR Then
                If (tableTouchR > 0 And lastToHit = Computer) Or (lastToHit = Player) Then
                    GoSub computer
                Else
                    GoSub player
                End If
            End If
            Exit Do
        End If

        ' collide left boundry
        If ballX - BallR < 0 Then
            If lastToHit = Server Then
                GoSub computer
                Exit Do
            End If
            If (tableTouchL > 0) And (lastToHit = Player) Then
                GoSub player
            ElseIf lastToHit = Computer Then
                GoSub player
            ElseIf ((tableTouchL = 0) And (lastToHit = Player)) Then ' player hit to far
                GoSub computer
            End If
            Exit Do
        ElseIf ballX + BallR > Xmax Then 'collide right boundary
            If lastToHit = Server Then
                GoSub computer
                Exit Do
            End If
            If (tableTouchR > 0 And lastToHit = Computer) Or (lastToHit = Player) Then
                GoSub computer
            Else ' computer hit too far
                GoSub player
            End If
            Exit Do
        End If
        fcirc ballX, ballY, BallR, &HFFFFFFFF
        _Display
        _Limit 60
    Loop
    _Delay 1
    If computerPt >= 21 Then
        _MessageBox "Sorry,", "The Computer out did you this game."
        computerPt = 0: playerPt = 0
    ElseIf playerPt >= 21 Then
        _MessageBox "Congrats!", "You beat the Computer."
        computerPt = 0: playerPt = 0
    End If
Loop
End

player:
For snd = 400 To 800 Step 20: Sound snd, .5: Next ' player pt
playerPt = playerPt + 1
makeSmile playerX, playerY
makeFrown computerX, computerY
fcirc ballX, ballY, BallR, &HFFFFFFFF
_Display
_Delay 1
Return

computer:
For snd = 800 To 400 Step -20: Sound snd, .5: Next
computerPt = computerPt + 1
makeSmile computerX, computerY
makeFrown playerX, playerY
fcirc ballX, ballY, BallR, &HFFFFFFFF
_Display
_Delay 1
Return

' ============================================================================= Code for this app

Sub makeSmile (x, y)
    arc x, y, 23, _D2R(55), _D2R(125), &HFFFF0000
    arc x, y, 24, _D2R(55), _D2R(125), &HFFFF0000
End Sub

Sub makeFrown (x, y)
    arc x, y + 46, 23, _D2R(240), _D2R(300), &HFFFF0000
    arc x, y + 46, 22, _D2R(240), _D2R(300), &HFFFF0000
End Sub

Sub makeEyes (x, y)
    Dim a
    fcirc x - 10, y, 8, &HFFFFFFFF
    fcirc x + 10, y, 8, &HFFFFFFFF
    a = _Atan2(ballY - y, ballX - (x - 10))
    fcirc x - 10 + 2.5 * Cos(a), y + 2.5 * Sin(a), 3, &HFF000000
    a = _Atan2(ballY - y, ballX - (x + 10))
    fcirc x + 10 + 2.5 * Cos(a), y + 2.5 * Sin(a), 3, &HFF000000
    Line (x - 3, y + 23)-Step(6, 2), &HFFFF0000, BF
End Sub

Sub makeLeftPaddle
    LPaddle = _NewImage(2 * PaddleR, 3 * PaddleR, 32)
    _Dest LPaddle
    Rectircle PaddleR - 1, 1.5 * PaddleR, 2 * PaddleR - 1, 3 * PaddleR - 1, PaddleR, &HFFBB6600, -1
    _Dest 0
End Sub

Sub makeTableImg
    Table = _NewImage(_Width, _Height, 32)
    _Dest Table
    Cls , &HFF000088
    Line (TableL, TableY)-(TableR, TableY + 20), &HFF008855, BF
    Line (TableL + 40, TableY + 20)-(TableL + 50, _Height), &HFF444444, BF
    Line (TableR - 50, TableY + 20)-(TableR - 40, _Height), &HFF444444, BF
    Line (NetL, NetY)-(NetR, TableY), &HFF444444, BF
    Line (NetL + 1, NetY)-(NetR - 1, NetY + 20), &HFFFFFFFF, BF
    _Dest 0
End Sub

' =========================================================================== from my Code Library

Sub fcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long) ' Gold standard for Circle Fill
    Dim Radius As Long, RadiusError As Long
    Dim X As Long, Y As Long
    Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
    If Radius = 0 Then PSet (CX, CY), C: Exit Sub
    Line (CX - X, CY)-(CX + X, CY), C, 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), C, BF
                Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
        Y = Y + 1
        Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
        Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
    Wend
End Sub

' this sub uses Sub arc (x, y, r, raStart, raStop, c As _Unsigned Long)
' this does not check raStart and raStop like arcC does
Sub Rectircle (cx, cy, w, h, r, c As _Unsigned Long, Fill) 'assume default single
    ' a Rectangle with arc circular corners
    ' cx, cy is the middle of the Squircle
    ' w, h = rectangle width and height
    ' r = radius of circular arc (as opposed to elliptical arc
    ' c is color
    'so r needs to be  < .5 * s ie if r = .5 * s then it's just a circle
    'likewise? if r = 0 then just a square
    Dim temp&, xo, yo, p, pd2, p32, xConst, yConst
    Static sd& ' so dont have to free image after each use
    sd& = _Dest ' save dest
    temp& = _NewImage(w + 1, h + 1, 32) ' create a drawing area  side of square
    _Dest temp&
    xo = w / 2: yo = h / 2 ' middles
    p = _Pi: pd2 = p / 2: p32 = p * 3 / 2
    xConst = .5 * (w - 2 * r) '             looks like this is first needed number
    yConst = .5 * (h - 2 * r) '             to get the 4 origins for the arcs from xm y center
    '4 arcs
    arc xo - xConst, yo - yConst, r, p, p32, c
    arc xo + xConst, yo - yConst, r, p32, 0, c
    arc xo + xConst, yo + yConst, r, 0, pd2, c
    arc xo - xConst, yo + yConst, r, pd2, p, c
    '4 lines
    Line (xo - xConst, yo - yConst - r)-(xo + xConst, yo - yConst - r), c
    Line (xo - xConst, yo + yConst + r)-(xo + xConst, yo + yConst + r), c
    Line (xo - xConst - r, yo - yConst)-(xo - xConst - r, yo + yConst), c
    Line (xo + xConst + r, yo - yConst)-(xo + xConst + r, yo + yConst), c
    If Fill Then Paint (xo, yo), c, c
    _Dest sd&
    _PutImage (cx - xo, cy - yo), temp&, sd&
End Sub

'use radians draw arc from Start to Stop Clockwise
' this does not check raStart and raStop like arcC does
Sub arc (x, y, r, raStart, raStop, c As _Unsigned Long)
    Dim al, a
    'x, y origin, r = radius, c = color

    'raStart is first angle clockwise from due East = 0 degrees
    ' arc will start drawing there and clockwise until raStop angle reached

    If raStop < raStart Then
        arc x, y, r, raStart, _Pi(2), c
        arc x, y, r, 0, raStop, c
    Else
        ' modified to easier way suggested by Steve
        'Why was the line method not good? I forgot.
        al = _Pi * r * r * (raStop - raStart) / _Pi(2)
        For a = raStart To raStop Step 1 / al
            PSet (x + r * Cos(a), y + r * Sin(a)), c
        Next
    End If
End Sub

'from Rain Drain 3 check of hitLine Function
Function hitLine (CircleX, CircleY, CircleR, xx1, yy1, xx2, yy2) ' circle intersect line seg
    Dim x1, y1, x2, y2
    x1 = xx1: y1 = yy1: x2 = xx2: y2 = yy2 ' copy these values so they dont get changed with swap
    If x1 > x2 Then Swap x1, x2: Swap y1, y2
    If CircleX + CircleR < x1 Or CircleX - CircleR > x2 Then hitLine = 0: Exit Function
    If ((y2 - y1) / (x2 - x1)) * (CircleX - x1) + y1 - CircleR < CircleY And_
     CircleY < ((y2 - y1) / (x2 - x1)) * (CircleX - x1) + y1 + CircleR Then

        hitLine = 1
    Else
        hitLine = 0
    End If
End Function

   
b = b + ...
Reply


Messages In This Thread
Profile Pong Game Development - by bplus - 02-04-2023, 08:30 PM
RE: Profile Pong Game Development - by bplus - 02-04-2023, 08:35 PM
RE: Profile Pong Game Development - by bplus - 02-04-2023, 08:43 PM
RE: Profile Pong Game Development - by bplus - 02-04-2023, 08:47 PM
RE: Profile Pong Game Development - by bplus - 02-04-2023, 08:51 PM
RE: Profile Pong Game Development - by mnrvovrfc - 02-04-2023, 09:07 PM
RE: Profile Pong Game Development - by bplus - 02-04-2023, 10:03 PM
RE: Profile Pong Game Development - by mnrvovrfc - 02-04-2023, 10:48 PM
RE: Profile Pong Game Development - by bplus - 02-05-2023, 12:01 AM
RE: Profile Pong Game Development - by bplus - 02-05-2023, 12:56 AM
RE: Profile Pong Game Development - by mnrvovrfc - 02-05-2023, 02:01 AM
RE: Profile Pong Game Development - by bplus - 02-05-2023, 06:36 AM
RE: Profile Pong Game Development - by bplus - 02-05-2023, 08:30 PM



Users browsing this thread: 4 Guest(s)