Skip to content
Snippets Groups Projects
Commit e0d1b702 authored by Mohannad Alaya's avatar Mohannad Alaya
Browse files

CTF_Done

parent baa2bbc1
No related branches found
No related tags found
No related merge requests found
data/bullet.png

1.18 KiB

File added
data/explosion.png

3.27 KiB

data/flag.png

845 B

data/grass.png

2.73 KiB

data/metalbox.png

1.7 KiB

data/rockbox.png

1.37 KiB

File added
data/tank_blue.png

1.06 KiB

data/tank_gray.png

1.01 KiB

data/tank_orange.png

1011 B

data/tank_red.png

1.02 KiB

data/tank_white.png

1.01 KiB

data/tank_yellow.png

1003 B

data/woodbox.png

1.49 KiB

import images
import pygame
import pymunk
import math
DEBUG = False # Change this to set it in debug mode
def physics_to_display(x):
""" This function is used to convert coordinates
in the physic engine into the display coordinates """
return x * images.TILE_SIZE
class GameObject:
""" Mostly handles visual aspects (pygame) of an object.
Subclasses need to implement two functions:
-screen_position that will return the position of the object
-screen_orientation that will return how much the object
is rotated on the screen (in degrees). """
def __init__(self, sprite):
""" Game object constructor """
self.sprite = sprite
def update(self):
""" Placeholder, supposed to be implemented in a subclass.
Should update the current state (after a tick) of the object."""
return
def post_update(self):
""" Should be implemented in a subclass. Make updates that depend on
other objects than itself."""
return
def update_screen(self, screen):
""" Updates the visual part of the game. Should NOT need to be changed
by a subclass."""
sprite = self.sprite
# Get the position of the object (pygame coordinates)
p = self.screen_position()
# Rotate the sprite using the rotation of the object
sprite = pygame.transform.rotate(sprite, self.screen_orientation())
# The position of the screen correspond to the center of the object,
# but the function screen.blit expect to receive the top left corner
# as argument, so we need to adjust the position p with an offset
# which is the vector between the center of the sprite and the top left
# corner of the sprite
offset = pymunk.Vec2d(sprite.get_size()) / 2.
p = p - offset
screen.blit(sprite, p) # Copy the sprite on the screen
class GamePhysicsObject(GameObject):
""" This class extends GameObject and it is used for objects which have a
physical shape(such as tanks and boxes). This class handle the physical
interaction of the objects.
"""
def __init__(self, x, y, orientation, sprite, space, movable):
""" Takes as parameters the starting coordinate (x,y), the orientation,
the sprite (aka the image representing the object), the physic
engine object(space) and whether the object can be moved (movable).
"""
super().__init__(sprite)
# Half dimensions of the object converted
# from screen coordinates to physic coordinates.
half_width = 0.5 * self.sprite.get_width() / images.TILE_SIZE
half_height = 0.5 * self.sprite.get_height() / images.TILE_SIZE
# Physical objects have a rectangular shape, the points
# correspond to the corners of that shape.
points = [[-half_width, -half_height],
[-half_width, half_height],
[half_width, half_height],
[half_width, -half_height]]
self.points = points
# Create a body (which is the physical representation
# of this game object in the physic engine)
if(movable):
# Create a movable object with some mass and moments
# (considering the game is a top view game, with no gravity,
# the mass is set to the same value for all objects)."""
mass = 10
moment = pymunk.moment_for_poly(mass, points)
self.body = pymunk.Body(mass, moment)
else:
# Create a non movable (static) object
self.body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.body.position = x, y
# orientation is provided in degress, but pymunk expects radians.
self.body.angle = math.radians(orientation)
# Create a polygon shape using the corner of the rectangle
self.shape = pymunk.Poly(self.body, points)
self.shape.parent = self
# Add the object to the physic engine
if(movable):
space.add(self.body, self.shape)
else:
space.add(self.shape)
def screen_position(self):
""" Converts the body's position in the physics engine to
screen coordinates. """
return physics_to_display(self.body.position)
def screen_orientation(self):
""" Angles are reversed from the engine to the display. """
return -math.degrees(self.body.angle)
def update_screen(self, screen):
""" Function for repaint the screen in its current state."""
super().update_screen(screen)
# debug draw
if DEBUG:
ps = [self.body.position+p for p in self.points]
ps = [physics_to_display(p) for p in ps]
ps += [ps[0]]
pygame.draw.lines(screen,pygame.color.THECOLORS["red"],False, ps,1)
def clamp(min_max, value):
""" Convenient helper function to bound a value to a specific interval. """
return min(max(-min_max, value), min_max)
class Tank(GamePhysicsObject):
""" Extends GamePhysicsObject and handles aspects which are specific
to our tanks. """
ACCELERATION = 0.8
NORMAL_MAX_SPEED = 4.0
FLAG_MAX_SPEED = NORMAL_MAX_SPEED * 0.5
def __init__(self, x, y, orientation, sprite, space):
""" Tank constructor """
super().__init__(x, y, orientation, sprite, space, True)
# Define variable used to apply motion to the tanks
self.shape.collision_type = 2
self.acceleration = 0 # 1 forward, 0 for stand still, -1 for backwards
self.rotation = 0 # 1 clockwise, 0 for no rotation, -1 counter clockwise
self.timer = 0
self.spawn_cooldown = 0
self.cooldown = 0
self.points = 0
self.hitpoints = 2
self.space = space
self.flag = None
self.max_speed = Tank.NORMAL_MAX_SPEED
self.start_position = pymunk.Vec2d(x, y)
def accelerate(self):
""" Call this function to make the tank move forward. """
self.acceleration = 1
def stop_moving(self):
""" Call this function to make the tank stop moving. """
self.acceleration = 0
self.body.velocity = pymunk.Vec2d.zero()
def decelerate(self):
""" Call this function to make the tank move backward. """
self.acceleration = -1
def turn_left(self):
""" Makes the tank turn left (counter clock-wise). """
self.rotation = -1
def turn_right(self):
""" Makes the tank turn right (clock-wise). """
self.rotation = 1
def stop_turning(self):
""" Call this function to make the tank stop turning. """
self.rotation = 0
self.body.angular_velocity = 0
def update(self):
""" A function to update the objects coordinates.
Gets called at every tick of the game. """
# Creates a vector in the direction we want accelerate / decelerate
acceleration_vector = pymunk.Vec2d\
(0,self.ACCELERATION*\
self.acceleration).rotated(self.body.angle)
# Applies the vector to our velocity
self.body.velocity += acceleration_vector
# Makes sure that we dont exceed our speed limit
velocity = clamp(self.max_speed, self.body.velocity.length)
self.body.velocity = pymunk.Vec2d(velocity, \
0).rotated(self.body.velocity.angle)
# Updates the rotation
self.body.angular_velocity += self.rotation * self.ACCELERATION
self.body.angular_velocity = clamp(self.max_speed, \
self.body.angular_velocity)
def post_update(self,flag):
# If the tank carries the flag, then update the positon of the flag
if(self.flag != None):
self.flag.x = self.body.position[0]
self.flag.y = self.body.position[1]
self.flag.orientation = -math.degrees(self.body.angle)
# Else ensure that the tank has its normal max speed
else:
self.max_speed = Tank.NORMAL_MAX_SPEED
self.try_grab_flag(flag)
self.timer += 1
self.spawn_cooldown += 1
self.cooldown -= 1
if self.cooldown > 0:
self.body.position = self.start_position
self.stop_moving()
def try_grab_flag(self, flag):
""" Call this function to try to grab the flag, if the
flag is not on other tank and it is close to the current tank,
then the current tank will grab the flag.
"""
# Check that the flag is not on other tank
if(not flag.is_on_tank):
# Check if the tank is close to the flag
flag_pos = pymunk.Vec2d(flag.x, flag.y)
if((flag_pos - self.body.position).length < 0.5):
# Grab the flag !
self.flag = flag
flag.is_on_tank = True
self.max_speed = Tank.FLAG_MAX_SPEED
def has_won(self):
""" Check if the current tank has won (if it is has the
flag and it is close to its start position). """
return self.flag != None and \
(self.start_position - self.body.position).length < 0.2
def shoot(self):
""" Call this function to shoot a missile"""
if self.timer > 60:
self.timer = 0
x = self.body.position[0]+ 0.3*math.cos(math.pi/2+self.body.angle)
y = self.body.position[1]+0.3*math.sin(math.pi/2+self.body.angle)
return Bullet(x, y, self.body.angle, images.bullet, self.space)
def on_death(self):
""" Reset the tank's position and set the cooldown when a tank is
destroyed. """
self.flag = None
if self.spawn_cooldown > 100:
if self.hitpoints > 1:
self.hitpoints = self.hitpoints-1
else:
self.body.position = self.start_position
self.cooldown = 120
self.max_speed = 0
self.spawn_cooldown = 0
class Box(GamePhysicsObject):
""" This class extends the GamePhysicsObject to handle box objects. """
def __init__(self, x, y, sprite, movable, space, destructable):
""" It takes as arguments the coordinate of the starting position
of the box (x,y) and the box model (boxmodel). """
super().__init__(x, y, 0, sprite, space, movable)
self.shape.collision_type = 3
self.destructable = destructable
self.hitpoints = 2
def get_box_with_type(x, y, type, space):
""" Return the box onject corresponding to the input type"""
(x, y) = (x + 0.5, y + 0.5) # set offsets in center of the tile
if type == 1: # Creates a non-movable non-destructable rockbox
return Box(x, y, images.rockbox, False, space, False)
if type == 2: # Creates a movable destructable woodbox
return Box(x, y, images.woodbox, True, space, True)
if type == 3: # Creates a movable non-destructable metalbox
return Box(x, y, images.metalbox, True, space, False)
class GameVisibleObject(GameObject):
""" This class extends GameObject for object that are visible on
screen but have no physical representation (bases and flag) """
def __init__(self, x, y, sprite):
""" It takes argument the coordinates (x,y) and the sprite. """
self.x = x
self.y = y
self.orientation = 0
super().__init__(sprite)
def screen_position(self):
return physics_to_display(pymunk.Vec2d(self.x, self.y))
def screen_orientation(self):
return self.orientation
class Flag(GameVisibleObject):
""" This class extends GameVisibleObject for representing flags."""
def __init__(self, x, y):
self.is_on_tank = False
super().__init__(x, y, images.flag)
class Bullet(GamePhysicsObject):
""" Class for the bullet objects in the game."""
def __init__(self, x, y, sprite, orientation, space):
"""Bullet constructor, take information from the tank that
shoots as input"""
super().__init__(x,y, sprite, orientation, space, True)
self.orientation = math.degrees(self.body.angle)
self.shape.collision_type = 1
self.velocity = 15
self.body.velocity = pymunk.Vec2d(\
(0,self.velocity)).rotated(self.orientation)
import pygame
import os
main_dir = os.path.split(os.path.abspath(__file__))[0]
def load_image(file):
""" Load an image from the data directory. """
file = os.path.join(main_dir, 'data', file)
try:
surface = pygame.image.load(file)
except pygame.error:
raise SystemExit('Could not load image "%s" %s'%\
(file, pygame.get_error()))
return surface.convert_alpha()
TILE_SIZE = 40 # Define the default size of tiles
explosion = load_image('explosion.png') # Image of an explosion
grass = load_image('grass.png') # Image of a grass tile
rockbox = load_image('rockbox.png') # Image of a rock box (wall)
metalbox = load_image('metalbox.png') # Image of a metal box
woodbox = load_image('woodbox.png') # Image of a wood box
flag = load_image('flag.png') # Image of flag
bullet = load_image('bullet.png')
bullet = pygame.transform.scale(bullet, (10, 10))
bullet = pygame.transform.rotate(bullet, -90)
# List of image of tanks of different colors
tanks = [load_image('tank_orange.png'), load_image('tank_blue.png'),\
load_image('tank_white.png'),
load_image('tank_yellow.png'), load_image('tank_red.png'),\
load_image('tank_gray.png')]
# List of image of bases corresponding to the color of each tank
bases = [load_image('base_orange.png'), load_image('base_blue.png'),\
load_image('base_white.png'),
load_image('base_yellow.png'), load_image('base_red.png'), \
load_image('base_gray.png')]
import gameobjects
from pygame.locals import *
from pygame.color import *
import pymunk
import images
import ai
def create_flag(game_objects_list,flag_start):
"""Create a flag object and add it to the list of game objects."""
flag = gameobjects.Flag(flag_start[0], flag_start[1])
game_objects_list.append(flag)
flag.is_on_tank = False
flag.x, flag.y = flag_start
return flag
def create_borders(space,current_map):
""" Create borders for the game map. """
static_body = space.static_body
static_lines = [
pymunk.Segment(static_body,
(-0.5, current_map.height), (-0.5, 0), 0.5
), # left
pymunk.Segment(static_body, (0, current_map.height+0.5),
(current_map.width, current_map.height+0.5),
0.5), # lower
pymunk.Segment(static_body,
(current_map.width+0.5, 0), (current_map.width+0.5,
current_map.height),
0.5), # right
pymunk.Segment(static_body, (0, -0.5), (current_map.width, -0.5),
0.5) # upper
]
static_lines[0].collision_type = 10
static_lines[1].collision_type = 10
static_lines[2].collision_type = 10
static_lines[3].collision_type = 10
space.add(*static_lines)
def create_background(current_map,background):
"""Create a background image for the game map."""
for x in range(0, current_map.width):
for y in range(0, current_map.height):
background.blit(images.grass,(x*images.TILE_SIZE, \
y*images.TILE_SIZE))
def create_boxes(game_objects_list , current_map, space):
"""Create boxes for the game map."""
for x in range(0, current_map.width):
for y in range(0, current_map.height):
# Get the type of boxes
box_type = current_map.boxAt(x, y)
if(box_type != 0):
box = gameobjects.get_box_with_type(x, y, box_type, space)
game_objects_list.append(box)
def create_tanks(tanks_list,game_objects_list,current_map,space,multi,ai_list):
""" create and manage tanks in the game. """
for i in range(0, len(current_map.start_positions)):
# Get the starting position of the tank "i"
pos = current_map.start_positions[i]
# Create the tank, images.tanks contains the image representing the tank
tank = gameobjects.Tank(pos[0], pos[1], pos[2], images.tanks[i], space)
# Add the tank to the list of objects to display
game_objects_list.append(tank)
# Add the tank to the list of tanks
tanks_list.append(tank)
if not multi:
for i in range(len(tanks_list)-1):
ai_list.append(ai.Ai(tanks_list[i+1], game_objects_list,\
tanks_list, space, current_map))
else:
for i in range(1,len(tanks_list)-1):
ai_list.append(ai.Ai(tanks_list[i+1], game_objects_list,\
tanks_list, space, current_map))
def create_bases(game_objects_list,current_map):
""" create all needed bases in the game. """
for i in range(0, len(current_map.start_positions)):
pos = current_map.start_positions[i]
base = gameobjects.GameVisibleObject(pos[0],pos[1],images.bases[i])
game_objects_list.append(base)
maps.py 0 → 100644
import images
import pygame
class Map:
""" An instance of Map is a blueprint for how the game map will look. """
def __init__(self, width, height, boxes, start_positions, flag_position):
""" Takes as argument the size of the map (width, height),
an array with the boxes type, the start position of tanks
(start_positions) and the position of the flag (flag_position).
"""
self.width = width
self.height = height
self.boxes = boxes
self.start_positions = start_positions
self.flag_position = flag_position
def rect(self):
""" Creates a rectangle for a specifc image. """
return pygame.Rect(0, 0, images.TILE_SIZE*self.width, \
images.TILE_SIZE*self.height)
def boxAt(self, x, y):
""" Return the type of the box at coordinates (x, y). """
return self.boxes[y][x]
map0 = Map(9, 9,
[ [0, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 2, 0, 2, 0, 1, 0],
[0, 2, 0, 1, 0, 1, 0, 2, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0],
[1, 1, 0, 3, 0, 3, 0, 1, 1],
[0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 2, 0, 1, 0, 1, 0, 2, 0],
[0, 1, 0, 2, 0, 2, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0] ],
[[0.5, 0.5, 0], [8.5, 0.5, 0],
[0.5, 8.5, 180], [8.5, 8.5, 180]], [4.5, 4.5])
map1 = Map(15, 11,
[ [ 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0],
[ 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0],
[ 0, 1, 0, 3, 1, 1, 0, 0, 0, 1, 1, 3, 0, 1, 0],
[ 0, 2, 0, 0, 3, 0, 0, 2, 0, 0, 3, 0, 0, 2, 0],
[ 2, 1, 0, 1, 1, 0, 1, 3, 1, 0, 1, 1, 0, 1, 2],
[ 1, 1, 3, 0, 3, 2, 3, 0, 3, 2, 3, 0, 3, 1, 1],
[ 2, 1, 0, 1, 1, 0, 1, 3, 1, 0, 1, 1, 0, 1, 2],
[ 0, 2, 0, 0, 3, 0, 0, 2, 0, 0, 3, 0, 0, 2, 0],
[ 0, 1, 0, 3, 1, 1, 0, 0, 0, 1, 1, 3, 0, 1, 0],
[ 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0],
[ 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0] ],
[[0.5, 0.5, 0], [14.5, 0.5, 0], [0.5, 10.5, 180],
[14.5, 10.5, 180], [7.5, 0.5, 0], [7.5, 10.5, 180]], [7.5, 5.5])
map2 = Map(10, 5,
[ [ 0, 2, 0, 2, 0, 0, 2, 0, 2, 0 ],
[ 0, 3, 0, 1, 3, 3, 1, 0, 3, 0 ],
[ 0, 1, 0, 1, 0, 0, 1, 0, 1, 0 ],
[ 0, 3, 0, 1, 3, 3, 1, 0, 3, 0 ],
[ 0, 2, 0, 2, 0, 0, 2, 0, 2, 0 ] ],
[[0.5, 2.5, 270], [9.5, 2.5, 90]], [5, 2.5] )
menu.py 0 → 100644
import pygame
import images
from pygame.locals import *
import maps
def main_menu():
"""
Displays the main menu screen, allowing the user to select options for
game play (singleplayer or multiplayer), map, fog, and game mode
(score limit, time limit, or round limit). """
multiplayer = 1
mapp = 2
fog = 3
game_mode = 4
return_ = 5
def get_text(var):
""" Returns the text to be displayed for each option in the main menu.
"""
white = (255,255,255)
font = pygame.font.SysFont('Corbel',35)
if var == multiplayer :
text1 = font.render('play:' , True , white)
text2 = font.render('Capture the Flag!' , True , white)
text3 = font.render('singleplayer: press 1!' , True , white)
text4 = font.render('multiplayer: press 2!' , True , white)
elif var == mapp :
text1 = font.render('Choose a map:' , True , white)
text2 = font.render('Capture the Flag!' , True , white)
text3 = font.render('Map1, Map2 or Map3' , True , white)
text4 = font.render('press: 1 , 2 or 3 ' , True , white)
elif var == fog :
text1 = font.render('Choose fog:' , True , white)
text2 = font.render('Capture the Flag!' , True , white)
text3 = font.render('With fog: press 1' , True , white)
text4 = font.render('Without fog: press 2' , True , white)
elif var == game_mode :
text1 = font.render('Choose a game mode:' , True , white)
text2 = font.render('Capture the Flag!' , True , white)
text3 = font.render('Score limit, Time limit or Round limit' ,\
True , white)
text4 = font.render('press: 1, 2 or 3 ' , True , white)
return text1,text2,text3,text4
def print_on_screen(lst):
""" prints the text on the screen """
green = (80,200,80)
width = 600
height = 600
screen = pygame.display.set_mode((width,height))
screen.fill(green)
screen.blit(lst[0], (width/6,height/3))
screen.blit(lst[1], (width/6,height/6))
screen.blit(lst[2], (width/6,height/3+30))
screen.blit(lst[3], (width/6,height/3+70))
pygame.display.update()
return_list = []
state = 1
while True:
print_on_screen(get_text(state))
for ev in pygame.event.get():
if ev.type == KEYDOWN:
temp = None
if ev.key == K_ESCAPE:
pygame.quit()
if ev.key == K_1:
if state == multiplayer :
temp = False
elif state == mapp :
temp = maps.map0
elif state == fog :
temp = True
elif state == game_mode :
temp = 1
elif ev.key == K_2:
if state == multiplayer :
temp = True
elif state == mapp :
temp = maps.map1
elif state == fog :
temp = False
elif state == game_mode :
temp = 2
elif ev.key == K_3:
if state == mapp :
temp = maps.map2
elif state == game_mode :
temp = 3
if temp != None:
return_list.append(temp)
state = state + 1
if state == return_ :
return return_list
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment