Improve drawing system

This commit is contained in:
Nguyễn Gia Phong 2017-10-19 20:28:56 +07:00
parent bc72fbf25f
commit 43c7c55a39
5 changed files with 102 additions and 72 deletions

View File

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

View File

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

View File

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

View File

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

70
brutalmaze/utils.py Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#
# 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