课程全名: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. 新版react踩坑总结

    使用es6语法与原本es5语法几个有区别的地方 1.React.creatClass与React.Component var Component = React.createClass({ rende ...

  2. iOS错误总结(三)

    1.如果tableView设置为分组的样式(默认是有cell之间的分割线,可以设置颜色),默认有组以及组尾的高度 需要手动在组头组尾的代理方法中进行组高的设置(如果想设置为0,最好写0.01) 2.组 ...

  3. Javascript中DOM的练习

    第一个题:html计时器 方法一: <body onLoad="show()" > <div id="b"></div> & ...

  4. logback logback.xml常用配置详解(三) <filter>

    <filter>: 过滤器,执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一.返回DENY,日志将立即被抛弃不再经过其他过滤器:返回NEUTRAL,有序列表 ...

  5. linux 程序管理与SElinux

    此文涉及的命令:&.jobs.fg.bg.kill.nohup.ps.top.pstree.free.uname.uptime.netstat.dmesg.vmstat.fuser.lsof. ...

  6. [转载]Matlab之静态文本多行输出

    转载文章,原文链接:Matlab中的静态文本框中显示多行内容 有时候,我们在GUI中利用静态文本框显示程序的结果,但是结果很长,一行未必可以显示的开,而静态文本框不像edit或listbox那样通过滚 ...

  7. MINA系列学习-mina整体介绍

    今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...

  8. 04 Apache Solr: 目录结构

         通过前面的介绍,我们已经能够看到管理员界面并对Solr形成了一个感性的认识.本篇将在物理上深入了解Solr的安装目录结构和Solr示例的主目录结构.   安装目录结构 Solr 6.3.0安 ...

  9. jquery each遍历节点使用

    ---恢复内容开始--- $("#aaa :input[type='text']").each(function(i){     alert(this.value); this.v ...

  10. C#(asp.net )读取ASHX文件(一般处理程序)

    c#后台获取asxh的返回数据,后台创建一个请求实例,获取请求实例的返回值 public string GetResponseByPost(string apiUrl, string queryStr ...