Give enemies eyes

This commit is contained in:
Nguyễn Gia Phong 2017-10-13 15:10:16 +07:00
parent 613732b7c6
commit 05bfead6e9
4 changed files with 75 additions and 48 deletions

View File

@ -4,6 +4,7 @@ Brutal Maze
**Brutal Maze** is a research hash and slash game with *polyart* graphic and
Tango color palette. Its primary goals are:
* Highly portable.
* Auto-generated and infinite maze.
* No binary data.
* Enemies with randomized attributes: stun, poison, etc.

View File

@ -47,6 +47,11 @@ def fill_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
class Hero:
"""Object representing the hero."""
def __init__(self, surface):
@ -60,12 +65,6 @@ class Hero:
self.speed = FPS // len(self.color)
self.spin_queue, self.slashing = deque(), False
def resize(self):
"""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)
def slash(self, hold=False):
"""Spin the hero. If the button is hold, delay before continue
each spin.
@ -92,6 +91,12 @@ class Hero:
self.angle = atan2(y - self.y, x - self.x)
self.draw()
def resize(self):
"""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)
class Enemy:
"""Object representing an enemy."""
@ -100,25 +105,24 @@ class Enemy:
self.x, self.y = x, y
self.angle, self.color = pi / 4, TANGO[TANGO_KEYS[n]]
self.moving = False
self.awake, self.moving = False, False
self.wound = 0
self.speed = FPS // len(self.color)
self.spin_queue, self.slashing = deque(), False
def draw(self, distance, middlex, middley, color=None):
"""Draw the enemy, given distance between blocks and the middle
block.
"""Draw the enemy, given distance between grids and the middle
grid.
"""
x = middlex + (self.x - MIDDLE)*distance
y = middley + (self.y - MIDDLE)*distance
x, y = pos(self.x, self.y, distance, middlex, middley)
square = regpoly(4, int(distance / SQRT2), x, y, self.angle)
fill_aapolygon(self.surface, square, color or self.color[self.wound])
def update(self, distance, middlex, middley):
"""Update the enemy."""
if (self.angle - pi/4) < FLOATING_ZERO: self.angle = pi / 4
if (self.angle - pi/4) < EPSILON: self.angle = pi / 4
self.draw(distance, middlex, middley, color=BG_COLOR)
if not self.spin_queue:
if self.awake and not self.spin_queue:
self.spin_queue.extend([randsign()] * self.speed)
if self.spin_queue and not self.moving:
self.angle += self.spin_queue.popleft() * pi / 2 / self.speed

View File

@ -20,7 +20,7 @@
from pygame.locals import *
from pygame.math import Vector2
FLOATING_ZERO = 8 ** -8
EPSILON = 8 ** -8
SQRT2 = 2 ** 0.5
FPS = 30

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# maze.py - module containing the maze object
# This file is part of brutalmaze
@ -19,12 +18,12 @@
# Copyright (C) 2017 Nguyễn Gia Phong
from collections import deque
from math import pi
from math import atan, cos, sin, pi
from random import getrandbits
import pygame
from .characters import regpoly, fill_aapolygon, Hero, Enemy
from .characters import pos, regpoly, fill_aapolygon, Hero, Enemy
from .constants import *
@ -33,6 +32,11 @@ def sign(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)
class Maze:
"""Object representing the maze, including the characters."""
def __init__(self, size):
@ -40,13 +44,13 @@ class Maze:
self.surface = pygame.display.set_mode(size, RESIZABLE)
self.distance = int((self.w * self.h / 416) ** 0.5)
self.step = self.distance // 5
self.x, self.y = self.w >> 1, self.h >> 1
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
self.rangex = range(MIDDLE - w, MIDDLE + w + 1)
self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
self.hero = Hero(self.surface)
self.enemies = [Enemy(self.surface, 4, 35, 35)]
self.enemies = [Enemy(self.surface, 4, 34, 34)]
self.right = self.down = self.offsetx = self.offsety = 0
def wall(bit, upper=True):
@ -68,38 +72,29 @@ class Maze:
def draw(self):
"""Draw the maze."""
self.surface.fill(BG_COLOR)
middlex = self.x + self.offsetx*self.step
middley = self.y + self.offsety*self.step
for i in self.rangex:
for j in self.rangey:
if not self.map[i][j]: continue
x = middlex + (i - MIDDLE)*self.distance
y = middley + (j - MIDDLE)*self.distance
x, y = pos(i, j, self.distance, self.middlex, self.middley)
square = regpoly(4, int(self.distance / SQRT2), x, y, pi / 4)
fill_aapolygon(self.surface, square, FG_COLOR)
def resize(self, w, h):
"""Resize the maze."""
size = self.w, self.h = w, h
self.surface = pygame.display.set_mode(size, RESIZABLE)
self.hero.resize()
self.distance = int((w * h / 416) ** 0.5)
self.step = self.distance // 5
self.x, self.y = w >> 1, h >> 1
w, h = self.w//self.distance+2 >> 1, self.h//self.distance+2 >> 1
self.rangex = range(MIDDLE - w, MIDDLE + w + 1)
self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
self.draw()
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.
"""
self.right += x
self.down += y
self.right, self.down = sign(self.right), sign(self.down)
def wake(self, enemy):
"""Wake the enemy up if it can see the hero."""
dx = (enemy.x - MIDDLE)*self.distance + self.offsetx*self.step
dy = (enemy.y - MIDDLE)*self.distance + self.offsety*self.step
mind = cosin(abs(atan(dy / dx)) if dx else 0) * self.distance
startx = starty = MIDDLE
stopx, stopy = enemy.x, enemy.y
if startx > stopx : startx, stopx = stopx, startx
if starty > stopy : starty, stopy = stopy, starty
for i in range(startx, stopx + 1):
for j in range(starty, stopy + 1):
if not self.map[i][j] or (i, j) == (enemy.x, enemy.y): continue
x, y = pos(i, j, self.distance, self.middlex, self.middley)
d = abs(dy*(x-self.x) - dx*(y-self.y)) / (dy**2 + dx**2)**0.5
if d <= mind: return
enemy.awake = True
def update(self):
"""Update the maze."""
@ -136,11 +131,38 @@ class Maze:
for d in self.map: d.rotate(s)
for enemy in self.enemies: enemy.place(0, s)
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)
middlex = self.x + self.offsetx*self.step
middley = self.y + self.offsety*self.step
for enemy in self.enemies:
enemy.update(self.distance, middlex, middley)
enemy.update(self.distance, self.middlex, self.middley)
self.hero.update()
pygame.display.flip()
def resize(self, w, h):
"""Resize the maze."""
size = self.w, self.h = w, h
self.surface = pygame.display.set_mode(size, RESIZABLE)
self.hero.resize()
self.distance = int((w * h / 416) ** 0.5)
self.step = self.distance // 5
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
self.rangex = range(MIDDLE - w, MIDDLE + w + 1)
self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
self.draw()
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.
"""
self.right += x
self.down += y
self.right, self.down = sign(self.right), sign(self.down)