From 8985c3317926fca64a5ca72f063a4d2551157314 Mon Sep 17 00:00:00 2001 From: ArneGleason Date: Sat, 17 May 2025 22:08:57 -0400 Subject: [PATCH] Add Ned's Soup Foraging Frenzy game --- ned_soup/README.md | 16 +++ ned_soup/main.py | 264 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 ned_soup/README.md create mode 100644 ned_soup/main.py diff --git a/ned_soup/README.md b/ned_soup/README.md new file mode 100644 index 0000000..58d3e03 --- /dev/null +++ b/ned_soup/README.md @@ -0,0 +1,16 @@ +# Ned's Soup Foraging Frenzy + +This is a simple retro-style arcade game built with **pygame**. Help Ned forage for soup ingredients while avoiding (or stunning) roaming Lugnutz. + +## Requirements +- Python 3.x +- pygame (`pip install pygame`) + +## Running the Game +``` +python main.py +``` + +Use the arrow keys to move Ned. Press `SPACE` to forage at nearby spots. If you collect junk, you can throw it at the nearest Lugnutz with `SHIFT`. + +Collect four ingredients and return to the home square to win. Have fun! diff --git a/ned_soup/main.py b/ned_soup/main.py new file mode 100644 index 0000000..835182f --- /dev/null +++ b/ned_soup/main.py @@ -0,0 +1,264 @@ +# Simple skeleton for Ned's Soup Foraging Frenzy +import pygame +import random +import math + +pygame.init() + +# Screen dimensions +WIDTH, HEIGHT = 800, 600 +screen = pygame.display.set_mode((WIDTH, HEIGHT)) +pygame.display.set_caption("Ned's Soup Foraging Frenzy") +clock = pygame.time.Clock() + +# Colors +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) +RED = (200, 50, 50) +GREEN = (50, 200, 50) +BLUE = (50, 50, 200) +YELLOW = (200, 200, 50) +ORANGE = (200, 150, 50) + +FONT = pygame.font.SysFont("Courier", 16) + +# Parameters for walking +FOOT_OFFSET = 5 +STRIDE_LENGTH = 15 +STEP_SPEED = 2 + +class Walker: + def __init__(self, pos, color, scale=1.0): + self.color = color + self.scale = scale + self.body = pygame.Vector2(pos) + offset = pygame.Vector2(0, FOOT_OFFSET * scale) + self.left_foot = self.body + pygame.Vector2(-offset.x, offset.y) + self.right_foot = self.body + pygame.Vector2(offset.x, offset.y) + self.swing = "left" + self.direction = pygame.Vector2(0, 0) + + def update(self, direction): + if direction.length_squared() > 0: + direction = direction.normalize() + self.direction = direction + self._step() + self.body = (self.left_foot + self.right_foot) / 2 + + def _step(self): + if self.direction.length_squared() == 0: + return + perp = pygame.Vector2(-self.direction.y, self.direction.x) + if self.swing == "left": + step_foot = self.left_foot + support = self.right_foot + sign = -1 + else: + step_foot = self.right_foot + support = self.left_foot + sign = 1 + target = support + self.direction * STRIDE_LENGTH * self.scale + perp * FOOT_OFFSET * sign * self.scale + move = target - step_foot + if move.length() > STEP_SPEED * self.scale: + move.scale_to_length(STEP_SPEED * self.scale) + if self.swing == "left": + self.left_foot += move + if (target - self.left_foot).length() < 0.5: + self.left_foot = target + self.swing = "right" + else: + self.right_foot += move + if (target - self.right_foot).length() < 0.5: + self.right_foot = target + self.swing = "left" + + def draw(self, surface): + r = int(3 * self.scale) + pygame.draw.circle(surface, self.color, self.left_foot, r) + pygame.draw.circle(surface, self.color, self.right_foot, r) + pygame.draw.circle(surface, self.color, self.body, int(4 * self.scale)) + +class ForageSpot: + def __init__(self, pos, good=True): + self.pos = pygame.Vector2(pos) + self.good = good + self.collected = False + self.timer = 0 + + def update(self): + if self.collected: + self.timer += 1 + + def draw(self, surface): + if self.collected: + if self.timer < 180: + color = ORANGE if self.good else RED + pygame.draw.rect(surface, color, (*self.pos - pygame.Vector2(5, 5), 10, 10)) + else: + color = GREEN if self.good else YELLOW + pygame.draw.rect(surface, color, (*self.pos - pygame.Vector2(5, 5), 10, 10)) + +class Lugnutz(Walker): + def __init__(self, pos): + super().__init__(pos, BLUE, scale=1.8) + self.state = "wander" + self.cooldown = 0 + + def think(self, player): + if self.cooldown > 0: + self.cooldown -= 1 + direction = pygame.Vector2(0, 0) + to_player = player.body - self.body + dist = to_player.length() + if self.cooldown == 0: + if dist < 150: + direction = to_player + self.state = "chase" + else: + self.state = "wander" + direction = pygame.Vector2(random.uniform(-1, 1), random.uniform(-1, 1)) + else: + self.state = "flee" + direction = -to_player + self.update(direction) + + def hit(self): + self.cooldown = 120 + +class Game: + def __init__(self): + self.player = Walker((WIDTH/2, HEIGHT/2), WHITE) + self.lugs = [Lugnutz((random.randint(50, WIDTH-50), random.randint(50, HEIGHT-50))) for _ in range(2)] + self.forage_spots = [] + for _ in range(4): + self.spawn_forage() + self.ingredient_count = 0 + self.junk_count = 0 + self.messages = [] + self.spawn_timer = 0 + self.home_rect = pygame.Rect(WIDTH-80, HEIGHT-80, 60, 60) + self.running = True + self.in_start = True + + def spawn_forage(self): + good = random.random() < 0.6 + x = random.randint(40, WIDTH-40) + y = random.randint(40, HEIGHT-40) + self.forage_spots.append(ForageSpot((x, y), good)) + + def process_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.in_start: + if event.key == pygame.K_SPACE: + self.in_start = False + + def update(self): + keys = pygame.key.get_pressed() + if self.in_start: + return + direction = pygame.Vector2(0, 0) + if keys[pygame.K_LEFT]: + direction.x -= 1 + if keys[pygame.K_RIGHT]: + direction.x += 1 + if keys[pygame.K_UP]: + direction.y -= 1 + if keys[pygame.K_DOWN]: + direction.y += 1 + if direction.length_squared() > 0: + direction = direction.normalize() + self.player.update(direction) + + if keys[pygame.K_SPACE]: + for spot in self.forage_spots: + if not spot.collected and (spot.pos - self.player.body).length() < 20: + spot.collected = True + if spot.good: + self.ingredient_count += 1 + self.messages.append("Found ingredient!") + else: + self.junk_count += 1 + self.messages.append("Found junk!") + break + if keys[pygame.K_LSHIFT] or keys[pygame.K_RSHIFT]: + if self.junk_count > 0: + closest = None + dist = 9999 + for lug in self.lugs: + d = (lug.body - self.player.body).length() + if d < dist: + dist = d + closest = lug + if closest and dist < 150: + closest.hit() + self.junk_count -= 1 + self.messages.append("Threw junk!") + + for lug in self.lugs: + lug.think(self.player) + for spot in self.forage_spots: + spot.update() + self.forage_spots = [s for s in self.forage_spots if not (s.collected and s.timer > 180)] + + self.spawn_timer += 1 + if self.spawn_timer > 480: + self.spawn_timer = 0 + self.spawn_forage() + + if self.player.body.x > self.home_rect.x and self.player.body.y > self.home_rect.y: + if self.ingredient_count >= 4: + self.messages.append("You made soup! You win!") + self.running = False + else: + self.messages.append("Need more ingredients before going home!") + + def draw_hud(self): + text = FONT.render(f"Ingredients: {self.ingredient_count} Junk: {self.junk_count}", True, WHITE) + screen.blit(text, (10, 10)) + if self.messages: + msg = FONT.render(self.messages[-1], True, YELLOW) + screen.blit(msg, (10, HEIGHT - 30)) + if self.junk_count > 0: + hint = FONT.render("Press SHIFT to throw junk", True, ORANGE) + screen.blit(hint, (10, HEIGHT - 50)) + + def draw_start(self): + screen.fill(BLACK) + title = FONT.render("Ned's Soup Foraging Frenzy", True, YELLOW) + legend = FONT.render("Arrow keys: move SPACE: forage", True, WHITE) + prompt = FONT.render("Press SPACE to start", True, GREEN) + screen.blit(title, (WIDTH/2 - title.get_width()/2, HEIGHT/2 - 40)) + screen.blit(legend, (WIDTH/2 - legend.get_width()/2, HEIGHT/2)) + screen.blit(prompt, (WIDTH/2 - prompt.get_width()/2, HEIGHT/2 + 40)) + pygame.display.flip() + + def draw(self): + screen.fill((30, 30, 50)) + for spot in self.forage_spots: + spot.draw(screen) + pygame.draw.rect(screen, (80, 80, 80), self.home_rect) + self.player.draw(screen) + for lug in self.lugs: + lug.draw(screen) + self.draw_hud() + pygame.display.flip() + + def run(self): + while self.running: + self.process_events() + if self.in_start: + self.draw_start() + clock.tick(60) + continue + self.update() + self.draw() + clock.tick(60) + +def main(): + game = Game() + game.run() + +if __name__ == "__main__": + main()