Update enemy.py
parent
869d2ea540
commit
07f589639f
65
enemy.py
65
enemy.py
|
|
@ -1,29 +1,39 @@
|
||||||
import pygame
|
import pygame
|
||||||
from settings import *
|
from settings import *
|
||||||
|
|
||||||
|
|
||||||
class Enemy:
|
class Enemy:
|
||||||
def __init__(self, x, y):
|
def __init__(self, x, y):
|
||||||
|
# Position & physics
|
||||||
|
self.pos = pygame.Vector2(x, y)
|
||||||
self.rect = pygame.Rect(x, y, 28, 48)
|
self.rect = pygame.Rect(x, y, 28, 48)
|
||||||
self.velocity = pygame.Vector2(0, 0)
|
self.velocity = pygame.Vector2(0, 0)
|
||||||
self.pos = pygame.Vector2(x, y)
|
|
||||||
|
# Health
|
||||||
self.health = ENEMY_HEALTH
|
self.health = ENEMY_HEALTH
|
||||||
self.max_health = ENEMY_HEALTH
|
self.max_health = ENEMY_HEALTH
|
||||||
|
self.alive = True
|
||||||
|
|
||||||
|
# Combat
|
||||||
|
self.attack_rect = pygame.Rect(x, y, 60, 60)
|
||||||
|
self.attack_damage = ENEMY_ATTACK_DAMAGE
|
||||||
|
self.attack_range = ENEMY_ATTACK_RANGE
|
||||||
|
|
||||||
|
# Timers
|
||||||
self.knockback_timer = 0
|
self.knockback_timer = 0
|
||||||
self.invulnerable_timer = 0
|
self.invulnerable_timer = 0
|
||||||
|
|
||||||
# Attack hitbox
|
|
||||||
self.attack_rect = pygame.Rect(x, y, 60, 60)
|
|
||||||
|
|
||||||
def update(self, dt, world, player):
|
def update(self, dt, world, player):
|
||||||
|
if not self.alive:
|
||||||
|
return
|
||||||
|
|
||||||
dt = min(dt, 0.05)
|
dt = min(dt, 0.05)
|
||||||
|
|
||||||
# Apply gravity (FIX for flying)
|
# Gravity
|
||||||
self.velocity.y += ENEMY_GRAVITY * dt
|
self.velocity.y += ENEMY_GRAVITY * dt
|
||||||
if self.velocity.y > MAX_FALL_SPEED:
|
if self.velocity.y > MAX_FALL_SPEED:
|
||||||
self.velocity.y = MAX_FALL_SPEED
|
self.velocity.y = MAX_FALL_SPEED
|
||||||
|
|
||||||
# Basic AI: follow player
|
# Basic AI: move toward player
|
||||||
if self.knockback_timer <= 0:
|
if self.knockback_timer <= 0:
|
||||||
if player.rect.x < self.rect.x:
|
if player.rect.x < self.rect.x:
|
||||||
self.velocity.x = -ENEMY_SPEED
|
self.velocity.x = -ENEMY_SPEED
|
||||||
|
|
@ -32,83 +42,82 @@ class Enemy:
|
||||||
else:
|
else:
|
||||||
self.knockback_timer -= dt
|
self.knockback_timer -= dt
|
||||||
|
|
||||||
# Update position
|
# Update horizontal position
|
||||||
self.pos.x += self.velocity.x * dt
|
self.pos.x += self.velocity.x * dt
|
||||||
self.rect.x = round(self.pos.x)
|
self.rect.x = round(self.pos.x)
|
||||||
self.handle_horizontal_collisions(world)
|
self.handle_horizontal_collisions(world)
|
||||||
|
|
||||||
|
# Update vertical position
|
||||||
self.pos.y += self.velocity.y * dt
|
self.pos.y += self.velocity.y * dt
|
||||||
self.rect.y = round(self.pos.y)
|
self.rect.y = round(self.pos.y)
|
||||||
self.handle_vertical_collisions(world)
|
self.handle_vertical_collisions(world)
|
||||||
|
|
||||||
# Update attack rect position
|
# Update attack rectangle
|
||||||
self.attack_rect.centerx = self.rect.centerx
|
self.attack_rect.center = self.rect.center
|
||||||
self.attack_rect.centery = self.rect.centery
|
|
||||||
|
|
||||||
# Decay invulnerability
|
# Decay invulnerability
|
||||||
if self.invulnerable_timer > 0:
|
if self.invulnerable_timer > 0:
|
||||||
self.invulnerable_timer -= dt
|
self.invulnerable_timer -= dt
|
||||||
|
|
||||||
|
# Check death
|
||||||
|
if self.health <= 0:
|
||||||
|
self.alive = False
|
||||||
|
|
||||||
def handle_horizontal_collisions(self, world):
|
def handle_horizontal_collisions(self, world):
|
||||||
"""Handle horizontal collision"""
|
|
||||||
for tile in world.get_nearby_tiles(self.rect):
|
for tile in world.get_nearby_tiles(self.rect):
|
||||||
if tile["solid"] and self.rect.colliderect(tile["rect"]):
|
if tile["solid"] and self.rect.colliderect(tile["rect"]):
|
||||||
if self.velocity.x > 0:
|
if self.velocity.x > 0:
|
||||||
self.rect.right = tile["rect"].left
|
self.rect.right = tile["rect"].left
|
||||||
elif self.velocity.x < 0:
|
elif self.velocity.x < 0:
|
||||||
self.rect.left = tile["rect"].right
|
self.rect.left = tile["rect"].right
|
||||||
|
|
||||||
self.pos.x = self.rect.x
|
self.pos.x = self.rect.x
|
||||||
self.velocity.x = 0
|
self.velocity.x = 0
|
||||||
|
|
||||||
def handle_vertical_collisions(self, world):
|
def handle_vertical_collisions(self, world):
|
||||||
"""Handle vertical collision"""
|
|
||||||
for tile in world.get_nearby_tiles(self.rect):
|
for tile in world.get_nearby_tiles(self.rect):
|
||||||
if tile["solid"] and self.rect.colliderect(tile["rect"]):
|
if tile["solid"] and self.rect.colliderect(tile["rect"]):
|
||||||
if self.velocity.y > 0:
|
if self.velocity.y > 0:
|
||||||
self.rect.bottom = tile["rect"].top
|
self.rect.bottom = tile["rect"].top
|
||||||
elif self.velocity.y < 0:
|
elif self.velocity.y < 0:
|
||||||
self.rect.top = tile["rect"].bottom
|
self.rect.top = tile["rect"].bottom
|
||||||
|
|
||||||
self.pos.y = self.rect.y
|
self.pos.y = self.rect.y
|
||||||
self.velocity.y = 0
|
self.velocity.y = 0
|
||||||
|
|
||||||
def take_damage(self, damage, direction):
|
def take_damage(self, damage, direction):
|
||||||
"""Take damage and apply knockback"""
|
if self.invulnerable_timer > 0 or not self.alive:
|
||||||
if self.invulnerable_timer > 0:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.health -= damage
|
self.health -= damage
|
||||||
self.invulnerable_timer = 0.3
|
self.invulnerable_timer = 0.3
|
||||||
self.knockback_timer = 0.15
|
self.knockback_timer = 0.15
|
||||||
|
|
||||||
# Apply knockback (affected by resistance)
|
# Knockback
|
||||||
knockback_force = 400 * ENEMY_KNOCKBACK_RESISTANCE
|
knockback_force = 400 * ENEMY_KNOCKBACK_RESISTANCE
|
||||||
self.velocity.x = direction * knockback_force
|
self.velocity.x = direction * knockback_force
|
||||||
self.velocity.y = -300 # Slight upward knockback
|
self.velocity.y = -300
|
||||||
|
|
||||||
|
if self.health <= 0:
|
||||||
|
self.alive = False
|
||||||
|
|
||||||
def draw(self, screen, camera):
|
def draw(self, screen, camera):
|
||||||
|
if not self.alive:
|
||||||
|
return
|
||||||
|
|
||||||
draw_rect = camera.apply(self.rect)
|
draw_rect = camera.apply(self.rect)
|
||||||
|
|
||||||
# Flash when invulnerable
|
# Flash when invulnerable
|
||||||
if self.invulnerable_timer > 0:
|
color = (100, 100, 255) if self.invulnerable_timer > 0 else (0, 0, 255)
|
||||||
color = (100, 100, 255) # Light blue
|
|
||||||
else:
|
|
||||||
color = (0, 0, 255) # Blue
|
|
||||||
|
|
||||||
pygame.draw.rect(screen, color, draw_rect)
|
pygame.draw.rect(screen, color, draw_rect)
|
||||||
|
|
||||||
if SHOW_COLLIDERS:
|
if SHOW_COLLIDERS:
|
||||||
pygame.draw.rect(screen, (0, 255, 0), draw_rect, 2)
|
pygame.draw.rect(screen, (0, 255, 0), draw_rect, 2)
|
||||||
# Draw attack hitbox
|
|
||||||
attack_draw_rect = camera.apply(self.attack_rect)
|
attack_draw_rect = camera.apply(self.attack_rect)
|
||||||
pygame.draw.rect(screen, (255, 0, 0), attack_draw_rect, 1)
|
pygame.draw.rect(screen, (255, 0, 0), attack_draw_rect, 1)
|
||||||
|
|
||||||
# Draw health bar
|
# Health bar
|
||||||
health_bar_width = 28
|
health_bar_width = 28
|
||||||
health_bar_height = 4
|
health_bar_height = 4
|
||||||
health_percent = self.health / self.max_health
|
health_percent = max(0, self.health / self.max_health)
|
||||||
|
|
||||||
health_bar_rect = pygame.Rect(
|
health_bar_rect = pygame.Rect(
|
||||||
draw_rect.x,
|
draw_rect.x,
|
||||||
draw_rect.y - 8,
|
draw_rect.y - 8,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue