课程全名: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的更多相关文章

  1. Mini projects #7 ---- Spaceship

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

  2. Mini projects #8–RiceRocks

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

  3. Mini projects #6 ---- Blackjack

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

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

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

  5. Mini projects #5 ---- Memory

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

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

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

  7. 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 ...

  8. 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, ...

  9. All the Apache Streaming Projects: An Exploratory Guide

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

随机推荐

  1. Android(Logcat、Monitors)

    刚学习Android 的时候总喜欢输出"Hello Word"这样的信息来判断是不是执行了某个方法,最初连Android Studio控制台.断点这些在哪里都要找好久,现在好了多点 ...

  2. vs2010边调试边编辑后台.cs文件的办法

    方法一:在web项目的属性页里的web标签页,选中“启用编辑并继续”项 方法二:菜单 工具+选项+调试+编辑并继续,选中“启用编辑并继续”项. 设置完之后,调试web项目的时候可以直接修改.cs文件, ...

  3. jquery实现动画

    animate() 方法 语法: $(selector).animate({params},speed,callback); 必需的 params 参数定义形成动画的 CSS 属性. 可选的 spee ...

  4. exception 'DOMException' with message 'Invalid Character Error' Php + Mongodb

    问题描述: 项目属于MVC设计模式,技术和框架采用了php5.6 + Yii2.0 + MongoDB. 在我从Controller中调用Model 的 findAll([]) 方法获取数据打印到屏幕 ...

  5. AWT布局管理器

    布局管理器 容器内可以存放各种组件,而组件的位置和大小是由容器内的布局管理器来决定的.在AWT中为我们提供了以下5种布局管理器: ①   FlowLayout 流式布局管理器 ②   BorderLa ...

  6. UIAlertViewController的使用

    UIAlertViewController是苹果自带的信息提示框,仅在iOS8.0以后可以使用 NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertContro ...

  7. FormatMessage与GetLastError配合使用,排查windows api调用过程中的错误

    前一段时间在学习windows api调用过程中,遇到过一些调用错误或者程序没能显示预期的结果,或者直接出现vc运行时错误. 这对新手来说是司空见惯的事,因为不太熟悉难免会出错,出错的信息如果能显示很 ...

  8. selenium2(WebDriver)环境搭建

    1.安装jdk并配置环境变量: jdk安装jdk下载地址: http://www.oracle.com/technetwork/java/javase/downloads/index.html环境变量 ...

  9. 非阻塞同步算法实战(二)-BoundlessCyclicBarrier

    本人是本文的作者,首发于ifeve(非阻塞同步算法实战(二)-BoundlessCyclicBarrier) 前言 相比上一 篇而言,本文不需要太多的准备知识,但技巧性更强一些.因为分析.设计的过程比 ...

  10. NOIP2016普及组

    普及组.代码有空发. 第一题就是买铅笔.暴力模拟绝对可取. 第二题就是回文日期.从t1的年份到t2的年份枚举每一年.头尾要特判. 第三题就是海港.骗了40分. 第四题就是魔法阵.不太好优化. 完.