Created
November 25, 2014 19:07
-
-
Save qzdc00/0b3684cf469c2e0f0abd to your computer and use it in GitHub Desktop.
homework for PythonMOOC one year ago...... http://www.codeskulptor.org/#user38_U8p9m2tTUF_2.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# implementation of Spaceship - program template for RiceRocks | |
import simplegui | |
import math | |
import random | |
# globals for user interface | |
WIDTH = 800 | |
HEIGHT = 600 | |
score = 0 | |
lives = 3 | |
time = 0 | |
started = False | |
sc = 0 | |
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.f2013.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 | |
# .ogg versions of sounds are also available, just replace .mp3 by .ogg | |
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() | |
def draw(self,canvas): | |
if self.thrust: | |
canvas.draw_image(self.image, [self.image_center[0] + self.image_size[0], self.image_center[1]] , self.image_size, | |
self.pos, self.image_size, self.angle) | |
else: | |
canvas.draw_image(self.image, self.image_center, self.image_size, | |
self.pos, self.image_size, self.angle) | |
# canvas.draw_circle(self.pos, self.radius, 1, "White", "White") | |
def update(self): | |
# update angle | |
self.angle += self.angle_vel | |
# update position | |
self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH | |
self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT | |
# update velocity | |
if self.thrust: | |
acc = angle_to_vector(self.angle) | |
self.vel[0] += acc[0] * .1 | |
self.vel[1] += acc[1] * .1 | |
self.vel[0] *= .99 | |
self.vel[1] *= .99 | |
def set_thrust(self, on): | |
self.thrust = on | |
if on: | |
ship_thrust_sound.rewind() | |
ship_thrust_sound.play() | |
else: | |
ship_thrust_sound.pause() | |
def increment_angle_vel(self): | |
self.angle_vel += .05 | |
def decrement_angle_vel(self): | |
self.angle_vel -= .05 | |
def get_pos(self): | |
return self.pos | |
def get_radius(self): | |
return self.radius | |
def shoot(self): | |
global missile_group | |
forward = angle_to_vector(self.angle) | |
missile_pos = [self.pos[0] + self.radius * forward[0], self.pos[1] + self.radius * forward[1]] | |
missile_vel = [self.vel[0] + 6 * forward[0], self.vel[1] + 6 * forward[1]] | |
missile = Sprite(missile_pos, missile_vel, 0, 0, missile_image, missile_info, missile_sound) | |
missile_group.add(missile) | |
# 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): | |
# update angle | |
self.angle += self.angle_vel | |
self.age += 1.5 | |
# update position | |
self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH | |
self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT | |
if self.age >= self.lifespan: | |
return True | |
else: | |
return False | |
def get_pos(self): | |
return self.pos | |
def get_radius(self): | |
return self.radius | |
def collide(self, other_object): | |
if dist(self.get_pos(), other_object.get_pos()) <= (self.get_radius() + other_object.get_radius()): | |
return True | |
else: | |
return False | |
# key handlers to control ship | |
def keydown(key): | |
if key == simplegui.KEY_MAP['left']: | |
my_ship.decrement_angle_vel() | |
elif key == simplegui.KEY_MAP['right']: | |
my_ship.increment_angle_vel() | |
elif key == simplegui.KEY_MAP['up']: | |
my_ship.set_thrust(True) | |
elif key == simplegui.KEY_MAP['space']: | |
my_ship.shoot() | |
def keyup(key): | |
if key == simplegui.KEY_MAP['left']: | |
my_ship.increment_angle_vel() | |
elif key == simplegui.KEY_MAP['right']: | |
my_ship.decrement_angle_vel() | |
elif key == simplegui.KEY_MAP['up']: | |
my_ship.set_thrust(False) | |
# process_sprite_group | |
def process_sprite_group(aset, canvas): | |
bset = set([]) | |
bset = aset | |
for objects in bset: | |
objects.draw(canvas) | |
objects.update() | |
if objects.update() == True: | |
bset.discard(objects) | |
# group_collide | |
def group_collide(aset, other_object): | |
bset = set([]) | |
bset = aset | |
remove = set([]) | |
i = 0 | |
for obj in bset: | |
if obj.collide(other_object) == True: | |
bset.discard(obj) | |
i = 1 | |
if i == 0: | |
return False | |
else: | |
return True | |
# group_group_collide | |
def group_group_collide(obj1, obj2): | |
objects = set([]) | |
global sc | |
for elem in obj2: | |
objects = elem | |
if group_collide(obj1, elem) == True: | |
sc += 1 | |
obj2.discard(elem) | |
return sc | |
# mouseclick handlers that reset UI and conditions whether splash image is drawn | |
def click(pos): | |
global started | |
center = [WIDTH / 2, HEIGHT / 2] | |
size = splash_info.get_size() | |
inwidth = (center[0] - size[0] / 2) < pos[0] < (center[0] + size[0] / 2) | |
inheight = (center[1] - size[1] / 2) < pos[1] < (center[1] + size[1] / 2) | |
if (not started) and inwidth and inheight: | |
started = True | |
def draw(canvas): | |
global time, started, lives, score | |
# animiate background | |
time += 1 | |
wtime = (time / 4) % WIDTH | |
center = debris_info.get_center() | |
size = debris_info.get_size() | |
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, size, (wtime - WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT)) | |
canvas.draw_image(debris_image, center, size, (wtime + WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT)) | |
# restart | |
if lives == 0: | |
started = False | |
score = 0 | |
lives = 3 | |
for rocks in rock_group: | |
rock_group.discard(rocks) | |
#group collide | |
if group_collide(rock_group, my_ship) == True: | |
lives -= 1 | |
# group-group collide | |
score = group_group_collide(rock_group, missile_group)* 50 | |
# draw UI | |
canvas.draw_text("Lives", [50, 50], 22, "White") | |
canvas.draw_text("Score", [680, 50], 22, "White") | |
canvas.draw_text(str(lives), [50, 80], 22, "White") | |
canvas.draw_text(str(score), [680, 80], 22, "White") | |
# draw ship and sprites | |
my_ship.draw(canvas) | |
process_sprite_group(missile_group, canvas) | |
process_sprite_group(rock_group, canvas) | |
# update ship and sprites | |
my_ship.update() | |
# draw splash screen if not started | |
if not started: | |
canvas.draw_image(splash_image, splash_info.get_center(), | |
splash_info.get_size(), [WIDTH / 2, HEIGHT / 2], | |
splash_info.get_size()) | |
# timer handler that spawns a rock | |
def rock_spawner(): | |
global rock_group, rock | |
rock_pos = [random.randrange(0, WIDTH), random.randrange(0, HEIGHT)] | |
rock_vel = [random.random() * .6 - .3, random.random() * .6 - .3] | |
rock_avel = random.random() * .2 - .1 | |
rock = Sprite(rock_pos, rock_vel, 0, rock_avel, asteroid_image, asteroid_info) | |
if len(rock_group) < 12 and started == True and dist(rock.pos, my_ship.pos) >= 200: | |
rock_group.add(rock) | |
# initialize stuff | |
frame = simplegui.create_frame("Asteroids", WIDTH, HEIGHT) | |
# initialize ship and two sprites | |
my_ship = Ship([WIDTH / 2, HEIGHT / 2], [0, 0], 0, ship_image, ship_info) | |
rock_group = set([]) | |
missile_group = set([]) | |
# register handlers | |
frame.set_keyup_handler(keyup) | |
frame.set_keydown_handler(keydown) | |
frame.set_mouseclick_handler(click) | |
frame.set_draw_handler(draw) | |
timer = simplegui.create_timer(1000.0, rock_spawner) | |
# get things rolling | |
timer.start() | |
frame.start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment