课程全名:An Introduction to Interactive Programming in Python,来自 Rice University

授课教授:Joe Warren, Scott Rixner, John Greiner, Stephen Wong

工具:http://www.codeskulptor.org/, simplegui 模块

最后两周就要结束了~~~

第七周:

先上图,这周完成Spaceship游戏的一部分。

在这图里面有什么?飞船,陨石,子弹,背景图….

用OO的对象来看,他们都对应一幅图像,那么抽象一个类ImageInfo来操作这些图像信息,它包括图像的center(中心位置),size(图像大小),radius(半径),lifespan(时间周期),animated(动画)。可能有些属性比较陌生,有些针对到具体的对象才有用。

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

有了图像的表示,那么我们还需要飞船,用Ship来表示

Ship有什么属性和方法呢?

pos:位置

vel:加速度

thrust:冲刺状态

angle:飞船旋转的角度

angle_vel:飞船旋转角速度

image:飞船图像

image_cener:飞船图像的中心位置

image_size:飞船图像的大小

image_radius:飞船半径?(这周作业没用到,不知道干嘛的)

飞船的方法:

draw(canvas): 绘制飞船,要求绘制根据是否在冲刺状态,绘制图像不同。所给的飞船image是tiled图像,所以绘制时候计算一下偏移就好

update():更新当前飞船位置以及角度。基本所有涉及到简单数学计算的公式,课上以及相关ppt都给出来,都比较简单,直接拿来用。对于角度的更新和Pong那周一样,用左右按键按下增加旋转角速度,放开减少旋转角速度,每次更新的时候就只用把飞船的角度加上旋转角速度。

飞船的位置更新同理,使用位置加上加速度,但是要考虑飞出边界,所以对WIDTH和HEIGHT分别取模。

这边与Pong不同的是加速度的计算,Pong只有上下方向,但这里飞船可以旋转指向各个方向,所以加速度修改飞船向着它转角的方向,原理还是一样,把转角方向向水平和垂直方向做投影乘以常量,然后加到原有的加速度上。

最后剩下的一个问题就是,外太空有<阻力>,所以飞船会不断减速直到速度为0,那么不断按照一定的比例缩小飞船的加速度,直到加速度为0,飞船的位置就不更新了。

update()的代码如下:

def update(self):
self.angle += self.angle_vel
self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH
self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT
c = 0.05
self.vel[0] *= (1 - c)
self.vel[1] *= (1 - c)
forward = angle_to_vector(self.angle)
if self.thrust:
self.vel[0] += forward[0] * 1.2
self.vel[1] += forward[1] * 1.2

change_angle_vel(ori, key_state):根据按键是left或者right和按键当前状态是按下或者松开,来改变飞船的旋转角速度

set_thruster(thruster_state):根据up按键来改变飞船的冲刺状态,并且播放和暂停响应的声音效果

shoot(): 飞船发子弹,初始化子弹,它的位置在飞船的炮孔位置,然后子弹的加速度等于,飞船的加速度,加上飞船角度在水平垂直分量的常量倍,这与飞船的加速思路一样的,子弹的角度和旋转角速度设置成0就好。

飞船处理完了,剩下的就是陨石和子弹,给的template中用sprite来抽象表示他们。

基本的属性和飞船差不多,pos, vel, angle, angle_vel, image, image_center, image_size, radius,多了lifespan, animated, age还有sound

主要方法:

draw(canvas): 直接根据image的信息进行绘制

update(canvas): 更新角度和位置,与飞船类似。超出边界要取模

其他的部分就是frame的draw事件模板里已经写好,key_up,key_down事件,上面也都提到处理方法。

这周的任务也就这样完工了。

完整的代码如下:

