游戏可以运行
This commit is contained in:
117
game/ui.py
Normal file
117
game/ui.py
Normal file
@@ -0,0 +1,117 @@
|
||||
import pygame
|
||||
from game.config import (
|
||||
WINDOW_WIDTH, WINDOW_HEIGHT, UI_TOP_HEIGHT, UI_BOTTOM_HEIGHT,
|
||||
CELL_SIZE, COLOR_BLACK, COLOR_WHITE, COLOR_GOLD, COLOR_RED,
|
||||
COLOR_GREEN, COLOR_DARK_GRAY, COLOR_GRAY, COLOR_BG,
|
||||
TOWER_DATA, INITIAL_LIVES, TOTAL_WAVES,
|
||||
)
|
||||
|
||||
|
||||
class UI:
|
||||
def __init__(self):
|
||||
self.selected_tower = None
|
||||
self.tower_buttons = []
|
||||
self.wave_button = pygame.Rect(WINDOW_WIDTH - 140, WINDOW_HEIGHT - UI_BOTTOM_HEIGHT + 10, 130, 40)
|
||||
self._init_tower_buttons()
|
||||
|
||||
def _init_tower_buttons(self):
|
||||
types = ["arrow", "cannon", "slow"]
|
||||
for i, t in enumerate(types):
|
||||
rect = pygame.Rect(10 + i * 160, WINDOW_HEIGHT - UI_BOTTOM_HEIGHT + 10, 150, 40)
|
||||
self.tower_buttons.append((rect, t))
|
||||
|
||||
def handle_click(self, pos, gold):
|
||||
for rect, t in self.tower_buttons:
|
||||
if rect.collidepoint(pos):
|
||||
price = TOWER_DATA[t]["price"]
|
||||
if gold >= price:
|
||||
self.selected_tower = t if self.selected_tower != t else None
|
||||
return None
|
||||
|
||||
if self.wave_button.collidepoint(pos):
|
||||
return "wave"
|
||||
|
||||
return None
|
||||
|
||||
def handle_grid_click(self, pos):
|
||||
if self.selected_tower is None:
|
||||
return None
|
||||
return self.selected_tower
|
||||
|
||||
def draw(self, surface, gold, lives, wave_num, wave_active, has_more, font, small_font):
|
||||
# Top bar
|
||||
pygame.draw.rect(surface, COLOR_DARK_GRAY, (0, 0, WINDOW_WIDTH, UI_TOP_HEIGHT))
|
||||
|
||||
gold_text = font.render(f"金币: {gold}", True, COLOR_GOLD)
|
||||
surface.blit(gold_text, (10, 10))
|
||||
|
||||
lives_text = font.render(f"生命: {lives}", True, COLOR_RED if lives <= 5 else COLOR_GREEN)
|
||||
surface.blit(lives_text, (200, 10))
|
||||
|
||||
wave_text = font.render(f"波次: {wave_num}/{TOTAL_WAVES}", True, COLOR_WHITE)
|
||||
surface.blit(wave_text, (380, 10))
|
||||
|
||||
# Bottom bar
|
||||
pygame.draw.rect(surface, COLOR_DARK_GRAY, (0, WINDOW_HEIGHT - UI_BOTTOM_HEIGHT, WINDOW_WIDTH, UI_BOTTOM_HEIGHT))
|
||||
|
||||
for rect, t in self.tower_buttons:
|
||||
data = TOWER_DATA[t]
|
||||
selected = self.selected_tower == t
|
||||
bg = (80, 80, 120) if selected else COLOR_GRAY
|
||||
pygame.draw.rect(surface, bg, rect, border_radius=5)
|
||||
pygame.draw.rect(surface, COLOR_WHITE if selected else COLOR_BLACK, rect, 2, border_radius=5)
|
||||
|
||||
icon_x = rect.x + 20
|
||||
icon_y = rect.y + rect.height // 2
|
||||
if t == "arrow":
|
||||
pygame.draw.rect(surface, data["color"], (icon_x - 5, icon_y - 5, 10, 10))
|
||||
elif t == "cannon":
|
||||
pygame.draw.circle(surface, data["color"], (icon_x, icon_y), 7)
|
||||
elif t == "slow":
|
||||
pts = [(icon_x, icon_y-7), (icon_x+7, icon_y), (icon_x, icon_y+7), (icon_x-7, icon_y)]
|
||||
pygame.draw.polygon(surface, data["color"], pts)
|
||||
|
||||
name_text = small_font.render(f"{data['name']} {data['price']}G", True, COLOR_WHITE)
|
||||
surface.blit(name_text, (icon_x + 15, icon_y - 7))
|
||||
|
||||
# Wave button
|
||||
if has_more:
|
||||
btn_color = COLOR_GREEN if not wave_active else COLOR_GRAY
|
||||
pygame.draw.rect(surface, btn_color, self.wave_button, border_radius=5)
|
||||
pygame.draw.rect(surface, COLOR_BLACK, self.wave_button, 2, border_radius=5)
|
||||
btn_text = small_font.render("开始波次" if not wave_active else "进行中...", True, COLOR_WHITE)
|
||||
surface.blit(btn_text, (self.wave_button.x + 10, self.wave_button.y + 12))
|
||||
|
||||
def draw_placement_preview(self, surface, mx, my, game_map):
|
||||
if self.selected_tower is None:
|
||||
return
|
||||
col, row = game_map.pixel_to_grid(mx, my)
|
||||
if col < 0 or row < 0:
|
||||
return
|
||||
px, py = game_map.grid_to_pixel(col, row)
|
||||
data = TOWER_DATA[self.selected_tower]
|
||||
|
||||
buildable = game_map.is_buildable(col, row)
|
||||
color = (*data["color"][:3], 60) if buildable else (255, 0, 0, 60)
|
||||
|
||||
preview = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA)
|
||||
preview.fill(color)
|
||||
surface.blit(preview, (col * CELL_SIZE, row * CELL_SIZE + UI_TOP_HEIGHT))
|
||||
|
||||
if buildable:
|
||||
pygame.draw.circle(surface, COLOR_WHITE, (px, py), data["range"], 1)
|
||||
|
||||
def draw_game_over(self, surface, won, font):
|
||||
overlay = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.SRCALPHA)
|
||||
overlay.fill((0, 0, 0, 150))
|
||||
surface.blit(overlay, (0, 0))
|
||||
|
||||
text = "胜利!" if won else "失败!"
|
||||
color = COLOR_GOLD if won else COLOR_RED
|
||||
rendered = font.render(text, True, color)
|
||||
rect = rendered.get_rect(center=(WINDOW_WIDTH // 2, WINDOW_HEIGHT // 2 - 20))
|
||||
surface.blit(rendered, rect)
|
||||
|
||||
hint = font.render("按 R 重新开始", True, COLOR_WHITE)
|
||||
hint_rect = hint.get_rect(center=(WINDOW_WIDTH // 2, WINDOW_HEIGHT // 2 + 30))
|
||||
surface.blit(hint, hint_rect)
|
||||
Reference in New Issue
Block a user