More content added, weapons, coin collecting, basic combat.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
filestructure.txt
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*\.pyc
|
*\.pyc
|
||||||
sounds/rec.sh
|
sounds/rec.sh
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"level_id": 1,
|
"level_id": 1,
|
||||||
"name": "The Mausoleum",
|
"name": "The Mausoleum",
|
||||||
"description": "After years of existing as a pile of bones, someone was crazy enough to assemble your skeleton. Time to reak some havoc!",
|
"description": "After years of existing as a pile of bones, someone was crazy enough to assemble your skeleton. Time to wreak some havoc!",
|
||||||
"player_start": {
|
"player_start": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0
|
"y": 0
|
||||||
},
|
},
|
||||||
"objects": [
|
"objects": [
|
||||||
{
|
{
|
||||||
"x": 5,
|
"x_range": [5, 7],
|
||||||
"y": 3,
|
"y": 3,
|
||||||
"sound": "coin",
|
"sound": "coin",
|
||||||
"collectible": true,
|
"collectible": true,
|
||||||
@@ -17,9 +17,11 @@
|
|||||||
{
|
{
|
||||||
"x": 25,
|
"x": 25,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"sound": "goblin",
|
"enemy_type": "goblin",
|
||||||
"hazard": true,
|
"health": 5,
|
||||||
"static": false
|
"damage": 1,
|
||||||
|
"attack_range": 1,
|
||||||
|
"movement_range": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 50,
|
"x": 50,
|
||||||
|
BIN
sounds/player_shovel_attack.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/player_shovel_attack.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/player_shovel_hit.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/player_shovel_hit.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
105
src/enemy.py
Normal file
105
src/enemy.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
from libstormgames import *
|
||||||
|
from src.object import Object
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
|
||||||
|
class Enemy(Object):
|
||||||
|
def __init__(self, xRange, y, enemyType, sounds, **kwargs):
|
||||||
|
# Initialize base object properties
|
||||||
|
super().__init__(
|
||||||
|
xRange,
|
||||||
|
y,
|
||||||
|
f"{enemyType}", # Base sound for ambient noise
|
||||||
|
isStatic=False,
|
||||||
|
isHazard=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enemy specific properties
|
||||||
|
self.enemyType = enemyType
|
||||||
|
self.health = kwargs.get('health', 5) # Default 5 HP
|
||||||
|
self.damage = kwargs.get('damage', 1) # Default 1 damage
|
||||||
|
self.attackRange = kwargs.get('attack_range', 1) # Default 1 tile range
|
||||||
|
self.movementRange = kwargs.get('movement_range', 5) # Default 5 tile patrol
|
||||||
|
self.sounds = sounds # Store reference to game sounds
|
||||||
|
|
||||||
|
# Movement and behavior properties
|
||||||
|
self.movingRight = True # Initial direction
|
||||||
|
self.movementSpeed = 0.03 # Slightly slower than player
|
||||||
|
self.patrolStart = self.xRange[0]
|
||||||
|
self.patrolEnd = self.xRange[0] + self.movementRange
|
||||||
|
self.lastAttackTime = 0
|
||||||
|
self.attackCooldown = 1000 # 1 second between attacks
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xPos(self):
|
||||||
|
"""Current x position"""
|
||||||
|
return self._currentX if hasattr(self, '_currentX') else self.xRange[0]
|
||||||
|
|
||||||
|
@xPos.setter
|
||||||
|
def xPos(self, value):
|
||||||
|
"""Set current x position"""
|
||||||
|
self._currentX = value
|
||||||
|
|
||||||
|
def update(self, currentTime, player):
|
||||||
|
"""Update enemy position and handle attacks"""
|
||||||
|
if not self.isActive or self.health <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update position based on patrol behavior
|
||||||
|
if self.movingRight:
|
||||||
|
self.xPos += self.movementSpeed
|
||||||
|
if self.xPos >= self.patrolEnd:
|
||||||
|
self.movingRight = False
|
||||||
|
else:
|
||||||
|
self.xPos -= self.movementSpeed
|
||||||
|
if self.xPos <= self.patrolStart:
|
||||||
|
self.movingRight = True
|
||||||
|
|
||||||
|
# Check for attack opportunity
|
||||||
|
if self.can_attack(currentTime, player):
|
||||||
|
self.attack(currentTime, player)
|
||||||
|
|
||||||
|
def can_attack(self, currentTime, player):
|
||||||
|
"""Check if enemy can attack player"""
|
||||||
|
# Must have cooled down from last attack
|
||||||
|
if currentTime - self.lastAttackTime < self.attackCooldown:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Don't attack if player is jumping
|
||||||
|
if player.isJumping:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check if player is in range and on same side we're facing
|
||||||
|
distance = abs(player.xPos - self.xPos)
|
||||||
|
tolerance = 0.5 # Same tolerance as we used for the grave
|
||||||
|
|
||||||
|
if distance <= (self.attackRange + tolerance):
|
||||||
|
# Only attack if we're facing the right way
|
||||||
|
playerOnRight = player.xPos > self.xPos
|
||||||
|
return playerOnRight == self.movingRight
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def attack(self, currentTime, player):
|
||||||
|
"""Perform attack on player"""
|
||||||
|
self.lastAttackTime = currentTime
|
||||||
|
# Play attack sound
|
||||||
|
attackSound = f"{self.enemyType}_attack"
|
||||||
|
if attackSound in self.sounds:
|
||||||
|
self.sounds[attackSound].play()
|
||||||
|
# Deal damage to player
|
||||||
|
player.set_health(player.get_health() - self.damage)
|
||||||
|
speak(f"The {self.enemyType} hits you!")
|
||||||
|
|
||||||
|
def take_damage(self, amount):
|
||||||
|
"""Handle enemy taking damage"""
|
||||||
|
self.health -= amount
|
||||||
|
if self.health <= 0:
|
||||||
|
self.die()
|
||||||
|
|
||||||
|
def die(self):
|
||||||
|
"""Handle enemy death"""
|
||||||
|
self.isActive = False
|
||||||
|
if self.channel:
|
||||||
|
obj_stop(self.channel)
|
||||||
|
self.channel = None
|
91
src/level.py
91
src/level.py
@@ -1,17 +1,40 @@
|
|||||||
|
import pygame
|
||||||
from libstormgames import *
|
from libstormgames import *
|
||||||
from src.player import Player
|
from src.enemy import Enemy
|
||||||
from src.object import Object
|
from src.object import Object
|
||||||
|
from src.player import Player
|
||||||
|
|
||||||
class Level:
|
class Level:
|
||||||
def __init__(self, levelData, sounds):
|
def __init__(self, levelData, sounds):
|
||||||
self.sounds = sounds
|
self.sounds = sounds
|
||||||
self.objects = []
|
self.objects = []
|
||||||
|
self.enemies = []
|
||||||
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"])
|
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"])
|
||||||
|
|
||||||
# Load objects from level data
|
# Load objects and enemies from level data
|
||||||
for obj in levelData["objects"]:
|
for obj in levelData["objects"]:
|
||||||
|
# Handle x position or range
|
||||||
|
if "x_range" in obj:
|
||||||
|
xPos = obj["x_range"]
|
||||||
|
else:
|
||||||
|
xPos = [obj["x"], obj["x"]] # Single position as range
|
||||||
|
|
||||||
|
# Check if this is an enemy
|
||||||
|
if "enemy_type" in obj:
|
||||||
|
enemy = Enemy(
|
||||||
|
xPos,
|
||||||
|
obj["y"],
|
||||||
|
obj["enemy_type"],
|
||||||
|
self.sounds,
|
||||||
|
health=obj.get("health", 5),
|
||||||
|
damage=obj.get("damage", 1),
|
||||||
|
attack_range=obj.get("attack_range", 1),
|
||||||
|
movement_range=obj.get("movement_range", 5)
|
||||||
|
)
|
||||||
|
self.enemies.append(enemy)
|
||||||
|
else:
|
||||||
gameObject = Object(
|
gameObject = Object(
|
||||||
obj["x"],
|
xPos,
|
||||||
obj["y"],
|
obj["y"],
|
||||||
obj["sound"],
|
obj["sound"],
|
||||||
isStatic=obj.get("static", True),
|
isStatic=obj.get("static", True),
|
||||||
@@ -21,56 +44,58 @@ class Level:
|
|||||||
self.objects.append(gameObject)
|
self.objects.append(gameObject)
|
||||||
|
|
||||||
def update_audio(self):
|
def update_audio(self):
|
||||||
# Update all object sounds based on player position
|
currentTime = pygame.time.get_ticks()
|
||||||
|
|
||||||
|
# Update regular objects
|
||||||
for obj in self.objects:
|
for obj in self.objects:
|
||||||
if not obj.isActive:
|
if not obj.isActive:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# For non-static objects like goblins, ensure continuous sound
|
|
||||||
if not obj.isStatic:
|
if not obj.isStatic:
|
||||||
# If channel doesn't exist or sound stopped playing, restart it
|
|
||||||
if obj.channel is None or not obj.channel.get_busy():
|
if obj.channel is None or not obj.channel.get_busy():
|
||||||
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
|
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
|
||||||
else:
|
else:
|
||||||
# Original logic for static objects
|
|
||||||
if obj.channel is None:
|
if obj.channel is None:
|
||||||
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
|
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
|
||||||
|
|
||||||
# Update position-based audio for all objects
|
|
||||||
if obj.channel is not None:
|
if obj.channel is not None:
|
||||||
obj.channel = obj_update(obj.channel, self.player.xPos, obj.xPos)
|
obj.channel = obj_update(obj.channel, self.player.xPos, obj.xPos)
|
||||||
|
|
||||||
|
# Update enemies
|
||||||
|
for enemy in self.enemies:
|
||||||
|
if not enemy.isActive:
|
||||||
|
continue
|
||||||
|
|
||||||
|
enemy.update(currentTime, self.player)
|
||||||
|
|
||||||
|
if enemy.channel is None or not enemy.channel.get_busy():
|
||||||
|
enemy.channel = obj_play(self.sounds, enemy.enemyType, self.player.xPos, enemy.xPos)
|
||||||
|
if enemy.channel is not None:
|
||||||
|
enemy.channel = obj_update(enemy.channel, self.player.xPos, enemy.xPos)
|
||||||
|
|
||||||
|
def handle_combat(self, currentTime):
|
||||||
|
"""Handle combat interactions between player and enemies"""
|
||||||
|
attackRange = self.player.get_attack_range(currentTime)
|
||||||
|
if attackRange:
|
||||||
|
for enemy in self.enemies:
|
||||||
|
if enemy.isActive and enemy.xPos >= attackRange[0] and enemy.xPos <= attackRange[1]:
|
||||||
|
self.sounds[self.player.currentWeapon.hitSound].play()
|
||||||
|
enemy.take_damage(self.player.currentWeapon.damage)
|
||||||
|
|
||||||
def handle_collisions(self):
|
def handle_collisions(self):
|
||||||
for obj in self.objects:
|
for obj in self.objects:
|
||||||
if not obj.isActive:
|
if not obj.isActive:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Single-tile collision detection (more precise)
|
if obj.is_in_range(self.player.xPos):
|
||||||
collision_threshold = 0.5 # Half a tile width from center
|
if obj.isCollectible and self.player.isJumping:
|
||||||
distance = abs(self.player.xPos - obj.xPos)
|
currentPos = round(self.player.xPos)
|
||||||
|
if currentPos not in obj.collectedPositions:
|
||||||
if distance <= collision_threshold:
|
|
||||||
if obj.isCollectible:
|
|
||||||
# Coins must be collected while jumping
|
|
||||||
if self.player.isJumping:
|
|
||||||
self.sounds[f'get_{obj.soundName}'].play()
|
self.sounds[f'get_{obj.soundName}'].play()
|
||||||
speak(f"Collected {obj.soundName}")
|
speak(f"Collected {obj.soundName}")
|
||||||
obj.isActive = False
|
obj.collect_at_position(currentPos)
|
||||||
obj_stop(obj.channel)
|
|
||||||
self.player.collectedItems.append(obj.soundName)
|
self.player.collectedItems.append(obj.soundName)
|
||||||
elif obj.isHazard:
|
elif obj.isHazard and not self.player.isJumping:
|
||||||
# Only affect player if they're not jumping (for ground-based hazards)
|
|
||||||
if not self.player.isJumping:
|
|
||||||
if obj.soundName == "grave":
|
|
||||||
self.sounds['grave'].play()
|
|
||||||
speak("You fell into a pit!")
|
|
||||||
elif obj.soundName == "goblin":
|
|
||||||
self.sounds['goblin'].play()
|
|
||||||
speak("A goblin got you!")
|
|
||||||
else: # Other hazards
|
|
||||||
self.sounds[obj.soundName].play()
|
self.sounds[obj.soundName].play()
|
||||||
speak(f"A {obj.soundName} got you!")
|
speak("You fell in an open grave!")
|
||||||
|
self.player.set_health(0)
|
||||||
# Apply knockback for any hazard hit
|
|
||||||
knockback = 2
|
|
||||||
self.player.xPos = self.player.xPos - knockback if self.player.facingRight else self.player.xPos + knockback
|
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
|
from libstormgames import *
|
||||||
|
|
||||||
class Object:
|
class Object:
|
||||||
def __init__(self, xPos, yPos, soundName, isStatic=True, isCollectible=False, isHazard=False):
|
def __init__(self, x, yPos, soundName, isStatic=True, isCollectible=False, isHazard=False):
|
||||||
self.xPos = xPos
|
# x can be either a single position or a range [start, end]
|
||||||
|
self.xRange = [x, x] if isinstance(x, (int, float)) else x
|
||||||
self.yPos = yPos
|
self.yPos = yPos
|
||||||
self.soundName = soundName
|
self.soundName = soundName
|
||||||
self.isStatic = isStatic
|
self.isStatic = isStatic
|
||||||
@@ -8,3 +11,25 @@ class Object:
|
|||||||
self.isHazard = isHazard
|
self.isHazard = isHazard
|
||||||
self.channel = None # For tracking the sound channel
|
self.channel = None # For tracking the sound channel
|
||||||
self.isActive = True
|
self.isActive = True
|
||||||
|
# For collectibles in a range, track which positions have been collected
|
||||||
|
self.collectedPositions = set()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xPos(self):
|
||||||
|
"""Return center of range for audio positioning"""
|
||||||
|
return (self.xRange[0] + self.xRange[1]) / 2
|
||||||
|
|
||||||
|
def is_in_range(self, x):
|
||||||
|
"""Check if a given x position is within this object's range"""
|
||||||
|
tolerance = 0.5 # Half a unit tolerance
|
||||||
|
return (self.xRange[0] - tolerance) <= x <= (self.xRange[1] + tolerance)
|
||||||
|
|
||||||
|
def collect_at_position(self, x):
|
||||||
|
"""Mark a specific position in the range as collected"""
|
||||||
|
self.collectedPositions.add(x)
|
||||||
|
# If all positions in range are collected, deactivate the object and stop sound
|
||||||
|
if len(self.collectedPositions) == int(self.xRange[1] - self.xRange[0] + 1):
|
||||||
|
self.isActive = False
|
||||||
|
if self.channel:
|
||||||
|
obj_stop(self.channel)
|
||||||
|
self.channel = None
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
|
from src.weapon import Weapon
|
||||||
|
|
||||||
class Player:
|
class Player:
|
||||||
def __init__(self, xPos, yPos):
|
def __init__(self, xPos, yPos):
|
||||||
|
# Movement attributes
|
||||||
self.xPos = xPos
|
self.xPos = xPos
|
||||||
self.yPos = yPos
|
self.yPos = yPos
|
||||||
self.moveSpeed = 0.05
|
self.moveSpeed = 0.05
|
||||||
@@ -7,7 +10,76 @@ class Player:
|
|||||||
self.jumpStartTime = 0
|
self.jumpStartTime = 0
|
||||||
self.isJumping = False
|
self.isJumping = False
|
||||||
self.facingRight = True
|
self.facingRight = True
|
||||||
self.collectedItems = []
|
|
||||||
# Track distance for footsteps
|
# Stats and tracking
|
||||||
|
self._health = 10
|
||||||
|
self._lives = 1
|
||||||
self.distanceSinceLastStep = 0
|
self.distanceSinceLastStep = 0
|
||||||
self.stepDistance = 0.5 # Play a step sound every 0.5 units moved
|
self.stepDistance = 0.5
|
||||||
|
|
||||||
|
# Inventory system
|
||||||
|
self.inventory = []
|
||||||
|
self.collectedItems = []
|
||||||
|
self.coins = 0
|
||||||
|
|
||||||
|
# Combat related attributes
|
||||||
|
self.weapons = []
|
||||||
|
self.currentWeapon = None
|
||||||
|
self.isAttacking = False
|
||||||
|
self.lastAttackTime = 0
|
||||||
|
|
||||||
|
# Initialize starting weapon (rusty shovel)
|
||||||
|
self.add_weapon(Weapon(
|
||||||
|
name="rusty_shovel",
|
||||||
|
damage=2,
|
||||||
|
range=2,
|
||||||
|
attackSound="player_shovel_attack",
|
||||||
|
hitSound="player_shovel_hit",
|
||||||
|
attackDuration=200 # 200ms attack duration
|
||||||
|
))
|
||||||
|
|
||||||
|
def get_health(self):
|
||||||
|
"""Get current health"""
|
||||||
|
return self._health
|
||||||
|
|
||||||
|
def set_health(self, value):
|
||||||
|
"""Set health and handle death if needed"""
|
||||||
|
self._health = max(0, value) # Health can't go below 0
|
||||||
|
if self._health == 0:
|
||||||
|
self._lives -= 1
|
||||||
|
if self._lives > 0:
|
||||||
|
self._health = 10 # Reset health if we still have lives
|
||||||
|
|
||||||
|
def get_lives(self):
|
||||||
|
"""Get remaining lives"""
|
||||||
|
return self._lives
|
||||||
|
|
||||||
|
def add_weapon(self, weapon):
|
||||||
|
"""Add a new weapon to inventory and equip if first weapon"""
|
||||||
|
self.weapons.append(weapon)
|
||||||
|
if len(self.weapons) == 1: # If this is our first weapon, equip it
|
||||||
|
self.equip_weapon(weapon)
|
||||||
|
|
||||||
|
def equip_weapon(self, weapon):
|
||||||
|
"""Equip a specific weapon"""
|
||||||
|
if weapon in self.weapons:
|
||||||
|
self.currentWeapon = weapon
|
||||||
|
|
||||||
|
def add_item(self, item):
|
||||||
|
"""Add an item to inventory"""
|
||||||
|
self.inventory.append(item)
|
||||||
|
self.collectedItems.append(item)
|
||||||
|
|
||||||
|
def start_attack(self, currentTime):
|
||||||
|
"""Attempt to start an attack with the current weapon"""
|
||||||
|
if self.currentWeapon and self.currentWeapon.start_attack(currentTime):
|
||||||
|
self.isAttacking = True
|
||||||
|
self.lastAttackTime = currentTime
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_attack_range(self, currentTime):
|
||||||
|
"""Get the current attack's range based on position and facing direction"""
|
||||||
|
if not self.currentWeapon or not self.currentWeapon.is_attack_active(currentTime):
|
||||||
|
return None
|
||||||
|
return self.currentWeapon.get_attack_range(self.xPos, self.facingRight)
|
||||||
|
33
src/weapon.py
Normal file
33
src/weapon.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
class Weapon:
|
||||||
|
def __init__(self, name, damage, range, attackSound, hitSound, cooldown=500, attackDuration=200):
|
||||||
|
self.name = name
|
||||||
|
self.damage = damage
|
||||||
|
self.range = range # Range in tiles
|
||||||
|
self.attackSound = attackSound
|
||||||
|
self.hitSound = hitSound
|
||||||
|
self.cooldown = cooldown # Milliseconds between attacks
|
||||||
|
self.attackDuration = attackDuration # Milliseconds the attack is active
|
||||||
|
self.lastAttackTime = 0
|
||||||
|
|
||||||
|
def can_attack(self, currentTime):
|
||||||
|
"""Check if enough time has passed since last attack"""
|
||||||
|
return currentTime - self.lastAttackTime >= self.cooldown
|
||||||
|
|
||||||
|
def get_attack_range(self, playerPos, facingRight):
|
||||||
|
"""Calculate the area that this attack would hit"""
|
||||||
|
if facingRight:
|
||||||
|
return (playerPos, playerPos + self.range)
|
||||||
|
else:
|
||||||
|
return (playerPos - self.range, playerPos)
|
||||||
|
|
||||||
|
def start_attack(self, currentTime):
|
||||||
|
"""Begin an attack and return True if allowed"""
|
||||||
|
if self.can_attack(currentTime):
|
||||||
|
self.lastAttackTime = currentTime
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_attack_active(self, currentTime):
|
||||||
|
"""Check if the attack is still in its active frames"""
|
||||||
|
timeSinceAttack = currentTime - self.lastAttackTime
|
||||||
|
return 0 <= timeSinceAttack <= self.attackDuration
|
@@ -27,34 +27,36 @@ class WickedQuest:
|
|||||||
def handle_input(self):
|
def handle_input(self):
|
||||||
keys = pygame.key.get_pressed()
|
keys = pygame.key.get_pressed()
|
||||||
player = self.currentLevel.player
|
player = self.currentLevel.player
|
||||||
|
currentTime = pygame.time.get_ticks()
|
||||||
|
|
||||||
# Calculate current speed based on jumping state
|
# Calculate current speed based on jumping state
|
||||||
currentSpeed = player.moveSpeed * 1.5 if player.isJumping else player.moveSpeed
|
currentSpeed = player.moveSpeed * 1.5 if player.isJumping else player.moveSpeed
|
||||||
|
|
||||||
# Track movement distance for this frame
|
# Track movement distance for this frame
|
||||||
movement = 0
|
movementDistance = 0
|
||||||
|
|
||||||
# Horizontal movement
|
# Horizontal movement
|
||||||
if keys[pygame.K_a]: # Left
|
if keys[pygame.K_a]: # Left
|
||||||
movement = currentSpeed
|
movementDistance = currentSpeed
|
||||||
player.xPos -= currentSpeed
|
player.xPos -= currentSpeed
|
||||||
player.facingRight = False
|
player.facingRight = False
|
||||||
elif keys[pygame.K_d]: # Right
|
elif keys[pygame.K_d]: # Right
|
||||||
movement = currentSpeed
|
movementDistance = currentSpeed
|
||||||
player.xPos += currentSpeed
|
player.xPos += currentSpeed
|
||||||
player.facingRight = True
|
player.facingRight = True
|
||||||
|
|
||||||
|
# Handle attack with either CTRL key
|
||||||
|
if (keys[pygame.K_LCTRL] or keys[pygame.K_RCTRL]) and player.start_attack(currentTime):
|
||||||
|
self.sounds[player.currentWeapon.attackSound].play()
|
||||||
|
|
||||||
# Play footstep sounds if moving and not jumping
|
# Play footstep sounds if moving and not jumping
|
||||||
if movement > 0 and not player.isJumping:
|
if movementDistance > 0 and not player.isJumping:
|
||||||
player.distanceSinceLastStep += movement
|
player.distanceSinceLastStep += movementDistance
|
||||||
if player.distanceSinceLastStep >= player.stepDistance:
|
if player.distanceSinceLastStep >= player.stepDistance:
|
||||||
self.sounds['footstep'].play()
|
self.sounds['footstep'].play()
|
||||||
player.distanceSinceLastStep = 0
|
player.distanceSinceLastStep = 0
|
||||||
|
|
||||||
# Handle jumping
|
# Handle jumping
|
||||||
currentTime = pygame.time.get_ticks()
|
|
||||||
|
|
||||||
# Start jump
|
|
||||||
if keys[pygame.K_w] and not player.isJumping:
|
if keys[pygame.K_w] and not player.isJumping:
|
||||||
player.isJumping = True
|
player.isJumping = True
|
||||||
player.jumpStartTime = currentTime
|
player.jumpStartTime = currentTime
|
||||||
@@ -69,7 +71,9 @@ class WickedQuest:
|
|||||||
def game_loop(self):
|
def game_loop(self):
|
||||||
clock = pygame.time.Clock()
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
while True:
|
while self.currentLevel.player.get_health() > 0 and self.currentLevel.player.get_lives() > 0:
|
||||||
|
currentTime = pygame.time.get_ticks()
|
||||||
|
|
||||||
if check_for_exit():
|
if check_for_exit():
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -79,13 +83,21 @@ class WickedQuest:
|
|||||||
self.currentLevel.update_audio()
|
self.currentLevel.update_audio()
|
||||||
self.currentLevel.handle_collisions()
|
self.currentLevel.handle_collisions()
|
||||||
|
|
||||||
|
# Handle combat interactions
|
||||||
|
self.currentLevel.handle_combat(currentTime)
|
||||||
|
|
||||||
clock.tick(60) # 60 FPS
|
clock.tick(60) # 60 FPS
|
||||||
|
|
||||||
|
# Player died or ran out of lives
|
||||||
|
speak("Game Over")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while True:
|
while True:
|
||||||
choice = game_menu(self.sounds, "play", "instructions", "learn_sounds", "credits", "donate")
|
choice = game_menu(self.sounds, "play", "instructions", "learn_sounds", "credits", "donate", "exit")
|
||||||
|
|
||||||
if choice == "play":
|
if choice == "exit":
|
||||||
|
exit_game()
|
||||||
|
elif choice == "play":
|
||||||
if self.load_level(1):
|
if self.load_level(1):
|
||||||
self.game_loop()
|
self.game_loop()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user