# 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.f2014.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() def draw(self,canvas):
if self.thrust:
center = (self.image_center[0]+self.image_size[0], self.image_center[1])
canvas.draw_image(self.image, center, 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) def update(self):
self.angle += self.angle_vel
self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH
self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT
c = 0.05
self.vel[0] *= (1 - c)
self.vel[1] *= (1 - c)
forward = angle_to_vector(self.angle)
if self.thrust:
self.vel[0] += forward[0] * 1.2
self.vel[1] += forward[1] * 1.2 def change_angle_vel(self, ori, key_state):
if ((ori == "right" and key_state == "keyup") or
(ori == "left" and key_state == "keydown")):
self.angle_vel -= 0.1
elif ((ori == "right" and key_state == "keydown") or
(ori == "left" and key_state == "keyup")):
self.angle_vel += 0.1 def set_thruster(self, thruster_state):
self.thrust = thruster_state
if self.thrust:
ship_thrust_sound.rewind()
ship_thrust_sound.play()
else:
ship_thrust_sound.rewind() def shoot(self):
global a_missile
offset = self.image_size[0] / 2.0
forward = angle_to_vector(self.angle)
pos = [self.pos[0] + offset * forward[0], self.pos[1] + offset * forward[1]]
vel = [self.vel[0] + 4 * forward[0], self.vel[1] + 4 * forward[1]]
ang = 0
ang_vel = 0
a_missile = Sprite(pos, vel, ang, ang_vel, 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.angle += self.angle_vel
self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH
self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT def draw(canvas):
global time # 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)) # 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() # draw lives
canvas.draw_text("Lives", [WIDTH / 12, HEIGHT / 12], 30, "White")
canvas.draw_text(str(lives), [WIDTH / 12, HEIGHT / 12 + 40], 30, "White") # draw score
canvas.draw_text("Score", [10 * WIDTH / 12, HEIGHT/12], 30, "White")
canvas.draw_text(str(score), [10 * WIDTH /12, HEIGHT/12 + 40], 30, "White") # timer handler that spawns a rock
def rock_spawner():
global a_rock
pos = [random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1)]
vel = [random.randrange(1, 5, 1)*random.choice([1, -1]), random.randrange(1, 5, 1)*random.choice([1, -1])]
ang = 0
ang_vel = random.randrange(5, 10, 1) / 100.0 * random.choice([1, -1])
a_rock = Sprite(pos, vel, ang, ang_vel, asteroid_image, asteroid_info) def key_up(key):
if simplegui.KEY_MAP['left'] == key:
my_ship.change_angle_vel("left", "keyup")
elif simplegui.KEY_MAP['right'] == key:
my_ship.change_angle_vel("right", "keyup")
elif simplegui.KEY_MAP['up'] == key:
my_ship.set_thruster(False) def key_down(key):
if simplegui.KEY_MAP['left'] == key:
my_ship.change_angle_vel("left", "keydown")
elif simplegui.KEY_MAP['right'] == key:
my_ship.change_angle_vel("right", "keydown")
elif simplegui.KEY_MAP['up'] == key:
my_ship.set_thruster(True)
elif simplegui.KEY_MAP['space'] == key:
my_ship.shoot() # initialize frame
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)
a_rock = Sprite([WIDTH / 3, HEIGHT / 3], [1, 1], 0, 0, 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()

期待着最后一周,游戏完整的代码。就要完成Coursera的一门这么有意思的课,课程难度很小,乐趣十足。

Mini projects #7 ---- Spaceship的更多相关文章

  1. Mini projects #8–RiceRocks

    课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...

  2. Mini projects #6 ---- Blackjack

    课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...

  3. Mini projects #3 ---- Stopwatch: The Game

    课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...

  4. Mini projects #5 ---- Memory

    课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...

  5. Mini projects #4 ---- Pong

    课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...

  6. A Complete List of .NET Open Source Developer Projects

    http://scottge.net/2015/07/08/a-complete-list-of-net-open-source-developer-projects/?utm_source=tuic ...

  7. Building Xcode iOS projects and creating *.ipa file from the command line

    For our development process of iOS applications, we are using Jenkins set up on the Mac Mini Server, ...

  8. All the Apache Streaming Projects: An Exploratory Guide

    The speed at which data is generated, consumed, processed, and analyzed is increasing at an unbeliev ...

  9. Golang优秀开源项目汇总, 10大流行Go语言开源项目, golang 开源项目全集(golang/go/wiki/Projects), GitHub上优秀的Go开源项目

    Golang优秀开源项目汇总(持续更新...)我把这个汇总放在github上了, 后面更新也会在github上更新. https://github.com/hackstoic/golang-open- ...

随机推荐

  1. crontab使用

    结合一条命令:0 */4 * * * curl http://xxxx.abc.com/admin.php?s=/Crontab/exec_114study_urltags

  2. [ftp]Centos 创建 sftp 步骤

    来自:http://blog.csdn.net/xinxin19881112/article/details/46831311 1.创建sftp组 groupadd sftp 2.创建一个sftp用户 ...

  3. 常用的PHP框架

    ThinkPHP  http://www.thinkphp.cn Yii            http://www.yiichina.com laravel      https://laravel ...

  4. CoordinatorLayout+TabLayout+ViewPager

    <?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.C ...

  5. 启动Tomcat时报 Expected stackmap frame at this location.(JDK1.7编译)

    从svn上下的项目,部署到tomcat 7.0.19 上, 并且配置的是jdk7.  启动时出现以下问题. Location: com/genlot/loms/service/SysPermissio ...

  6. C++基础-01

    指针 - 指针的基本操作间接引用指针所指向的对象 - 机器一般按字节寻址,所以能够独立分配的最小空间是1字节,也就是说指针指向的 最小空间为1字节.特别地,对于bool变量,虽然实际需要的是1bit, ...

  7. Spring环境搭建之:导入jar包、配置文件名称及放置位置

    Spring环境搭建之:导入jar包.配置文件名称及放置位置 现在项目开发中spring框架应用的还是比较多的,自己用的还不太熟练,每次用的时候总配置半天,总有些配置弄错,就找个时间总结以下,方便以后 ...

  8. jdk8 Lambda表达式与匿名内部类比较

    Labmda表达式与匿名内部类 前言 Java Labmda表达式的一个重要用法是简化某些匿名内部类(Anonymous Classes)的写法.实际上Lambda表达式并不仅仅是匿名内部类的语法糖, ...

  9. 清空IE缓存

    1.打开IE Internet选项 点击设置 2.打开临时文件 点击 查看文件 将目录下的 文件全部删除  重新打开网站即可 到此IE缓存就被删除.

  10. HandlerThread源码分析

    其实原本HandlerThread的分析不应该单独开一篇博客的,应该在讲消息机制的那一片中一起分析. 但当时忘记了,而且今天第一次用MarkDown写博客,有点上瘾,就再来一篇,权当滥竽充数过过手瘾. ...