Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : PicoMite 1.28" round display ideas challenge
Page 1 of 2 | |||||
Author | Message | ||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 9122 |
Lewis recently sent me a 1.28" Round LCD HAT for Raspberry Pi Pico with a request to create a driver for it. This I have done and rather than add it to my huge box of unused displays we have agreed to send the display (not the cheapest) to the person who comes up with the most interesting idea for using it, with of course a commitment to building their idea. Details of the display are in the link. The PCB is 37mm at its widest point and 58mm tall and of course includes the 5 position joystick switch. It plugs directly onto a standard Pico Please post ideas on this thread and Lewis and I will judge the best with a Christmas deadline. Extra points will be given to anyone who models and demonstrates their idea on any other Pico display. |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
Ideal for some sort of 3D tunnel based vector shooter like Tempest, but I'm not committing to writing one . Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4243 |
Idea: outdoor tool Phase 1: magnetic sensor, create compass on LCD. Phase 2: add GPS receiver, enter target coordinates and follow the pointer to target (combination of GPS and Magneto). In fact you create a simple "Garmin GPS". Volhout PicomiteVGA PETSCII ROBOTS |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4243 |
Second idea: game Use the joystick to move the bullets Very expensive solution, since these cost 25 cents in plastic ..... Edited 2021-12-15 21:53 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
Proof of concept for Cylindrical Co-ordinate Snake. I might have been able to implement it so far, but it's insane trying to get your head around the navigation to actually play it and I haven't quite worked out how to do the collision detection yet, but this is my entry (assuming I'm allowed) and I commit to finishing it if I win. https://www.youtube.com/watch?v=IGKXw6mC5Ss Warning very crappy unfinished code: Option Base 0 Option Default None Option Explicit On Const HEIGHT% = 240 Const WIDTH% = 240 Const MAX_RADIUS! = 110.0 Const INCREASE% = 1, DECREASE% = 2, ANTICLOCKWISE% = 3, CLOCKWISE% = 4 Const SNAKE_SIZE% = 500 Dim radius! = 10 Dim theta! = 0 Dim theta_delta! = 1 Dim snake!(SNAKE_SIZE%, 1) Dim head% = 200 Dim tail% = 0 Dim display%(240*240/64) Cls Circle MAX_RADIUS! + 10.0, MAX_RADIUS! + 10.0, MAX_RADIUS! + 10.0, 2, 1, Rgb(GREY) Dim cmd%, x!, y! Dim result% Dim die% = 0 Dim oldx%, oldy% On Key on_key() Do oldx% = CInt(x!) oldy% = CInt(y!) y! = (Sin(Rad(90.0 - theta!)) * radius!) If theta! <= 180.0 Then x! = Sqr(Abs(radius!^2 - y!^2)) Else x! = -Sqr(Abs(radius!^2 - y!^2)) EndIf snake!(head%, 0) = x! snake!(head%, 1) = y! Box snake!(tail%, 0) + width% / 2, snake!(tail%, 1) + height% / 2, 4, 4, 1, Rgb(0,0,0), Rgb(0,0,0) Box snake!(head%, 0) + width% / 2, snake!(head%, 1) + height% / 2, 4, 4, 1, Rgb(255,0,0), Rgb(255,0,0) If oldx% <> CInt(x!) And oldy% <> CInt(y!) Then result% = set%(snake!(tail%, 0) + width% / 2, snake!(tail%, 1) + height% / 2) Else result% = 0 EndIf unset(snake!(tail%, 0) + width% / 2, snake!(tail%, 1) + height% / 2) Inc die%, result% ' If die% = 2 Then End If result% = 0 Then die% = 0 Inc head% head% = head% Mod SNAKE_SIZE% Inc tail% tail% = tail% Mod SNAKE_SIZE% Pause 10 If theta_delta! > 0.0 Then Inc theta!, theta_delta! If theta! >= 360.0 Then theta! = 0.0 ElseIf theta_delta! < 0.0 Then Inc theta!, theta_delta! If theta! <= 0.0 Then theta! = 360.0 EndIf If cmd% = INCREASE% Then Inc radius!, 3 ElseIf cmd% = DECREASE% Then Inc radius!, -3 ElseIf cmd%= CLOCKWISE% Then If theta_delta! = 1 Then theta_delta! = -1 Inc radius!, 3 Endif ElseIf cmd%= ANTICLOCKWISE% Then If theta_delta! = -1 Then theta_delta! = 1 Inc radius!, 3 Endif EndIf If cmd% <> 0 Then cmd% = 0 radius! = Min(Max(radius!, 3.0), MAX_RADIUS!) Loop Function set%(x%, y%) Local bit% = y% * 240 + x% Local byte% = bit% \ 8 bit% = bit% Mod 8 Local value% = Peek(Var display%(), byte%) If value% And (1 << bit%) Then set% = 1 value% = value% Or (1 << bit%) Poke Var display%(), byte%, value% End Function Sub unset(x%, y%) Local bit% y% * 240 + x% Local byte% = bit% \ 8 bit% = bit% Mod 8 Local value% = Peek(Var display%(), byte%) value% = value% Xor (1 << bit%) Poke Var display%(), byte%, value% End Sub Sub on_key() Local k$ k$ = Inkey$ Select Case k$ Case "a" : cmd% = INCREASE% Case "z" : cmd% = DECREASE% Case "," : cmd% = ANTICLOCKWISE% Case "." : cmd% = CLOCKWISE% End Select End Sub Best wishes, Tom Edited 2021-12-15 23:04 by thwill Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4243 |
Wauw... I haven't even finished thinking about the idea's, and you have finished the code. I am impressed. You are just as fast as Peter.... Think of it ... its done ... Difficult to play with a constant angular velocity. Volhout PicomiteVGA PETSCII ROBOTS |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
The secret is to avoid cartesian and do everything in cylindrical co-ordinates except for the actual screen plotting. I'd appreciate it if nobody "finished" this for me because I think it's a neat idea and would like to pursue it myself. Thank you, high praise indeed. I believe "Challenging" is the word to put on the marketing material. Best wishes, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Calli Regular Member Joined: 20/10/2021 Location: GermanyPosts: 74 |
I would do a small dart target with it... Oh wait... I wish I had a simulator cockpit... C! |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
Attach a motion sensor to it and create a virtual, if 2D, snow globe ... doesn't make any use of the joystick though. Best wishes, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Mixtel90 Guru Joined: 05/10/2019 Location: United KingdomPosts: 6798 |
Oh, let's see... A Vertigo record label simulator, using the joystick for variable speed, direction and sickness level. No. Maybe not. :) I know! A pocket Interocitor! I might have a severe problem with the implementation though as some components are out of stock everywhere: bead condenser (model # AB-619), cathermin tube with an indium complex of +4, intensifier disk. :( Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
It is of course Polar-Coordinate "Snake", not Cylindical-Coordinate "Snake", the latter really would be mad . Pretty playable now, though some graphical glitches to work out: https://youtu.be/wFxldIa4hpc And the code: ' Copyright (c) 2021 Thomas Hugo Williams ' License MIT <https://opensource.org/licenses/MIT> ' For MMBasic 5.07 Option Base 0 Option Default None Option Explicit On Const VERSION$ = "0.2" Const IS_CMM2% = Left$(Mm.Device$, 17) = "Colour Maximite 2" If IS_CMM2% Then Option Console Serial Mode 7 EndIf ' Save "polar-snake.bas" Const X_OFFSET% = MM.HRes \ 2 Const Y_OFFSET% = MM.VRes \ 2 Const HEIGHT% = 240 Const WIDTH% = 240 Const MAX_RADIUS% = Y_OFFSET% - 5 Const OUTWARD% = 0, CLOCKWISE% = 1, INWARD% = 2, ANTICLOCKWISE% = 3 Const UP% = 5, DOWN% = 6, LEFT% = 7, RIGHT% = 8, FIRE% = 9 Const MAX_SNAKE_SIZE% = 1000 Dim score% Dim lives% = 3 Dim radius% = MAX_RADIUS% \ 2 Dim theta% = 0 Dim snake%(MAX_SNAKE_SIZE%, 1) Dim head% = 20 Dim tail% = 0 Dim collision%(360 * MAX_RADIUS% / 64) Dim direction% Dim cmd% Dim result% Dim apple_x%, apple_y% Dim snake_x%, snake_y% On Key on_key() Const FRAME_DURATION% = 10 Dim next_frame% = Timer + FRAME_DURATION% Cls Circle X_OFFSET%, Y_OFFSET%, MAX_RADIUS% + 5, 2, 1, RGB(GREY) wipe() show_text("POLAR SNAKE") Pause 2000 wipe() Do While lives% > 0 start_round() Do snake%(head%, 0) = radius% snake%(head%, 1) = theta% to_cartesian(radius%, theta%, snake_x%, snake_y%) eat_apple() draw_snake() If set%(radius%, theta%, 1) = 1 Then die() Exit Do EndIf result% = set%(snake%(tail%, 0), snake%(tail%, 1)) move_snake() check_direction() If apple_x% = -999 Then new_apple() Else eat_apple() ' Wait for next "frame". Do While Timer < next_frame% : Loop Inc next_frame%, FRAME_DURATION% Loop Loop game_over() End Sub start_round() Local i% radius% = MAX_RADIUS% \ 2 theta% = 0 For i% = 0 To Bound(snake%(), 1) snake%(i%, 0) = 0 snake%(i%, 1) = 0 Next i% For i% = 0 To Bound(collision%(), 1) collision%(i%) = 0 Next direction% = CLOCKWISE% cmd% = 0 apple_x% = -999 apple_y% = -999 Circle X_OFFSET%, Y_OFFSET%, MAX_RADIUS% + 5, 2, 1, RGB(GREY) show_text("LIVES: " + Str$(lives%)) Pause 2000 wipe() next_frame% = Timer + FRAME_DURATION% End Sub Sub die() Circle snake_x% + X_OFFSET%, snake_y% + Y_OFFSET%, 2, 1, 1, RGB(255,255,0), RGB(255,255,0) Pause 500 Circle snake_x% + X_OFFSET%, snake_y% + Y_OFFSET%, 2, 1, 1, RGB(Black), RGB(Black) Inc lives%, -1 wipe() End Sub Sub game_over() show_text("GAME OVER") Pause 2000 wipe() show_text("SCORE: " + Str$(score%)) Pause 2000 wipe() End Sub Sub wipe() Local r% For r% = 10 To MAX_RADIUS% Step 5 Circle X_OFFSET%, Y_OFFSET%, r% - 5, 5, 1, RGB(0,0,0) Circle X_OFFSET%, Y_OFFSET%, r%, 5, 1, RGB(255,0,0) Pause 50 Next Circle X_OFFSET%, Y_OFFSET%, r% - 5, 5, 1, RGB(0,0,0) End Sub Sub show_text(s$) Text X_OFFSET%, Y_OFFSET%, s$, "CM", 1, 2, RGB(Red) End Sub Sub to_cartesian(r%, t%, x%, y%) Local yy! = Sin(Rad(90 - t%)) * r% y% = CInt(yy!) x% = Choice(t% <= 180, 1, -1) * CInt(Sqr(Abs(r%^2 - yy!^2))) End Sub Function set%(r%, t%, z%) Local t_% = Choice(r% = 0, 0, t%) Local bit% = r% * 360 + t_% Local byte% = bit% \ 8 bit% = bit% Mod 8 Local v% = Peek(Var collision%(), byte%) If v% And (1 << bit%) Then set% = 1 If z% Then v% = v% Or (1 << bit%) Else v% = v% And Inv (1 << bit%) EndIf Poke Var collision%(), byte%, v% End Function Sub new_apple() If Rnd() < 0.8 Then Exit Sub Local r% = Rnd() * MAX_RADIUS% If r% < 40 Or Abs(radius% - r%) < 10 Then Exit Sub Local t% = Rnd() * 360 If Abs(theta% - t%) < 10 Then Exit Sub to_cartesian(r%, t%, apple_x%, apple_y%) draw_apple() End Sub Sub eat_apple() If Abs(snake_x% - apple_x%) < 6 And Abs(snake_y% - apple_y%) < 6 Then erase_apple() apple_x% = -999 Inc score% Local i% For i% = 1 To 10 head% = (head% + 1) Mod MAX_SNAKE_SIZE% snake%(head%, 0) = radius% snake%(head%, 1) = theta% Next EndIf End Sub Sub draw_snake() Local x%, y% ' Erase tail. to_cartesian(snake%(tail%, 0), snake%(tail%, 1), x%, y%) Circle x% + X_OFFSET%, y% + Y_OFFSET%, 2, 1, 1, RGB(0,0,0), RGB(0,0,0) ' Draw head. to_cartesian(snake%(head%, 0), snake%(head%, 1), x%, y%) Circle x% + X_OFFSET%, y% + Y_OFFSET%, 2, 1, 1, RGB(255,0,0), RGB(255,0,0) Print radius%, theta%, x%, y% End Sub Sub move_snake() head% = (head% + 1) Mod MAX_SNAKE_SIZE% tail% = (tail% + 1) Mod MAX_SNAKE_SIZE% Select Case direction% Case OUTWARD% radius% = Min(radius% + 1, MAX_RADIUS% + 2) Case INWARD% Inc radius%, - 1 If radius% < 0 Then radius% = -radius% theta% = (theta% + 180) Mod 360 direction% = OUTWARD% EndIf Case CLOCKWISE% Inc theta%, -1 ' Correct this If theta% = -1 Then theta% = 359 Case ANTICLOCKWISE% Inc theta% If theta% = 360 Then theta% = 0 End Select End Sub Sub check_direction() If radius% <= 20 Then Exit Sub Select Case cmd% Case LEFT% Inc direction%, -1 If direction% < 0 Then direction% = 3 Case RIGHT% Inc direction%, 1 If direction% > 3 Then direction% = 0 End Select cmd% = 0 End Sub Sub draw_apple() Local x% = apple_x% + X_OFFSET% Local y% = apple_y% + Y_OFFSET% Line x% - 4, y% - 5, x%, y%, 1, RGB(149,69,53) Line x% - 3, y% - 5, x% + 1, y%, 1, RGB(149,69,53) Circle x%, y%, 4, 1, 1, RGB(0,255,0), RGB(0,255,0) End Sub Sub erase_apple() Local x% = apple_x% + X_OFFSET% Local y% = apple_y% + Y_OFFSET% Line x% - 4, y% - 5, x%, y%, 1, RGB(0,0,0) Line x% - 3, y% - 5, x% + 1, y%, 1, RGB(0,0,0) Circle x%, y%, 4, 1, 1, RGB(0,0,0), RGB(0,0,0) End Sub Sub on_key() Select Case LCase$(Inkey$) Case "a" : cmd% = UP% Case "z" : cmd% = DOWN% Case "," : cmd% = LEFT% Case "." : cmd% = RIGHT% Case " " : cmd% = FIRE% End Select End Sub Should run on PicoMite and CMM2 as is, and I assume it will work on the PicoMite VGA Edition with only one or two changed lines. Only two keys to play, "," and "." for turn left and right. Users of non-UK/US keyboards might want to change the key mapping in the on_key() subroutine. Best wishes, Tom Edited 2021-12-19 09:26 by thwill Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Cyber Senior Member Joined: 13/01/2019 Location: UkrainePosts: 161 |
This is cool!! |
||||
lew247 Guru Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
That looks awesome but I can't see anyone being able to simulate that on the Pico, especially with that graphic detail |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
Final (?) version of "Polar-coordinate Snake": ' Copyright (c) 2021 Thomas Hugo Williams ' License MIT <https://opensource.org/licenses/MIT> ' For MMBasic 5.07 ' Music by Trevor Bailey Option Base 0 Option Default None Option Explicit On Const VERSION$ = "1.0" Const IS_CMM2% = Left$(MM.Device$, 17) = "Colour Maximite 2" If IS_CMM2% Then Option Console Serial Mode 7 Page Write 1 EndIf ' Save "polar-snake.bas" Const X_OFFSET% = MM.HRes \ 2 Const Y_OFFSET% = MM.VRes \ 2 Const MAX_RADIUS% = Y_OFFSET% - 5 Const MAX_SNAKE_SIZE% = 1000 Const OUTWARD% = 0, CLOCKWISE% = 1, INWARD% = 2, ANTICLOCKWISE% = 3 Const UP% = 5, DOWN% = 6, LEFT% = 7, RIGHT% = 8, FIRE% = 9 ' These would be constants but MMBasic does not support constant arrays Dim SOUNDFX_NOTHING%(1) = (&hFFFFFFFFFFFFFFFF, &hFFFFFFFFFFFFFFFF) Dim SOUNDFX_EAT%(1) = (&hFFFFFFFFFF100C04, &hFFFFFFFFFFFFFFFF) Dim SOUNDFX_DIE%(2) = (&h0F10111213141516, &h0708090A0B0C0D0E, &hFF00010203040506) Dim SOUNDFX_WIPE%(2) = (&h0706050403020100, &h0F0E0D0C0B0A0908, &hFF16151413121110) Dim score% Dim lives% = 3 Dim difficulty% = 1 Dim game_type% = 1 Dim radius% = MAX_RADIUS% \ 2 Dim theta% Dim snake%(MAX_SNAKE_SIZE%, 1) Dim head% Dim tail% Dim collision%(360 * MAX_RADIUS% / 64) Dim direction% Dim cmd% Dim apple_x%, apple_y% Dim snake_x%, snake_y% Dim frame_duration% Dim next_frame% Dim music_flag% = 1 Dim music_ptr% = Peek(CFunAddr music_data) + 4 Dim soundfx_flag% = 1 Dim soundfx_ptr% = Peek(VarAddr SOUNDFX_NOTHING%()) ' Music and sound effects are played on SetTick interrupts. SetTick 250, play_music, 1 SetTick 40, play_soundfx, 2 On Key on_key() CLS draw_border() Do show_title() show_menu() init_game() Do While lives% > 0 game_loop() Loop show_game_over() show_score() Loop End Sub show_title() clear_display() Text X_OFFSET%, Y_OFFSET% - 15, "POLAR SNAKE", "CM", 1, 2, RGB(White) Text X_OFFSET%, Y_OFFSET% + 8, "(c) 2021 Thomas Hugo Williams", "CM", 7, 1, RGB(Red) Text X_OFFSET%, Y_OFFSET% + 20, "www.sockpuppetstudios.com", "CM", 7, 1, RGB(Red) Text X_OFFSET%, Y_OFFSET% + 40, "PRESS " + Choice(IS_CMM2%, "SPACE", "SELECT"), "CM", 1, 1, RGB(White) If IS_CMM2% Then Page Copy 1 To 0, B wait() End Sub Sub clear_display() Circle X_OFFSET%, Y_OFFSET%, MAX_RADIUS% + 3, 1, 1, RGB(BLACK), RGB(BLACK) draw_border() End Sub Sub draw_border() Circle X_OFFSET%, Y_OFFSET%, MAX_RADIUS% + 5, 2, 1, RGB(GREY) End Sub Sub wait(duration%) cmd% = 0 If duration% = 0 Then Do While cmd% <> FIRE% : Loop Else Local expires% = Timer + duration% Do While Timer < expires% And cmd% <> FIRE% : Loop EndIf End Sub Sub show_menu() Const x% = X_OFFSET% - 45 Local item% = 0, update% = 1 clear_display() Text X_OFFSET%, Y_OFFSET% + 70, "Music by Trevor Bailey", "CM", 7, 1, RGB(Red) Text X_OFFSET%, Y_OFFSET% + 85, "Game Version " + VERSION$, "CM", 7, 1, RGB(Red) Do If update% Then Text x%, Y_OFFSET% - 65, "START GAME", , 1, 1, RGB(White) Text x%, Y_OFFSET% - 45, "DIFFICULTY: " + Str$(difficulty%), , 1, 1, RGB(White) Text x%, Y_OFFSET% - 25, "GAME TYPE: " + Str$(game_type%), , 1, 1, RGB(White) Text x%, Y_OFFSET% - 5, "MUSIC: " + Choice(music_flag%, " ON", "OFF"), , 1, 1, RGB(White) Text x%, Y_OFFSET% + 15, "SOUND FX: " + Choice(soundfx_flag%, " ON", "OFF"), , 1, 1, RGB(White) Text x%, Y_OFFSET% + 35, "QUIT", , 1, 1, RGB(White) Text x% - 10, Y_OFFSET% - 65 + item% * 20, Chr$(137), , 1, 1, RGB(Red) If IS_CMM2% Then Page Copy 1 To 0, B Pause 100 cmd% = 0 update% = 0 EndIf Select Case cmd% Case UP% If item% > 0 Then Text x% - 10, Y_OFFSET% - 65 + item% * 20, Chr$(137), , 1, 1, RGB(Black) Inc item%, -1 update% = 1 EndIf Case DOWN% If item% < 5 Then Text x% - 10, Y_OFFSET% - 65 + item% * 20, Chr$(137), , 1, 1, RGB(Black) Inc item% update% = 1 EndIf Case LEFT%, RIGHT%, FIRE% Select Case item% Case 0 If cmd% = FIRE% Then Exit Case 1 ' Difficulty Inc difficulty%, Choice(cmd% = LEFT%, -1, 1) difficulty% = Min(5, Max(difficulty%, 1)) update% = 1 Case 2 ' Game type Inc game_type%, Choice(cmd% = LEFT%, -1, 1) game_type% = Min(2, Max(game_type%, 1)) update% = 1 Case 3 ' Music music_flag% = Not music_flag% update% = 1 Case 4 ' Sound FX soundfx_flag% = Not soundfx_flag% update% = 1 Case 5 ' Quit If cmd% = FIRE% Then End End Select Case Else cmd% = 0 End Select If update% = 1 Then start_soundfx(Peek(VarAddr SOUNDFX_EAT%())) Loop End Sub Sub init_game() lives% = 3 score% = 0 head% = 20 tail% = 0 frame_duration% = 5 + (6 - difficulty%) End Sub Sub game_loop() clear_display() Text X_OFFSET%, Y_OFFSET%, "LIVES: " + Str$(lives%), "CM", 1, 2, RGB(White) If IS_CMM2% Then Page Copy 1 To 0, B wait(2000) wipe() init_round() Do eat_apple() If apple_x% = -999 Then new_apple() draw_snake() If IS_CMM2% Then Page Copy 1 To 0, I If Not move_snake%() Then Exit check_direction() ' Wait for next "frame". Do While Timer < next_frame% : Loop Inc next_frame%, frame_duration% Loop die() End Sub Sub wipe() Local r% start_soundfx(Peek(VarAddr soundfx_wipe%())) For r% = 10 To MAX_RADIUS% Step 5 Circle X_OFFSET%, Y_OFFSET%, r% - 5, 5, 1, RGB(0,0,0) Circle X_OFFSET%, Y_OFFSET%, r%, 5, 1, RGB(255,0,0) If IS_CMM2% Then Page Copy 1 To 0, B Pause 30 Next clear_display() If IS_CMM2% Then Page Copy 1 To 0, B End Sub Sub init_round() Local i% radius% = MAX_RADIUS% \ 2 theta% = 0 For i% = 0 To Bound(snake%(), 1) snake%(i%, 0) = 0 snake%(i%, 1) = 0 Next i% snake%(head%, 0) = radius% snake%(head%, 1) = theta% to_cartesian(radius%, theta%, snake_x%, snake_y%) For i% = 0 To Bound(collision%(), 1) collision%(i%) = 0 Next direction% = CLOCKWISE% cmd% = 0 apple_x% = -999 apple_y% = -999 next_frame% = Timer + frame_duration% End Sub Sub to_cartesian(r%, t%, x%, y%) Local yy! = Sin(Rad(90 - t%)) * r% y% = Cint(yy!) x% = Choice(t% <= 180, 1, -1) * Cint(Sqr(Abs(r%^2 - yy!^2))) End Sub Sub eat_apple() If Abs(snake_x% - apple_x%) < 6 And Abs(snake_y% - apple_y%) < 6 Then start_soundfx(Peek(VarAddr SOUNDFX_EAT%())) draw_apple(0) apple_x% = -999 Inc score% Local i% For i% = 1 To 10 head% = (head% + 1) Mod MAX_SNAKE_SIZE% snake%(head%, 0) = radius% snake%(head%, 1) = theta% Next EndIf End Sub Sub draw_snake() Local x%, y% ' Erase tail. to_cartesian(snake%(tail%, 0), snake%(tail%, 1), x%, y%) Circle x% + X_OFFSET%, y% + Y_OFFSET%, 2, 1, 1, RGB(Black), RGB(Black) ' Redraw apple incase we have erased part of it. draw_apple(1) ' Draw head. Circle snake_x% + X_OFFSET%, snake_y% + Y_OFFSET%, 2, 1, 1, RGB(Red), RGB(Red) ' Print radius%, theta%, snake_x%, snake_y% End Sub Sub die() start_soundfx(Peek(VarAddr soundfx_die%())) Local i% = head%, x%, y% Local sz% = Choice(head% > tail%, head% - tail%, head% + MAX_SNAKE_SIZE% - tail%) Local count% Do While i% <> tail% to_cartesian(snake%(i%, 0), snake%(i%, 1), x%, y%) Circle x% + X_OFFSET%, y% + Y_OFFSET%, 2, 1, 1, RGB(0,0,0), RGB(0,0,0) Inc i%, -1 If i% < 0 Then i% = Bound(snake%(), 1) Inc count% If count% >= sz% \ 100 Then draw_border() If IS_CMM2% Then Page Copy 1 To 0, B count% = 0 EndIf Loop ' Ensure last element of tail is deleted. to_cartesian(snake%(tail%, 0), snake%(tail%, 1), x%, y%) Circle x% + X_OFFSET%, y% + Y_OFFSET%, 2, 1, 1, RGB(0,0,0), RGB(0,0,0) If IS_CMM2% Then Page Copy 1 To 0, B ' Wait for the dying sound effect to complete. Do While Peek(Byte soundfx_ptr%) <> &hFF : Loop Inc lives%, -1 End Sub Sub show_game_over() clear_display() Text X_OFFSET%, Y_OFFSET%, "GAME OVER", "CM", 1, 2, RGB(White) If IS_CMM2% Then Page Copy 1 To 0, B wait(5000) End Sub Sub show_score() clear_display() Text X_OFFSET%, Y_OFFSET%, "SCORE: " + Str$(score%), "CM", 1, 2, RGB(White) If IS_CMM2% Then Page Copy 1 To 0, B wait(5000) End Sub Function move_snake%() ' Clear the tail from the collision map. Local ignored% = set%(snake%(tail%, 0), snake%(tail%, 1), 0) head% = (head% + 1) Mod MAX_SNAKE_SIZE% tail% = (tail% + 1) Mod MAX_SNAKE_SIZE% Select Case direction% Case OUTWARD% radius% = radius% + 1 If radius% > MAX_RADIUS% Then Exit Function Case INWARD% Inc radius%, - 1 If radius% < 0 Then radius% = -radius% theta% = (theta% + 180) Mod 360 direction% = OUTWARD% EndIf Case CLOCKWISE% Inc theta%, -1 ' Correct this If theta% = -1 Then theta% = 359 Case ANTICLOCKWISE% Inc theta% If theta% = 360 Then theta% = 0 End Select snake%(head%, 0) = radius% snake%(head%, 1) = theta% to_cartesian(radius%, theta%, snake_x%, snake_y%) ' Set the head, if it is already set then return 0. move_snake% = Not set%(radius%, theta%, 1) End Function Function set%(r%, t%, z%) Local t_% = Choice(r% = 0, 0, t%) Local bit% = r% * 360 + t_% Local byte% = bit% \ 8 bit% = bit% Mod 8 Local v% = Peek(Var collision%(), byte%) If v% And (1 << bit%) Then set% = 1 If z% Then v% = v% Or (1 << bit%) Else v% = v% And INV (1 << bit%) EndIf Poke Var collision%(), byte%, v% End Function Sub check_direction() If radius% <= 20 Then Exit Sub If game_type% = 1 Then Select Case cmd% Case LEFT% Inc direction%, -1 If direction% < 0 Then direction% = 3 Case RIGHT% Inc direction%, 1 If direction% > 3 Then direction% = 0 End Select Else Select Case cmd% Case UP% direction% = OUTWARD% Case DOWN% direction% = INWARD% Case LEFT% direction% = ANTICLOCKWISE% Case RIGHT% direction% = CLOCKWISE% End Select EndIf cmd% = 0 End Sub Sub new_apple() If Rnd() < 0.8 Then Exit Sub Local r% = Rnd() * MAX_RADIUS% If r% < 40 Or Abs(radius% - r%) < 10 Then Exit Sub Local t% = Rnd() * 360 If Abs(theta% - t%) < 10 Then Exit Sub to_cartesian(r%, t%, apple_x%, apple_y%) draw_apple(1) End Sub Sub draw_apple(show%) If apple_x% = -999 Then Exit Sub Local x% = apple_x% + X_OFFSET% Local y% = apple_y% + Y_OFFSET% Local stalk% = Choice(show%, RGB(Brown), RGB(Black)) Local apple% = Choice(show%, RGB(Green), RGB(Black)) Line x% - 4, y% - 5, x%, y%, 1, stalk% Line x% - 3, y% - 5, x% + 1, y%, 1, stalk% Circle x%, y%, 4, 1, 1, apple%, apple% End Sub Sub on_key() Select Case LCase$(Inkey$) Case "a" : cmd% = UP% Case "z" : cmd% = DOWN% Case "," : cmd% = LEFT% Case "." : cmd% = RIGHT% Case " " : cmd% = FIRE% End Select End Sub ' Called from interrupt to play next note of music. Sub play_music() If music_flag% Then Local note% = Peek(Byte music_ptr%) If note% = &hFF Then music_ptr% = Peek(CFunAddr music_data) + 4 note% = Peek(Byte music_ptr%) EndIf Play Sound 1, B, s, 440 * 2 ^ ((note% - 2) / 12.0), 15 Inc music_ptr% Else Play Sound 1, B, O EndIf End Sub ' Start a new sound effect. Sub start_soundfx(ptr%) If Not soundfx_flag% Then Exit Sub ' Wait for current sound effect to end. Do While Peek(Byte soundfx_ptr%) <> &hFF : Loop soundfx_ptr% = ptr% ' Wait for first note of new sound effect to play. Do While soundfx_ptr% = ptr% : Loop End Sub ' Called from interrupt to play next note of current sound effect. Sub play_soundfx() If soundfx_flag% Then Local note% = Peek(Byte soundfx_ptr%) If note% < &hFF Then Play Sound 2, B, s, 440 * 2 ^ ((note% - 2) / 12.0) Inc soundfx_ptr% Else Play Sound 2, B, O EndIf Else Play Sound 2, B, O EndIf End Sub CSub music_data() 00000000 00000220 09000905 09000905 09000905 09000905 09000905 09000905 09000905 09000905 18181815 1818181A 18181815 1818181A 15161816 13111516 15161816 13111516 18181815 1518151A 18181815 1818181A 15161813 15131516 0C0E0C13 0704000C 18181815 1818181A 18181815 1818181A 15161816 13111516 15161816 13111516 18181815 1518151A 18181815 1818181A 15161813 15131516 091D0511 0509051D 1515150E 15151516 1515150E 15151516 10131513 10131513 10131513 00040013 1515150E 15151516 1515150E 15151516 13111013 15131115 16151316 00000C18 18181815 1818181A 18181815 1818181A 15161816 13111516 15161816 13111516 18181815 1518151A 18181815 1818181A 15161813 15131516 0C0E0C13 0704000C 18181815 1818181A 18181815 1818181A 15161816 13111516 15161816 13111516 18181815 1518151A 18181815 1818181A 15161813 15131516 091D0511 0509051D 1515150E 15151516 1515150E 15151516 10131513 10131513 10131513 00040013 1515150E 15151516 1515150E 15151516 13111013 15131115 16151316 00000C18 18181815 1818181A 18181815 1818181A 15161816 13111516 15161816 13111516 18181815 1518151A 18181815 1818181A 15161813 15131516 0C0E0C13 0704000C 18181815 1818181A 18181815 1818181A 15161816 13111516 15161816 13111516 18181815 1518151A 18181815 1818181A 15161813 15131516 091D0511 0509051D FFFFFFFF End CSub Keys for menu are: [A] - up [Z] - down [<] - left [>] - right [Space] - select Keys for game type 1 are: [<] - turn left [>] - turn right Keys for game type 2 are: [A] - move outwards [Z] - move inwards [<] - move anti-clockwise [>] - move clockwise Running on a PicoMite: https://youtu.be/LbC8pWRzu-4 Note that the PicoMite version does have audio, but mine isn't yet wired for sound ... TBH I'm a little suprised I didn't get an error about the fact that OPTION AUDIO is unset (Peter?) Running on a Colour Maximite 2: https://youtu.be/quosIboidbM Code will go up on GitHub when I have a moment. Merry Christmas, Tom Edited 2021-12-23 23:34 by thwill Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4243 |
Wauw, you did it Tom !!! This looks vey nice... Volhout PicomiteVGA PETSCII ROBOTS |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 9122 |
After due consideration, the judges (Lewis and me) are happy to award the display to Tom (thwill). I'll get it in the post after Christmas. Congrats to Tom for an inspired idea and implementation |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
Thank you Peter and Lewis, as you probably guessed I really wanted this device and really appreciate winning it. I actually had a more original (game) idea but I was already half-way through the implementation of Polar-Snake. Hopefully I'll be able to follow-up on that in the New Year ... just need to knuckle down and deliver serial comms for MMB4L first. Merry Christmas, Tom Edited 2021-12-24 03:22 by thwill Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3150 |
Can you explain a little more about the mechanics of the game? I can't determine the difference between the circumstances in which the target appears to be eaten, and those in which it successfully moves away. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 4042 |
Hi Lance, I had to scratch my head to work out what you were talking about . I think you are seeing something that isn't there. Whenever the head of the snake touches an apple (strictly speaking delta x and delta y between the two centers is less than 6 pixels) then the snake "eats" the apple, the apple never "moves away". What I think has confused you is that the (random) delay between one apple being eaten and the next appearing is not long enough, consequently if the two positions are close it looks like the apple may have moved - is that it ? Merry Christmas, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3150 |
Approximately. I thought the "3 lives" meant the game was over when the apple was eaten 3 times, but it apparently continues, but at some point the number of lives is reduced. I guess what I should have asked is "What constitutes a 'life'?" (And shouldn't the snake be eating mice--what's an apple got to do with it? In the snake and apple story I'm familiar with, it's the humans who eat the apple, not the snake. Sorry, unmitigated pedantry.) PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Page 1 of 2 |
Print this page |