Enable pausing, fix sticky move bug and clean up
This commit is contained in:
parent
c5a67b0e59
commit
aafa943a53
|
@ -4,7 +4,7 @@ Brutal Maze
|
|||
Brutal Maze is a research hash and slash game with fast-paced action and a
|
||||
minimalist art style.
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/McSinyx/brutalmaze/master/brutalmaze/icon.png
|
||||
.. image:: https://raw.githubusercontent.com/McSinyx/brutalmaze/master/screenshot.png
|
||||
|
||||
The game features a trigon trapped in an infinite maze. As our hero tries to
|
||||
escape, the maze's border turn into aggressive squares trying to stop him. Your
|
||||
|
@ -26,8 +26,8 @@ Installation
|
|||
Brutal Maze is written in Python and is compatible with both version 2 and 3.
|
||||
The installation procedure should be as simply as follow:
|
||||
|
||||
* Make sure you have Python and `pip <https://pip.pypa.io/en/latest/>`_
|
||||
installed on your system.
|
||||
* Install Python and `pip <https://pip.pypa.io/en/latest/>`_. Make sure the
|
||||
directory for Python executables is your ``PATH``.
|
||||
* Clone the Github repository or download the Zip achieve and unpack.
|
||||
* Open Terminal in the directory containing the repo's folder and run
|
||||
``pip install --user brutalmaze``.
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
#
|
||||
# Copyright (C) 2017 Nguyễn Gia Phong
|
||||
|
||||
__doc__ = 'brutalmaze module for hero and enemy classes'
|
||||
|
||||
from collections import deque
|
||||
from math import atan2, sin, pi
|
||||
from random import shuffle
|
||||
from random import choice, shuffle
|
||||
|
||||
import pygame
|
||||
|
||||
from .constants import *
|
||||
from .utils import randsign, regpoly, fill_aapolygon, pos, sign
|
||||
|
||||
__doc__ = 'brutalmaze module for hero and enemy classes'
|
||||
|
||||
|
||||
class Hero:
|
||||
"""Object representing the hero."""
|
||||
|
@ -40,15 +40,15 @@ class Hero:
|
|||
|
||||
self.next_strike = 0
|
||||
self.slashing = self.firing = False
|
||||
self.spin_speed = fps / len(self.color)
|
||||
self.spin_speed = fps / HERO_HP
|
||||
self.spin_queue = self.wound = 0.0
|
||||
|
||||
def update(self, fps):
|
||||
"""Update the hero."""
|
||||
old_speed, time = self.spin_speed, pygame.time.get_ticks()
|
||||
self.spin_speed = fps / (len(self.color)-self.wound**0.5)
|
||||
self.spin_speed = fps / (HERO_HP-self.wound**0.5)
|
||||
self.spin_queue *= self.spin_speed / old_speed
|
||||
self.wound -= HEAL_SPEED / len(self.color) / self.spin_speed
|
||||
self.wound -= HEAL_SPEED / self.spin_speed / HERO_HP
|
||||
if self.wound < 0: self.wound = 0.0
|
||||
|
||||
if self.slashing and time >= self.next_strike:
|
||||
|
@ -74,9 +74,9 @@ class Hero:
|
|||
|
||||
class Enemy:
|
||||
"""Object representing an enemy."""
|
||||
def __init__(self, surface, fps, maze, kind, x, y):
|
||||
def __init__(self, surface, fps, maze, x, y):
|
||||
self.surface, self.maze = surface, maze
|
||||
self.angle, self.color = pi / 4, TANGO[kind]
|
||||
self.angle, self.color = pi / 4, TANGO[choice(ENEMIES)]
|
||||
self.x, self.y = x, y
|
||||
self.maze[x][y] = ENEMY
|
||||
|
||||
|
@ -84,7 +84,7 @@ class Enemy:
|
|||
self.next_move = 0
|
||||
self.move_speed = fps / MOVE_SPEED
|
||||
self.offsetx = self.offsety = 0
|
||||
self.spin_speed = fps / len(self.color)
|
||||
self.spin_speed = fps / ENEMY_HP
|
||||
self.spin_queue = self.wound = 0.0
|
||||
|
||||
def firable(self):
|
||||
|
@ -137,7 +137,7 @@ class Enemy:
|
|||
def update(self, fps, distance, middlex, middley):
|
||||
"""Update the enemy."""
|
||||
if self.awake:
|
||||
self.spin_speed, old_speed = fps / len(self.color), self.spin_speed
|
||||
self.spin_speed, old_speed = fps / ENEMY_HP, self.spin_speed
|
||||
self.spin_queue *= self.spin_speed / old_speed
|
||||
if not self.spin_queue and not self.move(fps):
|
||||
self.spin_queue = randsign() * self.spin_speed
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# Copyright (C) 2017 Nguyễn Gia Phong
|
||||
|
||||
from pygame import image
|
||||
from pygame.locals import *
|
||||
from pkg_resources import resource_filename
|
||||
|
||||
__doc__ = 'brutalmaze module for shared constants'
|
||||
|
@ -29,6 +28,7 @@ SQRT2 = 2 ** 0.5
|
|||
GOLDEN_MEAN = 5**0.5/2 + 0.5
|
||||
|
||||
INIT_FPS = 30.0
|
||||
MAX_FPS = 144.0
|
||||
SIZE = 640, 480
|
||||
MAZE_SIZE = 10
|
||||
ROAD_WIDTH = 5 # grids
|
||||
|
@ -38,7 +38,7 @@ LAST_ROW = (MAZE_SIZE-1) * ROAD_WIDTH * 2
|
|||
INIT_SCORE = 208.2016
|
||||
MOVE_SPEED = 5 # grid/s
|
||||
BULLET_SPEED = 10 # grid/s
|
||||
HEAL_SPEED = 1.0 # HP/s
|
||||
HEAL_SPEED = 1 # HP/s
|
||||
ATTACK_SPEED = 333 # ms/strike
|
||||
BULLET_LIFETIME = 1000 # ms
|
||||
|
||||
|
@ -56,5 +56,7 @@ TANGO = {'Butter': ((252, 233, 79), (237, 212, 0), (196, 160, 0)),
|
|||
(136, 138, 133), (85, 87, 83), (46, 52, 54))}
|
||||
ENEMIES = ('Butter', 'Orange', 'Chocolate', 'Chameleon',
|
||||
'Sky Blue', 'Plum', 'Scarlet Red')
|
||||
ENEMY_HP = 3
|
||||
HERO_HP = 6
|
||||
BG_COLOR = TANGO['Aluminium'][-1]
|
||||
FG_COLOR = TANGO['Aluminium'][0]
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
from collections import deque
|
||||
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
|
||||
from .constants import *
|
||||
from .constants import ICON, SIZE, INIT_FPS, MAX_FPS
|
||||
from .maze import Maze
|
||||
|
||||
|
||||
|
@ -38,25 +39,27 @@ def main():
|
|||
if event.type == QUIT:
|
||||
going = False
|
||||
elif event.type == KEYDOWN:
|
||||
if event.key in (K_UP, K_w):
|
||||
maze.move(0, 1)
|
||||
if event.key in (K_ESCAPE, K_p):
|
||||
maze.paused ^= True
|
||||
elif event.key in (K_UP, K_w):
|
||||
maze.move(up=-1)
|
||||
elif event.key in (K_LEFT, K_a):
|
||||
maze.move(1, 0)
|
||||
maze.move(left=-1)
|
||||
elif event.key in (K_DOWN, K_s):
|
||||
maze.move(0, -1)
|
||||
maze.move(down=-1)
|
||||
elif event.key in (K_RIGHT, K_d):
|
||||
maze.move(-1, 0)
|
||||
maze.move(right=-1)
|
||||
elif event.key == K_RETURN:
|
||||
maze.hero.slashing = True
|
||||
elif event.type == KEYUP:
|
||||
if event.key in (K_UP, K_w):
|
||||
maze.move(0, -1)
|
||||
maze.move(up=1)
|
||||
elif event.key in (K_LEFT, K_a):
|
||||
maze.move(-1, 0)
|
||||
maze.move(left=1)
|
||||
elif event.key in (K_DOWN, K_s):
|
||||
maze.move(0, 1)
|
||||
maze.move(down=1)
|
||||
elif event.key in (K_RIGHT, K_d):
|
||||
maze.move(1, 0)
|
||||
maze.move(right=1)
|
||||
elif event.key == K_RETURN:
|
||||
maze.hero.slashing = False
|
||||
elif event.type == MOUSEBUTTONDOWN:
|
||||
|
@ -73,8 +76,11 @@ def main():
|
|||
maze.resize(event.w, event.h)
|
||||
if len(flash_time) > 5:
|
||||
new_fps = 5000.0 / (flash_time[-1] - flash_time[0])
|
||||
fps += -1 if new_fps < fps else 5
|
||||
flash_time.popleft()
|
||||
if new_fps < fps:
|
||||
fps -= 1
|
||||
elif fps < MAX_FPS and not maze.paused:
|
||||
fps += 5
|
||||
maze.update(fps)
|
||||
flash_time.append(pygame.time.get_ticks())
|
||||
clock.tick(fps)
|
||||
|
|
|
@ -22,6 +22,7 @@ from math import pi, atan, atan2, log
|
|||
from random import choice, getrandbits, uniform
|
||||
|
||||
import pygame
|
||||
from pygame import RESIZABLE
|
||||
|
||||
from .characters import Hero, Enemy
|
||||
from .constants import *
|
||||
|
@ -64,11 +65,12 @@ class Maze:
|
|||
self.rangex = range(MIDDLE - w, MIDDLE + w + 1)
|
||||
self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
|
||||
self.offsetx = self.offsety = 0.0
|
||||
self.score = INIT_SCORE
|
||||
self.paused, self.score = False, INIT_SCORE
|
||||
|
||||
self.map = deque()
|
||||
for _ in range(MAZE_SIZE): self.map.extend(new_column())
|
||||
self.right = self.down = self.rotatex = self.rotatey = 0
|
||||
self.up = self.left = self.down = self.right = 0
|
||||
self.rotatex = self.rotatey = 0
|
||||
self.bullets, self.enemies = [], []
|
||||
self.add_enemy()
|
||||
self.hero = Hero(self.surface, fps)
|
||||
|
@ -85,8 +87,7 @@ class Maze:
|
|||
x, y = choice(walls)
|
||||
if all(self.map[x + a][y + b] == WALL for a, b in ADJACENT_GRIDS):
|
||||
continue
|
||||
self.enemies.append(
|
||||
Enemy(self.surface, self.fps, self.map, choice(ENEMIES), x, y))
|
||||
self.enemies.append(Enemy(self.surface, self.fps, self.map, x, y))
|
||||
walls.remove((x, y))
|
||||
|
||||
def draw(self):
|
||||
|
@ -135,6 +136,7 @@ class Maze:
|
|||
for i, enemy in enumerate(self.enemies):
|
||||
enemy.place(x, y)
|
||||
if enemy.x not in self.rangex or enemy.y not in self.rangey:
|
||||
self.score += enemy.wound
|
||||
enemy.die()
|
||||
killist.append(i)
|
||||
for i in reversed(killist): self.enemies.pop(i)
|
||||
|
@ -175,7 +177,7 @@ class Maze:
|
|||
d = length(x, y, self.x, self.y)
|
||||
if d <= self.slashd:
|
||||
enemy.wound += (self.slashd-d) / unit
|
||||
if enemy.wound >= len(enemy.color):
|
||||
if enemy.wound >= ENEMY_HP:
|
||||
self.score += enemy.wound
|
||||
enemy.die()
|
||||
killist.append(i)
|
||||
|
@ -186,11 +188,11 @@ class Maze:
|
|||
"""Handle the bullets."""
|
||||
fallen, time = [], pygame.time.get_ticks()
|
||||
for enemy in self.enemies:
|
||||
# Chance that an enemy fire increase from 25% to 50%
|
||||
if uniform(-2, 2) > (INIT_SCORE/self.score)**2 and enemy.firable():
|
||||
x, y = enemy.pos(self.distance, self.middlex, self.middley)
|
||||
self.bullets.append(
|
||||
Bullet(self.surface, x, y, atan2(self.y - y, self.x - x),
|
||||
enemy.color[0]))
|
||||
angle, color = atan2(self.y - y, self.x - x), enemy.color[0]
|
||||
self.bullets.append(Bullet(self.surface, x, y, angle, color))
|
||||
if (self.hero.firing and not self.hero.slashing
|
||||
and time >= self.hero.next_strike):
|
||||
self.hero.next_strike = time + ATTACK_SPEED
|
||||
|
@ -211,7 +213,7 @@ class Maze:
|
|||
x, y = enemy.pos(self.distance, self.middlex, self.middley)
|
||||
if length(bullet.x, bullet.y, x, y) < self.distance:
|
||||
enemy.wound += wound
|
||||
if enemy.wound >= len(enemy.color):
|
||||
if enemy.wound >= ENEMY_HP:
|
||||
self.score += enemy.wound
|
||||
enemy.die()
|
||||
self.enemies.pop(j)
|
||||
|
@ -224,32 +226,29 @@ class Maze:
|
|||
|
||||
def update(self, fps):
|
||||
"""Update the maze."""
|
||||
if self.paused: return
|
||||
self.offsetx *= fps / self.fps
|
||||
self.offsety *= fps / self.fps
|
||||
self.fps, self.speed = fps, fps / MOVE_SPEED
|
||||
self.step = self.distance / self.speed
|
||||
|
||||
dx, dy, d = 0, 0, self.distance*1.5 - self.hero.R
|
||||
if self.right:
|
||||
self.offsetx += self.right
|
||||
s = sign(self.offsetx) * 2
|
||||
if ((self.map[MIDDLE - s][MIDDLE - 1]
|
||||
or self.map[MIDDLE - s][MIDDLE]
|
||||
or self.map[MIDDLE - s][MIDDLE + 1])
|
||||
d = self.distance*1.5 - self.hero.R
|
||||
dx, dy = sign(self.right) - sign(self.left), sign(self.down) - sign(self.up)
|
||||
self.offsetx += dx
|
||||
self.offsety += dy
|
||||
x, y = MIDDLE - sign(self.offsetx)*2, MIDDLE - sign(self.offsety)*2
|
||||
if ((self.map[x][MIDDLE - 1] != EMPTY
|
||||
or self.map[x][MIDDLE] != EMPTY
|
||||
or self.map[x][MIDDLE + 1] != EMPTY)
|
||||
and abs(self.offsetx*self.step) > d):
|
||||
self.offsetx -= self.right
|
||||
else:
|
||||
dx = self.right
|
||||
if self.down:
|
||||
self.offsety += self.down
|
||||
s = sign(self.offsety) * 2
|
||||
if ((self.map[MIDDLE - 1][MIDDLE - s]
|
||||
or self.map[MIDDLE][MIDDLE - s]
|
||||
or self.map[MIDDLE + 1][MIDDLE - s])
|
||||
self.offsetx -= dx
|
||||
dx = 0
|
||||
if ((self.map[MIDDLE - 1][y] != EMPTY
|
||||
or self.map[MIDDLE][y] != EMPTY
|
||||
or self.map[MIDDLE + 1][y] != EMPTY)
|
||||
and abs(self.offsety*self.step) > d):
|
||||
self.offsety -= self.down
|
||||
else:
|
||||
dy = self.down
|
||||
self.offsety -= dy
|
||||
dy = 0
|
||||
|
||||
if dx or dy:
|
||||
self.map[MIDDLE][MIDDLE] = EMPTY
|
||||
|
@ -263,15 +262,15 @@ class Maze:
|
|||
for bullet in self.bullets: bullet.place(dx, dy, self.step)
|
||||
|
||||
self.draw()
|
||||
self.slash()
|
||||
self.track_bullets()
|
||||
for enemy in self.enemies:
|
||||
enemy.update(fps, self.distance, self.middlex, self.middley)
|
||||
self.hero.update(fps)
|
||||
self.slash()
|
||||
self.track_bullets()
|
||||
pygame.display.flip()
|
||||
pygame.display.set_caption('Brutal Maze - Score: {}'.format(
|
||||
int(self.score - INIT_SCORE)))
|
||||
if self.hero.wound + 1 > len(self.hero.color): self.lose()
|
||||
if self.hero.wound + 1 > HERO_HP: self.lose()
|
||||
|
||||
def resize(self, w, h):
|
||||
"""Resize the maze."""
|
||||
|
@ -289,14 +288,14 @@ class Maze:
|
|||
self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
|
||||
self.slashd = self.hero.R + self.distance/SQRT2
|
||||
|
||||
def move(self, x, y):
|
||||
"""Command the maze to move x step/frame faster to the left and
|
||||
y step/frame faster upward so the hero will move in the reverse
|
||||
direction.
|
||||
def move(self, up=0, left=0, down=0, right=0):
|
||||
"""Make the maze to move in the given directions by moving the
|
||||
maze in the reverse way.
|
||||
"""
|
||||
self.right += x
|
||||
self.down += y
|
||||
self.right, self.down = sign(self.right), sign(self.down)
|
||||
self.up += up
|
||||
self.left += left
|
||||
self.down += down
|
||||
self.right += right
|
||||
|
||||
def lose(self):
|
||||
"""Handle loses."""
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
#
|
||||
# Copyright (C) 2017 Nguyễn Gia Phong
|
||||
|
||||
__doc__ = 'brutalmaze module for hero and enemy classes'
|
||||
|
||||
from math import cos, sin, pi
|
||||
|
||||
import pygame
|
||||
from pygame.gfxdraw import filled_polygon, aapolygon
|
||||
|
||||
from .constants import *
|
||||
from .constants import MIDDLE
|
||||
|
||||
__doc__ = 'brutalmaze module for hero and enemy classes'
|
||||
|
||||
|
||||
def round2(number):
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
#
|
||||
# Copyright (C) 2017 Nguyễn Gia Phong
|
||||
|
||||
__doc__ = 'brutalmaze module for weapon classes'
|
||||
|
||||
from math import pi, cos, sin
|
||||
from math import cos, sin
|
||||
|
||||
from pygame.time import get_ticks
|
||||
|
||||
from .constants import *
|
||||
from .utils import randsign, regpoly, fill_aapolygon, pos, sign
|
||||
from .constants import BULLET_LIFETIME, BULLET_SPEED
|
||||
from .utils import regpoly, fill_aapolygon
|
||||
|
||||
__doc__ = 'brutalmaze module for weapon classes'
|
||||
|
||||
|
||||
class Bullet:
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 9.8 KiB |
4
setup.py
4
setup.py
|
@ -24,9 +24,9 @@ setup(
|
|||
'Natural Language :: English',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Games/Entertainment :: Role-Playing'],
|
||||
'Topic :: Games/Entertainment :: Arcade'],
|
||||
keywords='',
|
||||
packages=['brutalmaze'],
|
||||
install_requires=['pygame>=1.9'],
|
||||
package_data={'brutalmaze': ['*.xm']},
|
||||
package_data={'brutalmaze': ['icon.png']},
|
||||
entry_points={'gui_scripts': ['brutalmaze = brutalmaze:main']})
|
||||
|
|
Loading…
Reference in New Issue