Upload files to "/"
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,235 @@
|
||||
import math
|
||||
import random
|
||||
import pygame
|
||||
|
||||
|
||||
class GObj:
|
||||
def __init__(self, x, y, radius, speed, turn_rate, heading, sight_distance,
|
||||
color="white", fill=0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.radius = radius
|
||||
self.speed = speed
|
||||
self.turn_rate = turn_rate
|
||||
self.heading = heading
|
||||
self.sight_distance = sight_distance
|
||||
self.color = color
|
||||
self.fill = fill
|
||||
def pos(self):
|
||||
return (self.x, self.y)
|
||||
def move(self, dt, direction=1.0):
|
||||
self.x += direction*self.speed*dt*math.cos(self.heading)
|
||||
self.y += direction*self.speed*dt*math.sin(self.heading)
|
||||
def turn(self, dt, direction):
|
||||
self.heading += direction*self.turn_rate*dt
|
||||
# def can_see(self, gameobj):
|
||||
# ox = gameobj.x
|
||||
# oy = gameobj.y
|
||||
|
||||
# x1 = self.x
|
||||
# y1 = self.y
|
||||
# x2 = x1+math.cos(self.heading)*self.sight_distance
|
||||
# y2 = y1+math.sin(self.heading)*self.sight_distance
|
||||
# D = x1*y2 - x2*y1
|
||||
# I = gameobj.radius**2 * self.sight_distance**2 - D**2
|
||||
# return I >= 0
|
||||
def check_collision(self, gameobj):
|
||||
distance = math.sqrt( (gameobj.x-self.x)**2 + (gameobj.y-self.y)**2 )
|
||||
if distance < self.radius+gameobj.radius:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def onscreen(self, rect):
|
||||
if (self.x+self.radius >= rect[0] and
|
||||
self.x-self.radius <= rect[2] and
|
||||
self.y+self.radius >= rect[1] and
|
||||
self.y-self.radius <= rect[3]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def draw(self, screen):
|
||||
pygame.draw.circle(
|
||||
screen,
|
||||
self.color,
|
||||
(self.x, self.y),
|
||||
self.radius,
|
||||
self.fill
|
||||
)
|
||||
|
||||
class Player(GObj):
|
||||
def __init__(self, x, y, radius=10, speed=100, turn_rate=5.0,
|
||||
heading=0, sight_distance=0, color="darkorchid",
|
||||
fill=0):
|
||||
GObj.__init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance, color,
|
||||
fill)
|
||||
def draw(self, screen):
|
||||
GObj.draw(self, screen)
|
||||
pygame.draw.line(
|
||||
screen,
|
||||
"black",
|
||||
(self.x, self.y),
|
||||
(
|
||||
self.x+math.cos(self.heading)*self.radius,
|
||||
self.y+math.sin(self.heading)*self.radius
|
||||
),
|
||||
2)
|
||||
|
||||
|
||||
class Goal(GObj):
|
||||
def __init__(self, x, y, radius=20, speed=0, turn_rate=0.0,
|
||||
heading=0.0, sight_distance=0.0,
|
||||
color="red", fill=3):
|
||||
GObj.__init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance, color,
|
||||
fill)
|
||||
self.touched = False
|
||||
def touch(self):
|
||||
self.color = "green"
|
||||
self.touched = True
|
||||
def is_touched(self):
|
||||
return self.touched
|
||||
|
||||
class Enemy(GObj):
|
||||
def __init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance,
|
||||
color, fill, goals):
|
||||
GObj.__init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance, color,
|
||||
fill)
|
||||
self.goals = goals
|
||||
self.sight_cone_color_clear = 'white'
|
||||
self.sight_cone_color_obj = 'fuchsia'
|
||||
self.sight_cone_color = self.sight_cone_color_clear
|
||||
|
||||
x0 = self.x
|
||||
y0 = self.y
|
||||
x1 = self.x+math.cos(self.heading-math.pi/6)*(self.radius+self.sight_distance)
|
||||
y1 = self.y+math.sin(self.heading-math.pi/6)*(self.radius+self.sight_distance)
|
||||
x2 = self.x+math.cos(self.heading+math.pi/6)*(self.radius+self.sight_distance)
|
||||
y2 = self.y+math.sin(self.heading+math.pi/6)*(self.radius+self.sight_distance)
|
||||
|
||||
self.sight_cone = [
|
||||
(x0,y0),
|
||||
(x1,y1),
|
||||
(x2,y2)
|
||||
]
|
||||
|
||||
def draw(self, screen):
|
||||
xy0 = self.sight_cone[0]
|
||||
xy1 = self.sight_cone[1]
|
||||
xy2 = self.sight_cone[2]
|
||||
|
||||
pygame.draw.line(
|
||||
screen,
|
||||
self.sight_cone_color,
|
||||
(xy0[0], xy0[1]),
|
||||
(xy1[0], xy1[1]),
|
||||
1)
|
||||
pygame.draw.line(
|
||||
screen,
|
||||
self.sight_cone_color,
|
||||
(xy1[0],xy1[1]),
|
||||
(xy2[0],xy2[1]),
|
||||
1)
|
||||
pygame.draw.line(
|
||||
screen,
|
||||
self.sight_cone_color,
|
||||
(xy2[0],xy2[1]),
|
||||
(xy0[0],xy0[1]),
|
||||
1)
|
||||
|
||||
GObj.draw(self, screen)
|
||||
|
||||
def update(self, gameobj):
|
||||
ox = gameobj.x
|
||||
oy = gameobj.y
|
||||
|
||||
x0 = self.x
|
||||
y0 = self.y
|
||||
x1 = self.x+math.cos(self.heading-math.pi/6)*(self.radius+self.sight_distance)
|
||||
y1 = self.y+math.sin(self.heading-math.pi/6)*(self.radius+self.sight_distance)
|
||||
x2 = self.x+math.cos(self.heading+math.pi/6)*(self.radius+self.sight_distance)
|
||||
y2 = self.y+math.sin(self.heading+math.pi/6)*(self.radius+self.sight_distance)
|
||||
|
||||
self.sight_cone[0] = (x0, y0)
|
||||
self.sight_cone[1] = (x1, y1)
|
||||
self.sight_cone[2] = (x2, y2)
|
||||
|
||||
|
||||
for i in range(len(self.sight_cone)):
|
||||
x1 = self.sight_cone[i][0]
|
||||
y1 = self.sight_cone[i][1]
|
||||
x2 = self.sight_cone[(i+1)%len(self.sight_cone)][0]
|
||||
y2 = self.sight_cone[(i+1)%len(self.sight_cone)][1]
|
||||
if (x2-x1)*(oy-y1) - (y2-y1)*(ox-x1) <= 0:
|
||||
self.sight_cone_color = self.sight_cone_color_clear
|
||||
return (False,None)
|
||||
self.sight_cone_color = self.sight_cone_color_obj
|
||||
dx = ox-self.x
|
||||
dy = oy-self.y
|
||||
dist = math.sqrt(dx*dx + dy*dy)
|
||||
dx /= dist
|
||||
dy /= dist
|
||||
return (True, (dx, dy), dist)
|
||||
|
||||
# Base class AI routine
|
||||
def ai(self, percept, goals, comms):
|
||||
|
||||
return (0.0, 0.0, None)
|
||||
|
||||
|
||||
class EnemyYellow(Enemy):
|
||||
def __init__(self, x, y, radius=10, speed=90, turn_rate=3.0,
|
||||
heading=0.0, sight_distance=120,
|
||||
color="yellow", fill=0, goals=[]):
|
||||
Enemy.__init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance, color,
|
||||
fill, goals)
|
||||
self.ticks = 0
|
||||
# This is ai routine for the type A enemy.
|
||||
def ai(self, percept, goals, comms):
|
||||
if self.ticks > 0:
|
||||
self.ticks-=1
|
||||
elif self.ticks == 0 and percept[0]:
|
||||
self.ticks = 60*4
|
||||
return (0.0, 0.0, ("Don't make me chase you!",2000) )
|
||||
return (0.0, 0.0, None)
|
||||
|
||||
|
||||
class EnemyBlue(Enemy):
|
||||
def __init__(self, x, y, radius=10, speed=90, turn_rate=3.0,
|
||||
heading=0.0, sight_distance=120,
|
||||
color="dodgerblue", fill=0, goals=[]):
|
||||
Enemy.__init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance, color,
|
||||
fill, goals)
|
||||
|
||||
self.ticks = 0
|
||||
# This is the ai routing for the type B enemy.
|
||||
def ai(self, percept, goals, comms):
|
||||
if self.ticks > 0:
|
||||
self.ticks-=1
|
||||
elif self.ticks == 0 and percept[0]:
|
||||
self.ticks = 60*4
|
||||
return (0.0, 0.0, ("I see you!",2000) )
|
||||
return (0.0, 0.0, None)
|
||||
|
||||
class EnemyRed(Enemy):
|
||||
def __init__(self, x, y, radius=10, speed=90, turn_rate=3.0,
|
||||
heading=0.0, sight_distance=120,
|
||||
color="red", fill=0, goals=[]):
|
||||
Enemy.__init__(self, x, y, radius, speed, turn_rate,
|
||||
heading, sight_distance, color,
|
||||
fill, goals)
|
||||
|
||||
self.ticks = 0
|
||||
|
||||
# This is the ai routing for the type B enemy.
|
||||
def ai(self, percept, goals, comms):
|
||||
if self.ticks > 0:
|
||||
self.ticks-=1
|
||||
elif self.ticks == 0 and percept[0]:
|
||||
self.ticks = 60*4
|
||||
return (0.0, 0.0, ("Enemy!",2000) )
|
||||
return (0.0, 0.0, None)
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
import pygame
|
||||
import pygame.freetype
|
||||
import math
|
||||
import random
|
||||
import gobjs
|
||||
|
||||
class Display:
|
||||
def __init__(self, screen, clock):
|
||||
self.screen = screen
|
||||
self.clock = clock
|
||||
self.run = True
|
||||
self.delta = 0
|
||||
self.font = None
|
||||
|
||||
def draw_gobj(self, gobj):
|
||||
pygame.draw.circle(
|
||||
self.screen,
|
||||
gobj.color,
|
||||
gobj.pos(),
|
||||
gobj.radius)
|
||||
def draw_text(self, msg, x, y, color):
|
||||
surface, rect = self.font.render(msg, color)
|
||||
self.screen.blit(surface, (x-rect.w//2, y-rect.h))
|
||||
|
||||
|
||||
def init_display(sw, sh):
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode((sw,sh))
|
||||
clock = pygame.time.Clock()
|
||||
display = Display(screen, clock)
|
||||
display.font = pygame.freetype.Font('JuliaMono-Bold.ttf', 18)
|
||||
return display
|
||||
|
||||
def handle_input(keys, dt, player, win_w, win_h):
|
||||
pos = player.pos()
|
||||
r = player.radius
|
||||
|
||||
if keys[pygame.K_a]:
|
||||
player.turn(dt, -1)
|
||||
elif keys[pygame.K_d]:
|
||||
player.turn(dt, 1)
|
||||
if keys[pygame.K_w]:
|
||||
player.move(dt)
|
||||
elif keys[pygame.K_s]:
|
||||
player.move(dt, -1.0)
|
||||
|
||||
def gather_perecpts(enemy, player):
|
||||
return enemy.can_see(player)
|
||||
|
||||
def game_loop(display):
|
||||
|
||||
win_w, win_h = pygame.display.get_window_size()
|
||||
d_rect = (0, 0, win_w, win_h)
|
||||
|
||||
# NOTE: You are welcome to modify some aspects of the following
|
||||
# The player and enemy classes do take additional parameters
|
||||
# which are currently set to defaults. You are welcome to
|
||||
# override them to get a different scenario.
|
||||
|
||||
# Possible Player start locations (x, y, heading)
|
||||
start_locs = [
|
||||
(50,50, math.pi/4),
|
||||
(win_w//2, 50, math.pi/2),
|
||||
(win_w-50, 50, 3*math.pi/4),
|
||||
(50, win_h//2, 0),
|
||||
(win_w-50, win_h//2, math.pi),
|
||||
(50, win_h-50, -math.pi/4),
|
||||
(win_w//2, win_h-50, -math.pi/2),
|
||||
(win_w-50, win_h-50, -3*math.pi/4)
|
||||
]
|
||||
# Randomly choose one.
|
||||
player_start = random.choice(start_locs)
|
||||
player = gobjs.Player(player_start[0], player_start[1], heading=player_start[2])
|
||||
|
||||
# Goals. The number passed into the Goal contructor are the x,y coords.
|
||||
goals = [
|
||||
gobjs.Goal(200, 200),
|
||||
gobjs.Goal(win_w-200, 200),
|
||||
gobjs.Goal(200, win_h-200),
|
||||
gobjs.Goal(win_w-200, win_h-200),
|
||||
gobjs.Goal(win_w//2, win_h//2)
|
||||
]
|
||||
|
||||
# The enemies.
|
||||
enemy1 = gobjs.EnemyYellow(win_w//2+50, win_h//2, heading=0)
|
||||
enemy2 = gobjs.EnemyBlue(win_w//2-50, win_h//2, heading=math.pi)
|
||||
enemy3 = gobjs.EnemyRed(win_w//2, win_h//2-50, heading=-math.pi/2)
|
||||
enemies = [enemy1, enemy2, enemy3]
|
||||
comms = {
|
||||
"R": None,
|
||||
"B": None,
|
||||
"Y": None
|
||||
}
|
||||
|
||||
tick = 0
|
||||
goal_count = 0
|
||||
winner = "Draw"
|
||||
msgs = []
|
||||
|
||||
|
||||
# You probably don't need to modify anything in the main loop
|
||||
while display.run:
|
||||
dt = display.clock.tick(60) / 1000
|
||||
|
||||
# Check event queue for quit
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
display.run = False
|
||||
|
||||
display.screen.fill("black")
|
||||
|
||||
next_msgs = []
|
||||
for msg in msgs:
|
||||
if pygame.time.get_ticks() - msg[2] < msg[0][1]:
|
||||
display.draw_text(msg[0][0], msg[1].x, msg[1].y-(msg[1].radius+3), msg[1].color)
|
||||
next_msgs.append(msg)
|
||||
msgs = next_msgs
|
||||
|
||||
for g in goals:
|
||||
if not g.is_touched():
|
||||
if g.check_collision(player):
|
||||
g.touch()
|
||||
goal_count += 1
|
||||
if goal_count == len(goals):
|
||||
display.run = False
|
||||
winner = "Player"
|
||||
g.draw(display.screen)
|
||||
|
||||
# Call Enemy AI and draw
|
||||
for e in enemies:
|
||||
mt = e.ai(e.update(player), goals, comms)
|
||||
e.turn(dt, mt[0])
|
||||
e.move(dt, mt[1])
|
||||
if mt[2] is not None:
|
||||
msgs.append( (mt[2], e, pygame.time.get_ticks()) )
|
||||
if e.check_collision(player):
|
||||
display.run = False
|
||||
winner = "AI"
|
||||
if not e.onscreen(d_rect):
|
||||
display.run = False
|
||||
winner = "Player"
|
||||
e.draw(display.screen)
|
||||
|
||||
# Move and draw the player
|
||||
keys = pygame.key.get_pressed()
|
||||
handle_input(keys, dt, player, win_w, win_h)
|
||||
player.draw(display.screen)
|
||||
|
||||
if not player.onscreen(d_rect):
|
||||
winner = "AI"
|
||||
display.run=False
|
||||
|
||||
pygame.display.flip()
|
||||
|
||||
print(f"The winner is the {winner}.")
|
||||
|
||||
|
||||
def main():
|
||||
display = init_display(800, 800)
|
||||
game_loop(display)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user