Renamed maguro-game to game-maguro.

This commit is contained in:
JustinOros
2025-11-18 10:57:25 -07:00
parent 3adeac627e
commit 1a6b214947
27 changed files with 590 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
# <h1 align="center">🍣🐱 MAGURO CAT GAME 🐱🍣
![Maguro Screenshot](screenshot_maguro.png)
**Maguro Cat Game** is a whimsical arcade-style game where you play as a sushi-loving cat! Catch delicious sushi, avoid the dreaded wasabi, and grow bigger with every bite. A soothing soundtrack and drifting petals set the tone for this cute yet challenging experience.
---
## 🎮 Gameplay Overview
You control a growing cat standing at the bottom of the screen. Sushi, edamame, and wasabi rain from the sky. Your job is to:
* 🥢 Catch sushi to score points and grow!
* 🫘 Catch edamame for bonus points.
* ❌ Avoid wasabi or it's game over!
As time progresses, objects fall faster, raising the stakes!
---
## 🕹️ Controls
### Keyboard
* **Move Left:** `A` or `←`
* **Move Right:** `D` or `→`
* **Pause / Unpause:** `Esc`
* **Quit Game:** `Q`
### Controller (Optional)
* **Move Left / Right:** Left Stick, Right Stick
* **Pause / Unpause:** `Start`
* **Quit Game:** `Start` then `X`
---
## 📋 Features
* Fullscreen immersive gameplay
* Controller and keyboard support
* Dynamic difficulty scaling over time
* Satisfying chomp and meow sound effects
* Growing cat mechanic
* Randomized sushi visuals and falling edamame
* Peaceful petals and drifting clouds
---
## 🚀 Getting Started
Run the game using Python (and Pygame):
```bash
python3 maguro-game.py
```
</h1>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

