Mini projects #4 ---- Pong
课程全名:An Introduction to Interactive Programming in Python,来自 Rice University
授课教授:Joe Warren, Scott Rixner, John Greiner, Stephen Wong
工具:http://www.codeskulptor.org/, simplegui 模块
第四次作业,完成一个弹球的游戏,游戏的界面如下,规则也很简单,球不断在两边的paddle之间撞击后速度会不断加快,直到有一名玩家无法将球回击,则另一名玩家得分。
之前得了解一下控制物体移动的方式。
假设物体与点p相对应,第一种方式是直接通过控制点p的坐标来实现移动。
在draw_handler中不用进行更新,只用绘制他的position就可以
坐标的变化放在key_handler中进行修改,比如
key_handler:
Left Arrow –> p[0] –= c
Right Arrow –> p[0] += c
Up Arrow –> p[1] –= c
Down Arrow –> p[1] += c
代码如下:
import simplegui WIDTH = 500
HEIGHT = 300
p = [WIDTH/2, HEIGHT/2] def draw(canvas):
canvas.draw_circle(p, 30, 1, "White", "White") def key_down(key):
c = 4
if key == simplegui.KEY_MAP['up']:
p[1] -= c
elif key == simplegui.KEY_MAP['down']:
p[1] +=c
elif key == simplegui.KEY_MAP['left']:
p[0] -= c
elif key == simplegui.KEY_MAP['right']:
p[0] += c # Create a frame and assign callbacks to event handlers
frame = simplegui.create_frame("Position Control", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(key_down) # Start the frame animation
frame.start()
第二种方式通过控制点p的速率(velocity)变化来实现移动。
draw_handler中进行坐标的更新和绘制
在key_handler中进行速率的调整
draw_handler:
p[0] += v[0]
p[1] += v[1]
key_handler:
Left Arrow –> v[0] –= c
Right Arrow –> v[0] += c
Up Arrow –> v[1] –= c
Down Arrow –> v[1] += c
代码如下:
import simplegui WIDTH = 500
HEIGHT = 300
v = [0, 0]
p = [WIDTH/2, HEIGHT/2] def draw(canvas):
p[0] += v[0]
p[1] += v[1]
canvas.draw_circle(p, 30, 1, "White", "White") def key_down(key):
c = 1
if key == simplegui.KEY_MAP['up']:
v[1] -= c
elif key == simplegui.KEY_MAP['down']:
v[1] +=c
elif key == simplegui.KEY_MAP['left']:
v[0] -= c
elif key == simplegui.KEY_MAP['right']:
v[0] += c # Create a frame and assign callbacks to event handlers
frame = simplegui.create_frame("Position Control", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(key_down) # Start the frame animation
frame.start()
这里再提一下碰撞的处理,上下碰撞,只用把v[1]的方向取反,左右碰撞,把v[0]的方向取反。
主要就是边界位置的判断,对于一个假定中心为p,半径为r的求来说:
碰撞如下:
Left Wall:
p[0] <= r
Right Wall:
p[0] >= (width-1)-r
Top Wall:
p[1] <= r
Bottom Wall:
p[1] >= (height-1)-r
下面两张图来自老师的课件,关于定义


回归到这个游戏,基本要用到的知识也就这么多,移动paddle处理方式稍微特殊一点,keydown_handler进行velocity的正方向增加,那么keyup_handler进行velocity的负方向增加,这样就可以实现,按下按键后paddle持续移动,释放按键后paddle停止移动。
对于小球,初始随机给一个velocity,只要不是垂直或者水平,然后处理碰撞,在进行paddle碰撞后,要给予小球10%velocity上的增量。
完整代码如下:
# Implementation of classic arcade game Pong import simplegui
import random # initialize globals - pos and vel encode vertical info for paddles
WIDTH = 600
HEIGHT = 400
BALL_RADIUS = 20
PAD_WIDTH = 8
PAD_HEIGHT = 80
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2
LEFT = False
RIGHT = True # initialize ball_pos and ball_vel for new bal in middle of table
# if direction is RIGHT, the ball's velocity is upper right, else upper left
def spawn_ball(direction):
global ball_pos, ball_vel # these are vectors stored as lists
ball_pos = [WIDTH/2, HEIGHT/2]
ball_dir = 1 if direction == RIGHT else -1
ball_vel = [ball_dir * random.randrange(2, 4), -random.randrange(1, 3)] # define event handlers
def new_game():
global paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel # these are numbers
global score1, score2 # these are ints
spawn_ball(random.choice([LEFT, RIGHT]))
paddle1_pos, paddle2_pos = HEIGHT / 2, HEIGHT / 2
paddle1_vel, paddle2_vel = 0, 0
score1, score2 = 0, 0 def draw(canvas):
global score1, score2, paddle1_pos, paddle2_pos, ball_pos, ball_vel # draw mid line and gutters
canvas.draw_line([WIDTH / 2, 0],[WIDTH / 2, HEIGHT], 1, "White")
canvas.draw_line([PAD_WIDTH, 0],[PAD_WIDTH, HEIGHT], 1, "White")
canvas.draw_line([WIDTH - PAD_WIDTH, 0],[WIDTH - PAD_WIDTH, HEIGHT], 1, "White") # update ball
new_ball_posX = ball_pos[0] + ball_vel[0]
new_ball_posY = ball_pos[1] + ball_vel[1]
if new_ball_posY <= BALL_RADIUS:
ball_pos[1] = BALL_RADIUS
ball_vel[1] *= -1
elif new_ball_posY >= HEIGHT - 1 - BALL_RADIUS:
ball_pos[1] = HEIGHT - 1 - BALL_RADIUS
ball_vel[1] *= -1
else:
ball_pos[1] = new_ball_posY # hit the left gutter
if new_ball_posX <= PAD_WIDTH + BALL_RADIUS:
ball_pos[0] = PAD_WIDTH + BALL_RADIUS
if (ball_pos[1] >= paddle1_pos - HALF_PAD_HEIGHT
and ball_pos[1] <= paddle1_pos + HALF_PAD_HEIGHT):
ball_vel[0] = -(ball_vel[0] + 0.1 * ball_vel[0])
ball_vel[1] = ball_vel[1] + 0.1 * ball_vel[1]
else:
score2 = score2 + 1
spawn_ball(RIGHT) # hit the right gutter
elif new_ball_posX >= WIDTH - PAD_WIDTH - BALL_RADIUS:
ball_pos[0] = WIDTH - PAD_WIDTH - BALL_RADIUS
if (ball_pos[1] >= paddle2_pos - HALF_PAD_HEIGHT
and ball_pos[1] <= paddle2_pos + HALF_PAD_HEIGHT):
ball_vel[0] = -(ball_vel[0] + 0.1 * ball_vel[0])
ball_vel[1] = ball_vel[1] + 0.1 * ball_vel[1]
else:
score1 = score1 + 1
spawn_ball(LEFT)
else:
ball_pos[0] = new_ball_posX # draw ball
canvas.draw_circle(ball_pos, BALL_RADIUS, 1, "White", "White") # update paddle's vertical position, keep paddle on the screen
new_paddle1_pos = paddle1_pos + paddle1_vel
if new_paddle1_pos <= HALF_PAD_HEIGHT:
paddle1_pos = HALF_PAD_HEIGHT
elif new_paddle1_pos >= HEIGHT-HALF_PAD_HEIGHT:
paddle1_pos = HEIGHT-HALF_PAD_HEIGHT
else:
paddle1_pos = new_paddle1_pos new_paddle2_pos = paddle2_pos + paddle2_vel
if new_paddle2_pos <= HALF_PAD_HEIGHT:
paddle2_pos = HALF_PAD_HEIGHT
elif new_paddle2_pos >= HEIGHT-HALF_PAD_HEIGHT:
paddle2_pos = HEIGHT-HALF_PAD_HEIGHT
else:
paddle2_pos = new_paddle2_pos # draw paddles
canvas.draw_polygon([[0, paddle1_pos-HALF_PAD_HEIGHT],
[PAD_WIDTH-1, paddle1_pos-HALF_PAD_HEIGHT],
[PAD_WIDTH-1, paddle1_pos+HALF_PAD_HEIGHT],
[0, paddle1_pos+HALF_PAD_HEIGHT]], 1, "White", "White")
canvas.draw_polygon([[WIDTH-PAD_WIDTH+1, paddle2_pos-HALF_PAD_HEIGHT],
[WIDTH, paddle2_pos-HALF_PAD_HEIGHT],
[WIDTH, paddle2_pos+HALF_PAD_HEIGHT],
[WIDTH-PAD_WIDTH+1, paddle2_pos+HALF_PAD_HEIGHT]], 1, "White", "White")
# draw scores
canvas.draw_text(str(score1), (WIDTH/4, HEIGHT/5), 50, "Red")
canvas.draw_text(str(score2), (WIDTH/4*3, HEIGHT/5), 50, "Red")
canvas.draw_text("Author: Tiny656", (WIDTH/5*3, HEIGHT/20*18), 18, "Green")
canvas.draw_text("Mail: 236798656@qq.com", (WIDTH/5*3, HEIGHT/20*19), 18, "Green") def keydown(key):
global paddle1_vel, paddle2_vel
acc = 3
if key == simplegui.KEY_MAP['w']:
paddle1_vel -= acc
elif key == simplegui.KEY_MAP['s']:
paddle1_vel += acc
if key == simplegui.KEY_MAP['up']:
paddle2_vel -= acc
elif key == simplegui.KEY_MAP['down']:
paddle2_vel += acc def keyup(key):
global paddle1_vel, paddle2_vel
acc = 3
if key == simplegui.KEY_MAP['w']:
paddle1_vel += acc
elif key == simplegui.KEY_MAP['s']:
paddle1_vel -= acc
if key == simplegui.KEY_MAP['up']:
paddle2_vel += acc
elif key == simplegui.KEY_MAP['down']:
paddle2_vel -= acc def reset():
new_game() # create frame
frame = simplegui.create_frame("Pong", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(keydown)
frame.set_keyup_handler(keyup)
frame.add_button("Reset", reset, 200) # start frame
new_game()
frame.start()
Mini projects #4 ---- Pong的更多相关文章
- Mini projects #7 ---- Spaceship
课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...
- Mini projects #8–RiceRocks
课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...
- Mini projects #6 ---- Blackjack
课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...
- Mini projects #3 ---- Stopwatch: The Game
课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...
- Mini projects #5 ---- Memory
课程全名:An Introduction to Interactive Programming in Python,来自 Rice University 授课教授:Joe Warren, Scott ...
- Golang优秀开源项目汇总, 10大流行Go语言开源项目, golang 开源项目全集(golang/go/wiki/Projects), GitHub上优秀的Go开源项目
Golang优秀开源项目汇总(持续更新...)我把这个汇总放在github上了, 后面更新也会在github上更新. https://github.com/hackstoic/golang-open- ...
- 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 ...
- 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, ...
- All the Apache Streaming Projects: An Exploratory Guide
The speed at which data is generated, consumed, processed, and analyzed is increasing at an unbeliev ...
随机推荐
- 新版react踩坑总结
使用es6语法与原本es5语法几个有区别的地方 1.React.creatClass与React.Component var Component = React.createClass({ rende ...
- iOS错误总结(三)
1.如果tableView设置为分组的样式(默认是有cell之间的分割线,可以设置颜色),默认有组以及组尾的高度 需要手动在组头组尾的代理方法中进行组高的设置(如果想设置为0,最好写0.01) 2.组 ...
- Javascript中DOM的练习
第一个题:html计时器 方法一: <body onLoad="show()" > <div id="b"></div> & ...
- logback logback.xml常用配置详解(三) <filter>
<filter>: 过滤器,执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一.返回DENY,日志将立即被抛弃不再经过其他过滤器:返回NEUTRAL,有序列表 ...
- linux 程序管理与SElinux
此文涉及的命令:&.jobs.fg.bg.kill.nohup.ps.top.pstree.free.uname.uptime.netstat.dmesg.vmstat.fuser.lsof. ...
- [转载]Matlab之静态文本多行输出
转载文章,原文链接:Matlab中的静态文本框中显示多行内容 有时候,我们在GUI中利用静态文本框显示程序的结果,但是结果很长,一行未必可以显示的开,而静态文本框不像edit或listbox那样通过滚 ...
- MINA系列学习-mina整体介绍
今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...
- 04 Apache Solr: 目录结构
通过前面的介绍,我们已经能够看到管理员界面并对Solr形成了一个感性的认识.本篇将在物理上深入了解Solr的安装目录结构和Solr示例的主目录结构. 安装目录结构 Solr 6.3.0安 ...
- jquery each遍历节点使用
---恢复内容开始--- $("#aaa :input[type='text']").each(function(i){ alert(this.value); this.v ...
- C#(asp.net )读取ASHX文件(一般处理程序)
c#后台获取asxh的返回数据,后台创建一个请求实例,获取请求实例的返回值 public string GetResponseByPost(string apiUrl, string queryStr ...