|
| 1 | +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries |
| 2 | +# SPDX-License-Identifier: MIT |
1 | 3 | import random
|
2 | 4 | import sys
|
3 | 5 | import terminalio
|
@@ -222,6 +224,16 @@ def recycle_post(self, post):
|
222 | 224 | self.pool.append(post)
|
223 | 225 |
|
224 | 226 |
|
| 227 | +class GameOverException(Exception): |
| 228 | + """ |
| 229 | + Exception that will be raised when the player loses the game. |
| 230 | + """ |
| 231 | + |
| 232 | + def __init__(self, msg): |
| 233 | + self.msg = msg |
| 234 | + super().__init__(self.msg) |
| 235 | + |
| 236 | + |
225 | 237 | # palette of colors for the trail
|
226 | 238 | trail_palette = Palette(10)
|
227 | 239 | # rainbow colors
|
@@ -326,14 +338,30 @@ def recycle_post(self, post):
|
326 | 338 | nyan_tg.y = 50
|
327 | 339 |
|
328 | 340 | # text label for the current score
|
329 |
| -score_lbl = Label(terminalio.FONT, text="0", color=0xFFFFFF, scale=2) |
| 341 | +score_lbl = Label(terminalio.FONT, text="Spacebar", color=0xFFFFFF, scale=2) |
330 | 342 | # move it to the bottom left corner
|
331 | 343 | score_lbl.anchor_point = (0, 1)
|
332 | 344 | score_lbl.anchored_position = (2, display.height - 2)
|
333 | 345 |
|
334 | 346 | # add it to the main_group
|
335 | 347 | main_group.append(score_lbl)
|
336 | 348 |
|
| 349 | +game_over_label = Label( |
| 350 | + terminalio.FONT, |
| 351 | + text="", |
| 352 | + color=0xFFFFFF, |
| 353 | + background_color=0x000000, |
| 354 | + padding_top=10, |
| 355 | + padding_bottom=10, |
| 356 | + padding_left=10, |
| 357 | + padding_right=10, |
| 358 | +) |
| 359 | +game_over_label.anchor_point = (0.5, 0.5) |
| 360 | +game_over_label.anchored_position = (display.width // 2, display.height // 2) |
| 361 | +game_over_label.hidden = True |
| 362 | + |
| 363 | +main_group.append(game_over_label) |
| 364 | + |
337 | 365 | # set the main_group to show on the display
|
338 | 366 | display.root_group = main_group
|
339 | 367 |
|
@@ -450,96 +478,129 @@ def shift_post(post):
|
450 | 478 | playing = False
|
451 | 479 |
|
452 | 480 | while True:
|
| 481 | + try: |
| 482 | + # if the player hasn't started yet |
| 483 | + if not playing: |
| 484 | + while True: |
| 485 | + # check if any keys were pressed |
| 486 | + available = supervisor.runtime.serial_bytes_available |
| 487 | + |
| 488 | + # if one or more keys was pressed |
| 489 | + if available: |
| 490 | + # read the value |
| 491 | + cur_btn_val = sys.stdin.read(available) |
| 492 | + else: |
| 493 | + cur_btn_val = None |
| 494 | + |
| 495 | + # if spacebar was pressed |
| 496 | + if cur_btn_val == " ": |
| 497 | + # do the first jump |
| 498 | + cat_speed = -JUMP_SPEED |
| 499 | + |
| 500 | + # set playing to true and breakout of the pause loop |
| 501 | + playing = True |
| 502 | + break |
| 503 | + |
| 504 | + # check if the cat is touching the first post |
| 505 | + if first_post.check_collision(nyan_tg): |
| 506 | + raise GameOverException( |
| 507 | + f"Kitty got distracted by the scratchers post.\nScore: {score}" |
| 508 | + ) |
| 509 | + |
| 510 | + # check if the cat is touching the second post |
| 511 | + if second_post.check_collision(nyan_tg): |
| 512 | + raise GameOverException( |
| 513 | + f"Kitty got distracted by the scratchers post.\nScore: {score}" |
| 514 | + ) |
| 515 | + |
| 516 | + # check if any keyboard data is available |
| 517 | + available = supervisor.runtime.serial_bytes_available |
| 518 | + if available: |
| 519 | + # read the data if there is some available |
| 520 | + cur_btn_val = sys.stdin.read(available) |
| 521 | + else: |
| 522 | + cur_btn_val = None |
453 | 523 |
|
454 |
| - # if the player hasn't started yet |
455 |
| - if not playing: |
456 |
| - while True: |
457 |
| - # check if any keys were pressed |
458 |
| - available = supervisor.runtime.serial_bytes_available |
| 524 | + # apply gravity to the cat, maxing out at terminal velocity |
| 525 | + cat_speed = min(cat_speed + FALL_SPEED, TERMINAL_VELOCITY) |
459 | 526 |
|
460 |
| - # if one or more keys was pressed |
461 |
| - if available: |
462 |
| - # read the value |
463 |
| - cur_btn_val = sys.stdin.read(available) |
464 |
| - else: |
465 |
| - cur_btn_val = None |
| 527 | + # if there is keyboard data and spacebar was pressed |
| 528 | + if cur_btn_val is not None and " " in cur_btn_val: |
| 529 | + cat_speed = -JUMP_SPEED |
466 | 530 |
|
467 |
| - # if spacebar was pressed |
468 |
| - if cur_btn_val == " ": |
469 |
| - # do the first jump |
470 |
| - cat_speed = -JUMP_SPEED |
| 531 | + # award a point for each jump |
| 532 | + score += 1 |
| 533 | + elif cur_btn_val is not None and "s" in cur_btn_val: |
| 534 | + swap_trail() |
| 535 | + # award a point for swapping the trail |
| 536 | + score += 1 |
471 | 537 |
|
472 |
| - # set playing to true and breakout of the pause loop |
473 |
| - playing = True |
474 |
| - break |
| 538 | + # move the cat down by cat_speed amount of pixels |
| 539 | + nyan_tg.y += cat_speed |
475 | 540 |
|
476 |
| - # check if the cat is touching the first post |
477 |
| - if first_post.check_collision(nyan_tg): |
478 |
| - raise KeyboardInterrupt( |
479 |
| - f"Kitty got distracted by the scratchers post. Score: {score}" |
480 |
| - ) |
| 541 | + # if the cat has touched the top or bottom edge |
| 542 | + if nyan_tg.y > display.height // 2 or nyan_tg.y < 0: |
| 543 | + raise GameOverException(f"Kitty wandered away.\nScore: {score}") |
481 | 544 |
|
482 |
| - # check if the cat is touching the second post |
483 |
| - if second_post.check_collision(nyan_tg): |
484 |
| - raise KeyboardInterrupt( |
485 |
| - f"Kitty got distracted by the scratchers post. Score: {score}" |
486 |
| - ) |
487 |
| - |
488 |
| - # check if any keyboard data is available |
489 |
| - available = supervisor.runtime.serial_bytes_available |
490 |
| - if available: |
491 |
| - # read the data if there is some available |
492 |
| - cur_btn_val = sys.stdin.read(available) |
493 |
| - else: |
494 |
| - cur_btn_val = None |
| 545 | + # current coordinates of the cat |
| 546 | + draw_coords = [nyan_tg.x // 2, nyan_tg.y // 2] |
495 | 547 |
|
496 |
| - # apply gravity to the cat, maxing out at terminal velocity |
497 |
| - cat_speed = min(cat_speed + FALL_SPEED, TERMINAL_VELOCITY) |
| 548 | + try: |
| 549 | + # erase the trail |
| 550 | + erase_trail() |
| 551 | + except ValueError as exc: |
| 552 | + raise GameOverException(f"Kitty wandered away.\nScore: {score}") from exc |
498 | 553 |
|
499 |
| - # if there is keyboard data and spacebar was pressed |
500 |
| - if cur_btn_val is not None and " " in cur_btn_val: |
501 |
| - cat_speed = -JUMP_SPEED |
| 554 | + # shift the trail coordinates over |
| 555 | + shift_trail() |
502 | 556 |
|
503 |
| - # award a point for each jump |
504 |
| - score += 1 |
505 |
| - elif cur_btn_val is not None and "s" in cur_btn_val: |
506 |
| - swap_trail() |
507 |
| - # award a point for swapping the trail |
508 |
| - score += 1 |
| 557 | + # add new coordinates to the trail at the cats current location |
| 558 | + trail_coords.append(draw_coords) |
509 | 559 |
|
510 |
| - # move the cat down by cat_speed amount of pixels |
511 |
| - nyan_tg.y += cat_speed |
| 560 | + # if the trail is at its maximum length |
| 561 | + if len(trail_coords) > TRAIL_LENGTH: |
| 562 | + # remove the oldest coordinate from the trail coordinates list. |
| 563 | + trail_coords.pop(0) |
512 | 564 |
|
513 |
| - # if the cat has touched the top or bottom edge |
514 |
| - if nyan_tg.y > display.height // 2 or nyan_tg.y < 0: |
515 |
| - raise KeyboardInterrupt(f"Kitty wandered away. Score: {score}") |
| 565 | + # draw the trail |
| 566 | + draw_trail() |
516 | 567 |
|
517 |
| - # current coordinates of the cat |
518 |
| - draw_coords = [nyan_tg.x // 2, nyan_tg.y // 2] |
| 568 | + # shift the posts over |
| 569 | + first_post = shift_post(first_post) |
| 570 | + second_post = shift_post(second_post) |
519 | 571 |
|
520 |
| - # erase the trail |
521 |
| - erase_trail() |
| 572 | + # update the score label |
| 573 | + score_lbl.text = str(score) |
522 | 574 |
|
523 |
| - # shift the trail coordinates over |
524 |
| - shift_trail() |
| 575 | + # refresh the display |
| 576 | + display.refresh(target_frames_per_second=30) |
525 | 577 |
|
526 |
| - # add new coordinates to the trail at the cats current location |
527 |
| - trail_coords.append(draw_coords) |
| 578 | + except GameOverException as e: |
| 579 | + # update the game over message |
| 580 | + game_over_label.text = str(f"{e.msg}\nPress P to play again\nPress Q to quit") |
| 581 | + # make the game over message visible |
| 582 | + game_over_label.hidden = False |
528 | 583 |
|
529 |
| - # if the trail is at its maximum length |
530 |
| - if len(trail_coords) > TRAIL_LENGTH: |
531 |
| - # remove the oldest coordinate from the trail coordinates list. |
532 |
| - trail_coords.pop(0) |
| 584 | + # refresh display so the message shows |
| 585 | + display.refresh() |
| 586 | + break |
533 | 587 |
|
534 |
| - # draw the trail |
535 |
| - draw_trail() |
| 588 | +# wait for the player to press a key |
| 589 | +while True: |
| 590 | + # check if any keys were pressed |
| 591 | + available = supervisor.runtime.serial_bytes_available |
536 | 592 |
|
537 |
| - # shift the posts over |
538 |
| - first_post = shift_post(first_post) |
539 |
| - second_post = shift_post(second_post) |
| 593 | + # if one or more keys was pressed |
| 594 | + if available: |
| 595 | + # read the value |
| 596 | + cur_btn_val = sys.stdin.read(available) |
540 | 597 |
|
541 |
| - # update the score label |
542 |
| - score_lbl.text = str(score) |
| 598 | + # if player pressed p |
| 599 | + if "p" in cur_btn_val: |
| 600 | + supervisor.set_next_code_file(__file__) |
| 601 | + supervisor.reload() |
543 | 602 |
|
544 |
| - # refresh the display |
545 |
| - display.refresh(target_frames_per_second=30) |
| 603 | + # if player pressed q |
| 604 | + elif "q" in cur_btn_val: |
| 605 | + print("exiting") |
| 606 | + break |
0 commit comments