Skip to content

Commit

Permalink
added player's victory and death sound handling, fixed bug with enemy…
Browse files Browse the repository at this point in the history
… hit sound stacking
  • Loading branch information
pietrykovsky committed Jan 17, 2024
1 parent 888fd47 commit ea1149d
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 23 deletions.
7 changes: 7 additions & 0 deletions raycaster/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
DELTA_ANGLE = math.radians(Settings().FOV / Settings().RAY_COUNT)
PLAYER_INIT_HEALTH = 100


class PlayerState(Enum):
DEATH = "death"
HIT = "hit"
VICTORY = "victory"


# MAP RELATED
SCREEN_DISTANCE = (Settings().SCREEN_WIDTH // 2) / math.tan(
math.radians(Settings().FOV // 2)
Expand Down
19 changes: 14 additions & 5 deletions raycaster/game/asset_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
import pygame

from raycaster.core import Settings
from raycaster.const import EnemyState, WeaponRepresentation, EFFECTS_VOLUME
from raycaster.const import (
EnemyState,
WeaponRepresentation,
EFFECTS_VOLUME,
PlayerState,
)


class AssetLoader:
Expand Down Expand Up @@ -87,13 +92,17 @@ def load_doom_font(cls, size: int) -> pygame.font.Font:
return pygame.font.Font(font_path, size)

@classmethod
def load_player_hit_sound(cls) -> pygame.mixer.Sound:
def load_player_sounds(cls) -> dict[PlayerState, pygame.mixer.Sound]:
"""
Loads the player hit sound from the assets/player directory.
"""
hit_sound = pygame.mixer.Sound(os.path.join(cls.PLAYER_PATH, "hit.mp3"))
hit_sound.set_volume(EFFECTS_VOLUME)
return hit_sound
player_sounds = {}
for player_state in PlayerState:
sound_path = os.path.join(cls.PLAYER_PATH, f"{player_state.value}.mp3")
sound = pygame.mixer.Sound(sound_path)
sound.set_volume(EFFECTS_VOLUME)
player_sounds[player_state] = sound
return player_sounds

@classmethod
def _load_walls_textures(cls) -> dict[int, pygame.Surface]:
Expand Down
6 changes: 5 additions & 1 deletion raycaster/game/game_state_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import TYPE_CHECKING
import pygame
from raycaster.core import Updatable, Drawable, Settings
from raycaster.const import PlayerState


if TYPE_CHECKING:
Expand Down Expand Up @@ -78,7 +79,8 @@ def _handle_gameplay_events(cls, event: pygame.event.Event):
if event.type == pygame.KEYDOWN and event.key == pygame.K_F4:
cls.settings.MINIMAP_VISIBLE = not cls.settings.MINIMAP_VISIBLE
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
cls.player.shoot_handler.invoke()
if cls.player.weapon is not None and cls.player.weapon.can_shoot():
cls.player.shoot_handler.invoke()

@classmethod
def _handle_start_game_events(cls, event: pygame.event.Event):
Expand All @@ -96,5 +98,7 @@ def _update_gameplay(cls):
Updatable.update_all()
if cls.player.is_dead():
cls.current_state = GameState.GAME_OVER
cls.player.sounds.get(PlayerState.DEATH).play()
elif len(cls.object_manager.enemies) == 0:
cls.current_state = GameState.VICTORY
cls.player.sounds.get(PlayerState.VICTORY).play()
13 changes: 6 additions & 7 deletions raycaster/game/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pygame

from raycaster.core import Updatable, Settings, Event
from raycaster.const import PLAYER_INIT_HEALTH
from raycaster.const import PLAYER_INIT_HEALTH, PlayerState
from raycaster.game.asset_loader import AssetLoader

if TYPE_CHECKING:
Expand All @@ -22,7 +22,7 @@ def __init__(self, clock: pygame.time.Clock, map: "Map"):
self.angle = 45
self.delta_time = 1
self.hitbox_radius = self.settings.PLAYER_HITBOX_RADIUS
self.hit_sound = AssetLoader().load_player_hit_sound()
self.sounds = AssetLoader().load_player_sounds()

self.weapon = None
self.update_position_handler = Event()
Expand All @@ -34,7 +34,7 @@ def __init__(self, clock: pygame.time.Clock, map: "Map"):

def apply_damage(self, damage: float):
self._health -= damage
self.hit_sound.play()
self.sounds.get(PlayerState.HIT).play()

def add_score(self, score: int):
self._score += score
Expand Down Expand Up @@ -108,18 +108,17 @@ def handle_camera(self):
self.angle = self.angle % (2 * math.pi)

def _shoot(self):
if self.weapon is not None and self.weapon.can_shoot():
self.weapon.shoot()
self.weapon.shoot()

def is_dead(self):
return self.health <= 0

def reset(self):
self.angle = 0
self.angle = 45
self.x = 3.5 * self.settings.CELL_SIZE
self.y = 3.5 * self.settings.CELL_SIZE
self.weapon = None
self._health = 100
self._health = PLAYER_INIT_HEALTH
self._score = 0

def update(self):
Expand Down
18 changes: 8 additions & 10 deletions raycaster/objects/object_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from raycaster.objects.enemy import Enemy
from raycaster.game.map import Map
from raycaster.objects.weapons import Weapon
from raycaster.rendering.ray import Ray


class ObjectManager:
Expand Down Expand Up @@ -189,15 +188,14 @@ def _on_enemy_attack(cls, enemy: "Enemy"):
@classmethod
def _on_player_shot(cls):
ray = cls.raycaster.cast_ray(cls.player.angle)
if cls.player.weapon:
for enemy in sorted(cls._enemies, key=lambda e: e.distance):
if (
SpriteProjectionProcessor.intersects_screen_center(enemy)
and not (ray.hit_wall and ray.length < enemy.distance)
and cls.player.in_fov(enemy.angle)
):
enemy.apply_damage(cls.player.weapon.damage)
return
for enemy in sorted(cls._enemies, key=lambda e: e.distance):
if (
SpriteProjectionProcessor.intersects_screen_center(enemy)
and not (ray.hit_wall and ray.length < enemy.distance)
and cls.player.in_fov(enemy.angle)
):
enemy.apply_damage(cls.player.weapon.damage)
return

@classmethod
def reset(cls):
Expand Down

0 comments on commit ea1149d

Please sign in to comment.