import pygame import traceback import random import math class Player: def __init__(self, x, y): self.x = x self.y = y self.vx = 0 self.vy = 0 self.is_solid = False def tick(self, pressed, entities): if pressed[pygame.K_LEFT]: self.vx = -2 elif pressed[pygame.K_RIGHT]: self.vx = 2 else: self.vx = 0 if pressed[pygame.K_UP]: self.vy = -2 elif pressed[pygame.K_DOWN]: self.vy = 2 else: self.vy = 0 for ent in entities: if not ent.is_solid: continue if ent.overlaps_circle(self.x+self.vx, self.y+self.vy, 16): self.vx = 0 self.vy = 0 self.x += self.vx self.y += self.vy def draw(self, screen): pygame.draw.circle(screen, (0, 128, 255), # color (r,g,b) (self.x, self.y), # pos 8) # radius class Enemy: def __init__(self, x, y): self.x = x self.y = y self.vx = 0 self.vy = 0 self.is_solid = False def tick(self, _pressed, entities): player = entities[0] prediction = 120 # "Steering behaviors" tx = player.x + player.vx * prediction ty = player.y + player.vy * prediction dx = tx - self.x dy = ty - self.y if dx < 0: self.vx = -1 elif dx > 0: self.vx = 1 else: self.vx = 0 if dy < 0: self.vy = -1 elif dy > 0: self.vy = 1 else: self.vy = 0 for ent in entities: if not ent.is_solid: continue if ent.overlaps_rect(self.x+self.vx, self.y+self.vy, 8, 8): self.vx = 0 self.vy = 0 self.x += self.vx self.y += self.vy def draw(self, screen): pygame.draw.rect(screen, (255, 0, 0), # color (r,g,b) (self.x, self.y, 8, 8)) # rect (x,y,w,h) RANDOM_MOVE_TIMER_MIN = 30 RANDOM_MOVE_TIMER_MAX = 60 class RandomEnemy: def __init__(self, x, y): self.x = x self.y = y self.vx = 0 self.vy = 0 self.is_solid = False self.move_timer = random.randint(RANDOM_MOVE_TIMER_MIN, RANDOM_MOVE_TIMER_MAX) def tick(self, _pressed, entities): player = entities[0] self.move_timer -= 1 if self.move_timer <= 0: self.vx = random.randint(-1,1) self.vy = random.randint(-1,1) self.move_timer = random.randint(RANDOM_MOVE_TIMER_MIN, RANDOM_MOVE_TIMER_MAX) dx = player.x - self.x dy = player.y - self.y if math.sqrt(dx**2 + dy**2) < 64: if dx < 0: self.vx = -2 elif dx > 0: self.vx = 2 else: self.vx = 0 if dy < 0: self.vy = -2 elif dy > 0: self.vy = 2 else: self.vy = 0 for ent in entities: if not ent.is_solid: continue if ent.overlaps_rect(self.x+self.vx, self.y+self.vy, 16, 16): self.vx = 0 self.vy = 0 self.x += self.vx self.y += self.vy def draw(self, screen): pygame.draw.rect(screen, (255, 0, 0), # color (r,g,b) (self.x, self.y, 16, 16)) # rect (x,y,w,h) class Wall: """An immovable obstacle which prevents any entity moving through it.""" def __init__(self, x, y, w, h): self.x = x self.y = y self.w = w self.h = h self.is_solid = True def tick(self, pressed, entities): pass def draw(self, screen): pygame.draw.rect(screen, (128, 0, 0), (self.x, self.y, self.w, self.h)) def overlaps_rect(self, r1x, r1y, r1w, r1h): return r1x + r1w >= self.x and \ r1x <= self.x + self.w and \ r1y + r1h >= self.y and \ r1y <= self.y + self.h def overlaps_circle(self, cx, cy, r): pass def game_step(screen, pressed, entities): # Simulation for ent in entities: ent.tick(pressed, entities) # Rendering for ent in entities: ent.draw(screen) def play(): pygame.init() screen = pygame.display.set_mode((320, 240)) # "Surface" done = False clock = pygame.time.Clock() entities = [Player(50, 50), Enemy(100, 100), RandomEnemy(75, 150), Wall(0, 0, 320, 16), Wall(0, 240-16, 320, 16), Wall(0, 0, 16, 240), Wall(320-16, 0, 16, 240), Wall(160-16, 120-16, 32, 32)] while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True pressed = pygame.key.get_pressed() if pressed[pygame.K_ESCAPE]: done = True screen.fill((0, 0, 0)) game_step(screen, pressed, entities) pygame.display.flip() clock.tick(60) pygame.quit() try: play() except Exception: traceback.print_exc() pygame.quit()