Make enemies chase the hero

This commit is contained in:
Nguyễn Gia Phong 2017-10-13 21:56:03 +07:00
parent 05bfead6e9
commit 62c8b2a81c
3 changed files with 60 additions and 39 deletions

View File

@ -19,6 +19,7 @@
from collections import deque
from math import atan2, cos, sin, pi
from random import shuffle
import pygame
from pygame.gfxdraw import filled_polygon, aapolygon
@ -31,7 +32,7 @@ def randsign():
return (pygame.time.get_ticks() & 1)*2 - 1
def regpoly(n, R, x, y, r):
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).
@ -52,6 +53,11 @@ def pos(x, y, distance, middlex, middley):
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
class Hero:
"""Object representing the hero."""
def __init__(self, surface):
@ -75,7 +81,7 @@ class Hero:
def draw(self, color=None):
"""Draw the hero."""
trigon = regpoly(3, self.R, self.x, self.y, self.angle)
trigon = regpoly(3, self.R, self.angle, self.x, self.y)
fill_aapolygon(self.surface, trigon, color or self.color[self.wound])
def update(self):
@ -100,38 +106,58 @@ class Hero:
class Enemy:
"""Object representing an enemy."""
def __init__(self, surface, n, x, y):
self.surface = surface
self.x, self.y = x, y
def __init__(self, surface, maze, n, x, y):
self.surface, self.maze = surface, maze
self.angle, self.color = pi / 4, TANGO[TANGO_KEYS[n]]
self.x, self.y = x, y
self.awake, self.moving = False, False
self.wound = 0
self.awake = False
self.offsetx = self.offsety = 0
self.spin_queue = []
self.speed = FPS // len(self.color)
self.spin_queue, self.slashing = deque(), False
self.wound = 0
def draw(self, distance, middlex, middley, color=None):
"""Draw the enemy, given distance between grids and the middle
grid.
"""
"""Draw the enemy, given distance between grids and the middle grid."""
x, y = pos(self.x, self.y, distance, middlex, middley)
square = regpoly(4, int(distance / SQRT2), x, y, self.angle)
step = distance // 5
square = regpoly(4, int(distance / SQRT2), self.angle,
x + self.offsetx*step, y + self.offsety*step)
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) < EPSILON: self.angle = pi / 4
self.draw(distance, middlex, middley, color=BG_COLOR)
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
self.draw(distance, middlex, middley)
def place(self, x, y):
def place(self, x=0, y=0):
"""Move the enemy by (x, y)."""
self.x += x
self.y += y
def move(self, x, y):
"""Command the enemy to move by (x, y)."""
def move(self):
"""Handle the movement of the enemy.
Return True if it moved, False otherwise.
"""
if self.offsetx:
self.offsetx -= sign(self.offsetx)
return True
if self.offsety:
self.offsety -= sign(self.offsety)
return True
directions = [(sign(MIDDLE - self.x), 0), (0, sign(MIDDLE - self.y))]
shuffle(directions)
for x, y in directions:
if (x or y) and self.maze[self.x + x][self.y + y] == False:
self.offsetx = x * -4
self.offsety = y * -4
self.place(x, y)
return True
return False
def update(self, distance, middlex, middley):
"""Update the enemy."""
if self.awake:
self.draw(distance, middlex, middley, color=BG_COLOR)
if not self.spin_queue and not self.move():
self.spin_queue.extend([randsign()] * self.speed)
if self.spin_queue:
self.angle += self.spin_queue.pop() * pi / 2 / self.speed
self.draw(distance, middlex, middley)

View File

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

View File

@ -23,15 +23,10 @@ from random import getrandbits
import pygame
from .characters import pos, regpoly, fill_aapolygon, Hero, Enemy
from .characters import pos, sign, regpoly, fill_aapolygon, Hero, Enemy
from .constants import *
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)
@ -49,10 +44,6 @@ class Maze:
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, 34, 34)]
self.right = self.down = self.offsetx = self.offsety = 0
def wall(bit, upper=True):
if bit: return deque([True]*ROAD_WIDTH + [False]*ROAD_WIDTH)
if upper: return deque([True] * (ROAD_WIDTH<<1))
@ -67,6 +58,9 @@ class Maze:
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__())
self.hero = Hero(self.surface)
self.enemies = [Enemy(self.surface, self.map, 4, 34, 34)]
self.right = self.down = self.offsetx = self.offsety = 0
self.draw()
def draw(self):
@ -76,7 +70,7 @@ class Maze:
for j in self.rangey:
if not self.map[i][j]: continue
x, y = pos(i, j, self.distance, self.middlex, self.middley)
square = regpoly(4, int(self.distance / SQRT2), x, y, pi / 4)
square = regpoly(4, int(self.distance / SQRT2), pi / 4, x, y)
fill_aapolygon(self.surface, square, FG_COLOR)
def wake(self, enemy):
@ -120,16 +114,18 @@ class Maze:
modified = True
if modified:
self.map[MIDDLE][MIDDLE] = False
if abs(self.offsetx) == 5:
s = sign(self.offsetx)
self.offsetx = 0
self.map.rotate(s)
for enemy in self.enemies: enemy.place(s, 0)
for enemy in self.enemies: enemy.place(x=s)
if abs(self.offsety) == 5:
s = sign(self.offsety)
self.offsety = 0
for d in self.map: d.rotate(s)
for enemy in self.enemies: enemy.place(0, s)
for enemy in self.enemies: enemy.place(y=s)
self.map[MIDDLE][MIDDLE] = None
self.middlex = self.x + self.offsetx*self.step
self.middley = self.y + self.offsety*self.step