Files
mygame/game/main.py
2026-05-20 20:21:27 +08:00

152 lines
4.7 KiB
Python

import sys
import pygame
from game.config import (
WINDOW_WIDTH, WINDOW_HEIGHT, FPS,
COLOR_BG, COLOR_WHITE, INITIAL_GOLD, INITIAL_LIVES,
UI_TOP_HEIGHT, UI_BOTTOM_HEIGHT, GAME_HEIGHT, TOWER_DATA,
TOTAL_WAVES,
)
from game.map import GameMap
from game.enemy import Enemy
from game.tower import Tower
from game.projectile import Projectile
from game.wave import WaveManager
from game.ui import UI
class Game:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("塔防游戏")
self.clock = pygame.time.Clock()
self.font = pygame.font.SysFont("microsoftyahei", 20)
self.small_font = pygame.font.SysFont("microsoftyahei", 16)
self.big_font = pygame.font.SysFont("microsoftyahei", 48)
self.reset()
def reset(self):
self.game_map = GameMap()
self.enemies = []
self.towers = []
self.projectiles = []
self.wave_mgr = WaveManager()
self.ui = UI()
self.gold = INITIAL_GOLD
self.lives = INITIAL_LIVES
self.game_over = False
self.won = False
def run(self):
while True:
dt = self.clock.tick(FPS) / 1000.0
dt = min(dt, 0.05)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self._handle_event(event)
if not self.game_over:
self._update(dt)
self._draw()
def _handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = event.pos
if self.game_over:
return
action = self.ui.handle_click(pos, self.gold)
if action == "wave":
if self.wave_mgr.has_more_waves() and not self.wave_mgr.wave_active:
self.wave_mgr.start_next_wave()
return
tower_type = self.ui.handle_grid_click(pos)
if tower_type:
col, row = self.game_map.pixel_to_grid(*pos)
if self.game_map.is_buildable(col, row):
occupied = any(t.col == col and t.row == row for t in self.towers)
price = TOWER_DATA[tower_type]["price"]
if not occupied and self.gold >= price:
px, py = self.game_map.grid_to_pixel(col, row)
self.towers.append(Tower(tower_type, col, row, px, py))
self.gold -= price
self.ui.selected_tower = None
return
self.ui.selected_tower = None
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and self.game_over:
self.reset()
if event.key == pygame.K_ESCAPE:
self.ui.selected_tower = None
def _update(self, dt):
self.wave_mgr.update(dt, self.enemies)
for e in self.enemies:
e.update(dt)
if e.reached_end:
self.lives -= 2 if e.type == "boss" else 1
if self.lives <= 0:
self.lives = 0
self.game_over = True
self.won = False
for t in self.towers:
t.update(dt, self.enemies, self.projectiles)
for p in self.projectiles:
p.update(dt, self.enemies)
for e in self.enemies:
if not e.alive and not e.reached_end:
self.gold += e.reward
e.reward = 0
self.enemies = [e for e in self.enemies if e.alive]
self.projectiles = [p for p in self.projectiles if p.alive]
if self.wave_mgr.all_waves_done or (self.wave_mgr.current_wave >= TOTAL_WAVES and not self.wave_mgr.wave_active and not self.enemies):
if not self.game_over:
self.game_over = True
self.won = True
def _draw(self):
self.screen.fill(COLOR_BG)
self.game_map.draw(self.screen)
for t in self.towers:
t.draw(self.screen)
for e in self.enemies:
e.draw(self.screen)
for p in self.projectiles:
p.draw(self.screen)
mx, my = pygame.mouse.get_pos()
self.ui.draw_placement_preview(self.screen, mx, my, self.game_map)
self.ui.draw(
self.screen, self.gold, self.lives,
self.wave_mgr.current_wave, self.wave_mgr.wave_active,
self.wave_mgr.has_more_waves(),
self.font, self.small_font,
)
if self.game_over:
self.ui.draw_game_over(self.screen, self.won, self.big_font)
pygame.display.flip()
if __name__ == "__main__":
Game().run()