From 22bb77f9184b813bf0841a0939546d5eeb0c58e3 Mon Sep 17 00:00:00 2001 From: Raphael McSinyx Date: Mon, 16 Oct 2017 22:12:32 +0700 Subject: Make maze truely infinite and polish up --- brutalmaze/__init__.py | 4 +++ brutalmaze/characters.py | 12 ++++--- brutalmaze/constants.py | 13 ++++++-- brutalmaze/icon.png | Bin 0 -> 12771 bytes brutalmaze/main.py | 3 ++ brutalmaze/maze.py | 79 ++++++++++++++++++++++++++++++++--------------- 6 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 brutalmaze/icon.png diff --git a/brutalmaze/__init__.py b/brutalmaze/__init__.py index c28a133..a2a2b70 100644 --- a/brutalmaze/__init__.py +++ b/brutalmaze/__init__.py @@ -1 +1,5 @@ +"""Brutal Maze is a research hash and slash game with polyart graphic +and Tango color palette. +""" + from .main import main diff --git a/brutalmaze/characters.py b/brutalmaze/characters.py index b2eb99e..0ef5d17 100644 --- a/brutalmaze/characters.py +++ b/brutalmaze/characters.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# characters.py - module containing objects representing heroes and enemies +# characters.py - module for hero and enemy classes # This file is part of brutalmaze # # brutalmaze is free software: you can redistribute it and/or modify @@ -17,6 +17,8 @@ # # Copyright (C) 2017 Nguyễn Gia Phong +__doc__ = 'brutalmaze module for hero and enemy classes' + from collections import deque from math import atan2, cos, sin, pi from random import shuffle @@ -44,7 +46,7 @@ def regpoly(n, R, r, x, y): def fill_aapolygon(surface, points, color): """Draw a filled polygon with anti aliased edges onto a surface.""" - aapolygon(surface, points, BG_COLOR) + aapolygon(surface, points, color) filled_polygon(surface, points, color) @@ -109,7 +111,7 @@ class Hero: """Resize the hero.""" w, h = self.surface.get_width(), self.surface.get_height() self.x, self.y = w >> 1, h >> 1 - self.R = int((w * h / sin(pi*2/3) / 624) ** 0.5) + self.R = (w * h / sin(pi*2/3) / 624) ** 0.5 class Enemy: @@ -129,12 +131,12 @@ class Enemy: def pos(self, distance, middlex, middley): """Return coordinate of the center of the enemy.""" x, y = pos(self.x, self.y, distance, middlex, middley) - step = distance // MOVE_SPEED + step = distance / MOVE_SPEED return x + self.offsetx*step, y + self.offsety*step def draw(self, distance, middlex, middley, color): """Draw the enemy, given distance between grids and the middle grid.""" - square = regpoly(4, int(distance / SQRT2), self.angle, + square = regpoly(4, distance / SQRT2, self.angle, *self.pos(distance, middlex, middley)) fill_aapolygon(self.surface, square, color) diff --git a/brutalmaze/constants.py b/brutalmaze/constants.py index 304f2d7..367bcb0 100644 --- a/brutalmaze/constants.py +++ b/brutalmaze/constants.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# constants.py - shared constants +# constants.py - module for shared constants # This file is part of brutalmaze # # brutalmaze is free software: you can redistribute it and/or modify @@ -17,17 +17,24 @@ # # 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' + +ICON = image.load(resource_filename('brutalmaze', 'icon.png')) SQRT2 = 2 ** 0.5 GOLDEN_MEAN = 5**0.5/2 + 0.5 FPS = 30 SIZE = 400, 400 -MAZE_SIZE = 8 +MAZE_SIZE = 10 ROAD_WIDTH = 5 MIDDLE = (MAZE_SIZE + (MAZE_SIZE&1) - 1)*ROAD_WIDTH + (ROAD_WIDTH >> 1) -INIT_SCORE = 208 +LAST_ROW = (MAZE_SIZE-1) * ROAD_WIDTH * 2 +INIT_SCORE = 208.2016 MOVE_SPEED = 5 # step/grid HEAL_SPEED = 1.0 # HP/s diff --git a/brutalmaze/icon.png b/brutalmaze/icon.png new file mode 100644 index 0000000..6e7d7dd Binary files /dev/null and b/brutalmaze/icon.png differ diff --git a/brutalmaze/main.py b/brutalmaze/main.py index ff614b1..c41d444 100644 --- a/brutalmaze/main.py +++ b/brutalmaze/main.py @@ -24,7 +24,10 @@ from .maze import Maze def main(): + """Start game and main loop.""" pygame.init() + pygame.display.set_caption('Brutal Maze') + pygame.display.set_icon(ICON) pygame.fastevent.init() maze, going, clock = Maze(SIZE), True, pygame.time.Clock() while going: diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py index 3b5e76b..1eb1784 100644 --- a/brutalmaze/maze.py +++ b/brutalmaze/maze.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# maze.py - module containing the maze object +# maze.py - module for the maze class # This file is part of brutalmaze # # brutalmaze is free software: you can redistribute it and/or modify @@ -26,6 +26,8 @@ import pygame from .characters import pos, sign, regpoly, fill_aapolygon, Hero, Enemy from .constants import * +__doc__ = 'brutalmaze module for the maze class' + def cosin(x): """Return the sum of cosine and sine of x (measured in radians).""" @@ -39,34 +41,43 @@ def length(x0, y0, 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) + if upper: return deque([WALL] * (ROAD_WIDTH<<1)) + return deque([EMPTY] * (ROAD_WIDTH<<1)) + + +def new_column(): + """Return a newly generated column of the maze.""" + column = deque() + upper, lower = deque(), deque() + for _ in range(MAZE_SIZE): + b = getrandbits(1) + upper.extend(cell(b)) + lower.extend(cell(b, False)) + for _ in range(ROAD_WIDTH): column.append(upper.__copy__()) + for _ in range(ROAD_WIDTH): column.append(lower.__copy__()) + return column + + class Maze: """Object representing the maze, including the characters.""" def __init__(self, size): self.w, self.h = size self.surface = pygame.display.set_mode(size, RESIZABLE) - self.distance = int((self.w * self.h / 416) ** 0.5) - self.step = self.distance // MOVE_SPEED + self.distance = (self.w * self.h / 416) ** 0.5 + self.step = self.distance / MOVE_SPEED self.middlex, self.middley = self.x, self.y = self.w >> 1, self.h >> 1 - w, h = self.w//self.distance+2 >> 1, self.h//self.distance+2 >> 1 + 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.right = self.down = self.offsetx = self.offsety = 0 self.score = INIT_SCORE - def wall(bit, upper=True): - if bit: return deque([WALL]*ROAD_WIDTH + [EMPTY]*ROAD_WIDTH) - if upper: return deque([WALL] * (ROAD_WIDTH<<1)) - return deque([EMPTY] * (ROAD_WIDTH<<1)) - self.map = deque() - for _ in range(MAZE_SIZE): - upper, lower = deque(), deque() - for _ in range(MAZE_SIZE): - b = getrandbits(1) - upper.extend(wall(b)) - lower.extend(wall(b, False)) - for _ in range(ROAD_WIDTH): self.map.append(upper.__copy__()) - for _ in range(ROAD_WIDTH): self.map.append(lower.__copy__()) + for _ in range(MAZE_SIZE): self.map.extend(new_column()) + self.rotatex = self.rotatey = 0 self.enemies = [] self.add_enemy() self.hero = Hero(self.surface) @@ -76,13 +87,17 @@ class Maze: def add_enemy(self): """Add enough enemies.""" - while len(self.enemies) < log(self.score, GOLDEN_MEAN): - x, y = choice(self.rangex), choice(self.rangey) - if self.map[x][y] != WALL: continue + walls, length = [], log(self.score, GOLDEN_MEAN) + for i in self.rangex: + for j in self.rangey: + if self.map[i][j] == WALL: walls.append((i, j)) + while walls and len(self.enemies) < length: + 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.map, choice(ENEMIES), x, y)) + walls.remove((x, y)) def draw(self): """Draw the maze.""" @@ -91,7 +106,7 @@ class Maze: for j in self.rangey: if self.map[i][j] != WALL: continue x, y = pos(i, j, self.distance, self.middlex, self.middley) - square = regpoly(4, int(self.distance / SQRT2), pi / 4, x, y) + square = regpoly(4, self.distance / SQRT2, pi / 4, x, y) fill_aapolygon(self.surface, square, FG_COLOR) def wake(self, enemy): @@ -117,9 +132,23 @@ class Maze: if x: self.offsetx = 0 self.map.rotate(x) + self.rotatex = (self.rotatex+x) % (ROAD_WIDTH*2) if y: self.offsety = 0 for d in self.map: d.rotate(y) + self.rotatey = (self.rotatey+y) % (ROAD_WIDTH*2) + if not self.rotatex and not self.rotatey: + for _ in range(ROAD_WIDTH * 2): self.map.pop() + self.map.extend(new_column()) + for i in range(MAZE_SIZE): + b = getrandbits(1) + for j, grid in enumerate(cell(b)): + for k in range(ROAD_WIDTH): + self.map[i*2*ROAD_WIDTH+k][LAST_ROW + j] = grid + for j, grid in enumerate(cell(b, False)): + for k in range(ROAD_WIDTH): + self.map[(i*2+1)*ROAD_WIDTH+k][LAST_ROW + j] = grid + killist = [] for i, enemy in enumerate(self.enemies): enemy.place(x, y) @@ -138,9 +167,9 @@ class Maze: if d <= self.slashd: enemy.wound += (self.slashd-d) / unit if enemy.wound >= len(enemy.color): + self.score += enemy.wound enemy.die() killist.append(i) - self.score += 1 for i in reversed(killist): self.enemies.pop(i) self.add_enemy() @@ -197,12 +226,12 @@ class Maze: self.surface = pygame.display.set_mode(size, RESIZABLE) self.hero.resize() - self.distance = int((w * h / 416) ** 0.5) - self.step = self.distance // MOVE_SPEED + self.distance = (w * h / 416) ** 0.5 + self.step = self.distance / MOVE_SPEED 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 = self.w//self.distance+2 >> 1, self.h//self.distance+2 >> 1 + 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.draw() -- cgit 1.4.1