![]() |
Forum Index : Microcontroller and PC projects : tetris for Armmite F4
Author | Message | ||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 4857 |
Just to prove I can do it, I wrote a tetris game for the Armmite F4. The game is not finished, but it is playable. The game plays on the ArmmiteF4 LCD, but is in this phase controlled from the PC terminal. A move left, S move right, H rotate piece, <space> move down. There is an anonymous high score list The code needs cleanup, and makes use of goto and gosub a lot (sorry Geoff, MMBasic can do so much better). At least I dropped the line numbers...hihi. Here is the current code: ' -------------------- tetris for Armmite F4 ---------------------- ' ' the game has a playfield of 20 deep and 10 wide ' the game plays on this field, and is pasted into suitable graphics per ' platform. For F4 this is the ILI9341 320x240 display configuration ' OPTION LCDPANEL ILI9341_16, RLANDSCAPE ' OPTION TOUCH PB12, PC5 ' ' keyboard controls: a/s for left-right, h for rotate, d for down, ' space for fast down ' ' empty playfield = 0, live pieces 1-6 have color 1-6. ' locked pieces color -1..-6 ' ' to do: ' - implement buttons at GPIO ' - make hiscore list non volatile (F4 only) ' - add T piece (7'th piece, forgotten) ' - add startup screen ' - add end screen ' - make speed variable ' ' -- 31-7-2020 -------------------------------------- Volhout ----- '------------------------ declare variables ----------------------- Dim field(10,20) 'playing field 10x20,each cell is 0(empty) or a color Dim pieces(6,8,4) '6 different pieces, each 4 coordinates, 4 orientations Dim hiscore(8) 'the hiscore list 8 deep (no player names) Dim colors(6) 'the 6 colors for the 6 different pieces 'if virgin start, hiscore list is empy (adapt to non-volatile list) For i=1 To 8:hiscore(i)=0:Next i '---------------------- init varaibles ------------------------ startgame: 'init all the variables for a new game 'clear field For i=1 To 10:For j=1 To 20: field(i,j)=0: Next j: Next i 'load pieces Restore For o=1 To 2: For i=1 To 6:For j=1 To 8:Read pieces(i,j,o):Next j:Next i:Next o Restore For o=3 To 4: For i=1 To 6:For j=1 To 8 Read u pieces(i,j,o)=-u 'orientations 3 and 4 are mirrors of 1 and 2 Next j:Next i:Next o 'init the colors colors(1)=RGB(yellow):colors(2)=RGB(red):colors(3)=RGB(blue) colors(4)=RGB(green):colors(5)=RGB(cyan):colors(6)=RGB(magenta) colors(0)=RGB(black) 'setup game start score=0 : gameend=0 startx=5 : starty=1 : startorientation=1 o=startorientation c=Int(1+6*Rnd(Pi)) : cc = c 'make the first piece a random GoSub size '------------------------ GAME START -------------------- CLS ' gosub gameintro CLS 'clear lcd screen GoSub lcdborder GoSub newpiece 'start game SetTick 1000,godown 'here we can vary the game speed 'SetTick 300,godown '------------------------ GAME LOOP -------------------------- mainloop: 'keyboard input a$ = Inkey$ Pause 10 ' during this pause the "d" key is enforced by the timer If a$="" GoTo mainloop Print a$ 'debug 'first erase the piece at the old location GoSub clearpiece 'check for the change, and execute it 'left (a) and right (s) movement If a$="a" And x+xl=>2 Then oke=1 For i=1 To 7 Step 2 'check 4 coordinates per piece If field(x-1+pieces(c,i,o),y+pieces(c,i+1,o)) < 0 Then oke=0 Next i If oke Then x=x-1 End If If a$="s" And x+xr=<9 Then oke=1 For i=1 To 7 Step 2 'check 4 coordinates per piece If field(x+1+pieces(c,i,o),y+pieces(c,i+1,o)) < 0 Then oke=0 Next i If oke Then x=x+1 End If 'down will go automatic, but can also be manual '<space> will move the piece all the way down If a$="d" Or a$=" " Then loop_d: score = score+1 If y+yd=20 Then 'we are at the bottom GoSub lockpiece GoSub newpiece Else 'check if we can go down further oke=1 For i=1 To 7 Step 2 'check 4 coordinates per piece If field(x+pieces(c,i,o),1+y+pieces(c,i+1,o)) < 0 Then oke=0 Next i If oke Then 'if OK then we go down y=y+1 Else 'if not, we lock the piece into place by changin color GoSub lockpiece If y=1 Then 'if this happens top line of field, it is game end gameend=1 Else 'not game end: generate new piece GoSub newpiece End If End If End If If oke And a$=" " Then GoTo loop_d 'if space was hit we cycle once more End If 'rotate piece to 90 degrees orientation If a$="h" Then o=(o Mod 4)+1 GoSub adjust End If 'show the changes on the board GoSub showpiece 'update field with the new piece locatio 'GoSub showfield 'prints the field on the serial terminal GoSub lcdfield 'shows the field in graphics If gameend=1 Then 'at game end process high score list hi=score GoSub sortscores GoSub highscoreshow 'End 'GoSub endgame 'nice graphics to show the end 'with text "press key for next game" waitforkey: a$=Inkey$:If a$="" Then GoTo waitforkey GoTo startgame 'start new game End If GoTo mainloop '---------------------- GAME SUBS --------------------- 'sort the high score list by shifting entries down to make room sortscores: i=1:added=0 sortloop: If hiscore(i)<hi Then For j=7 To i Step -1 hiscore(j+1)=hiscore(j) Next j hiscore(i)=hi added=1 Else i=i+1 End If If added=0 Then GoTo sortloop Return 'generate a random new piece after checking if there is a full line newpiece: GoSub checkfullline x=startx:y=starty:o=startorientation c=cc '(c Mod 6)+1 GoSub size GoSub previewnext Return 'show the next piece (cc) in the preview window on lcd only previewnext: Box 3,165,68,68,4,RGB(white),RGB(black) cc=Int(6*Rnd(6)+1) xc=3+34:yc=165+34 For i=1 To 7 Step 2 Box pieces(cc,i,4)*15+xc,pieces(cc,i+1,4)*15+yc,15,15,1,0,colors(cc) Next Return 'after rotation, the geometry has changed. make it fit on the field. adjust: GoSub size If x+xl<1 Then x=1-xl If x+xr>10 Then x=10-xr If y+yu<1 Then y=1-yu Return 'calculate the max piece size around it's centre, after rotation size: xl=Min(pieces(c,1,o),pieces(c,3,o),pieces(c,5,o),pieces(c,7,o)) xr=Max(pieces(c,1,o),pieces(c,3,o),pieces(c,5,o),pieces(c,7,o)) yu=Min(pieces(c,2,o),pieces(c,4,o),pieces(c,6,o),pieces(c,8,o)) yd=Max(pieces(c,2,o),pieces(c,4,o),pieces(c,6,o),pieces(c,8,o)) Return 'paste the piece into the playing field at location x,y showpiece: For i=1 To 7 Step 2 '4 coordinates per piece field(x+pieces(c,i,o),y+pieces(c,i+1,o))=c Next i Return 'erase the (former) position of the piece from the playing field 'by setting the field positions back to 0 clearpiece: For i=1 To 7 Step 2 '4 coordinates per piece field(x+pieces(c,i,o),y+pieces(c,i+1,o))=0 Next i Return 'lock a piece in position x,y by inverting the color lockpiece: For i=1 To 7 Step 2 '4 coordinates per piece field(x+pieces(c,i,o),y+pieces(c,i+1,o))=-c Next i Return 'show the field array on the serial terminal. 0=empty '1..6 = active piece,-6...-1 = locked piece showfield: For j = 1 To 20 For i = 1 To 10 Print field(i,j); Next Next Return 'draw the playing field borders and fixed texts on the LCD lcdborder: Box 3,3,310,160,4,RGB(white),RGB(black) Box 3,165,68,68,4,RGB(white),RGB(black) Text 80,165+34,"score","CMU",2,,RGB(cyan) Text 130,165+34,"high","CMU",2,,RGB(cyan) GoSub highscoreshow Return 'interrupt timer pushes a "d" into the main loop to force a piece to move down Sub godown a$="d" End Sub 'draw the active field into the playing field border and update the score lcdfield: For i=1 To 10 For j=1 To 20 lcdx=(10.5-i)*15 lcdy=(j-0.5)*15 Box lcdy,lcdx,15,15,1,0,colors(Abs(field(i,j))) Next j Next i 'score Text 100,165+5,Str$(score),"CBU",2,,RGB(yellow) Return 'check if we have a full line, and remove it by copying the upper 'part of the field 1 row down. Up:y=1, down:y=20 checkfullline: For j=2 To 20 oke=1 For i=1 To 10 If field(i,j)=0 Then oke=0 Next i If oke Then For jj=j-1 To 1 Step -1 For i=1 To 10 field(i,jj+1)=field(i,jj) Next i Next jj End If Next j Return 'show the highscore values on the LCD highscoreshow: For i=1 To 8 Text 130+20*i,165+5,Str$(hiscore(i)),"CBU",2,,RGB(yellow) Next Return '------------------------ PIECES -------------------------- 'pieces horizontal view Data 0,0,-1,0,0,1,1,1 'S Data 0,0,1,0,1,1,0,1 'cube Data 0,0,-1,0,1,0,2,0 'I Data 0,0,1,0,0,1,-1,1 'Z Data 0,0,1,0,-1,0,-1,1 'L Data 0,0,-1,0,1,0,1,1 'J 'pieces vertical view Data 0,0,0,1,1,0,1,-1 'S Data 0,0,1,0,1,1,0,1 'cube (no difference) Data 0,0,0,-1,0,1,0,2 'I Data 0,0,0,-1,1,0,1,1 'Z Data 0,0,0,-1,0,1,1,1 'L Data 0,0,0,-1,0,1,-1,1 'J Edited 2020-08-01 01:12 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
RonnS Senior Member ![]() Joined: 16/07/2015 Location: GermanyPosts: 120 |
many many thanks Volhout, i like Tetris !!!. the keypad control is suboptimal. but it looks very good.. and.... tetris is nothing without a big sound ( i remember my "AMIGA" time ) many thanks Ron Edited 2020-08-01 07:51 by RonnS |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 4857 |
Hi RonnS, I actually posted this tetris version with the intention to archive it, and not continue developing. The proof was given, I could write tetris. But your response changed my mindset. I will improve the game with your suggestions. By the way: keyboard controls sub optimal: what do you suggest as best keyboard controls (the Amiga ones ?) I am open to suggestions. I have converted the old gameboy soundtrack to 8 bit WAV, so I can addi it to the game. The moment I played the soundtrack, old memories came back. Yes...sound is needed. Regards, Volhout PicomiteVGA PETSCII ROBOTS |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 4857 |
New version with sound (at pins PA4 and PA5) and non volatile highscore list The sound is played from a file called "tet16cut.wav" that I will add to the zip once the game is finished. All that is needed now is more logical controls (RonnS ?) and intro screen. And some small changes (the T piece is missing). I ran into some issue with MMBasic with SD card files. At the commandline you can open a file on the SD card for outputs as #1 and close it. Then open the file again for input as #1 and close it. If you do this in the program you get an "file already open" error. I had to re-open the file inside the MMBasic program as #2...???? I was just reminded by my wife that there where multiple tunes to choose from in the original gameboy tetris... so there is more to do... ' -------------------- tetris for Armmite F4 ---------------------- ' ' the game has a playfield of 20 deep and 10 wide ' the game plays on this field, and is pasted into suitable graphics per ' platform. For F4 this is the ILI9341 320x240 display configuration ' OPTION LCDPANEL ILI9341_16, RLANDSCAPE ' OPTION TOUCH PB12, PC5 ' ' keyboard controls: a/s for left-right, h for rotate, d for down, ' space for fast down ' ' empty playfield = 0, live pieces 1-6 have color 1-6. ' locked pieces color -1..-6 ' ' to do: ' - implement buttons ' - add T piece (7'th piece) ' - implement variable speed ' ' -- 1-8-2020 -------------------------------------- Volhout ----- '------------------------ declare variables ----------------------- Dim field(10,20) 'playing field 10x20,each cell is 0(empty) or a color Dim pieces(6,8,4) '6 different pieces, each 4 coordinates, 4 orientations Dim hiscore(8) 'the hiscore list 8 deep (no player names) Dim colors(6) 'the 6 colors for the 6 different pieces 'if virgin start, hiscore list does not exist 'For i=1 To 8:hiscore(i)=0:Next i: GoSub writescores 'read hiscore list Open "hiscore" For input As #1 For i=1 To 8:Input #1,hiscore(i):Next i Close #1 'start endless music now Play volume 30 'adjust for best gameplay (0-100) restartplay 'start music (endless loop) '---------------------- init varaibles ------------------------ startgame: 'init all the variables for a new game 'clear field For i=1 To 10:For j=1 To 20: field(i,j)=0: Next j: Next i 'load pieces Restore For o=1 To 2: For i=1 To 6:For j=1 To 8:Read pieces(i,j,o):Next j:Next i:Next o Restore For o=3 To 4: For i=1 To 6:For j=1 To 8 Read u pieces(i,j,o)=-u Next j:Next i:Next o 'init the colors colors(1)=RGB(yellow):colors(2)=RGB(red):colors(3)=RGB(blue) colors(4)=RGB(green):colors(5)=RGB(cyan):colors(6)=RGB(magenta) colors(0)=RGB(black) 'setup game start score=0 : gameend=0 startx=5 : starty=1 : startorientation=1 o=startorientation c=Int(1+6*Rnd(Pi)) : cc = c 'make the first piece a random GoSub size '------------------------ GAME START -------------------- CLS ' gosub gameintro CLS 'clear lcd screen GoSub lcdborder GoSub newpiece 'start game SetTick 1000,godown 'here we can vary the game speed '------------------------ GAME LOOP -------------------------- mainloop: 'keyboard input a$ = Inkey$ Pause 10 ' during this pause the "d" key is enforced by the timer If a$="" GoTo mainloop Print a$ 'debug 'first erase the piece at the old location GoSub clearpiece 'check for the change, and execute it 'left (a) and right (s) movement If a$="a" And x+xl=>2 Then oke=1 For i=1 To 7 Step 2 'check 4 coordinates per piece If field(x-1+pieces(c,i,o),y+pieces(c,i+1,o)) < 0 Then oke=0 Next i If oke Then x=x-1 End If If a$="s" And x+xr=<9 Then oke=1 For i=1 To 7 Step 2 'check 4 coordinates per piece If field(x+1+pieces(c,i,o),y+pieces(c,i+1,o)) < 0 Then oke=0 Next i If oke Then x=x+1 End If 'down will go automatic, but can also be manual '<space> will move the piece all the way down If a$="d" Or a$=" " Then loop_d: score = score+1 If y+yd=20 Then 'we are at the bottom GoSub lockpiece GoSub newpiece Else 'check if we can go down further oke=1 For i=1 To 7 Step 2 'check 4 coordinates per piece If field(x+pieces(c,i,o),1+y+pieces(c,i+1,o)) < 0 Then oke=0 Next i If oke Then 'if OK then we go down y=y+1 Else 'if not, we lock the piece into place by changin color GoSub lockpiece If y=1 Then 'if this happens top line of field, it is game end gameend=1 Else 'not game end: generate new piece GoSub newpiece End If End If End If If oke And a$=" " Then GoTo loop_d 'if space was hit we cycle once more End If 'rotate piece to 90 degrees orientation If a$="h" Then o=(o Mod 4)+1 GoSub adjust End If 'show the changes on the board GoSub showpiece 'update field with the new piece locatio 'GoSub showfield 'prints the field on the serial terminal GoSub lcdfield 'shows the field in graphics If gameend=1 Then 'at game end process high score list hi=score GoSub sortscores GoSub highscoreshow 'End 'GoSub endgame 'nice graphics to show the end 'with text "press key for next game" waitforkey: a$=Inkey$:If a$="" Then GoTo waitforkey GoTo startgame 'start new game End If GoTo mainloop '---------------------- GAME SUBS --------------------- 'sort the high score list by shifting entries down to make room sortscores: i=1:added=0 sortloop: If hiscore(i)<hi Then For j=7 To i Step -1 hiscore(j+1)=hiscore(j) Next j hiscore(i)=hi added=1 Else i=i+1 End If If (added=0 And i<8) Then GoTo sortloop 'Return writescores: 'overwrite highscore list Open "hiscore" For output As #2 For i=1 To 8: Print #2, hiscore(i): Next i Close #2 Return 'for both sortscores as writescores 'generate a random new piece after checking if there is a full line newpiece: GoSub checkfullline x=startx:y=starty:o=startorientation c=cc '(c Mod 6)+1 GoSub size GoSub previewnext Return 'show the next piece (cc) in the preview window on lcd only previewnext: Box 3,165,68,68,4,RGB(white),RGB(black) cc=Int(6*Rnd(6)+1) xc=3+34:yc=165+34 For i=1 To 7 Step 2 Box pieces(cc,i,4)*15+xc,pieces(cc,i+1,4)*15+yc,15,15,1,0,colors(cc) Next Return 'after rotation, the geometry has changed. make it fit on the field. adjust: GoSub size If x+xl<1 Then x=1-xl If x+xr>10 Then x=10-xr If y+yu<1 Then y=1-yu Return 'calculate the max piece size around it's centre, after rotation size: xl=Min(pieces(c,1,o),pieces(c,3,o),pieces(c,5,o),pieces(c,7,o)) xr=Max(pieces(c,1,o),pieces(c,3,o),pieces(c,5,o),pieces(c,7,o)) yu=Min(pieces(c,2,o),pieces(c,4,o),pieces(c,6,o),pieces(c,8,o)) yd=Max(pieces(c,2,o),pieces(c,4,o),pieces(c,6,o),pieces(c,8,o)) Return 'paste the piece into the playing field at location x,y showpiece: For i=1 To 7 Step 2 '4 coordinates per piece field(x+pieces(c,i,o),y+pieces(c,i+1,o))=c Next i Return 'erase the (former) position of the piece from the playing field 'by setting the field positions back to 0 clearpiece: For i=1 To 7 Step 2 '4 coordinates per piece field(x+pieces(c,i,o),y+pieces(c,i+1,o))=0 Next i Return 'lock a piece in position x,y by inverting the color lockpiece: For i=1 To 7 Step 2 '4 coordinates per piece field(x+pieces(c,i,o),y+pieces(c,i+1,o))=-c Next i Return 'show the field array on the serial terminal. 0=empty '1..6 = active piece,-6...-1 = locked piece showfield: For j = 1 To 20 For i = 1 To 10 Print field(i,j); Next Next Return 'draw the playing field borders and fixed texts on the LCD lcdborder: Box 3,3,310,160,4,RGB(white),RGB(black) Box 3,165,68,68,4,RGB(white),RGB(black) Text 80,165+34,"score","CMU",2,,RGB(cyan) Text 130,165+34,"high","CMU",2,,RGB(cyan) GoSub highscoreshow Return 'interrupt timer pushes a "d" into the main loop to force a piece to move down Sub godown a$="d" End Sub 'timed interrupt to restart the gameboy tetris tune when ended (1:16 duration) Sub restartplay Play wav "tet16cut.wav",restartplay 'start music, and restart when end 'Play wav "tet16cut.wav" End Sub 'draw the active field into the playing field border and update the score lcdfield: For i=1 To 10 For j=1 To 20 lcdx=(10.5-i)*15 lcdy=(j-0.5)*15 Box lcdy,lcdx,15,15,1,0,colors(Abs(field(i,j))) Next j Next i 'score Text 100,165+5,Str$(score),"CBU",2,,RGB(yellow) Return 'check if we have a full line, and remove it by copying the upper 'part of the field 1 row down. Up:y=1, down:y=20 checkfullline: For j=2 To 20 oke=1 For i=1 To 10 If field(i,j)=0 Then oke=0 Next i If oke Then For jj=j-1 To 1 Step -1 For i=1 To 10 field(i,jj+1)=field(i,jj) Next i Next jj End If Next j Return 'show the highscore values on the LCD highscoreshow: For i=1 To 8 Text 130+20*i,165+5,Str$(hiscore(i)),"CBU",2,,RGB(yellow) Next Return '------------------------ PIECES -------------------------- 'pieces horizontal view Data 0,0,-1,0,0,1,1,1 'S Data 0,0,1,0,1,1,0,1 'cube Data 0,0,-1,0,1,0,2,0 'I Data 0,0,1,0,0,1,-1,1 'Z Data 0,0,1,0,-1,0,-1,1 'L Data 0,0,-1,0,1,0,1,1 'J 'pieces vertical view Data 0,0,0,1,1,0,1,-1 'S Data 0,0,1,0,1,1,0,1 'cube (no difference) Data 0,0,0,-1,0,1,0,2 'I Data 0,0,0,-1,1,0,1,1 'Z Data 0,0,0,-1,0,1,1,1 'L Data 0,0,0,-1,0,1,-1,1 'J Edited 2020-08-02 05:56 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 4857 |
I finally go time to finalize the game. I have made several changes from the earier versions, although the heart remains the same. - changed the LCD to portait more - added the intro screen, derived from the original game boy screen - added the music from the original game boy - added the 7'th piece (the "T" piece was missing) - changed the controls to the arrow keys It is running on the new 5.07 version beta 1 when checking the code, please understand that there is still a heritage from the original controls, that where based on characters. For now it is finished (terminal keyboard controls) but when I change it into a stand alone game, there will be control buttons on the GPIO pins of the F4 The intro screen ![]() The playfield ![]() The ZIP containing the program, intro screen, and music is below tetris_F4.zip Happy playing.... Volhout Edited 2021-02-27 04:30 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10069 |
Missing the hiscore file. Tried a blank file but didn't work |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 4857 |
Thanks for testing. That was an oops on my side. I had an "uncomment" line in the code. Have added an on-error to fix this. And used the sort for arrays, in stead of writing my own sort. MMBasic has so many options and usefull commands and functions. tetris_F4.zip For my testing of the sound I use this breadboard friendly circuit (please don't expect hifi audio from it...) ![]() Edited 2021-02-27 17:25 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |