Mini-project # 4 - "Pong"___An Introduction to Interactive Programming in Python"RICE"
Mini-project #4 - "Pong"
In this project, we will build a version of Pong,
one of the first arcade video games (1972). While Pong is not particularly exciting compared to today's video games, Pong is relatively simple to build and provides a nice opportunity to work on the skills that you will need to build a game like Asteroids.
As usual, we have provided a program
template that can be used to guide your development of Pong.
Mini-project development process
- Add code to the program template that draws a ball moving across the Pong table. We recommend that you add the positional update for the ball to the draw handler as shown in the second part of the "Motion" video.
- Add code to the function
spawn_ballthat
spawns a ball in the middle of the table and assigns the ball a fixed velocity (for now). Ignore the parameterdirectionat
this point. - Add a call to
spawn_ballin
the functionnew_gamewhich starts a game of Pong. Note
that the program templates includes an initial call tonew_gamein
the main body of your program to get a game going immediately. - Modify your code such that the ball collides with and bounces off of the top and bottom walls. Experiment with different hard-coded initial velocities to test your code.
- Add randomization to the velocity in
spawn_ball(direction)The
velocity of the ball should be upwards and towards the right ifdirectionand upwards and towards the left if
== RIGHTdirection. The exact values for the horizontal and vertical components of this velocity should be generated using
== LEFTrandom.randrange().
For the horizontal velocity, we suggest a speed of aroundrandom.randrange(120,pixels per second. For the vertical velocity, we suggest a speed of around
240)random.randrange(60,pixels per second. (You will need to set the signs of velocities appropriately.)
180) - Add code to the draw handler that tests whether the ball touches/collides with the left and right gutters. (Remember that the gutters are offset from the left and right edges of the canvas by the width of the paddle as described
in the "Pong" video.) When the ball touches a gutter, use eitherspawn_ball(LEFT)orspawn_ball(RIGHT)to
respawn the ball in the center of the table headed towards the opposite gutter. - Next, add code that draws the left and right paddles in their respective gutters. The vertical positions of these two paddles should depend on two global variables. (In the template, the variables were
paddle1_posandpaddle2_pos.) - Add code that modifies the values of these vertical positions via an update in the draw handler. The update should reference two global variables that contain the vertical velocities of the paddles. (In the template, the variables
werepaddle1_velandpaddle2_vel.) - Update the values of these two vertical velocities using key handlers. The "w" and "s" keys should control the vertical velocity of the left paddle while the "Up arrow" and "Down arrow" key should control the velocity of the
right paddle. In our version of Pong, the left paddle moves up at a constant velocity if the "w" key is pressed and moves down at a constant velocity if the "s" is pressed and is motionless if neither is pressed. (The motion if both are pressed is up to you.)
To achieve this effect, you will need to use both a keydown and a keyup handler to increase/decrease the vertical velocity in an appropriate manner. - Restrict your paddles to stay entirely on the canvas by adding a check before you update the paddles' vertical positions in the draw handler. In particular, test whether the current update for a paddle's position will move part
of the paddle off of the screen. If it does, don't allow the update. - Modify your collision code for the left and right gutters in step 6 to check whether the ball is actually striking a paddle when it touches a gutter. If so, reflect the ball back into play. This collision model eliminates the
possibility of the ball striking the edge of the paddle and greatly simplifies your collision/reflection code. - To moderately increase the difficulty of your game, increase the velocity of the ball by 10% each time it strikes a paddle.
- Add scoring to the game as shown in the Pong video lecture. Each time the ball strikes the left or right gutter (but not a paddle), the opposite player receives a point and ball is respawned appropriately.
- Finally, add code to
new_gamewhich
resets the score before callingspawn_ball. Add a "Restart"
button that callsnew_gameto reset the score and relaunch
the ball.
Your final version of Pong should be remarkably similar to the original arcade Pong game. Our full implementation of Pong took a little
more than 100 lines of code with comments.
Grading Rubric - 19 pts total (scaled to 100 pts)
- 1 pt - The ball spawns in the middle of the canvas with either an upward left or an upward right velocity. No credit if the ball moves only horizontally left or right. Bleh, that would be boring!
- 2 pts - The ball bounces off of the top and bottom walls correctly. (1 pt each)
- 2 pts - The ball respawns in the middle of the screen when it strikes the left or right gutter but not the paddles. (1 pt for each side) Give credit for this item even if the ball hits the edge of the canvas instead of the gutter.
- 1 pt - The left and right gutters (instead of the edges of the canvas) are properly used as the edges of the table.
- 1 pt - The ball spawns moving towards the player that won the last point.
- 2 pts - The 'w' and 's' keys correctly control the velocity of the left paddle as described above. Please test each key in isolation. (1 pt if the paddle moves, but in an incorrect manner in response to 'w' and 's' key presses.)
- 2 pts - The up and down arrows keys correctly control the velocity of the right paddle as described above. Please test each key in isolation. (1 pt if the paddle moves, but in an incorrect manner in response to up and down arrow key presses.)
- 2 pts - The edge of each paddle is flush with the gutter. (1 pt per paddle)
- 2 pts - The paddles stay on the canvas at all times. (1 pt per paddle)
- 2 pts - The ball correctly bounces off the left and right paddles. (1 pt per paddle)
- 1 pt - The scoring text is positioned and updated appropriately. The positioning need only approximate that in the video.
- 1 pt - The game includes a "Restart" button that resets the score and relaunches the ball.
# 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 paddle1_pos = HEIGHT/2 - HALF_PAD_HEIGHT
paddle2_pos = HEIGHT/2 - HALF_PAD_HEIGHT
paddle1_vel = 0
paddle2_vel = 0
score1 = 0
score2 = 0 # initialize ball_pos and ball_vel for new bal in middle of table
ball_pos = [WIDTH/2, HEIGHT/2]
ball_vel = [1, 1]
# 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_vel = [1, 0]
if (direction == RIGHT):
ball_vel = [-random.randrange(120, 240), -random.randrange(60, 180)]
elif (direction == LEFT):
ball_vel = [random.randrange(120, 240), -random.randrange(60, 180)] # 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.randrange(0, 2))
score1 = 0
score2 = 0
paddle1_pos = HEIGHT/2 - HALF_PAD_HEIGHT
paddle2_pos = HEIGHT/2 - HALF_PAD_HEIGHT
paddle1_vel = 0
paddle2_vel = 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") # draw ball
canvas.draw_circle(ball_pos, BALL_RADIUS, 2, 'white','orange') #collides with and bounces off of the top and bottom walls.
if (ball_pos[1] <= BALL_RADIUS) or (ball_pos[1]>=HEIGHT-BALL_RADIUS):
ball_vel[1] = - ball_vel[1]
# touches/collides with the left and right gutters
if ball_pos[0] <= BALL_RADIUS+PAD_WIDTH:
if (paddle1_pos - HALF_PAD_HEIGHT)<= ball_pos[1] <= (paddle1_pos + HALF_PAD_HEIGHT):
ball_vel[0] = - ball_vel[0]
ball_vel[0] = ball_vel[0] * 1.1
ball_vel[1] = ball_vel[1] * 1.1
else:
spawn_ball(LEFT)
score2 += 1
elif ball_pos[0] >= WIDTH - BALL_RADIUS:
if (paddle2_pos - HALF_PAD_HEIGHT)<= ball_pos[1] <= (paddle2_pos + HALF_PAD_HEIGHT):
ball_vel[0] = - ball_vel[0]
ball_vel[0] = ball_vel[0] * 1.1
ball_vel[1] = ball_vel[1] * 1.1
else:
spawn_ball(RIGHT)
score1 += 1
# update ball
ball_pos[0] = ball_pos[0] + ball_vel[0] / 60
ball_pos[1] = ball_pos[1] + ball_vel[1] / 60 # update paddle's vertical position, keep paddle on the screen
paddle1_pos = paddle1_pos + paddle1_vel
paddle2_pos = paddle2_pos + paddle2_vel
if paddle1_pos < 40:
paddle1_pos = 40
if paddle2_pos < 40:
paddle2_pos = 40
if paddle1_pos > 360:
paddle1_pos= 360
if paddle2_pos> 360:
paddle2_pos= 360
# draw paddles
canvas.draw_line((HALF_PAD_WIDTH,paddle1_pos - HALF_PAD_HEIGHT), (HALF_PAD_WIDTH,paddle1_pos + HALF_PAD_HEIGHT),
8, 'white') canvas.draw_line((WIDTH-HALF_PAD_WIDTH,paddle2_pos - HALF_PAD_HEIGHT), (WIDTH-HALF_PAD_WIDTH,paddle2_pos + HALF_PAD_HEIGHT),
8, 'white')
# draw scores
canvas.draw_text(str(score1),[250,50], 60, 'white')
canvas.draw_text(str(score2),[320,50], 60, 'white')
def keydown(key):
global paddle1_vel, paddle2_vel
if key == simplegui.KEY_MAP["w"]:
paddle1_vel = -10 if key == simplegui.KEY_MAP["s"]:
paddle1_vel = 10
if key == simplegui.KEY_MAP["up"]:
paddle2_vel = -10
if key == simplegui.KEY_MAP["down"]:
paddle2_vel = 10
def keyup(key):
global paddle1_vel, paddle2_vel
if key == simplegui.KEY_MAP["w"]:
paddle1_vel = 0
if key == simplegui.KEY_MAP["s"]:
paddle1_vel = 0
if key == simplegui.KEY_MAP["up"]:
paddle2_vel = 0
if key == simplegui.KEY_MAP["down"]:
paddle2_vel = 0 # create frame
frame = simplegui.create_frame("Pong", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(keydown)
frame.set_keyup_handler(keyup)
button1 = frame.add_button('Restart', new_game, 50) # start frame
new_game()
frame.start()
Mini-project # 4 - "Pong"___An Introduction to Interactive Programming in Python"RICE"的更多相关文章
- Mini-project # 1 - Rock-paper-scissors-___An Introduction to Interactive Programming in Python"RICE"
Mini-project description - Rock-paper-scissors-lizard-Spock Rock-paper-scissors is a hand game that ...
- An Introduction to Interactive Programming in Python (Part 1) -- Week 2_3 练习
Mini-project description - Rock-paper-scissors-lizard-Spock Rock-paper-scissors is a hand game that ...
- An Introduction to Interactive Programming in Python
这是在coursera上面的一门学习pyhton的基础课程,由RICE的四位老师主讲.生动有趣,一共是9周的课程,每一周都会有一个小游戏,经历一遍,对编程会产生很大的兴趣. 所有的程序全部在老师开发的 ...
- 【python】An Introduction to Interactive Programming in Python(week two)
This is a note for https://class.coursera.org/interactivepython-005 In week two, I have learned: 1.e ...
- An Introduction to Interactive Programming in Python (Part 1) -- Week 2_2 练习
#Practice Exercises for Logic and Conditionals # Solve each of the practice exercises below. # 1.Wri ...
- An Introduction to Interactive Programming in Python (Part 1) -- Week 2_1 练习
# Practice Exercises for Functions # Solve each of the practice exercises below. # 1.Write a Python ...
- Quiz 6b Question 8————An Introduction to Interactive Programming in Python
Question 8 We can use loops to simulate natural processes over time. Write a program that calcula ...
- Quiz 6b Question 7————An Introduction to Interactive Programming in Python
Question 7 Convert the following English description into code. Initialize n to be 1000. Initiali ...
- Quiz 6a Question 7————An Introduction to Interactive Programming in Python
First, complete the following class definition: class BankAccount: def __init__(self, initial_bal ...
随机推荐
- tomcat链接mysql时超时报错java.io.EOFException: Can not read response from server. Expected to read 4 bytes,
需要在配置文件里加上下面就ok了 <property name=”minEvictableIdleTimeMillis” value=”1800000″ /> <property n ...
- openstack nova修改实例路径,虚拟磁盘路径
#实例路径 --instances_path=$state_path/instances #日志的目录 --logdir=/var/log/nova #nova的目录 --state_path=/va ...
- php抽象类和接口
接口 使用接口,你可以指定某个类必须实现那些方法,但是不需要定义这些方法的具体内容,我们可以通过interface来定义一个接口,就像定义标准类一样,但其中定义所有的方法都是空的,接口中定义的所有的方 ...
- poj1363Rails(栈模拟)
主题链接: id=1363">啊哈哈,点我点我 思路: 这道题就是一道简单的栈模拟. .. .我最開始认为难处理是当出栈后top指针变化了. .当不满足条件时入栈的当前位置怎么办.这时 ...
- linux线程之pthread_join和pthread_detach
在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死.在 被其他线程回收之前,它的存储器资源(例如栈)是不释放的.相反 ...
- CSS通用编码规范
CSS通用编码规范 总结一部分前端编码规范,CSS部分先奉上,大多比较通用,应该是主流方式吧. 1 前言 本文档的目标是使 CSS 代码在团队中风格保持一致,容易被理解和被维护. 尽管本文档是针对 C ...
- 一道试题引发的血案 int *ptr2=(int *)((int)a+1);
某日,看到一道比较恶心的C语言的试题,考了很多比较绕的知识点,嘴脸如下: int main(void) { int a[4] = {1, 2, 3, 4}; int *ptr1=(int *)(&am ...
- Java中Calender引用类型
某些时候需要使用深拷贝: Calendar startTime = (Calendar) this._paramModel.getStartTime().clone(); 这样对startTime.a ...
- oracle复制表数据,复制表结构
1.不同用户之间的表数据复制 2.同用户表之间的数据复制 3.B.x中个别字段转移到B.y的相同字段 4.只复制表结构 加入了一个永远不可能成立的条件1=2,则此时表示的是只复制表结构,但是不复制表内 ...
- vs2012-vs2013编译出来的程序不能在xp上运行解决方法
在链接标志中加入参数: /SUBSYSTEM:WINDOWS,"5.01" 在ide环境下: 项目属性-常规-平台工具集-Visual Studio 2013 - Windows ...