Merge branch 'main' into feat/highscore
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 766 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 710 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 710 KiB |
+133
@@ -0,0 +1,133 @@
|
|||||||
|
import pygame
|
||||||
|
import random
|
||||||
|
from src.settings import (
|
||||||
|
ITEM_SPAWN_INTERVAL, ITEM_SHOPPING_TIMER, ITEM_SIZE,
|
||||||
|
COLOR_HP_BAR_YELLOW, COLOR_HP_BAR_BG
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Item:
|
||||||
|
def __init__(self, x, y, item_type):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.item_type = item_type
|
||||||
|
|
||||||
|
# collision rect for player (2 times item size for width and height)
|
||||||
|
self.rect = pygame.Rect(self.x, self.y, ITEM_SIZE, ITEM_SIZE)
|
||||||
|
|
||||||
|
# timer to store time when item appeared
|
||||||
|
self.spawn_time = pygame.time.get_ticks()
|
||||||
|
|
||||||
|
# try to load sprite with item type
|
||||||
|
try:
|
||||||
|
path = f"assets/items/{item_type}.png"
|
||||||
|
self.image = pygame.image.load(path).convert_alpha()
|
||||||
|
self.image = pygame.transform.scale(self.image, (ITEM_SIZE, ITEM_SIZE))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error loading item sprite {item_type}: {e}")
|
||||||
|
self.image = None
|
||||||
|
|
||||||
|
# to check if the time ran out to buy the item
|
||||||
|
def is_expired(self):
|
||||||
|
return pygame.time.get_ticks() - self.spawn_time >= ITEM_SHOPPING_TIMER
|
||||||
|
|
||||||
|
# cam offset to convert world coordinates to screen coordinates
|
||||||
|
def draw(self, screen, cam_x, cam_y):
|
||||||
|
draw_x = self.x - cam_x
|
||||||
|
draw_y = self.y - cam_y
|
||||||
|
|
||||||
|
if self.image is not None:
|
||||||
|
screen.blit(self.image, (draw_x, draw_y))
|
||||||
|
else:
|
||||||
|
# fallback using settings colors
|
||||||
|
# coffee brown, beer yellow
|
||||||
|
if self.item_type == "coffee":
|
||||||
|
color = (120, 70, 30)
|
||||||
|
else:
|
||||||
|
color = COLOR_HP_BAR_YELLOW
|
||||||
|
|
||||||
|
draw_rect = (draw_x, draw_y, ITEM_SIZE, ITEM_SIZE)
|
||||||
|
pygame.draw.rect(screen, color, draw_rect)
|
||||||
|
pygame.draw.rect(screen, COLOR_HP_BAR_BG, draw_rect, 2)
|
||||||
|
|
||||||
|
|
||||||
|
# try 50 times to find a free position to spawn item
|
||||||
|
def _random_position(room_rect, blocked_rects):
|
||||||
|
attempts = 0
|
||||||
|
max_attempts = 50
|
||||||
|
|
||||||
|
while attempts < max_attempts:
|
||||||
|
# generate random x/y coordinates with room boundaries
|
||||||
|
# * 2 to have a margin to walls
|
||||||
|
x = random.randint(room_rect.left + ITEM_SIZE, room_rect.right - ITEM_SIZE * 2)
|
||||||
|
y = random.randint(room_rect.top + ITEM_SIZE, room_rect.bottom - ITEM_SIZE * 2)
|
||||||
|
|
||||||
|
# create a rect at this position for testing collision
|
||||||
|
test_rect = pygame.Rect(x, y, ITEM_SIZE, ITEM_SIZE)
|
||||||
|
blocked = False
|
||||||
|
for b in blocked_rects:
|
||||||
|
if test_rect.colliderect(b):
|
||||||
|
blocked = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# if position is not blocked, return the position
|
||||||
|
if not blocked:
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
attempts += 1
|
||||||
|
|
||||||
|
# no spot after 50 attempts -> return
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ItemManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.items = []
|
||||||
|
self.last_spawn_time = pygame.time.get_ticks()
|
||||||
|
|
||||||
|
# remove expired items and spawn new ones
|
||||||
|
def update(self, room_rect, blocked_rects):
|
||||||
|
now = pygame.time.get_ticks()
|
||||||
|
|
||||||
|
remaining_items = []
|
||||||
|
|
||||||
|
for item in self.items:
|
||||||
|
if item.is_expired() == False:
|
||||||
|
remaining_items.append(item)
|
||||||
|
|
||||||
|
# replace the old list with the new temp_list
|
||||||
|
self.items = remaining_items
|
||||||
|
|
||||||
|
# spawn logic for new items
|
||||||
|
if room_rect is not None:
|
||||||
|
if now - self.last_spawn_time >= ITEM_SPAWN_INTERVAL:
|
||||||
|
pos = _random_position(room_rect, blocked_rects)
|
||||||
|
if pos is not None:
|
||||||
|
x, y = pos
|
||||||
|
item_type = random.choice(["coffee", "beer"])
|
||||||
|
self.items.append(Item(x, y, item_type))
|
||||||
|
|
||||||
|
self.last_spawn_time = now
|
||||||
|
|
||||||
|
# check if player press "e" to buy
|
||||||
|
def check_collect(self, player_rect, keys):
|
||||||
|
if keys[pygame.K_e]:
|
||||||
|
for item in self.items:
|
||||||
|
if player_rect.colliderect(item.rect):
|
||||||
|
return item
|
||||||
|
return None
|
||||||
|
|
||||||
|
# delete item from list after buying it
|
||||||
|
def remove_item(self, item):
|
||||||
|
if item in self.items:
|
||||||
|
self.items.remove(item)
|
||||||
|
|
||||||
|
# draw all active items
|
||||||
|
def draw(self, screen, cam_x, cam_y):
|
||||||
|
for item in self.items:
|
||||||
|
item.draw(screen, cam_x, cam_y)
|
||||||
|
|
||||||
|
# clear items when changing room
|
||||||
|
def clear(self):
|
||||||
|
self.items = []
|
||||||
|
self.last_spawn_time = pygame.time.get_ticks()
|
||||||
+19
-9
@@ -1,8 +1,8 @@
|
|||||||
# --- DESK ---
|
|
||||||
from typing import Mapping, Literal, Tuple
|
from typing import Mapping, Literal, Tuple
|
||||||
|
|
||||||
from src.map import tile_size
|
from src.map import tile_size
|
||||||
|
|
||||||
|
# --- DESK ---
|
||||||
DESK_WIDTH = 70
|
DESK_WIDTH = 70
|
||||||
DESK_HEIGHT = 40
|
DESK_HEIGHT = 40
|
||||||
|
|
||||||
@@ -13,13 +13,15 @@ DOOR_BORDER_WIDTH = 3
|
|||||||
|
|
||||||
COLOR_DOOR_BEIGE = (245, 245, 220)
|
COLOR_DOOR_BEIGE = (245, 245, 220)
|
||||||
COLOR_DOOR_BORDER = (100, 90, 80)
|
COLOR_DOOR_BORDER = (100, 90, 80)
|
||||||
COLOR_HP_BAR_GREEN = (0, 255, 0)
|
|
||||||
COLOR_HP_BAR_BG = (50, 50, 50)
|
|
||||||
|
|
||||||
|
|
||||||
|
# --- PLAYER ---
|
||||||
# Players Constants / Settings
|
# Players Constants / Settings
|
||||||
# Valid movement/animation directions.
|
# Valid movement/animation directions.
|
||||||
Direction = Literal["down", "left", "right", "up"]
|
Direction = Literal["down", "left", "right", "up"]
|
||||||
|
|
||||||
|
|
||||||
|
# --- SPRITE ---
|
||||||
# Sprite files are grouped by direction.
|
# Sprite files are grouped by direction.
|
||||||
# Example: "down" uses sprite_01.png, sprite_02.png, sprite_03.png.
|
# Example: "down" uses sprite_01.png, sprite_02.png, sprite_03.png.
|
||||||
DIRECTION_FRAMES: Mapping[Direction, Tuple[int, int, int]] = {
|
DIRECTION_FRAMES: Mapping[Direction, Tuple[int, int, int]] = {
|
||||||
@@ -33,33 +35,39 @@ DIRECTION_FRAMES: Mapping[Direction, Tuple[int, int, int]] = {
|
|||||||
DEFAULT_SPRITE_HEIGHT: int = 138
|
DEFAULT_SPRITE_HEIGHT: int = 138
|
||||||
DEFAULT_FRAME_TIME: float = 0.16
|
DEFAULT_FRAME_TIME: float = 0.16
|
||||||
|
|
||||||
|
|
||||||
# --- ECTS ---
|
# --- ECTS ---
|
||||||
START_ECTS_VALUE = 1 # how many ECTS are generated at the beginning
|
START_ECTS_VALUE = 1 # how many ECTS are generated at the beginning
|
||||||
ECTS_UPDATE_INTERVAL = 1000 # time in ms = 1 sec
|
ECTS_UPDATE_INTERVAL = 1000 # time in ms (1000 = 1 sec)
|
||||||
|
|
||||||
BEER_BOTTLE_ECTS_VALUE = 2
|
BEER_BOTTLE_ECTS_VALUE = 2
|
||||||
BEER_COST = 50
|
BEER_COST = 50
|
||||||
|
|
||||||
|
|
||||||
# --- BUTTONS ---
|
# --- BUTTONS ---
|
||||||
COLOR_BUTTON = (0, 255, 0)
|
COLOR_BUTTON = (0, 255, 0)
|
||||||
COLOR_BUTTON_HOVER = (200, 255, 0)
|
COLOR_BUTTON_HOVER = (200, 255, 0)
|
||||||
|
|
||||||
|
|
||||||
# --- STARTSCREEN ---
|
# --- STARTSCREEN ---
|
||||||
COLOR_STARTSCREEN_BACKGROUND = ((0, 0, 0))
|
COLOR_STARTSCREEN_BACKGROUND = (0, 0, 0)
|
||||||
COLOR_STARTSCREEN_FONT_TITLE = (0, 255, 0)
|
COLOR_STARTSCREEN_FONT_TITLE = (0, 255, 0)
|
||||||
COLOR_STARTSCREEN_FONT_LABEL = (0, 255, 255)
|
COLOR_STARTSCREEN_FONT_LABEL = (0, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
# --- ENDSCREEN ---
|
# --- ENDSCREEN ---
|
||||||
COLOR_ENDSCREEN_BACKGROUND = ((0, 0, 0))
|
COLOR_ENDSCREEN_BACKGROUND = (0, 0, 0)
|
||||||
COLOR_ENDSCREEN_TEXT = (255, 255, 255)
|
COLOR_ENDSCREEN_TEXT = (255, 255, 255)
|
||||||
COLOR_ENDSCREEN_WIN = (0, 255, 0)
|
COLOR_ENDSCREEN_WIN = (0, 255, 0)
|
||||||
COLOR_ENDSCREEN_LOSE = (255, 0, 0)
|
COLOR_ENDSCREEN_LOSE = (255, 0, 0)
|
||||||
FONT_ENDSCREEN = "Arial"
|
FONT_ENDSCREEN = "Arial"
|
||||||
|
|
||||||
|
|
||||||
# --- COFFEE ---
|
# --- COFFEE ---
|
||||||
COFFEE_COST = 30
|
COFFEE_COST = 30
|
||||||
COFFEE_HEAL_VALUE = 30
|
COFFEE_HEAL_VALUE = 30
|
||||||
|
|
||||||
|
|
||||||
# --- TOWER ---
|
# --- TOWER ---
|
||||||
TOWER_COST = 150
|
TOWER_COST = 150
|
||||||
PROJECTILE_DMG = 15
|
PROJECTILE_DMG = 15
|
||||||
@@ -68,11 +76,13 @@ COLOR_PROJECTILE = (200, 200, 0)
|
|||||||
TOWER_TIMER = 30000 # how long the tower stays and attack before it disappears
|
TOWER_TIMER = 30000 # how long the tower stays and attack before it disappears
|
||||||
|
|
||||||
|
|
||||||
# --- SHOPPING TIMER ---
|
# --- ITEM SPAWN TIMER ---
|
||||||
ITEM_SHOPPING_TIMER = 10000 # for items like coffee, beer, tower - how long u have time to buy it
|
ITEM_SPAWN_INTERVAL = 5000 # ms until a new item spawns
|
||||||
|
ITEM_SHOPPING_TIMER = 10000 # how long you have time to buy items before they despawn
|
||||||
|
ITEM_SIZE = 30
|
||||||
|
|
||||||
|
|
||||||
# -- ZOMBIE ---
|
# --- ZOMBIE ---
|
||||||
ZOMBIE_EASY_HP = 30
|
ZOMBIE_EASY_HP = 30
|
||||||
ZOMBIE_EASY_DMG = 3
|
ZOMBIE_EASY_DMG = 3
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user