游戏可以运行
This commit is contained in:
@@ -32,10 +32,17 @@ COLOR_GRAY = (120, 120, 120)
|
||||
COLOR_DARK_GRAY = (60, 60, 60)
|
||||
COLOR_GOLD = (255, 215, 0)
|
||||
COLOR_HIGHLIGHT = (255, 255, 255, 80)
|
||||
COLOR_DARK_BLUE = (30, 60, 150)
|
||||
COLOR_DARK_GREEN = (30, 130, 50)
|
||||
COLOR_BRIGHT_PURPLE = (180, 80, 255)
|
||||
COLOR_BRIGHT_GREEN = (100, 255, 100)
|
||||
COLOR_SILVER = (192, 192, 210)
|
||||
COLOR_PINK = (255, 130, 170)
|
||||
COLOR_LIGHT_BLUE = (100, 150, 255, 40)
|
||||
|
||||
# Game params
|
||||
INITIAL_GOLD = 200
|
||||
INITIAL_LIVES = 20
|
||||
INITIAL_LIVES = 10
|
||||
TOTAL_WAVES = 10
|
||||
|
||||
# Tower stats
|
||||
@@ -43,6 +50,9 @@ TOWER_DATA = {
|
||||
"arrow": {"damage": 20, "range": 120, "fire_rate": 0.5, "price": 50, "color": COLOR_BLUE, "name": "箭塔"},
|
||||
"cannon": {"damage": 80, "range": 100, "fire_rate": 1.5, "price": 100, "color": COLOR_ORANGE, "name": "炮塔", "splash": 60},
|
||||
"slow": {"damage": 5, "range": 130, "fire_rate": 0.8, "price": 75, "color": COLOR_CYAN, "name": "减速塔", "slow_factor": 0.5, "slow_duration": 2.0},
|
||||
"sniper": {"damage": 120, "range": 200, "fire_rate": 2.0, "price": 120, "color": COLOR_DARK_BLUE, "name": "狙击塔"},
|
||||
"poison": {"damage": 5, "range": 110, "fire_rate": 1.2, "price": 80, "color": COLOR_DARK_GREEN, "name": "毒塔", "poison_dps": 8, "poison_duration": 3.0},
|
||||
"lightning": {"damage": 40, "range": 140, "fire_rate": 1.0, "price": 150, "color": COLOR_BRIGHT_PURPLE, "name": "雷电塔", "chain_count": 2, "chain_range": 80, "chain_decay": 0.5},
|
||||
}
|
||||
|
||||
# Enemy stats
|
||||
@@ -51,6 +61,9 @@ ENEMY_DATA = {
|
||||
"fast": {"hp": 60, "speed": 4, "reward": 8, "color": COLOR_YELLOW, "size": 10, "name": "快速兵"},
|
||||
"heavy": {"hp": 300, "speed": 1, "reward": 25, "color": COLOR_PURPLE, "size": 14, "name": "重装兵"},
|
||||
"boss": {"hp": 800, "speed": 0.8, "reward": 100, "color": COLOR_DARK_RED, "size": 20, "name": "BOSS"},
|
||||
"swarm": {"hp": 30, "speed": 5, "reward": 3, "color": COLOR_BRIGHT_GREEN, "size": 7, "name": "虫群兵"},
|
||||
"shield": {"hp": 200, "speed": 1.5, "reward": 20, "color": COLOR_SILVER, "size": 15, "name": "护盾兵", "shield_hp": 200},
|
||||
"healer": {"hp": 150, "speed": 1.8, "reward": 30, "color": COLOR_PINK, "size": 12, "name": "治疗兵", "heal_range": 100, "heal_amount": 30, "heal_interval": 2.0},
|
||||
}
|
||||
|
||||
# Path waypoints (pixel coordinates)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import pygame
|
||||
import math
|
||||
from game.config import ENEMY_DATA, PATH_WAYPOINTS, COLOR_BLACK, COLOR_GREEN, COLOR_RED
|
||||
from game.config import ENEMY_DATA, PATH_WAYPOINTS, COLOR_BLACK, COLOR_GREEN, COLOR_RED, COLOR_BLUE
|
||||
from game.utils import distance
|
||||
|
||||
|
||||
class Enemy:
|
||||
@@ -17,6 +18,20 @@ class Enemy:
|
||||
self.alive = True
|
||||
self.reached_end = False
|
||||
|
||||
# Shield
|
||||
self.max_shield = data.get("shield_hp", 0)
|
||||
self.shield_hp = self.max_shield
|
||||
|
||||
# Poison DoT
|
||||
self.poison_timer = 0
|
||||
self.poison_dps = 0
|
||||
|
||||
# Healer
|
||||
self.heal_range = data.get("heal_range", 0)
|
||||
self.heal_amount = data.get("heal_amount", 0)
|
||||
self.heal_interval = data.get("heal_interval", 2.0)
|
||||
self.heal_timer = self.heal_interval
|
||||
|
||||
self.x, self.y = PATH_WAYPOINTS[0]
|
||||
self.waypoint_index = 1
|
||||
self.slow_timer = 0
|
||||
@@ -25,21 +40,50 @@ class Enemy:
|
||||
self.speed = self.base_speed * factor
|
||||
self.slow_timer = duration
|
||||
|
||||
def apply_poison(self, dps, duration):
|
||||
self.poison_dps = dps
|
||||
self.poison_timer = duration
|
||||
|
||||
def take_damage(self, damage):
|
||||
if self.shield_hp > 0:
|
||||
absorbed = min(self.shield_hp, damage)
|
||||
self.shield_hp -= absorbed
|
||||
damage -= absorbed
|
||||
if damage > 0:
|
||||
self.hp -= damage
|
||||
if self.hp <= 0:
|
||||
self.hp = 0
|
||||
self.alive = False
|
||||
|
||||
def update(self, dt):
|
||||
def update(self, dt, enemies=None):
|
||||
if not self.alive:
|
||||
return
|
||||
|
||||
# Poison DoT
|
||||
if self.poison_timer > 0:
|
||||
self.poison_timer -= dt
|
||||
self.hp -= self.poison_dps * dt
|
||||
if self.hp <= 0:
|
||||
self.hp = 0
|
||||
self.alive = False
|
||||
return
|
||||
|
||||
# Slow
|
||||
if self.slow_timer > 0:
|
||||
self.slow_timer -= dt
|
||||
if self.slow_timer <= 0:
|
||||
self.speed = self.base_speed
|
||||
|
||||
# Healer ability
|
||||
if self.type == "healer" and enemies:
|
||||
self.heal_timer -= dt
|
||||
if self.heal_timer <= 0:
|
||||
self.heal_timer = self.heal_interval
|
||||
for e in enemies:
|
||||
if e is not self and e.alive and distance(self.x, self.y, e.x, e.y) <= self.heal_range:
|
||||
e.hp = min(e.hp + self.heal_amount, e.max_hp)
|
||||
|
||||
# Movement
|
||||
if self.waypoint_index >= len(PATH_WAYPOINTS):
|
||||
self.reached_end = True
|
||||
self.alive = False
|
||||
@@ -62,14 +106,43 @@ class Enemy:
|
||||
if not self.alive:
|
||||
return
|
||||
ix, iy = int(self.x), int(self.y)
|
||||
|
||||
# Healer aura
|
||||
if self.type == "healer":
|
||||
aura = pygame.Surface((self.heal_range * 2, self.heal_range * 2), pygame.SRCALPHA)
|
||||
pygame.draw.circle(aura, (255, 130, 170, 30), (self.heal_range, self.heal_range), self.heal_range)
|
||||
surface.blit(aura, (ix - self.heal_range, iy - self.heal_range))
|
||||
|
||||
# Poison tint
|
||||
if self.poison_timer > 0:
|
||||
pygame.draw.circle(surface, (0, 180, 0), (ix, iy), self.size + 3)
|
||||
|
||||
pygame.draw.circle(surface, self.color, (ix, iy), self.size)
|
||||
pygame.draw.circle(surface, COLOR_BLACK, (ix, iy), self.size, 2)
|
||||
|
||||
# Boss eyes
|
||||
if self.type == "boss":
|
||||
for offset in [(-6, -6), (6, -6)]:
|
||||
pygame.draw.circle(surface, (255, 200, 0), (ix + offset[0], iy + offset[1]), 4)
|
||||
pygame.draw.circle(surface, COLOR_BLACK, (ix + offset[0], iy + offset[1]), 4, 1)
|
||||
|
||||
# Shield ring
|
||||
if self.type == "shield" and self.shield_hp > 0:
|
||||
shield_ratio = self.shield_hp / self.max_shield
|
||||
arc_color = COLOR_BLUE
|
||||
pygame.draw.circle(surface, arc_color, (ix, iy), self.size + 4, 2)
|
||||
|
||||
# Swarm wings
|
||||
if self.type == "swarm":
|
||||
for dx_off in [-4, 4]:
|
||||
pygame.draw.line(surface, (200, 255, 200), (ix + dx_off, iy - 3), (ix + dx_off * 2, iy - 7), 1)
|
||||
|
||||
# Healer cross
|
||||
if self.type == "healer":
|
||||
pygame.draw.rect(surface, (255, 255, 255), (ix - 1, iy - 5, 3, 10))
|
||||
pygame.draw.rect(surface, (255, 255, 255), (ix - 5, iy - 1, 10, 3))
|
||||
|
||||
# Health bar
|
||||
bar_w = self.size * 2 + 4
|
||||
if self.type == "boss":
|
||||
bar_w = self.size * 3
|
||||
@@ -79,3 +152,10 @@ class Enemy:
|
||||
ratio = self.hp / self.max_hp
|
||||
pygame.draw.rect(surface, COLOR_RED, (bx, by, bar_w, bar_h))
|
||||
pygame.draw.rect(surface, COLOR_GREEN, (bx, by, int(bar_w * ratio), bar_h))
|
||||
|
||||
# Shield bar
|
||||
if self.max_shield > 0 and self.shield_hp > 0:
|
||||
s_bar_h = 3
|
||||
s_ratio = self.shield_hp / self.max_shield
|
||||
pygame.draw.rect(surface, (80, 80, 80), (bx, by - s_bar_h - 1, bar_w, s_bar_h))
|
||||
pygame.draw.rect(surface, COLOR_BLUE, (bx, by - s_bar_h - 1, int(bar_w * s_ratio), s_bar_h))
|
||||
|
||||
@@ -88,10 +88,13 @@ class Game:
|
||||
self.ui.selected_tower = None
|
||||
|
||||
def _update(self, dt):
|
||||
if self.ui.selected_tower is not None:
|
||||
dt *= 0.3
|
||||
|
||||
self.wave_mgr.update(dt, self.enemies)
|
||||
|
||||
for e in self.enemies:
|
||||
e.update(dt)
|
||||
e.update(dt, self.enemies)
|
||||
if e.reached_end:
|
||||
self.lives -= 2 if e.type == "boss" else 1
|
||||
if self.lives <= 0:
|
||||
@@ -141,6 +144,8 @@ class Game:
|
||||
self.font, self.small_font,
|
||||
)
|
||||
|
||||
self.ui.draw_slow_overlay(self.screen)
|
||||
|
||||
if self.game_over:
|
||||
self.ui.draw_game_over(self.screen, self.won, self.big_font)
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import pygame
|
||||
import math
|
||||
from game.config import COLOR_WHITE, COLOR_ORANGE, COLOR_CYAN
|
||||
from game.config import COLOR_WHITE, COLOR_ORANGE, COLOR_CYAN, COLOR_DARK_GREEN, COLOR_BRIGHT_PURPLE
|
||||
from game.utils import distance
|
||||
|
||||
|
||||
class Projectile:
|
||||
def __init__(self, x, y, target, damage, proj_type="arrow", splash=0, slow_factor=0, slow_duration=0):
|
||||
def __init__(self, x, y, target, damage, proj_type="arrow", splash=0,
|
||||
slow_factor=0, slow_duration=0,
|
||||
poison_dps=0, poison_duration=0,
|
||||
chain_count=0, chain_range=0, chain_decay=0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.target = target
|
||||
@@ -14,6 +17,11 @@ class Projectile:
|
||||
self.splash = splash
|
||||
self.slow_factor = slow_factor
|
||||
self.slow_duration = slow_duration
|
||||
self.poison_dps = poison_dps
|
||||
self.poison_duration = poison_duration
|
||||
self.chain_count = chain_count
|
||||
self.chain_range = chain_range
|
||||
self.chain_decay = chain_decay
|
||||
self.speed = 400
|
||||
self.alive = True
|
||||
|
||||
@@ -39,6 +47,7 @@ class Projectile:
|
||||
|
||||
def _hit(self, enemies):
|
||||
self.alive = False
|
||||
|
||||
if self.proj_type == "cannon" and self.splash > 0:
|
||||
for e in enemies:
|
||||
if e.alive and distance(self.target.x, self.target.y, e.x, e.y) <= self.splash:
|
||||
@@ -49,6 +58,33 @@ class Projectile:
|
||||
if self.proj_type == "slow" and self.target.alive:
|
||||
self.target.apply_slow(self.slow_factor, self.slow_duration)
|
||||
|
||||
if self.proj_type == "poison" and self.target.alive:
|
||||
self.target.apply_poison(self.poison_dps, self.poison_duration)
|
||||
|
||||
if self.proj_type == "lightning" and self.chain_count > 0:
|
||||
self._chain_lightning(enemies, self.target, self.damage, self.chain_count)
|
||||
|
||||
def _chain_lightning(self, enemies, source, damage, chains_left):
|
||||
if chains_left <= 0:
|
||||
return
|
||||
hit = [self.target, source]
|
||||
current = source
|
||||
current_damage = damage
|
||||
for _ in range(chains_left):
|
||||
current_damage *= self.chain_decay
|
||||
best = None
|
||||
best_dist = self.chain_range
|
||||
for e in enemies:
|
||||
if e.alive and e not in hit:
|
||||
d = distance(current.x, current.y, e.x, e.y)
|
||||
if d < best_dist:
|
||||
best_dist = d
|
||||
best = e
|
||||
if best:
|
||||
best.take_damage(current_damage)
|
||||
hit.append(best)
|
||||
current = best
|
||||
|
||||
def draw(self, surface):
|
||||
if not self.alive:
|
||||
return
|
||||
@@ -59,3 +95,12 @@ class Projectile:
|
||||
pygame.draw.circle(surface, COLOR_ORANGE, (ix, iy), 5)
|
||||
elif self.proj_type == "slow":
|
||||
pygame.draw.circle(surface, COLOR_CYAN, (ix, iy), 4)
|
||||
elif self.proj_type == "sniper":
|
||||
pygame.draw.circle(surface, (150, 180, 255), (ix, iy), 4)
|
||||
pygame.draw.circle(surface, COLOR_WHITE, (ix, iy), 2)
|
||||
elif self.proj_type == "poison":
|
||||
pygame.draw.circle(surface, COLOR_DARK_GREEN, (ix, iy), 5)
|
||||
pygame.draw.circle(surface, (100, 255, 100), (ix, iy), 3)
|
||||
elif self.proj_type == "lightning":
|
||||
pygame.draw.circle(surface, COLOR_BRIGHT_PURPLE, (ix, iy), 5)
|
||||
pygame.draw.circle(surface, (255, 255, 255), (ix, iy), 2)
|
||||
|
||||
@@ -22,6 +22,11 @@ class Tower:
|
||||
self.splash = data.get("splash", 0)
|
||||
self.slow_factor = data.get("slow_factor", 0)
|
||||
self.slow_duration = data.get("slow_duration", 0)
|
||||
self.poison_dps = data.get("poison_dps", 0)
|
||||
self.poison_duration = data.get("poison_duration", 0)
|
||||
self.chain_count = data.get("chain_count", 0)
|
||||
self.chain_range = data.get("chain_range", 0)
|
||||
self.chain_decay = data.get("chain_decay", 0)
|
||||
self.cooldown = 0
|
||||
self.target = None
|
||||
|
||||
@@ -54,11 +59,16 @@ class Tower:
|
||||
|
||||
if self.target and self.cooldown <= 0:
|
||||
self.cooldown = self.fire_rate
|
||||
proj_type = {"arrow": "arrow", "cannon": "cannon", "slow": "slow"}[self.type]
|
||||
proj_type = {
|
||||
"arrow": "arrow", "cannon": "cannon", "slow": "slow",
|
||||
"sniper": "sniper", "poison": "poison", "lightning": "lightning",
|
||||
}[self.type]
|
||||
projectiles.append(Projectile(
|
||||
self.x, self.y, self.target, self.damage,
|
||||
proj_type=proj_type, splash=self.splash,
|
||||
slow_factor=self.slow_factor, slow_duration=self.slow_duration,
|
||||
poison_dps=self.poison_dps, poison_duration=self.poison_duration,
|
||||
chain_count=self.chain_count, chain_range=self.chain_range, chain_decay=self.chain_decay,
|
||||
))
|
||||
|
||||
def draw(self, surface):
|
||||
@@ -74,6 +84,25 @@ class Tower:
|
||||
points = [(ix, iy - 14), (ix + 14, iy), (ix, iy + 14), (ix - 14, iy)]
|
||||
pygame.draw.polygon(surface, self.color, points)
|
||||
pygame.draw.polygon(surface, COLOR_BLACK, points, 2)
|
||||
elif self.type == "sniper":
|
||||
pts = [(ix, iy - 16), (ix + 14, iy + 12), (ix - 14, iy + 12)]
|
||||
pygame.draw.polygon(surface, self.color, pts)
|
||||
pygame.draw.polygon(surface, COLOR_BLACK, pts, 2)
|
||||
pygame.draw.line(surface, (200, 200, 255), (ix, iy - 10), (ix, iy + 6), 2)
|
||||
elif self.type == "poison":
|
||||
pts = []
|
||||
for i in range(6):
|
||||
angle = math.pi / 3 * i - math.pi / 6
|
||||
pts.append((ix + int(14 * math.cos(angle)), iy + int(14 * math.sin(angle))))
|
||||
pygame.draw.polygon(surface, self.color, pts)
|
||||
pygame.draw.polygon(surface, COLOR_BLACK, pts, 2)
|
||||
elif self.type == "lightning":
|
||||
pts = [
|
||||
(ix - 2, iy - 14), (ix + 6, iy - 4), (ix, iy - 4),
|
||||
(ix + 4, iy + 14), (ix - 4, iy + 2), (ix + 1, iy + 2),
|
||||
]
|
||||
pygame.draw.polygon(surface, self.color, pts)
|
||||
pygame.draw.polygon(surface, COLOR_BLACK, pts, 2)
|
||||
|
||||
if self.target and self.target.alive:
|
||||
pygame.draw.line(surface, (*self.color, ), (ix, iy), (int(self.target.x), int(self.target.y)), 1)
|
||||
|
||||
55
game/ui.py
55
game/ui.py
@@ -1,9 +1,10 @@
|
||||
import math
|
||||
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,
|
||||
TOWER_DATA, INITIAL_LIVES, TOTAL_WAVES, COLOR_LIGHT_BLUE,
|
||||
)
|
||||
|
||||
|
||||
@@ -11,13 +12,17 @@ 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.wave_button = pygame.Rect(WINDOW_WIDTH - 120, WINDOW_HEIGHT - UI_BOTTOM_HEIGHT + 10, 110, 40)
|
||||
self._init_tower_buttons()
|
||||
|
||||
def _init_tower_buttons(self):
|
||||
types = ["arrow", "cannon", "slow"]
|
||||
types = ["arrow", "cannon", "slow", "sniper", "poison", "lightning"]
|
||||
btn_w = 120
|
||||
gap = 5
|
||||
total_w = len(types) * btn_w + (len(types) - 1) * gap
|
||||
start_x = (WINDOW_WIDTH - 120 - 20 - total_w) // 2 + 10
|
||||
for i, t in enumerate(types):
|
||||
rect = pygame.Rect(10 + i * 160, WINDOW_HEIGHT - UI_BOTTOM_HEIGHT + 10, 150, 40)
|
||||
rect = pygame.Rect(start_x + i * (btn_w + gap), WINDOW_HEIGHT - UI_BOTTOM_HEIGHT + 10, btn_w, 40)
|
||||
self.tower_buttons.append((rect, t))
|
||||
|
||||
def handle_click(self, pos, gold):
|
||||
@@ -45,11 +50,16 @@ class UI:
|
||||
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))
|
||||
lives_text = font.render(f"生命: {lives}", True, COLOR_RED if lives <= 3 else COLOR_GREEN)
|
||||
surface.blit(lives_text, (160, 10))
|
||||
|
||||
wave_text = font.render(f"波次: {wave_num}/{TOTAL_WAVES}", True, COLOR_WHITE)
|
||||
surface.blit(wave_text, (380, 10))
|
||||
surface.blit(wave_text, (310, 10))
|
||||
|
||||
# Slow-time indicator
|
||||
if self.selected_tower:
|
||||
slow_text = small_font.render("[ 子弹时间 ]", True, (100, 180, 255))
|
||||
surface.blit(slow_text, (500, 12))
|
||||
|
||||
# Bottom bar
|
||||
pygame.draw.rect(surface, COLOR_DARK_GRAY, (0, WINDOW_HEIGHT - UI_BOTTOM_HEIGHT, WINDOW_WIDTH, UI_BOTTOM_HEIGHT))
|
||||
@@ -61,7 +71,7 @@ class UI:
|
||||
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_x = rect.x + 18
|
||||
icon_y = rect.y + rect.height // 2
|
||||
if t == "arrow":
|
||||
pygame.draw.rect(surface, data["color"], (icon_x - 5, icon_y - 5, 10, 10))
|
||||
@@ -70,9 +80,24 @@ class UI:
|
||||
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)
|
||||
elif t == "sniper":
|
||||
pts = [(icon_x, icon_y-8), (icon_x+7, icon_y+6), (icon_x-7, icon_y+6)]
|
||||
pygame.draw.polygon(surface, data["color"], pts)
|
||||
elif t == "poison":
|
||||
pts = []
|
||||
for i in range(6):
|
||||
angle = math.pi / 3 * i - math.pi / 6
|
||||
pts.append((icon_x + int(7 * math.cos(angle)), icon_y + int(7 * math.sin(angle))))
|
||||
pygame.draw.polygon(surface, data["color"], pts)
|
||||
elif t == "lightning":
|
||||
pts = [
|
||||
(icon_x-1, icon_y-7), (icon_x+4, icon_y-2), (icon_x, icon_y-2),
|
||||
(icon_x+2, icon_y+7), (icon_x-3, icon_y+1), (icon_x+1, icon_y+1),
|
||||
]
|
||||
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))
|
||||
surface.blit(name_text, (icon_x + 12, icon_y - 7))
|
||||
|
||||
# Wave button
|
||||
if has_more:
|
||||
@@ -115,3 +140,15 @@ class UI:
|
||||
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)
|
||||
|
||||
def draw_slow_overlay(self, surface):
|
||||
if self.selected_tower is None:
|
||||
return
|
||||
border = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.SRCALPHA)
|
||||
pygame.draw.rect(border, (100, 150, 255, 25), (0, 0, WINDOW_WIDTH, WINDOW_HEIGHT))
|
||||
for side_w in [4]:
|
||||
pygame.draw.rect(border, (100, 150, 255, 60), (0, 0, side_w, WINDOW_HEIGHT))
|
||||
pygame.draw.rect(border, (100, 150, 255, 60), (WINDOW_WIDTH - side_w, 0, side_w, WINDOW_HEIGHT))
|
||||
pygame.draw.rect(border, (100, 150, 255, 60), (0, 0, WINDOW_WIDTH, side_w))
|
||||
pygame.draw.rect(border, (100, 150, 255, 60), (0, WINDOW_HEIGHT - side_w, WINDOW_WIDTH, side_w))
|
||||
surface.blit(border, (0, 0))
|
||||
|
||||
14
game/wave.py
14
game/wave.py
@@ -3,15 +3,15 @@ from game.enemy import Enemy
|
||||
|
||||
WAVE_DATA = [
|
||||
[{"type": "normal", "count": 5, "interval": 1.0}],
|
||||
[{"type": "normal", "count": 8, "interval": 0.8}],
|
||||
[{"type": "normal", "count": 6, "interval": 0.8}, {"type": "swarm", "count": 4, "interval": 0.3}],
|
||||
[{"type": "normal", "count": 5, "interval": 0.8}, {"type": "fast", "count": 3, "interval": 0.6}],
|
||||
[{"type": "fast", "count": 8, "interval": 0.5}],
|
||||
[{"type": "swarm", "count": 10, "interval": 0.25}, {"type": "normal", "count": 5, "interval": 0.7}],
|
||||
[{"type": "normal", "count": 5, "interval": 0.6}, {"type": "heavy", "count": 2, "interval": 1.5}, {"type": "boss", "count": 1, "interval": 2.0}],
|
||||
[{"type": "normal", "count": 10, "interval": 0.5}, {"type": "fast", "count": 5, "interval": 0.4}],
|
||||
[{"type": "heavy", "count": 5, "interval": 1.0}, {"type": "fast", "count": 5, "interval": 0.5}],
|
||||
[{"type": "normal", "count": 8, "interval": 0.4}, {"type": "heavy", "count": 3, "interval": 0.8}, {"type": "fast", "count": 6, "interval": 0.4}],
|
||||
[{"type": "heavy", "count": 8, "interval": 0.7}, {"type": "fast", "count": 8, "interval": 0.3}],
|
||||
[{"type": "normal", "count": 10, "interval": 0.3}, {"type": "heavy", "count": 5, "interval": 0.5}, {"type": "fast", "count": 10, "interval": 0.3}, {"type": "boss", "count": 2, "interval": 2.0}],
|
||||
[{"type": "normal", "count": 8, "interval": 0.5}, {"type": "fast", "count": 5, "interval": 0.4}, {"type": "swarm", "count": 8, "interval": 0.2}],
|
||||
[{"type": "shield", "count": 3, "interval": 1.2}, {"type": "healer", "count": 2, "interval": 1.5}, {"type": "normal", "count": 6, "interval": 0.6}],
|
||||
[{"type": "heavy", "count": 4, "interval": 0.8}, {"type": "fast", "count": 5, "interval": 0.5}, {"type": "shield", "count": 3, "interval": 1.0}],
|
||||
[{"type": "swarm", "count": 15, "interval": 0.15}, {"type": "healer", "count": 3, "interval": 1.0}, {"type": "heavy", "count": 4, "interval": 0.7}],
|
||||
[{"type": "normal", "count": 10, "interval": 0.3}, {"type": "heavy", "count": 5, "interval": 0.5}, {"type": "fast", "count": 8, "interval": 0.3}, {"type": "shield", "count": 4, "interval": 0.8}, {"type": "healer", "count": 2, "interval": 1.0}, {"type": "boss", "count": 2, "interval": 2.0}],
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user