Game of Pong
(... in less than 1K of compiled code)
|
With the Nextion NX3224K024 attached to the Scamp, we can create a simple game... the classic game of Pong.
For this, as well as the LCD you will need pot connected to pin 2 of your Scamp to use as a paddle/bat. You will also need the LCD words added to your Scamp's dictionary. |
Source Code
For this game, we will use variables to store the current coordinates of the ball, the rate of movement of the ball in the x and y axes, the location of where the bat was, the location of where the bat now is, and a flag to indicate a miss.
variable ballx \ ball x location
variable bally \ ball y location
variable xdir \ delta x
variable ydir \ delta y
variable oldbat \ previous bat location
variable newbat \ current bat location
variable crash \ flag
The next word draws a yellow ($ff00) paddle on the screen. It takes a value from the stack (y screen coordinate).
: paddle ( y -- )
$ff00 swap \ swap color
15 swap 40 swap \ width height
0 swap \ x coord
area \ draw it
;
You can test it by typing 50 paddle. Make sure you've run setbaud and 0 lcdcls first.
The next word samples the pot for its current value and scales this 12-bit number down to the vertical screen size of the LCD (allowing for the height of the paddle). This value is then stored to the variable holding the current bat location.
The next word samples the pot for its current value and scales this 12-bit number down to the vertical screen size of the LCD (allowing for the height of the paddle). This value is then stored to the variable holding the current bat location.
: gety \ gets current location of bat
sample 19 u/ \ scale it
dup 208 > if \ if it's greater than 208
drop 209 \ just make it 209
then
newbat ! \ store it the bat location variable
;
The following word initializes everything for the game. It increases the baud rate of the LCD, sets up the analog input, clears the LCD with a black background and sets up the variables.
: ponginit
fastbaud
2 analog \ control pot connected to pin 2
2 channel
0 lcdcls \ clear the screen, black background
gety \ initial y coord
newbat @ oldbat !
newbat @ paddle \ draw paddle at starting position
100 ballx ! \ starting x position
random 280 u/ bally ! \ random y position
0 crash ! \ clear the miss flag
;
Type ponginit to initialize things, so that you can test as you go.
Next we create a word to clear the screen and display "GAME OVER" in red letters.
Next we create a word to clear the screen and display "GAME OVER" in red letters.
: gameover \ clear screen and print "GAME OVER"
0 lcdcls
lcd
." xstr 80,100,150,40,0,RED,BLACK,1,1,1,"
34 emit
." GAME OVER"
34 emit
eoc console
;
Type gameover and you should see a message appear on the screen.
As the bat moves we need to erase the pixels of the bat at its previous location. Since the bat lives in the left most part of the screen, we can cheat and just draw black rectangles above and below the current bat location. This word does just that:
As the bat moves we need to erase the pixels of the bat at its previous location. Since the bat lives in the left most part of the screen, we can cheat and just draw black rectangles above and below the current bat location. This word does just that:
: erasebat \ removes old bat
newbat @ 209 < if \ if not at bottom erase below
0 \ color
15 \ width
239 newbat @ 40 + - \ required height
0 \ x
newbat @ 40 + \ y
area
then
newbat @ 0 > if \ if not at top erase above
0 \ color
15 \ width
newbat @ 1 - \ required height
0 \ x
0 \ y starting pos
area
then
;
The next three words draw the bat and ball at their current positions, and erase the ball.
: bat \ draw the bat
gety \ read pot
newbat @ oldbat @ \ compare with previous position
<> if \ bat has moved?
newbat @
dup paddle \ draw bat at new position
erasebat \ erase old bat pixels
oldbat ! \ set to the (new) old position
then
;
: ball \ draw the ball
$ffff \ ball color
5 \ radius
ballx @ bally @ \ get location
filledcircle
;
: eraseball \ draw black ball to erase old one
0 5 ballx @ bally @ filledcircle
;
Next we need words to update the ball location:
: movex \ new ball x position
xdir @ ballx @ +
dup
11 314 within \ check it's within valid boundaries
if
ballx !
else \ change direction
drop
xdir @ negate xdir !
then
;
: movey \ new ball y position
ydir @ bally @ +
dup
6 234 within \ check it's within valid boundaries
if
bally !
else \ change direction
drop
ydir @ negate ydir !
then
;
If we're at the left side of the screen, we need to check if the bat is within the same y location. This word does that:
: miss?
ballx @ 25 < \ if we're at the left side
if
bally @ \ get current y location of ball
newbat @ 10 - dup \ next to the bat?
50 + within 0=
if \ no
1 crash ! \ flag a miss
7 emit \ beep
gameover \ print game over
then
then
;
Putting it all together:
: pong \ the game
ponginit \ set everything up
10 xdir ! \ ball speed in x direction
5 ydir ! \ ball speed in x direction
1500 ms 7 emit \ wait 1.5 secs then beep
begin
bat \ draw the bat
eraseball \ erase the old ball
movex movey ball \ move the ball and draw it
miss? \ was it a miss?
crash @ key? or until \ keep going until a miss or key press
;
To run, type pong at the prompt.
This is a very quick version. Experiment with the code. I'm sure you can polish it to make it even better.
And just note that the entire game only uses 874 bytes of flash and 14 bytes of RAM. Forth is very efficient!
This is a very quick version. Experiment with the code. I'm sure you can polish it to make it even better.
And just note that the entire game only uses 874 bytes of flash and 14 bytes of RAM. Forth is very efficient!