In this mini-projects, we will build a 2D space game RiceRocks that is inspired by the classic arcade game Asteroids (1979). Asteroids is a relatively simple game by today's standards, but was still immensely popular during its time.In the game, the player controls a spaceship via four buttons: two buttons that rotate the spaceship clockwise or counterclockwise (independent of its current velocity), a thrust button that accelerates the ship in its forward direction and a fire button that shoots missiles. Large asteroids spawn randomly on the screen with random velocities. The player's goal is to destroy these asteroids before they strike the player's ship. In the arcade version, a large rock hit by a missile split into several fast moving small asteroids that themselves must be destroyed. Occasionally, a flying saucer also crosses the screen and attempts to destroy the player's spaceship.
Here is the link to my code on codeskulptor :
Spaceship
Game Source Code:
# program template for Spaceship
import simplegui
import math
import random
# globals for user interface
width = 800
height = 600
score = 0
lives = 3
time = 0.5
class ImageInfo:
def __init__(self, center, size, radius = 0, lifespan = None, animated = False):
self.center = center
self.size = size
self.radius = radius
if lifespan:
self.lifespan = lifespan
else:
self.lifespan = float('inf')
self.animated = animated
def get_center(self):
return self.center
def get_size(self):
return self.size
def get_radius(self):
return self.radius
def get_lifespan(self):
return self.lifespan
def get_animated(self):
return self.animated
# art assets created by Kim Lathrop, may be freely re-used in non-commercial projects, please credit Kim
# debris images - debris1_brown.png, debris2_brown.png, debris3_brown.png, debris4_brown.png
# debris1_blue.png, debris2_blue.png, debris3_blue.png, debris4_blue.png, debris_blend.png
debris_info = ImageInfo([320, 240], [640, 480])
debris_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png")
# nebula images - nebula_brown.png, nebula_blue.png
nebula_info = ImageInfo([400, 300], [800, 600])
nebula_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/nebula_blue.png")
# splash image
splash_info = ImageInfo([200, 150], [400, 300])
splash_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/splash.png")
# ship image
ship_info = ImageInfo([45, 45], [90, 90], 35)
ship_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/double_ship.png")
# missile image - shot1.png, shot2.png, shot3.png
missile_info = ImageInfo([5,5], [10, 10], 3, 50)
missile_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/shot2.png")
# asteroid images - asteroid_blue.png, asteroid_brown.png, asteroid_blend.png
asteroid_info = ImageInfo([45, 45], [90, 90], 40)
asteroid_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png")
# animated explosion - explosion_orange.png, explosion_blue.png, explosion_blue2.png, explosion_alpha.png
explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True)
explosion_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/explosion_alpha.png")
# sound assets purchased from sounddogs.com, please do not redistribute
soundtrack = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/soundtrack.mp3")
missile_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/missile.mp3")
missile_sound.set_volume(.5)
ship_thrust_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/thrust.mp3")
explosion_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/explosion.mp3")
# helper functions to handle transformations
def angle_to_vector(ang):
return [math.cos(ang), math.sin(ang)]
def dist(p,q):
return math.sqrt((p[0]-q[0])**2+(p[1]-q[1])**2)
# Ship class
class Ship:
def __init__(self, pos, vel, angle, image, info):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.thrust = False
self.angle = angle
self.angle_vel = 0
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
self.forward = [0,0]
def draw(self,canvas):
#canvas.draw_circle(self.pos, self.radius, 1, "White", "White")
canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle)
if self.thrust == True:
canvas.draw_image(self.image, [self.image_center[0] + 90, self.image_center[1]], self.image_size, self.pos, self.image_size, self.angle)
def update(self):
self.angle += self.angle_vel
self.pos[0] += self.vel[0]
self.pos[1] += self.vel[1]
if self.pos[0] // 800 == 1:
self.pos[0] = 0
elif self.pos[0] // 800 < 0:
self.pos[0] = 800
if self.pos[1] // 600 == 1:
self.pos[1] = 0
elif self.pos[1] // 600 < 0:
self.pos[1] = 600
# the following two lines are to induce friction, which caps maximum velocity
# and also causes ship to slowly stop by itself when thrusters are off
self.vel[0] *= .99
self.vel[1] *= .99
if self.thrust == True:
self.forward = angle_to_vector(self.angle)
self.vel[0] += self.forward[0] * .12
self.vel[1] += self.forward[1] * .12
def keydown(self,key):
ang_vel = .09
if key == simplegui.KEY_MAP['left']:
self.angle_vel = - ang_vel
elif key == simplegui.KEY_MAP['right']:
self.angle_vel = ang_vel
elif key == simplegui.KEY_MAP['up']:
self.thrust = True
if self.thrust == True:
sound = ship_thrust_sound
sound.play()
elif key == simplegui.KEY_MAP['space']:
self.shoot()
def keyup(self,key):
angle_vel = 0
if key == simplegui.KEY_MAP['right']:
my_ship.angle_vel = angle_vel
elif key == simplegui.KEY_MAP['left']:
my_ship.angle_vel = angle_vel
elif key == simplegui.KEY_MAP['up']:
self.thrust = False
if self.thrust == False:
self.forward = [0,0]
sound = ship_thrust_sound
sound.pause()
def shoot(self):
global a_missile
vector = angle_to_vector(my_ship.angle)
a_missile = Sprite([my_ship.pos[0] + (vector[0] * my_ship.radius),my_ship.pos[1] + (vector[1] * my_ship.radius)], [my_ship.vel[0] + (vector[0] * 5),my_ship.vel[1] + (vector[1] * 5)], 0, 0, missile_image, missile_info, missile_sound)
# Sprite class
class Sprite:
def __init__(self, pos, vel, ang, ang_vel, image, info, sound = None):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.angle = ang
self.angle_vel = ang_vel
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
self.lifespan = info.get_lifespan()
self.animated = info.get_animated()
self.age = 0
if sound:
sound.rewind()
sound.play()
def draw(self, canvas):
canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle)
def update(self):
self.pos[0] += self.vel[0]
self.pos[1] += self.vel[1]
self.angle += self.angle_vel
def draw(canvas):
global time
# animate background
time += 1
center = debris_info.get_center()
size = debris_info.get_size()
wtime = (time / 8) % center[0]
canvas.draw_image(nebula_image, nebula_info.get_center(), nebula_info.get_size(), [width/2, height/2], [width, height])
canvas.draw_image(debris_image, [center[0]-wtime, center[1]], [size[0]-2*wtime, size[1]],
[width/2+1.25*wtime, height/2], [width-2.5*wtime, height])
canvas.draw_image(debris_image, [size[0]-wtime, center[1]], [2*wtime, size[1]],
[1.25*wtime, height/2], [2.5*wtime, height])
# draw ship and sprites
my_ship.draw(canvas)
a_rock.draw(canvas)
a_missile.draw(canvas)
# update ship and sprites
my_ship.update()
a_rock.update()
a_missile.update()
# timer handler that spawns a rock
def rock_spawner():
global a_rock
a_rock = Sprite([width * random.random(), height * random.random()], [random.random() * 3 - 1.5,random.random() * 3 - 1.5], 0, (random.random() - .5) / 8, asteroid_image, asteroid_info)
def key_down(key):
my_ship.keydown(key)
def key_up(key):
my_ship.keyup(key)
# initialize frame
frame = simplegui.create_frame("Asteroids", width, height)
# initialize ship and two sprites
my_ship = Ship([width / 2, height / 2], [0, 0], 1.5 * math.pi, ship_image, ship_info)
a_rock = Sprite([width * random.random(), height * random.random()], [random.random() * 3 - 1.5,random.random() * 3 - 1.5], 0, (random.random() - .5) / 8, asteroid_image, asteroid_info)
a_missile = Sprite([2 * width / 3, 2 * height / 3], [-1,1], 0, 0, missile_image, missile_info, missile_sound)
# register handlers
frame.set_draw_handler(draw)
frame.set_keydown_handler(key_down)
frame.set_keyup_handler(key_up)
timer = simplegui.create_timer(1000.0, rock_spawner)
# get things rolling
timer.start()
frame.start()
Here is the link to my code on codeskulptor :
Spaceship
Game Source Code:
# program template for Spaceship
import simplegui
import math
import random
# globals for user interface
width = 800
height = 600
score = 0
lives = 3
time = 0.5
class ImageInfo:
def __init__(self, center, size, radius = 0, lifespan = None, animated = False):
self.center = center
self.size = size
self.radius = radius
if lifespan:
self.lifespan = lifespan
else:
self.lifespan = float('inf')
self.animated = animated
def get_center(self):
return self.center
def get_size(self):
return self.size
def get_radius(self):
return self.radius
def get_lifespan(self):
return self.lifespan
def get_animated(self):
return self.animated
# art assets created by Kim Lathrop, may be freely re-used in non-commercial projects, please credit Kim
# debris images - debris1_brown.png, debris2_brown.png, debris3_brown.png, debris4_brown.png
# debris1_blue.png, debris2_blue.png, debris3_blue.png, debris4_blue.png, debris_blend.png
debris_info = ImageInfo([320, 240], [640, 480])
debris_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png")
# nebula images - nebula_brown.png, nebula_blue.png
nebula_info = ImageInfo([400, 300], [800, 600])
nebula_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/nebula_blue.png")
# splash image
splash_info = ImageInfo([200, 150], [400, 300])
splash_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/splash.png")
# ship image
ship_info = ImageInfo([45, 45], [90, 90], 35)
ship_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/double_ship.png")
# missile image - shot1.png, shot2.png, shot3.png
missile_info = ImageInfo([5,5], [10, 10], 3, 50)
missile_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/shot2.png")
# asteroid images - asteroid_blue.png, asteroid_brown.png, asteroid_blend.png
asteroid_info = ImageInfo([45, 45], [90, 90], 40)
asteroid_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png")
# animated explosion - explosion_orange.png, explosion_blue.png, explosion_blue2.png, explosion_alpha.png
explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True)
explosion_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/explosion_alpha.png")
# sound assets purchased from sounddogs.com, please do not redistribute
soundtrack = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/soundtrack.mp3")
missile_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/missile.mp3")
missile_sound.set_volume(.5)
ship_thrust_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/thrust.mp3")
explosion_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/explosion.mp3")
# helper functions to handle transformations
def angle_to_vector(ang):
return [math.cos(ang), math.sin(ang)]
def dist(p,q):
return math.sqrt((p[0]-q[0])**2+(p[1]-q[1])**2)
# Ship class
class Ship:
def __init__(self, pos, vel, angle, image, info):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.thrust = False
self.angle = angle
self.angle_vel = 0
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
self.forward = [0,0]
def draw(self,canvas):
#canvas.draw_circle(self.pos, self.radius, 1, "White", "White")
canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle)
if self.thrust == True:
canvas.draw_image(self.image, [self.image_center[0] + 90, self.image_center[1]], self.image_size, self.pos, self.image_size, self.angle)
def update(self):
self.angle += self.angle_vel
self.pos[0] += self.vel[0]
self.pos[1] += self.vel[1]
if self.pos[0] // 800 == 1:
self.pos[0] = 0
elif self.pos[0] // 800 < 0:
self.pos[0] = 800
if self.pos[1] // 600 == 1:
self.pos[1] = 0
elif self.pos[1] // 600 < 0:
self.pos[1] = 600
# the following two lines are to induce friction, which caps maximum velocity
# and also causes ship to slowly stop by itself when thrusters are off
self.vel[0] *= .99
self.vel[1] *= .99
if self.thrust == True:
self.forward = angle_to_vector(self.angle)
self.vel[0] += self.forward[0] * .12
self.vel[1] += self.forward[1] * .12
def keydown(self,key):
ang_vel = .09
if key == simplegui.KEY_MAP['left']:
self.angle_vel = - ang_vel
elif key == simplegui.KEY_MAP['right']:
self.angle_vel = ang_vel
elif key == simplegui.KEY_MAP['up']:
self.thrust = True
if self.thrust == True:
sound = ship_thrust_sound
sound.play()
elif key == simplegui.KEY_MAP['space']:
self.shoot()
def keyup(self,key):
angle_vel = 0
if key == simplegui.KEY_MAP['right']:
my_ship.angle_vel = angle_vel
elif key == simplegui.KEY_MAP['left']:
my_ship.angle_vel = angle_vel
elif key == simplegui.KEY_MAP['up']:
self.thrust = False
if self.thrust == False:
self.forward = [0,0]
sound = ship_thrust_sound
sound.pause()
def shoot(self):
global a_missile
vector = angle_to_vector(my_ship.angle)
a_missile = Sprite([my_ship.pos[0] + (vector[0] * my_ship.radius),my_ship.pos[1] + (vector[1] * my_ship.radius)], [my_ship.vel[0] + (vector[0] * 5),my_ship.vel[1] + (vector[1] * 5)], 0, 0, missile_image, missile_info, missile_sound)
# Sprite class
class Sprite:
def __init__(self, pos, vel, ang, ang_vel, image, info, sound = None):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.angle = ang
self.angle_vel = ang_vel
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
self.lifespan = info.get_lifespan()
self.animated = info.get_animated()
self.age = 0
if sound:
sound.rewind()
sound.play()
def draw(self, canvas):
canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle)
def update(self):
self.pos[0] += self.vel[0]
self.pos[1] += self.vel[1]
self.angle += self.angle_vel
def draw(canvas):
global time
# animate background
time += 1
center = debris_info.get_center()
size = debris_info.get_size()
wtime = (time / 8) % center[0]
canvas.draw_image(nebula_image, nebula_info.get_center(), nebula_info.get_size(), [width/2, height/2], [width, height])
canvas.draw_image(debris_image, [center[0]-wtime, center[1]], [size[0]-2*wtime, size[1]],
[width/2+1.25*wtime, height/2], [width-2.5*wtime, height])
canvas.draw_image(debris_image, [size[0]-wtime, center[1]], [2*wtime, size[1]],
[1.25*wtime, height/2], [2.5*wtime, height])
# draw ship and sprites
my_ship.draw(canvas)
a_rock.draw(canvas)
a_missile.draw(canvas)
# update ship and sprites
my_ship.update()
a_rock.update()
a_missile.update()
# timer handler that spawns a rock
def rock_spawner():
global a_rock
a_rock = Sprite([width * random.random(), height * random.random()], [random.random() * 3 - 1.5,random.random() * 3 - 1.5], 0, (random.random() - .5) / 8, asteroid_image, asteroid_info)
def key_down(key):
my_ship.keydown(key)
def key_up(key):
my_ship.keyup(key)
# initialize frame
frame = simplegui.create_frame("Asteroids", width, height)
# initialize ship and two sprites
my_ship = Ship([width / 2, height / 2], [0, 0], 1.5 * math.pi, ship_image, ship_info)
a_rock = Sprite([width * random.random(), height * random.random()], [random.random() * 3 - 1.5,random.random() * 3 - 1.5], 0, (random.random() - .5) / 8, asteroid_image, asteroid_info)
a_missile = Sprite([2 * width / 3, 2 * height / 3], [-1,1], 0, 0, missile_image, missile_info, missile_sound)
# register handlers
frame.set_draw_handler(draw)
frame.set_keydown_handler(key_down)
frame.set_keyup_handler(key_up)
timer = simplegui.create_timer(1000.0, rock_spawner)
# get things rolling
timer.start()
frame.start()
No comments:
Post a Comment