diff --git a/brutalmaze/characters.py b/brutalmaze/characters.py index 8a7ff8d..395514a 100644 --- a/brutalmaze/characters.py +++ b/brutalmaze/characters.py @@ -27,7 +27,7 @@ from sys import modules import pygame from .constants import * -from .utils import sign, cosin, randsign, regpoly, fill_aapolygon, choices +from .misc import sign, cosin, randsign, regpoly, fill_aapolygon, choices, play from .weapons import Bullet @@ -61,12 +61,10 @@ class Hero: self.spin_speed = fps / HERO_HP self.spin_queue = self.wound = 0.0 - self.sfx_shot = pygame.mixer.Sound(SFX_SHOT_HERO) - def update(self, fps): """Update the hero.""" if self.dead: - self.spin_queue = 0 + self.spin_queue = 0.0 return old_speed, time = self.spin_speed, pygame.time.get_ticks() self.spin_speed = fps / (HERO_HP-self.wound**0.5) @@ -111,6 +109,7 @@ class Enemy: spin_speed (float): speed of spinning (in frames per slash) spin_queue (float): frames left to finish spinning wound (float): amount of wound + sfx_slash (Sound): sound effect indicating close-range attack damage """ def __init__(self, maze, x, y, color): self.maze = maze @@ -125,7 +124,7 @@ class Enemy: self.spin_speed = self.maze.fps / ENEMY_HP self.spin_queue = self.wound = 0.0 - self.sfx_shot = pygame.mixer.Sound(SFX_SHOT_ENEMY) + self.sfx_slash = pygame.mixer.Sound(SFX_SLASH_HERO) def get_pos(self): """Return coordinate of the center of the enemy.""" @@ -200,15 +199,17 @@ class Enemy: return True return False - def slash(self): + def get_slash(self): """Return the enemy's close-range damage.""" - if self.spin_queue: - d = self.maze.slashd - self.maze.get_distance(*self.get_pos()) - wound = d / self.maze.hero.R / self.spin_speed - if wound >= 0: - self.maze.hit(wound, self.color, per_frame=True) - return wound - return 0.0 + d = self.maze.slashd - self.maze.get_distance(*self.get_pos()) + wound = d / self.maze.hero.R + return wound if wound > 0 else 0.0 + + def slash(self): + """Return the enemy's close-range damage per frame.""" + wound = self.get_slash() / self.spin_speed + if self.spin_queue: self.maze.hit_hero(wound, self.color) + return wound def draw(self): """Draw the enemy.""" @@ -224,6 +225,7 @@ class Enemy: self.spin_queue *= self.spin_speed / tmp if not self.spin_queue and not self.fire() and not self.move(): self.spin_queue = randsign() * self.spin_speed + play(self.sfx_slash, self.get_slash()) if abs(self.spin_queue) > 0.5: self.angle += sign(self.spin_queue) * pi / 2 / self.spin_speed self.spin_queue -= sign(self.spin_queue) @@ -231,12 +233,9 @@ class Enemy: self.angle, self.spin_queue = pi / 4, 0.0 self.draw() - def hit(self, wound, per_frame=False): + def hit(self, wound): """Handle the enemy when it's attacked.""" self.wound += wound - if not per_frame: - self.sfx_shot.set_volume(wound) - self.sfx_shot.play() def die(self): """Handle the enemy's death.""" @@ -268,10 +267,10 @@ class Chameleon(Enemy): if not self.awake or pygame.time.get_ticks() <= self.visible: Enemy.draw(self) - def hit(self, wound, per_frame=False): + def hit(self, wound): """Handle the Chameleon when it's attacked.""" self.visible = pygame.time.get_ticks() + 1000//ENEMY_SPEED - Enemy.hit(self, wound, per_frame) + Enemy.hit(self, wound) class Plum(Enemy): diff --git a/brutalmaze/constants.py b/brutalmaze/constants.py index 6c896e1..2f756e6 100644 --- a/brutalmaze/constants.py +++ b/brutalmaze/constants.py @@ -25,8 +25,11 @@ from pkg_resources import resource_filename ICON = image.load(resource_filename('brutalmaze', 'icon.png')) MUSIC = resource_filename('brutalmaze', 'soundfx/music.ogg') +SFX_SLASH_ENEMY = resource_filename('brutalmaze', 'soundfx/slash-enemy.ogg') +SFX_SLASH_HERO = resource_filename('brutalmaze', 'soundfx/slash-hero.ogg') SFX_SHOT_ENEMY = resource_filename('brutalmaze', 'soundfx/shot-enemy.ogg') SFX_SHOT_HERO = resource_filename('brutalmaze', 'soundfx/shot-hero.ogg') +SFX_MISSED = resource_filename('brutalmaze', 'soundfx/missed.ogg') SFX_LOSE = resource_filename('brutalmaze', 'soundfx/lose.ogg') UP = (K_UP, K_w) diff --git a/brutalmaze/main.py b/brutalmaze/main.py index 291981a..c3db5e9 100644 --- a/brutalmaze/main.py +++ b/brutalmaze/main.py @@ -24,7 +24,7 @@ from pygame.locals import * from .constants import * from .maze import Maze -from .utils import some +from .misc import some def main(): diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py index 8597055..0ca75ae 100644 --- a/brutalmaze/maze.py +++ b/brutalmaze/maze.py @@ -25,10 +25,12 @@ from random import choice, getrandbits, uniform import pygame from pygame import RESIZABLE +from pygame.mixer import Sound, set_num_channels +from pygame.time import get_ticks from .characters import Hero, new_enemy from .constants import * -from .utils import round2, sign, regpoly, fill_aapolygon +from .misc import round2, sign, regpoly, fill_aapolygon, play from .weapons import Bullet @@ -73,7 +75,11 @@ class Maze: enemies (list of Enemy): alive enemies hero (Hero): the hero next_move (int): the tick that the hero gets mobilized + next_slashfx (int): the tick to play next slash effect of the hero slashd (float): minimum distance for slashes to be effective + sfx_slash (Sound): sound effect indicating an enemy get slashed + sfx_shot (Sound): sound effect indicating an enemy get shot + sfx_lose (Sound): sound effect to be played when you lose """ def __init__(self, size, fps): self.w, self.h = size @@ -96,7 +102,12 @@ class Maze: self.add_enemy() self.hero = Hero(self.surface, fps) self.map[MIDDLE][MIDDLE] = HERO - self.next_move, self.slashd = 0, self.hero.R + self.distance/SQRT2 + self.next_move = self.next_slashfx = 0 + self.slashd = self.hero.R + self.distance/SQRT2 + + self.sfx_slash = Sound(SFX_SLASH_ENEMY) + self.sfx_shot = Sound(SFX_SHOT_ENEMY) + self.sfx_lose = Sound(SFX_LOSE) def add_enemy(self): """Add enough enemies.""" @@ -104,7 +115,8 @@ class Maze: if self.map[i][j] == WALL] plums = [e for e in self.enemies if e.color == 'Plum' and e.awake] plum = choice(plums) if plums else None - while walls and len(self.enemies) < log(self.score, INIT_SCORE): + num = log(self.score, INIT_SCORE) + while walls and len(self.enemies) < num: x, y = choice(walls) if all(self.map[x + a][y + b] == WALL for a, b in ADJACENT_GRIDS): continue @@ -114,6 +126,7 @@ class Maze: walls.remove((x, y)) else: self.map[x][y] = WALL + set_num_channels(int(num * 3)) def get_pos(self, x, y): """Return coordinate of the center of the grid (x, y).""" @@ -183,14 +196,11 @@ class Maze: """ return ((self.x-x)**2 + (self.y-y)**2)**0.5 - def hit(self, wound, color, per_frame=False): + def hit_hero(self, wound, color): """Handle the hero when he loses HP.""" - if not per_frame: - self.hero.sfx_shot.set_volume(wound) - self.hero.sfx_shot.play() fx = (uniform(0, sum(self.enemy_weights.values())) < self.enemy_weights[color]) - time = pygame.time.get_ticks() + time = get_ticks() if (color == 'Butter' or color == 'ScarletRed') and fx: self.hero.wound += wound * 2.5 elif color == 'Orange' and fx: @@ -207,12 +217,15 @@ class Maze: """Handle close-range attacks.""" for enemy in self.enemies: enemy.slash() if not self.hero.spin_queue: return - unit, killist = self.distance/SQRT2 * self.hero.spin_speed, [] + killist = [] for i, enemy in enumerate(self.enemies): - x, y = enemy.get_pos() - d = self.get_distance(x, y) - if d <= self.slashd: - enemy.hit((self.slashd-d) / unit, per_frame=True) + d = self.slashd - self.get_distance(*enemy.get_pos()) + if d > 0: + wound, time = d * SQRT2 / self.distance, get_ticks() + if time >= self.next_slashfx: + play(self.sfx_slash, wound) + self.next_slashfx = time + ATTACK_SPEED + enemy.hit(wound / self.hero.spin_speed) if enemy.wound >= ENEMY_HP: self.score += enemy.wound enemy.die() @@ -222,7 +235,7 @@ class Maze: def track_bullets(self): """Handle the bullets.""" - fallen, time = [], pygame.time.get_ticks() + fallen, time = [], get_ticks() if (self.hero.firing and not self.hero.slashing and time >= self.hero.next_strike): self.hero.next_strike = time + ATTACK_SPEED @@ -240,6 +253,7 @@ class Maze: fallen.append(i) continue for j, enemy in enumerate(self.enemies): + if not enemy.awake: continue x, y = enemy.get_pos() if bullet.get_distance(x, y) < self.distance: enemy.hit(wound) @@ -247,10 +261,15 @@ class Maze: self.score += enemy.wound enemy.die() self.enemies.pop(j) + play(self.sfx_shot, wound) fallen.append(i) break elif bullet.get_distance(self.x, self.y) < self.distance: - if not self.hero.spin_queue: self.hit(wound, bullet.color) + if self.hero.spin_queue: + play(bullet.sfx_missed, wound) + else: + self.hit_hero(wound, bullet.color) + play(bullet.sfx_hit, wound) fallen.append(i) for i in reversed(fallen): self.bullets.pop(i) @@ -298,7 +317,7 @@ class Maze: def move(self, x, y, fps): """Command the hero to move faster in the given direction.""" - stunned = pygame.time.get_ticks() < self.next_move + stunned = get_ticks() < self.next_move velocity = self.distance * HERO_SPEED / fps accel = velocity * HERO_SPEED / fps if stunned or not x: @@ -344,4 +363,4 @@ class Maze: self.hero.dead = True self.hero.slashing = self.hero.firing = False self.vx = self.vy = 0.0 - pygame.mixer.Sound(SFX_LOSE).play() + self.sfx_lose.play() diff --git a/brutalmaze/utils.py b/brutalmaze/misc.py similarity index 95% rename from brutalmaze/utils.py rename to brutalmaze/misc.py index 387fea3..431b5e6 100644 --- a/brutalmaze/utils.py +++ b/brutalmaze/misc.py @@ -81,3 +81,9 @@ def choices(d): num = uniform(0, cum_weights[-1]) for i, w in enumerate(cum_weights): if num <= w: return population[i] + + +def play(sound, volume): + """Play a pygame.mixer.Sound at the given volume.""" + sound.set_volume(volume) + sound.play() diff --git a/brutalmaze/soundfx/lose.ogg b/brutalmaze/soundfx/lose.ogg index a71cc0f..4baa6e9 100644 Binary files a/brutalmaze/soundfx/lose.ogg and b/brutalmaze/soundfx/lose.ogg differ diff --git a/brutalmaze/soundfx/missed.ogg b/brutalmaze/soundfx/missed.ogg new file mode 100644 index 0000000..844abc0 Binary files /dev/null and b/brutalmaze/soundfx/missed.ogg differ diff --git a/brutalmaze/soundfx/music.ogg b/brutalmaze/soundfx/music.ogg index 9e764bf..73e2157 100644 Binary files a/brutalmaze/soundfx/music.ogg and b/brutalmaze/soundfx/music.ogg differ diff --git a/brutalmaze/soundfx/shot-enemy.ogg b/brutalmaze/soundfx/shot-enemy.ogg index adc80cf..3c5811a 100644 Binary files a/brutalmaze/soundfx/shot-enemy.ogg and b/brutalmaze/soundfx/shot-enemy.ogg differ diff --git a/brutalmaze/soundfx/shot-hero.ogg b/brutalmaze/soundfx/shot-hero.ogg index 94bf4a1..2c2256c 100644 Binary files a/brutalmaze/soundfx/shot-hero.ogg and b/brutalmaze/soundfx/shot-hero.ogg differ diff --git a/brutalmaze/soundfx/slash-enemy.ogg b/brutalmaze/soundfx/slash-enemy.ogg new file mode 100644 index 0000000..73848d9 Binary files /dev/null and b/brutalmaze/soundfx/slash-enemy.ogg differ diff --git a/brutalmaze/soundfx/slash-hero.ogg b/brutalmaze/soundfx/slash-hero.ogg new file mode 100644 index 0000000..aa3a3ce Binary files /dev/null and b/brutalmaze/soundfx/slash-hero.ogg differ diff --git a/brutalmaze/weapons.py b/brutalmaze/weapons.py index 8f1ee72..c0c860a 100644 --- a/brutalmaze/weapons.py +++ b/brutalmaze/weapons.py @@ -22,9 +22,10 @@ __doc__ = 'brutalmaze module for weapon classes' from math import cos, sin from pygame.time import get_ticks +from pygame.mixer import Sound -from .constants import BULLET_LIFETIME, BULLET_SPEED, ENEMY_HP, TANGO -from .utils import regpoly, fill_aapolygon +from .constants import * +from .misc import regpoly, fill_aapolygon class Bullet: @@ -36,11 +37,18 @@ class Bullet: angle (float): angle of the direction the bullet pointing (in radians) color (str): bullet's color name fall_time (int): the tick that the bullet will fall down + sfx_hit (Sound): sound effect indicating the bullet hits the target + sfx_missed (Sound): sound effect indicating the bullet hits the target """ def __init__(self, surface, x, y, angle, color): self.surface = surface self.x, self.y, self.angle, self.color = x, y, angle, color self.fall_time = get_ticks() + BULLET_LIFETIME + # Sound effects of bullets shot by hero are stored in Maze to avoid + # unnecessary duplication + if color != 'Aluminium': + self.sfx_hit = Sound(SFX_SHOT_HERO) + self.sfx_missed = Sound(SFX_MISSED) def update(self, fps, distance): """Update the bullet.""" diff --git a/setup.py b/setup.py index 364a7c0..f7a480a 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open('README.rst') as f: setup( name='brutalmaze', - version='0.2.2', + version='0.3.0', description='A hash and slash game with fast-paced action and a minimalist art style', long_description=long_description, url='https://github.com/McSinyx/brutalmaze',