From 43c7c55a396968d013e01648d77625ad6075f418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Gia=20Phong?= Date: Thu, 19 Oct 2017 20:28:56 +0700 Subject: [PATCH] Improve drawing system --- brutalmaze/characters.py | 66 +++++++++++-------------------------- brutalmaze/constants.py | 2 +- brutalmaze/main.py | 4 +-- brutalmaze/maze.py | 32 +++++++----------- brutalmaze/utils.py | 70 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 72 deletions(-) create mode 100644 brutalmaze/utils.py diff --git a/brutalmaze/characters.py b/brutalmaze/characters.py index 250d9be..198c8d8 100644 --- a/brutalmaze/characters.py +++ b/brutalmaze/characters.py @@ -20,44 +20,13 @@ __doc__ = 'brutalmaze module for hero and enemy classes' from collections import deque -from math import atan2, cos, sin, pi +from math import atan2, sin, pi from random import shuffle import pygame -from pygame.gfxdraw import filled_polygon, aapolygon from .constants import * - - -def randsign(): - """Return either -1 or 1 (kind of) randomly.""" - return (pygame.time.get_ticks() & 1)*2 - 1 - - -def regpoly(n, R, r, x, y): - """Return the pointlist of the regular polygon with n sides, - circumradius of R, the center point I(x, y) and one point A make the - vector IA with angle r (in radians). - """ - r %= pi * 2 - angles = [r + pi*2*side/n for side in range(n)] - return [(x + R*cos(angle), y + R*sin(angle)) for angle in angles] - - -def fill_aapolygon(surface, points, color): - """Draw a filled polygon with anti aliased edges onto a surface.""" - aapolygon(surface, points, color) - filled_polygon(surface, points, color) - - -def pos(x, y, distance, middlex, middley): - """Return coordinate of the center of the grid (x, y).""" - return middlex + (x - MIDDLE)*distance, middley + (y - MIDDLE)*distance - - -def sign(n): - """Return the sign of number n.""" - return -1 if n < 0 else 1 if n else 0 +from .utils import randsign, regpoly, fill_aapolygon, pos, sign class Hero: @@ -85,20 +54,19 @@ class Hero: if hold: self.spin_queue.extend([0] * (self.spin_speed >> 1)) self.spin_queue.extend([randsign()] * self.spin_speed) - def draw(self, color=None): + def draw(self): """Draw the hero.""" trigon = regpoly(3, self.R, self.angle, self.x, self.y) - fill_aapolygon(self.surface, trigon, color or self.get_color()) + fill_aapolygon(self.surface, trigon, self.get_color()) def update(self, fps): """Update the hero.""" self.spin_speed = int(round(fps / (len(self.color)-self.wound))) - self.wound -= HEAL_SPEED / len(self.color) / (self.spin_speed or 1) + self.wound -= HEAL_SPEED / len(self.color) / self.spin_speed if self.wound < 0: self.wound = 0.0 self.slash(hold=True) direction = self.spin_queue.popleft() if self.spin_queue else 0 - self.draw(color=BG_COLOR) if direction: self.angle += direction * pi * 2 / 3 / self.spin_speed else: @@ -125,9 +93,8 @@ class Enemy: self.awake = False self.move_speed = fps / MOVE_SPEED self.offsetx = self.offsety = 0 - self.spin_speed = int(round(fps / len(self.color))) - self.spin_queue = [] - self.wound = 0.0 + self.spin_speed = fps / len(self.color) + self.spin_queue = self.wound = 0.0 def pos(self, distance, middlex, middley): """Return coordinate of the center of the enemy.""" @@ -135,11 +102,12 @@ class Enemy: step = distance / self.move_speed return x + self.offsetx*step, y + self.offsety*step - def draw(self, distance, middlex, middley, color): + def draw(self, distance, middlex, middley): """Draw the enemy, given distance between grids and the middle grid.""" radious = distance/SQRT2 - self.awake*2 square = regpoly(4, radious, self.angle, *self.pos(distance, middlex, middley)) + color = self.color[int(self.wound)] if self.awake else FG_COLOR fill_aapolygon(self.surface, square, color) def place(self, x=0, y=0): @@ -177,14 +145,16 @@ class Enemy: def update(self, fps, distance, middlex, middley): """Update the enemy.""" if self.awake: - self.draw(distance, middlex, middley, BG_COLOR) + self.spin_speed, old_speed = fps / len(self.color), self.spin_speed + self.spin_queue *= self.spin_speed / old_speed if not self.spin_queue and not self.move(fps): - self.spin_speed = int(round(fps / len(self.color))) - self.spin_queue.extend([randsign()] * self.spin_speed) - if self.spin_queue: - self.angle += self.spin_queue.pop() * pi / 2 / self.spin_speed - self.draw(distance, middlex, middley, - self.color[int(self.wound)] if self.awake else FG_COLOR) + self.spin_queue = randsign() * self.spin_speed + 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) + else: + self.angle, self.spin_queue = pi / 4, 0 + self.draw(distance, middlex, middley) def die(self): """Kill the enemy.""" diff --git a/brutalmaze/constants.py b/brutalmaze/constants.py index e87a33b..fb10e28 100644 --- a/brutalmaze/constants.py +++ b/brutalmaze/constants.py @@ -30,7 +30,7 @@ GOLDEN_MEAN = 5**0.5/2 + 0.5 INIT_FPS = 30.0 SIZE = 640, 480 -MAZE_SIZE = 12 +MAZE_SIZE = 10 ROAD_WIDTH = 5 CELL_WIDTH = ROAD_WIDTH * 2 MIDDLE = (MAZE_SIZE + MAZE_SIZE%2 - 1)*ROAD_WIDTH + ROAD_WIDTH//2 diff --git a/brutalmaze/main.py b/brutalmaze/main.py index 73d4427..7a1dbf0 100644 --- a/brutalmaze/main.py +++ b/brutalmaze/main.py @@ -69,8 +69,8 @@ def main(): maze.hero.slashing = False elif event.type == VIDEORESIZE: maze.resize(event.w, event.h) - if len(flash_time) > 10: - new_fps = 10000.0 / (flash_time[-1] - flash_time[0]) + 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() maze.update(fps) diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py index 8e3a5ad..85187a7 100644 --- a/brutalmaze/maze.py +++ b/brutalmaze/maze.py @@ -18,29 +18,18 @@ # Copyright (C) 2017 Nguyễn Gia Phong from collections import deque -from math import pi, atan, cos, sin, log +from math import pi, atan, log from random import choice, getrandbits import pygame -from .characters import pos, sign, regpoly, fill_aapolygon, Hero, Enemy +from .characters import Hero, Enemy from .constants import * +from .utils import pos, sign, cosin, length, regpoly, fill_aapolygon __doc__ = 'brutalmaze module for the maze class' -def cosin(x): - """Return the sum of cosine and sine of x (measured in radians).""" - return cos(x) + sin(x) - - -def length(x0, y0, x1, y1): - """Return the length of the line segment joining the two points - (x0, y0) and (x1, y1). - """ - return ((x0-x1)**2 + (y0-y1)**2)**0.5 - - def cell(bit, upper=True): """Return a half of a cell of the maze based on the given bit.""" if bit: return deque([WALL]*ROAD_WIDTH + [EMPTY]*ROAD_WIDTH) @@ -70,7 +59,7 @@ class Maze: self.distance = (self.w * self.h / 416) ** 0.5 self.step = self.distance / self.speed self.middlex, self.middley = self.x, self.y = self.w >> 1, self.h >> 1 - w, h = (int((i/self.distance+2) / 2) for i in size) + w, h = (int(i/self.distance/2 + 2) for i in size) self.rangex = range(MIDDLE - w, MIDDLE + w + 1) self.rangey = range(MIDDLE - h, MIDDLE + h + 1) self.offsetx = self.offsety = 0.0 @@ -219,10 +208,10 @@ class Maze: self.map[MIDDLE][MIDDLE] = HERO self.middlex = self.x + self.offsetx*self.step self.middley = self.y + self.offsety*self.step - self.draw() for enemy in self.enemies: if not enemy.awake: self.wake(enemy) + self.draw() for enemy in self.enemies: enemy.update(fps, self.distance, self.middlex, self.middley) self.hero.update(fps) @@ -230,9 +219,9 @@ class Maze: for enemy in self.enemies: if not enemy.spin_queue: continue x, y = enemy.pos(self.distance, self.middlex, self.middley) - d = length(x, y, self.x, self.y) - if d <= self.slashd: - self.hero.wound += (self.slashd-d) / self.hero.R / enemy.spin_speed + d = self.slashd - length(x, y, self.x, self.y) + if d >= 0: + self.hero.wound += d / self.hero.R / enemy.spin_speed pygame.display.flip() pygame.display.set_caption('Brutal Maze - Score: {}'.format( int(self.score - INIT_SCORE))) @@ -249,9 +238,10 @@ class Maze: self.middlex = self.x + self.offsetx*self.step self.middley = self.y + self.offsety*self.step self.x, self.y = w >> 1, h >> 1 - w, h = int((w/self.distance+2) / 2), int((h/self.distance+2) / 2) + w, h = int(w/self.distance/2 + 2), int(h/self.distance/2 + 2) self.rangex = range(MIDDLE - w, MIDDLE + w + 1) self.rangey = range(MIDDLE - h, MIDDLE + h + 1) + self.slashd = self.hero.R + self.distance/SQRT2 self.draw() def move(self, x, y): @@ -265,4 +255,4 @@ class Maze: def lose(self): """Handle loses.""" - quit() + pygame.quit() diff --git a/brutalmaze/utils.py b/brutalmaze/utils.py new file mode 100644 index 0000000..d198ef5 --- /dev/null +++ b/brutalmaze/utils.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# characters.py - module for shared functions and macros +# This file is part of brutalmaze +# +# brutalmaze is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# brutalmaze is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with brutalmaze. If not, see . +# +# 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 * + + +def randsign(): + """Return either -1 or 1 (kind of) randomly.""" + return (pygame.time.get_ticks() & 1)*2 - 1 + + +def regpoly(n, R, r, x, y): + """Return the pointlist of the regular polygon with n sides, + circumradius of R, the center point I(x, y) and one point A make the + vector IA with angle r (in radians). + """ + r %= pi * 2 + angles = [r + pi*2*side/n for side in range(n)] + return [(x + R*cos(angle), y + R*sin(angle)) for angle in angles] + + +def fill_aapolygon(surface, points, color): + """Draw a filled polygon with anti aliased edges onto a surface.""" + aapolygon(surface, points, color) + filled_polygon(surface, points, color) + + +def pos(x, y, distance, middlex, middley): + """Return coordinate of the center of the grid (x, y).""" + return middlex + (x - MIDDLE)*distance, middley + (y - MIDDLE)*distance + + +def sign(n): + """Return the sign of number n.""" + return -1 if n < 0 else 1 if n else 0 + + +def cosin(x): + """Return the sum of cosine and sine of x (measured in radians).""" + return cos(x) + sin(x) + + +def length(x0, y0, x1, y1): + """Return the length of the line segment joining the two points + (x0, y0) and (x1, y1). + """ + return ((x0-x1)**2 + (y0-y1)**2)**0.5