Enable pausing, fix sticky move bug and clean up

This commit is contained in:
Nguyễn Gia Phong 2017-10-22 17:07:05 +07:00
parent c5a67b0e59
commit aafa943a53
9 changed files with 83 additions and 76 deletions

View File

@ -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``.

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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])
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])
and abs(self.offsety*self.step) > d):
self.offsety -= self.down
else:
dy = self.down
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 -= 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 -= 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."""

View File

@ -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):

View File

@ -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:

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -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']})