HP Prime for All

English  Русский 
Pong games-app screenshot}}
Name Pong
Description The famous PONG game, now available on the Prime. Features: 3 modes (1 Player, 2 Players, and demo), 3 difficulty levels (beginner, intermediate, expert), and black and white graphics for the real retro feeling.
Author Jurgen Keller

Source code (download):

Source code formatted by website engine

//------------------------------------- // PONG for HP Prime // Version 0.1, March 2014 // Jurgen Keller < jkeller@gmx.ch > // http://calc.fjk.ch/ //------------------------------------- // Constants, see Initialize() // Background/Foreground color LOCAL Color0, Color1; // Keys to control paddles LOCAL Kup, Kdn; // Outer court (top left/bottom right) LOCAL Fx1, Fy1, Fx2, Fy2; // Center position on the court LOCAL Mx, My; // Number of points needed to win LOCAL Win; // Difficulty settings LOCAL Difficulty; // Size of a single score bitmap // in pixels LOCAL Scx, Scy; // Scale factor for score bitmaps LOCAL Scf; //------------------------------------- // Game variables // Current play mode: // 1 - 1 Player // 2 - 2 Players // 3 - Demo // 0 - Quit LOCAL Mode; // Current difficulty level: // 1 - > beginner // 2 - > intermediate // 3 - > expert LOCAL Level; // Current score for player 1 and 2 LOCAL Score; // Flag to signal that ball is about // to go out of bounds, i.e., that it // passed a paddle. // 0 - > ball is inside // 1 - > ball has passed P1's paddle // 2 - > ball has passed P2's paddle LOCAL Out; // Player who is designated the server LOCAL Server; // Ball position (top left) LOCAL Bpx, Bpy; // Ball size in pixels LOCAL Bsx, Bsy; // Ball motion vector LOCAL Bmx, Bmy; // Min/Max X/Y position of ball LOCAL BpxMin, BpxMax, BpyMin, BpyMax; // Paddle positions (top left) LOCAL Ppx, Ppy; // Paddle size in pixels LOCAL Psx, Psy; // Paddle speed LOCAL Pmy; // Min/Max Y position of paddles LOCAL PpyMin, PpyMax; // The y position where an automatic // player wants to hit the paddle LOCAL HitPt; // Inner court (top left/bottom right); // this is where the ball moves around LOCAL Ix1, Iy1, Ix2, Iy2; //------------------------------------- // Initialize all constant values. // Initialize() BEGIN // B&W for the real retro feeling Color0 := RGB(0, 0, 0); Color1 := RGB(255, 255, 255); // Outer court Fx1 := 4; Fy1 := 4; Fx2 := 320-Fx1; Fy2 := 240-Fy1; // center position Mx := (Fx1+Fx2) / 2; My := (Fy1+Fy2) / 2; // control keys Kup := {32, 35}; // '7' and '/' Kdn := {47, 50}; // '0' and '+' // score bitmap size and scaling Scx := 7; Scy := 5; Scf := 4; // difficulty settings // (ball speed factor, paddle length, // auto paddle speed) Difficulty := { {2.2, 46, 1.4}, {2.8, 36, 2.1}, {3.4, 28, 2.8} }; // others Win := 10; END; //------------------------------------- // Clear the screen. Cls() BEGIN RECT_P(Color0); END; //------------------------------------- // Wait until user presses a key from // a list. Returns index of the key. // ReadKey(Keys) BEGIN LOCAL I, J, K; I := -1; WHILE I < 0 DO K := GETKEY(); FOR J FROM 1 TO SIZE(Keys) DO IF K == Keys[J] THEN I := J; END; END; END; RETURN I; END; //------------------------------------- // Draw a multi-line text on G. // Parameters: // Txt - a list of strings; // use an empty string to // start new paragraph // X, Y - top left position // Height - line height in pixels // Font - font size // DrawText(G, Txt, X, Y, Height, Font) BEGIN LOCAL I, V := Y; FOR I FROM 1 TO SIZE(Txt) DO IF SIZE(Txt[I]) > 0 THEN TEXTOUT_P(Txt[I], G, X, V, Font, Color1, 320, Color0); V := V+Height; ELSE // new paragraph V := V+Height/2; END; END; END; //------------------------------------- // Draw the PONG logo on G. // DrawLogo(G) BEGIN // PONG bitmap DIMGROB_P(G6, 20, 5, {#7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF00007FFF:64h, #7FFF00007FFF7FFF:64h, #7FFF7FFF7FFF:64h, #7FFF000000007FFF:64h, #7FFF0000:64h, #7FFF00007FFF:64h, #7FFF00007FFF0000:64h, #0:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF0000:64h, #7FFF00007FFF:64h, #7FFF00007FFF0000:64h, #7FFF7FFF0000:64h, #7FFF:64h, #7FFF0000:64h, #7FFF00007FFF:64h, #7FFF00007FFF0000:64h, #7FFF00000000:64h, #7FFF:64h, #7FFF7FFF7FFF0000:64h, #7FFF00007FFF:64h, #7FFF00007FFF0000:64h, #7FFF7FFF7FFF:64h}); BLIT_P(G, 60, 30, 260, 80, G6, 0, 0, 20, 5); END; //------------------------------------- // Draw the court on G. // DrawCourt(G, Mode) BEGIN LOCAL X, Y, S; // top and bottom border RECT_P(G, Fx1, Fy1, Fx2-1, Iy1-1, Color1); RECT_P(G, Fx1, Iy2, Fx2-1, Fy2-1, Color1); // dotted line in the middle S := Iy1-Fy1; X := (Fx1+Fx2+1-W) / 2; FOR Y FROM Iy1+1 TO Iy2 STEP 2*S DO RECT_P(G, X, Y, X+S-1, Y+S-1, Color1); END; IF Mode == 3 THEN TEXTOUT_P("Press Esc to quit demo mode", G, 68, 210, 3, Color1, 320, Color0); END; END; //------------------------------------- // Draw current score on G. // DrawScore(G) BEGIN LOCAL W := Scx*Scf; LOCAL H := Scy*Scf; LOCAL Y1, Y2; Y1 := Iy1+8; Y2 := Score[1]*H; BLIT_P(G, 118, Y1, G3, 0, Y2, W, Y2+H); Y2 := Score[2]*H; BLIT_P(G, 174, Y1, G3, W, Y2, 2*W, Y2+H); END; //------------------------------------- // Prepare graphical objects for fast // drawing. // Usage of graphics objects: // G1 - used to assemble a frame // G2 - court // G3 - score bitmap // G4 - paddle // G5 - ball // MakeGrobs() BEGIN LOCAL Scw, Sch; DIMGROB_P(G1, 320, 240, Color0); // Court DIMGROB_P(G2, 320, 240, Color0); DrawCourt(G2, Mode); // Paddle DIMGROB_P(G4, Psx, Psy, Color1); // Ball DIMGROB_P(G5, Bsx, Bsy, Color1); // Score Bitmap DIMGROB_P(G6, 14, 55, {#7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF0000:64h, #7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF0000:64h, #7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF7FFF00000000:64h, #7FFF7FFF00000000:64h, #0:64h, #0:64h, #7FFF0000:64h, #7FFF0000:64h, #0:64h, #7FFF000000000000:64h, #7FFF000000000000:64h, #0:64h, #0:64h, #7FFF0000:64h, #7FFF0000:64h, #0:64h, #7FFF000000000000:64h, #7FFF000000000000:64h, #0:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #0:64h, #7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF0000:64h, #7FFF0000:64h, #0:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF7FFF00000000:64h, #7FFF7FFF00007FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF0000:64h, #7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #0:64h, #7FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF000000000000:64h, #0:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF0000:64h, #7FFF0000:64h, #0:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF0000:64h, #7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #0:64h, #7FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #0:64h, #7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF0000:64h, #7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF0000:64h, #7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF7FFF:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #7FFF000000000000:64h, #7FFF7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #0:64h, #7FFF00000000:64h, #7FFF00000000:64h, #0:64h, #7FFF7FFF7FFF0000:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF:64h, #7FFF00007FFF7FFF:64h, #7FFF7FFF7FFF7FFF:64h, #7FFF7FFF00007FFF:64h, #7FFF00007FFF7FFF:64h, #7FFF0000:64h, #7FFF00007FFF:64h, #7FFF000000007FFF:64h, #7FFF00007FFF0000:64h, #7FFF00000000:64h, #7FFF00007FFF:64h, #7FFF00007FFF0000:64h, #7FFF0000:64h, #7FFF00007FFF:64h, #7FFF000000007FFF:64h, #7FFF00007FFF0000:64h, #7FFF7FFF7FFF:64h, #7FFF7FFF00007FFF:64h, #7FFF7FFF:64h}); Scw := 2*Scx; // 2 digits per score Sch := 11*Scy; // 11 scores (0..10) DIMGROB_P(G3, Scw*Scf, Sch*Scf, Color0); BLIT_P(G3, 0, 0, Scw*Scf, Sch*Scf, G6, 0, 0, Scw, Sch); END; //------------------------------------- // Handle collision of ball with top // and bottom court boundaries. // HandleWallCollision() BEGIN IF Bpy < BpyMin THEN Bpy := 2*BpyMin-Bpy; Bmy := -Bmy; ELSE IF Bpy > BpyMax THEN Bpy := 2*BpyMax-Bpy; Bmy := -Bmy; END; END; END; //------------------------------------- // Handle collision of ball with one // of the paddles. // The new Y component of the ball's // motion vector depends on where the // ball hit the paddle. The hit point // is in the range: // [ - (Psy+Bsy) / 2, +(Psy+Bsy) / 2] // That value is scaled such that the // angle is not more than about 50 // degrees (TAN(angle)~ = 1.2). // HandlePaddleCollision() BEGIN LOCAL F := -1.2*Difficulty[Level, 1]; IF Bpx < BpxMin THEN Out := 1; IF Bpy > Ppy[1]-Bsy THEN IF Bpy < Ppy[1]+Psy THEN Bpx := 2*BpxMin-Bpx; Bmx := -Bmx; Bmy := Ppy[1]-Bpy + (Psy-Bsy) / 2; Bmy := F*Bmy / ((Psy+Bsy) / 2); Out := 0; END; END; ELSE IF Bpx > BpxMax THEN Out := 2; IF Bpy > Ppy[2]-Bsy THEN IF Bpy < Ppy[2]+Psy THEN Bpx := 2*BpxMax-Bpx; Bmx := -Bmx; Bmy := Ppy[2]-Bpy + (Psy-Bsy) / 2; Bmy := F*Bmy / ((Psy+Bsy) / 2); Out := 0; END; END; END; END; END; //------------------------------------- // Move the ball. Handle collisions // with court and paddles. // MoveBall() BEGIN Bpx := Bpx+Bmx; Bpy := Bpy+Bmy; HandleWallCollision(); IF NOT Out THEN HandlePaddleCollision(); END; END; //------------------------------------- // Let the computer move a paddle. // Strategy if ball leaves: // - > choose a random point around // the middle and move towards // that point // Strategy if ball approaches: // - > choose a random hit point on // the paddle, then align that // point to the ball // MoveAutoPaddle(Nr) BEGIN IF (Nr == 1 AND Bmx < 0) OR (Nr == 2 AND Bmx > 0) THEN IF HitPt[Nr] < 0 THEN // hit point might be outside the paddle // so that computer sometimes misses HitPt[Nr] := RANDOM(Psy+4) - 2; END; IF Bpy < Ppy[Nr]+HitPt[Nr]-2 THEN Ppy[Nr] := MAX(Ppy[Nr]-Pmy[Nr], PpyMin); ELSE IF Bpy > Ppy[Nr]+HitPt[Nr]+2 THEN Ppy[Nr] := MIN(Ppy[Nr]+Pmy[Nr], PpyMax); END; END; ELSE IF HitPt[Nr] >= 0 THEN HitPt[Nr] := - (My-Psy/2+RANDOM(80) - 40); END; IF Ppy[Nr] < -HitPt[Nr]-2 THEN Ppy[Nr] := Ppy[Nr]+Pmy[Nr]/2; ELSE IF Ppy[Nr] > -HitPt[Nr]+2 THEN Ppy[Nr] := Ppy[Nr]-Pmy[Nr]/2; END; END; END; END; //------------------------------------- // Move a user controlled paddle. // A short acceleration phase allows // for positioning the paddle more // precisely. // MoveUserPaddle(Nr) BEGIN LOCAL PmyMax := 1.5*Difficulty[Level, 3]; IF ISKEYDOWN(Kup[Nr]) THEN Ppy[Nr] := MAX(Ppy[Nr]-Pmy[Nr], PpyMin); Pmy[Nr] := MIN(1.1*Pmy[Nr], PmyMax); ELSE IF ISKEYDOWN(Kdn[Nr]) THEN Ppy[Nr] := MIN(Ppy[Nr]+Pmy[Nr], PpyMax); Pmy[Nr] := MIN(1.1*Pmy[Nr], PmyMax); ELSE Pmy[Nr] := PmyMax/4; END; END; END; //------------------------------------- // Move a paddle controlled by user or // computer. // MovePaddle(Nr) BEGIN IF (Mode == 1 AND Nr == 1) OR (Mode == 3) THEN MoveAutoPaddle(Nr); ELSE MoveUserPaddle(Nr); END; END; //------------------------------------- // Draw the current state of the game. // UpdateScreen() BEGIN // court BLIT_P(G1, G2); // score DrawScore(G1); // paddles BLIT_P(G1, Ppx[1], Ppy[1], G4, 0, 0, Psx, Psy); BLIT_P(G1, Ppx[2], Ppy[2], G4, 0, 0, Psx, Psy); // ball BLIT_P(G1, Bpx, Bpy, G5, 0, 0, Bsx, Bsy); // now display the frame BLIT_P(G0, G1); // for debugging // REPEAT UNTIL ISKEYDOWN(30); END; //------------------------------------- // Update score after ball went out // of the court. Player scores if // opponent missed the ball. // UpdateScore() BEGIN IF Mode > 0 THEN Server := 3-Out; Score[Server] := Score[Server]+1; END; END; //------------------------------------- // Position the ball in the middle and // choose a random ball motion towards // the opponent. // PrepareService() BEGIN Bpx := (2*Mx+2-Bsx) / 2; Bpy := (2*My-Bsy) / 2; // not more than ~20 degrees Bmx := Difficulty[Level, 1]; Bmy := Bmx*RANDINT(20) / 50; IF RANDINT THEN Bmy := -Bmy; END; IF Server == 2 THEN Bmx := -Bmx; END; Out := 0; END; //------------------------------------- // Center paddles and prepare service. // PrepareRally() BEGIN Ppy[1] := My-Psy/2; Ppy[2] := Ppy[1]; PrepareService(); END; //------------------------------------- // Rally ends if // - ball is outside the court // - or if user quits demo mode // IsRallyEnd() BEGIN IF Mode == 3 AND ISKEYDOWN(4) THEN // user requested to leave demo mode Mode := 0; END; RETURN NOT Mode OR (Out AND (Bpx < -Bsx OR Bpx > 320)); END; //------------------------------------- // Play a single rally. // PlayRally() BEGIN PrepareRally(); UpdateScreen(); IF Mode <> 3 THEN // allow players to prepare WAIT(1.5); END; REPEAT MoveBall(); MovePaddle(1); MovePaddle(2); UpdateScreen(); UNTIL IsRallyEnd(); UpdateScore(); UpdateScreen(); END; //------------------------------------- // Prepare a match. Initialize all the // game variables. Some of them depend // on the difficulty level, e.g., the // size of the paddles. // PrepareMatch() BEGIN // ball size Bsx := 8; Bsy := 8; // paddle size Psx := 8; Psy := Difficulty[Level, 2]; // inner court Ix1 := Fx1+Psx+4; Ix2 := Fx2-Psx-4; Iy1 := Fy1+2; Iy2 := Fy2-2; // paddle positions Ppx := {Ix1-Psx, Ix2}; Ppy := {0, 0}; // paddle speed Pmy := {Difficulty[Level, 3], Difficulty[Level, 3]}; // min/max ball position BpxMin := Ppx[1]+Psx; BpxMax := Ppx[2]-Bsx; BpyMin := Iy1; BpyMax := Iy2-Bsy; // min/max paddle position PpyMin := Iy1+1; PpyMax := Iy2-Psy-1; // server IF Mode == 1 THEN Server := 2; ELSE Server := 1; END; // reset score Score := {0, 0}; // Prepare bitmaps for drawing MakeGrobs(); // misc stuff HitPt := {-1, -1}; END; //------------------------------------- // Match ends if // - one of the players reached 10 pts // - or if user quits demo mode // IsMatchEnd() BEGIN RETURN NOT Mode OR (Score[1] == Win OR Score[2] == Win); END; //------------------------------------- // Presentation ceremony. // ShowWinner() BEGIN LOCAL X := 174; IF Score[1] == Win THEN X := 64; END; TEXTOUT_P("WINNER", G0, X, 40, 7, Color1); END; //------------------------------------- // Return // - true if user wants to play // another game // - false if user wants to quit // PlayAgain() BEGIN LOCAL Again := 0; CASE IF Mode == 1 OR Mode == 2 THEN TEXTOUT_P("Press Enter to play again or Esc to quit", G0, 38, 200, 3, Color1, 320, Color0); IF ReadKey({4, 30}) == 2 THEN Again := 1; END; END; IF Mode == 3 THEN // still in demo mode Again := WAIT(1); END; END; RETURN Again; END; //------------------------------------- // Play a match (a series of rallys) // and show the winner at the end. // PlayMatch() BEGIN REPEAT PrepareMatch(); REPEAT PlayRally(); UNTIL IsMatchEnd(); ShowWinner(); UNTIL NOT PlayAgain(); END; //------------------------------------- // Display help on how to play PONG. // ShowInstructions() BEGIN LOCAL Cap := { {"ONE PLAYER INSTRUCTIONS"}, {"TWO PLAYER INSTRUCTIONS"}}; LOCAL Txt := { {"Control the paddle on the right hand side", "of the screen using your keyboard.", "Use '/' to move the paddle up and '+' to", "move the paddle down.", "", "Points are scored when your opponent", "misses the ball. First player to reach 10", "points wins the game.", "", "Press Enter to continue"}, {"Player 1 controls the left hand paddle", "using the '7' (up) and '0' (down) keys.", "Player 2 controls the right hand paddle", "using the '/' (up) and '+' (down) keys.", "", "Points are scored when a player misses", "the ball. First player to reach 10 points", "wins the game.", "", "Press Enter to continue"}}; IF Mode == 1 OR Mode == 2 THEN Cls(); DrawText(G0, Cap[Mode], 24, 24, 18, 4); DrawText(G0, Txt[Mode], 24, 55, 18, 3); ReadKey({30}); END; END; //------------------------------------- // Let the user choose the difficulty // level (beginner, intermediate, or // expert). // ChooseLevel() BEGIN LOCAL Txt := { "[1] Beginner", "[2] Intermediate", "[3] Expert", "Esc to quit"}; IF Mode == 3 THEN // choose 'beginner' for demo Level := 1; ELSE Cls(); DrawLogo(G0); DrawText(G0, Txt, 100, 110, 25, 5); Level := ReadKey({4, 42, 43, 44}) - 1; END; END; //------------------------------------- // Let the user choose the play mode // (1 Player, 2 Players, Demo). // ChooseMode() BEGIN LOCAL Txt := { "[1] 1 Player", "[2] 2 Player", "[3] Demo Mode", "Esc to quit"}; Cls(); DrawLogo(G0); DrawText(G0, Txt, 100, 110, 25, 5); Mode := ReadKey({4, 42, 43, 44}) - 1; END; //------------------------------------- // The main function. // EXPORT PONG() BEGIN Initialize(); WHILE ChooseMode() > 0 DO IF ChooseLevel() > 0 THEN ShowInstructions(); PlayMatch(); END; END; END;

Comments