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