Загрузка данных
import pygame, math, random
pygame.init()
W, H = 950, 700
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("CS-Lite")
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 28)
font_big = pygame.font.SysFont("arial", 60, bold=True)
font_small = pygame.font.SysFont("arial", 20)
FLOOR_COLOR = (55, 50, 45)
WALL_COLOR = (90, 80, 70)
WALL_TOP = (120, 108, 95)
# ---------- КАРТА (стены как прямоугольники) ----------
walls = [
pygame.Rect(0, 0, W, 20), pygame.Rect(0, H-20, W, 20),
pygame.Rect(0, 0, 20, H), pygame.Rect(W-20, 0, 20, H),
pygame.Rect(200, 100, 30, 250),
pygame.Rect(400, 300, 250, 30),
pygame.Rect(650, 80, 30, 300),
pygame.Rect(120, 450, 300, 30),
pygame.Rect(550, 500, 30, 180),
pygame.Rect(750, 400, 150, 30),
]
def wall_blocks(x, y):
for w in walls:
if w.collidepoint(x, y):
return True
return False
def line_hits_wall(x1, y1, x2, y2, steps=40):
for i in range(steps + 1):
t = i / steps
x = x1 + (x2 - x1) * t
y = y1 + (y2 - y1) * t
if wall_blocks(x, y):
return (x, y)
return None
class Particle:
def __init__(self, x, y, color, speed_range=(1, 5), life_range=(10, 25), size=3):
self.x, self.y = x, y
angle = random.uniform(0, math.pi * 2)
speed = random.uniform(*speed_range)
self.vx = math.cos(angle) * speed
self.vy = math.sin(angle) * speed
self.life = random.uniform(*life_range)
self.max_life = self.life
self.color = color
self.size = size
def update(self):
self.x += self.vx
self.y += self.vy
self.vx *= 0.9
self.vy *= 0.9
self.life -= 1
def draw(self, surf):
if self.life > 0:
a = int(255 * (self.life / self.max_life))
s = pygame.Surface((self.size*2, self.size*2), pygame.SRCALPHA)
pygame.draw.circle(s, (*self.color, a), (self.size, self.size), self.size)
surf.blit(s, (self.x - self.size, self.y - self.size))
class Bullet:
def __init__(self, x, y, angle, owner):
self.x, self.y = x, y
self.vx = math.cos(angle) * 16
self.vy = math.sin(angle) * 16
self.owner = owner
self.trail = [(x, y)]
self.dead = False
def update(self):
self.x += self.vx
self.y += self.vy
self.trail.append((self.x, self.y))
if len(self.trail) > 4:
self.trail.pop(0)
if wall_blocks(self.x, self.y) or self.x < 0 or self.x > W or self.y < 0 or self.y > H:
self.dead = True
def draw(self, surf):
if len(self.trail) >= 2:
pygame.draw.line(surf, (255, 240, 150), self.trail[0], self.trail[-1], 2)
class Entity:
def __init__(self, x, y, color, is_player=False):
self.x, self.y = x, y
self.radius = 13
self.color = color
self.angle = 0
self.hp = 100
self.is_player = is_player
self.alive = True
self.reload_timer = 0
self.shoot_cooldown = 0
self.ai_dir_timer = 0
self.ai_move_angle = random.uniform(0, math.pi*2)
self.ai_shoot_timer = random.uniform(30, 90)
def try_move(self, dx, dy):
new_x = self.x + dx
new_y = self.y + dy
if not wall_blocks(new_x, self.y):
self.x = new_x
if not wall_blocks(self.x, new_y):
self.y = new_y
def draw(self, surf, light_pos=None):
# тень
shadow = pygame.Surface((self.radius*3, self.radius*1.5), pygame.SRCALPHA)
pygame.draw.ellipse(shadow, (0, 0, 0, 90), shadow.get_rect())
surf.blit(shadow, (self.x - self.radius*1.5, self.y + self.radius*0.6))
# тело
pygame.draw.circle(surf, (20, 20, 20), (int(self.x), int(self.y)), self.radius + 2)
pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), self.radius)
# оружие (линия в направлении взгляда)
gx = self.x + math.cos(self.angle) * (self.radius + 16)
gy = self.y + math.sin(self.angle) * (self.radius + 16)
pygame.draw.line(surf, (30, 30, 30), (self.x, self.y), (gx, gy), 5)
# полоска HP
bar_w = 34
pygame.draw.rect(surf, (40, 0, 0), (self.x - bar_w/2, self.y - self.radius - 16, bar_w, 6))
pygame.draw.rect(surf, (60, 220, 90), (self.x - bar_w/2, self.y - self.radius - 16, bar_w * (self.hp/100), 6))
player = Entity(80, 80, (70, 150, 230), is_player=True)
bots = [
Entity(850, 620, (220, 70, 70)),
Entity(880, 150, (220, 70, 70)),
Entity(500, 630, (220, 70, 70)),
]
bullets = []
particles = []
kills = 0
game_over = False
win = False
ammo = 12
max_ammo = 12
RELOAD_TIME = 90
def shoot(entity, targets_particles=True):
global ammo
if entity.is_player:
if ammo <= 0 or entity.reload_timer > 0:
return
ammo -= 1
bullets.append(Bullet(
entity.x + math.cos(entity.angle) * (entity.radius + 10),
entity.y + math.sin(entity.angle) * (entity.radius + 10),
entity.angle + random.uniform(-0.03, 0.03),
entity
))
for _ in range(6):
particles.append(Particle(
entity.x + math.cos(entity.angle) * (entity.radius + 12),
entity.y + math.sin(entity.angle) * (entity.radius + 12),
(255, 200, 80), speed_range=(2, 5), life_range=(6, 12), size=3
))
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and not game_over:
shoot(player)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and not game_over:
if ammo < max_ammo and player.reload_timer <= 0:
player.reload_timer = RELOAD_TIME
if event.key == pygame.K_r and game_over:
player = Entity(80, 80, (70, 150, 230), is_player=True)
bots = [
Entity(850, 620, (220, 70, 70)),
Entity(880, 150, (220, 70, 70)),
Entity(500, 630, (220, 70, 70)),
]
bullets, particles = [], []
kills = 0
ammo = max_ammo
game_over = False
win = False
keys = pygame.key.get_pressed()
mx, my = pygame.mouse.get_pos()
if not game_over:
player.angle = math.atan2(my - player.y, mx - player.x)
speed = 4.2
dx = dy = 0
if keys[pygame.K_w]: dy -= speed
if keys[pygame.K_s]: dy += speed
if keys[pygame.K_a]: dx -= speed
if keys[pygame.K_d]: dx += speed
if dx and dy:
dx *= 0.7071
dy *= 0.7071
player.try_move(dx, dy)
if player.reload_timer > 0:
player.reload_timer -= 1
if player.reload_timer == 0:
ammo = max_ammo
# AI ботов
for bot in bots:
if not bot.alive:
continue
dist_to_player = math.hypot(player.x - bot.x, player.y - bot.y)
los_block = line_hits_wall(bot.x, bot.y, player.x, player.y)
if los_block is None and dist_to_player < 500:
bot.angle = math.atan2(player.y - bot.y, player.x - bot.x)
bot.ai_shoot_timer -= 1
if bot.ai_shoot_timer <= 0:
shoot(bot)
bot.ai_shoot_timer = random.uniform(35, 70)
if dist_to_player > 220:
bot.try_move(math.cos(bot.angle)*2.4, math.sin(bot.angle)*2.4)
else:
bot.ai_dir_timer -= 1
if bot.ai_dir_timer <= 0:
bot.ai_move_angle = random.uniform(0, math.pi*2)
bot.ai_dir_timer = random.uniform(40, 90)
bot.angle = bot.ai_move_angle
bot.try_move(math.cos(bot.ai_move_angle)*1.8, math.sin(bot.ai_move_angle)*1.8)
# пули
for b in bullets[:]:
b.update()
targets = ([player] if not b.owner.is_player else bots)
for t in targets:
if t.alive and math.hypot(b.x - t.x, b.y - t.y) < t.radius + 4:
t.hp -= random.randint(18, 30)
for _ in range(14):
particles.append(Particle(t.x, t.y, (200, 30, 30), speed_range=(1,4), life_range=(15,30), size=3))
b.dead = True
if t.hp <= 0 and t.alive:
t.alive = False
if t.is_player:
game_over = True
win = False
else:
kills += 1
break
if b.dead:
bullets.remove(b)
for p in particles[:]:
p.update()
if p.life <= 0:
particles.remove(p)
if all(not b.alive for b in bots):
game_over = True
win = True
# ---------- ОТРИСОВКА ----------
screen.fill(FLOOR_COLOR)
# лёгкая текстура пола (полосы)
for i in range(0, W, 40):
pygame.draw.line(screen, (50, 45, 40), (i, 0), (i, H), 1)
for i in range(0, H, 40):
pygame.draw.line(screen, (50, 45, 40), (0, i), (W, i), 1)
for w in walls:
shadow_rect = w.copy()
shadow_rect.x += 6
shadow_rect.y += 6
pygame.draw.rect(screen, (0, 0, 0, 60), shadow_rect)
pygame.draw.rect(screen, WALL_COLOR, w)
pygame.draw.rect(screen, WALL_TOP, w, 3)
for b in bullets:
b.draw(screen)
for p in particles:
p.draw(screen)
if player.alive:
player.draw(screen)
for bot in bots:
if bot.alive:
bot.draw(screen)
# ---------- ОСВЕЩЕНИЕ (затемнение + свет вокруг игрока) ----------
darkness = pygame.Surface((W, H), pygame.SRCALPHA)
darkness.fill((5, 5, 10, 235))
light_radius = 260
light = pygame.Surface((light_radius*2, light_radius*2), pygame.SRCALPHA)
for i in range(light_radius, 0, -4):
alpha = int(235 * (1 - i / light_radius) ** 2)
pygame.draw.circle(light, (5, 5, 10, alpha), (light_radius, light_radius), i)
darkness.blit(light, (player.x - light_radius, player.y - light_radius), special_flags=pygame.BLEND_RGBA_MIN)
screen.blit(darkness, (0, 0))
# HUD
hud_ammo = font.render(f"{ammo} / {max_ammo}" + (" ПЕРЕЗАРЯДКА..." if player.reload_timer > 0 else ""), True, (255, 255, 255))
hud_kills = font.render(f"Убийств: {kills}/{len(bots)}", True, (255, 220, 100))
hud_hp = font.render(f"HP: {max(0, player.hp)}", True, (100, 255, 130))
screen.blit(hud_ammo, (20, H - 45))
screen.blit(hud_kills, (20, 20))
screen.blit(hud_hp, (20, 55))
hint = font_small.render("WASD — движение, мышь — прицел, ЛКМ — стрелять, R — перезарядка", True, (200, 200, 200))
screen.blit(hint, (W//2 - hint.get_width()//2, H - 30))
if game_over:
overlay = pygame.Surface((W, H), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 170))
screen.blit(overlay, (0, 0))
msg = "ПОБЕДА" if win else "ТЫ УБИТ"
color = (100, 255, 130) if win else (255, 70, 70)
text = font_big.render(msg, True, color)
screen.blit(text, (W//2 - text.get_width()//2, H//2 - 60))
restart = font.render("Нажми R чтобы сыграть заново", True, (255, 255, 255))
screen.blit(restart, (W//2 - restart.get_width()//2, H//2 + 20))
pygame.display.flip()
pygame.quit()