+533
View File
@@ -0,0 +1,533 @@
import pygame
import random
import sys
import math
pygame.init()
pygame.mixer.init()
pygame.joystick.init()
WIDTH, HEIGHT = pygame.display.Info().current_w, pygame.display.Info().current_h
SCREEN_SIZE = (WIDTH, HEIGHT)
CAT_INITIAL_SIZE = [160, 160]
CAT_MAX_SIZE = [320, 320]
SUSHI_SIZE = (75, 75)
WASABI_SIZE = (100,100)
CLOUD_SIZE = (200, 120)
PETAL_SIZE = (30, 30)
GAME_OVER_DELAY = 3000
WASABI_CHANCE = 0.1
def quit_game():
pygame.quit()
sys.exit()
class Cat:
def __init__(self, cat_right_img, pos, speed):
self.cat_right_base = cat_right_img
self.size = CAT_INITIAL_SIZE.copy()
self.speed = speed
self.facing = "right"
self.image_right = pygame.transform.smoothscale(self.cat_right_base, self.size)
self.image_left = pygame.transform.flip(self.image_right, True, False)
self.image = self.image_right
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.bottom = pos
self.grow_step = 1
def update_image(self):
if self.facing == "left":
self.image = pygame.transform.flip(self.image_right, True, False)
else:
self.image = self.image_right
def move(self, dx):
self.rect.x += dx * self.speed
self.rect.x = max(0, min(WIDTH - self.rect.width, self.rect.x))
self.rect.bottom = HEIGHT
def grow(self):
self.size[0] = min(self.size[0] + self.grow_step, CAT_MAX_SIZE[0])
self.size[1] = min(self.size[1] + self.grow_step, CAT_MAX_SIZE[1])
self.image_right = pygame.transform.smoothscale(self.cat_right_base, self.size)
self.update_image()
mid_x = self.rect.centerx
self.rect = self.image.get_rect()
self.rect.centerx = mid_x
self.rect.bottom = HEIGHT
def draw(self, surface):
surface.blit(self.image, self.rect)
class Sushi:
def __init__(self, image, pos, wasabi=False, speed=5):
self.image = image
self.rect = self.image.get_rect(midtop=pos)
self.wasabi = wasabi
self.speed = speed
def update(self, dt):
self.rect.y += self.speed * dt / 16.67
def draw(self, surface):
surface.blit(self.image, self.rect)
def off_screen(self):
return self.rect.top > HEIGHT
class Cloud:
def __init__(self, image, speed_multiplier=1.0):
self.image = image
self.speed_multiplier = speed_multiplier
self.size = self.image.get_size()
self.y = 50
self.phase = random.uniform(0, 2 * math.pi)
self.speed = random.choice([-1.5, 1.5]) * speed_multiplier
if self.speed > 0:
self.rect = self.image.get_rect(topleft=(-self.size[0], self.y))
else:
self.rect = self.image.get_rect(topleft=(WIDTH + self.size[0], self.y))
self.base_y = self.y
def update(self, dt, now):
self.rect.x += self.speed * dt / 16.67
vertical_offset = 10 * math.sin(2 * math.pi * now / 1000 + self.phase)
self.rect.y = self.base_y + vertical_offset
def off_screen(self):
if self.speed > 0:
return self.rect.left > WIDTH
else:
return self.rect.right < 0
def draw(self, surface):
surface.blit(self.image, self.rect)
class Petal:
def __init__(self, image, pos, petal_toggle, speed_multiplier=1.0):
self.image = image
self.rect = self.image.get_rect(topleft=pos)
self.speed_multiplier = speed_multiplier
self.drift = random.uniform(-0.0, 0.1)
self.phase = random.uniform(0, 2 * math.pi)
self.base_x = pos[0]
self.spawn_time = pygame.time.get_ticks()
self.petal_toggle = petal_toggle
def update(self, dt, now):
self.rect.y += 3 * self.speed_multiplier * dt / 16.67
sway = 15 * math.sin(0.5 * now / 1000 + self.phase)
time_since_spawn = (now - self.spawn_time) / 1000
drift_speed = 1.5 * self.speed_multiplier
self.rect.x = self.base_x + sway + self.drift * self.speed_multiplier + drift_speed * time_since_spawn * 60
def off_screen(self):
return self.rect.top > HEIGHT
def draw(self, surface):
surface.blit(self.image, self.rect)
class Edamame:
def __init__(self, image, pos, speed=4):
self.image = image
self.rect = self.image.get_rect(midtop=pos)
self.speed = speed
self.phase = random.uniform(0, 2 * math.pi)
self.base_x = self.rect.x
def update(self, dt, now):
self.rect.y += self.speed * dt / 16.67
sway = 20 * math.sin(0.005 * now + self.phase)
self.rect.x = self.base_x + sway
def off_screen(self):
return self.rect.top > HEIGHT
def draw(self, surface):
surface.blit(self.image, self.rect)
class Spawner:
def __init__(self, spawn_interval_ms):
self.spawn_interval = spawn_interval_ms
self.last_spawn = 0
def can_spawn(self, now):
return now - self.last_spawn > self.spawn_interval
def update_spawn_time(self, now):
self.last_spawn = now
class Game:
def __init__(self):
self.screen = pygame.display.set_mode(SCREEN_SIZE, pygame.FULLSCREEN)
pygame.mouse.set_visible(False)
pygame.display.set_caption("Maguro Cat Game")
self.wallpaper = pygame.image.load("image_wallpaper.png").convert()
self.wallpaper = pygame.transform.scale(self.wallpaper, SCREEN_SIZE)
self.cat_right_base = pygame.image.load("image_cat.png").convert_alpha()
self.sushi_images = []
for i in [1, 2, 4, 3]:
img = pygame.image.load(f"image_sushi{i}.png").convert_alpha()
img = pygame.transform.smoothscale(img, SUSHI_SIZE)
self.sushi_images.append(img)
self.wasabi_img = pygame.image.load("image_wasabi.png").convert_alpha()
self.wasabi_img = pygame.transform.smoothscale(self.wasabi_img, WASABI_SIZE)
self.cloud_base = pygame.image.load("image_cloud.png").convert_alpha()
self.cloud_img = pygame.transform.smoothscale(self.cloud_base, CLOUD_SIZE)
self.petal_base = pygame.image.load("image_petal.png").convert_alpha()
self.petal_img = pygame.transform.smoothscale(self.petal_base, PETAL_SIZE)
self.petal_img_flipped = pygame.transform.flip(self.petal_img, True, False)
self.edamame_img = pygame.image.load("image_edamame.png").convert_alpha()
self.edamame_img = pygame.transform.smoothscale(self.edamame_img, SUSHI_SIZE)
self.grumpy_img = pygame.transform.smoothscale(
pygame.image.load("image_grumpy.png").convert_alpha(),
(200, 200)
)
self.music_file = "audio_music.mp3"
self.chomp_sounds = [
pygame.mixer.Sound("audio_chomp_low.mp3"),
pygame.mixer.Sound("audio_chomp.mp3"),
pygame.mixer.Sound("audio_chomp_high.mp3")
]
self.meow_sound = pygame.mixer.Sound("audio_meow.mp3")
self.gamestart_sound = pygame.mixer.Sound("audio_gamestart.mp3")
self.gameover_sound = pygame.mixer.Sound("audio_gameover.mp3")
self.paused_sound = pygame.mixer.Sound("audio_paused.mp3")
self.unpaused_sound = pygame.mixer.Sound("audio_unpaused.mp3")
self.oof_sound = pygame.mixer.Sound("audio_oof.mp3")
self.joysticks = []
self.check_controllers()
self.font = pygame.font.Font("font_8bit.otf", 160)
self.jp_font = pygame.font.Font("font_notosansjp.ttf", 64)
self.small_font = pygame.font.SysFont(None, 32)
self.clock = pygame.time.Clock()
self.sushis = []
self.clouds = []
self.petals = []
self.edamames = []
self.reset_game()
def check_controllers(self):
self.joysticks.clear()
for i in range(pygame.joystick.get_count()):
joy = pygame.joystick.Joystick(i)
joy.init()
self.joysticks.append(joy)
def draw_intro(self):
now = pygame.time.get_ticks()
elapsed = now - self.intro_start_time
if elapsed >= 3000:
pygame.mixer.music.load(self.music_file)
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1)
return False
maguro_surf = self.font.render("MAGURO", True, (255, 255, 255))
jp_surf = self.jp_font.render("マグロ", True, (255, 255, 255))
self.screen.blit(maguro_surf, maguro_surf.get_rect(center=(WIDTH // 2, HEIGHT // 2 - 80)))
self.screen.blit(jp_surf, jp_surf.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 40)))
return True
def spawn_sushi(self):
x = random.randint(50, WIDTH - 50)
is_wasabi = random.random() < WASABI_CHANCE
img = self.wasabi_img if is_wasabi else random.choice(self.sushi_images)
sushi = Sushi(img, (x, -40), wasabi=is_wasabi, speed=self.sushi_fall_speed)
self.sushis.append(sushi)
def spawn_cloud(self):
cloud = Cloud(self.cloud_img, self.cloud_speed_multiplier)
self.clouds.append(cloud)
def spawn_petal(self):
x = random.randint(0, WIDTH)
image = self.petal_img_flipped if self.petal_toggle else self.petal_img
self.petal_toggle = not self.petal_toggle
petal = Petal(image, (x, -PETAL_SIZE[1]), self.petal_toggle, self.petal_speed_multiplier)
self.petals.append(petal)
def spawn_edamame(self):
x = random.randint(50, WIDTH - 50)
flipped = random.choice([True, False])
image = pygame.transform.flip(self.edamame_img, True, False) if flipped else self.edamame_img
edamame = Edamame(image, (x, -40), speed=self.edamame_fall_speed)
self.edamames.append(edamame)
def reset_game(self):
self.score = 0
self.sushis.clear()
self.clouds.clear()
self.petals.clear()
self.edamames.clear()
self.petal_toggle = False
self.game_over = False
self.game_over_time = None
self.paused = False
self.pause_by_controller = False
self.sushi_fall_speed = 5
self.cloud_speed_multiplier = 1.0
self.petal_speed_multiplier = 1.0
self.edamame_fall_speed = 2
self.cat = Cat(self.cat_right_base, (WIDTH // 2, HEIGHT), 14)
self.sushi_spawner = Spawner(125)
self.cloud_spawner = Spawner(4000)
self.petal_spawner = Spawner(200)
self.edamame_spawner = Spawner(1500)
self.speed_increase_time = pygame.time.get_ticks()
self.intro_start_time = pygame.time.get_ticks()
self.gamestart_sound.play()
def pause(self, by_controller=False):
if not self.paused and not self.show_intro:
self.paused = True
self.pause_by_controller = by_controller
pygame.mixer.music.pause()
self.paused_sound.play()
def unpause(self):
if self.paused:
self.paused = False
pygame.mixer.music.unpause()
self.unpaused_sound.play()
def run(self):
deadzone = 0.2
self.show_intro = True
while True:
dt = self.clock.tick(60)
now = pygame.time.get_ticks()
self.screen.blit(self.wallpaper, (0, 0))
keys = pygame.key.get_pressed()
move = 0
self.check_controllers()
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
if event.type == pygame.KEYDOWN:
if self.game_over:
self.reset_game()
elif event.key == pygame.K_ESCAPE:
if not self.game_over and not self.show_intro:
if self.paused:
self.unpause()
else:
self.pause(by_controller=False)
elif event.key == pygame.K_q:
quit_game()
if event.type == pygame.JOYBUTTONDOWN:
if self.game_over:
self.reset_game()
elif event.button in [7, 6]:
if not self.game_over and not self.show_intro:
if self.paused:
self.unpause()
else:
self.pause(by_controller=True)
elif self.paused and event.button == 2:
quit_game()
if self.show_intro:
if self.draw_intro():
pygame.display.flip()
continue
else:
self.show_intro = False
if self.paused:
self.draw_centered_text("PAUSED", (255, 255, 255))
if self.pause_by_controller:
instruction = self.small_font.render("Press START to resume or X to quit.", True, (255, 255, 255))
else:
instruction = self.small_font.render("Press ESC to resume or Q to quit.", True, (255, 255, 255))
instr_rect = instruction.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 40))
self.screen.blit(instruction, instr_rect)
pygame.display.flip()
continue
if now - self.speed_increase_time > 30000:
self.sushi_fall_speed += 1
self.cloud_speed_multiplier += 0.1
self.petal_speed_multiplier += 0.1
self.edamame_fall_speed += 0.1
self.speed_increase_time = now
if self.cloud_spawner.can_spawn(now):
self.spawn_cloud()
self.cloud_spawner.update_spawn_time(now)
if self.petal_spawner.can_spawn(now):
self.spawn_petal()
self.petal_spawner.update_spawn_time(now)
if self.edamame_spawner.can_spawn(now):
self.spawn_edamame()
self.edamame_spawner.update_spawn_time(now)
if not self.game_over and self.sushi_spawner.can_spawn(now):
self.spawn_sushi()
self.sushi_spawner.update_spawn_time(now)
for cloud in self.clouds[:]:
cloud.update(dt, now)
if cloud.off_screen():
self.clouds.remove(cloud)
for petal in self.petals[:]:
petal.update(dt, now)
if petal.off_screen():
self.petals.remove(petal)
for edamame in self.edamames[:]:
edamame.update(dt, now)
if edamame.off_screen():
self.edamames.remove(edamame)
if not self.game_over:
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
move = -1
self.cat.facing = "left"
elif keys[pygame.K_d] or keys[pygame.K_RIGHT]:
move = 1
self.cat.facing = "right"
for joy in self.joysticks:
axis0 = joy.get_axis(0)
axis2 = joy.get_axis(2)
if joy.get_numhats() > 0:
hat_x, _ = joy.get_hat(0)
else:
hat_x = 0
if move == 0:
if abs(axis0) > deadzone:
move = int(axis0 / abs(axis0))
self.cat.facing = "left" if axis0 < 0 else "right"
elif abs(axis2) > deadzone:
move = int(axis2 / abs(axis2))
self.cat.facing = "left" if axis2 < 0 else "right"
elif hat_x != 0:
move = hat_x
self.cat.facing = "left" if hat_x < 0 else "right"
self.cat.update_image()
self.cat.move(move)
cat_mid_y = self.cat.rect.top + self.cat.rect.height // 2
for sushi in self.sushis[:]:
sushi.speed = self.sushi_fall_speed
sushi.update(dt)
horizontal_overlap = sushi.rect.right > self.cat.rect.left and sushi.rect.left < self.cat.rect.right
if horizontal_overlap and sushi.rect.bottom >= cat_mid_y:
if sushi.wasabi:
self.meow_sound.play()
pygame.mixer.music.stop()
self.gameover_sound.play()
self.game_over = True
self.game_over_time = None
else:
self.score += 1
random.choice(self.chomp_sounds).play()
self.cat.grow()
self.sushis.remove(sushi)
elif sushi.off_screen():
self.sushis.remove(sushi)
for edamame in self.edamames[:]:
edamame.speed = self.edamame_fall_speed
edamame.update(dt, now)
horizontal_overlap = edamame.rect.right > self.cat.rect.left and edamame.rect.left < self.cat.rect.right
if horizontal_overlap and edamame.rect.bottom >= cat_mid_y:
self.oof_sound.play()
self.score += 1
self.edamames.remove(edamame)
elif edamame.off_screen():
self.edamames.remove(edamame)
else:
if self.game_over_time is None:
self.game_over_time = now
elif now - self.game_over_time >= GAME_OVER_DELAY:
quit_game()
for cloud in self.clouds:
cloud.draw(self.screen)
for petal in self.petals:
petal.draw(self.screen)
self.cat.draw(self.screen)
for sushi in self.sushis:
sushi.draw(self.screen)
for edamame in self.edamames:
edamame.draw(self.screen)
self.draw_text(f"Score: {self.score}", (10, 10))
if self.game_over:
big_font = pygame.font.Font(None, 96)
small_font = pygame.font.Font(None, 32)
grumpy_rect = self.grumpy_img.get_rect(center=(WIDTH // 2, HEIGHT // 2 - 160))
self.screen.blit(self.grumpy_img, grumpy_rect)
self.draw_centered_multiline_text(["GAME OVER"], color=(255, 0, 0), font=big_font, line_spacing=0)
game_over_surf = big_font.render("GAME OVER", True, (255, 0, 0))
x_center = WIDTH // 2
y_start = (HEIGHT // 2) + game_over_surf.get_height() // 2 + 20
if self.joysticks:
prompt_text = "Press any button to try again!"
else:
prompt_text = "Press any key to try again!"
prompt_surf = small_font.render(prompt_text, True, (255, 255, 255))
prompt_rect = prompt_surf.get_rect(center=(x_center, y_start + prompt_surf.get_height() // 2))
self.screen.blit(prompt_surf, prompt_rect)
pygame.display.flip()
def draw_text(self, text, pos, color=(255, 255, 255)):
surf = self.small_font.render(text, True, color)
self.screen.blit(surf, pos)
def draw_centered_text(self, text, color=(255, 255, 255)):
surf = self.small_font.render(text, True, color)
rect = surf.get_rect(center=(WIDTH // 2, HEIGHT // 2))
self.screen.blit(surf, rect)
def draw_centered_multiline_text(self, lines, color=(255, 255, 255), line_spacing=10, font=None):
if font is None:
font = self.small_font
total_height = 0
rendered_lines = []
for line in lines:
surf = font.render(line, True, color)
rendered_lines.append(surf)
total_height += surf.get_height() + line_spacing
total_height -= line_spacing
y = (HEIGHT - total_height) // 2
for surf in rendered_lines:
rect = surf.get_rect(center=(WIDTH // 2, y + surf.get_height() // 2))
self.screen.blit(surf, rect)
y += surf.get_height() + line_spacing
if __name__ == "__main__":
game = Game()
game.reset_game()
game.run()
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB