IIPP迷你项目(四)"Pong"

1 小球在墙面的反弹

1-1 让小球在画布上匀速运动

在这一步中,首先应该明确小球是如何匀速运动的。它的方法是规定一个列表v,Scott老师说这代表着“速度(Velocity)”,但是我觉得也可以拿“向量(Vector)”理解,它指明了“小球该往哪个方向运动”。

现在我们写写代码做做这个实验。如前述,我们知道小球的当前位置用列表p来表示,假如我们给定一个列表v=[20,20],然后不借用任何timer,仅仅靠画布自身的一秒钟刷新60次来完成小球位置的更新——也就是,在我们眼中,小球是沿着给定方向“动起来”了。

import SimpleGUICS2Pygame.simpleguics2pygame as simplegui

### globals ###
WIDTH = 600
HEIGHT = 400
BALL_RADIUS = 20

p = [WIDTH/2,HEIGHT/2]
v = [20,20]

### event handlers ###
def draw(canvas):
    p[0] += v[0]
    p[1] += v[1]

    canvas.draw_circle(p,BALL_RADIUS,2,"Red","White")

### create frame ###
frame = simplegui.create_frame("Ball physics",WIDTH,HEIGHT)

### register event handlers ###
frame.set_draw_handler(draw)

### start frame ###
frame.start()

事实上,我们规定的v列表代表了各方向的速度,而canva一秒钟刷新60次的机制给定了时间。用简单的物理语言描述出来,即“每隔1/60秒,小球沿着x方向移动20个像素点,与此同时沿着y方向移动20个像素点(因此看起来就像是小球“斜着”动起来的)”。换算一下,也就是小球每秒在x、y方向各运动20*60=1200个像素点,这速度实在是太快了——而通过实验,也可以发现画布中小球的确是一闪而过的,这正好证实了我们的推论。

而通过调整v列表中元素的大小,我们也的确能够控制小球运动的速度,这就和现实中的“调整速度”是一样的。

1-2 判断小球撞在墙面上

这一步我们根据小球球心的坐标来判断。假设小球的当前位置为p=[x,y],则p[0]、p[1]分别为小球的横坐标和纵坐标。

和我做过的毕业设计一样,在计算机中规定画布的右下角的坐标为(width,height),这里的坐标系相当于数学中常用的平面直角坐标系关于x轴的轴对称,也就意味着越往右,x越大;越往下,y越大。

规定小球的半径为r,如图所示,我在图中标注出了当小球撞在四面壁上其圆心坐标分别是怎样一个情况,其中打*的代表“取值多少都可以”。

根据这幅图,并且规定圆心坐标为(p[0],p[1]),我们很容易得到“碰壁”的条件:

(1)碰左壁:p[0]≤r;

(2)碰右壁:p[0]≥width-r;

(3)碰上壁:p[1]≤r;

(4)碰下壁:p[1]≥height-r。

1-3 小球在墙壁上的反弹

这一部分我们首先应结合1-2判断小球是否撞在墙面上,然后才谈得上对撞在墙面上的小球的反弹。

现在我们假设小球确实已经撞在一面墙壁上了,为了方便观看,我们先把小球当做一个质点来处理。如图所示,当一个物体被反弹时,可知入射角等于反射角,且反射前后速度的模值是不变的(|v|、v[0]、v[1]的大小皆保持不变)。

我将入射速度与反射速度分别用一个向量来表示,并且把它们分别分解为水平方向和竖直方向的两个分向量,如图所示,其中紫色的为入射速度的分量,红色的为反射速度的分量。可以很容易发现:竖直方向的分量大小、方向皆没有发生变化;水平方向分量则是大小不变,方向与原来相反。

用Python语言描述出来,反射后的速度应作如下变化:

v[0] = -v[0] # 水平方向大小不变,方向相反
v[1] = v[1] # 竖直方向保持不变

应注意,上面的分析我们仅仅针对小球往左边或者右边的壁碰撞,如果是往上、下壁碰撞,则情况不再是“水平翻转,竖直不变”了,而是“水平不变,竖直翻转”。作为拓展练习,我写了一个小球在一个框内到处反弹的程序。

import SimpleGUICS2Pygame.simpleguics2pygame as simplegui

### globals ###
WIDTH = 600
HEIGHT = 400
r = 20

p = [WIDTH/2,HEIGHT/2]
v = [20,20]

### event handlers ###
def draw(canvas):
    p[0] += v[0]
    p[1] += v[1]

    # reflection
    if ( p[0] <= r ):
        v[0] = -v[0]
        v[1] = v[1]
    elif ( p[0] >= (WIDTH-r) ):
        v[0] = -v[0]
        v[1] = v[1]
    elif ( p[1] <= r ):
        v[0] = v[0]
        v[1] = -v[1]
    elif ( p[1] >= (HEIGHT-r) ):
        v[0] = v[0]
        v[1] = -v[1]        

    canvas.draw_circle(p,r,2,"Red","White")

### create frame ###
frame = simplegui.create_frame("Ball physics",WIDTH,HEIGHT)

### register event handlers ###
frame.set_draw_handler(draw)

### start frame ###
frame.start()

这个程序的运行效果如图所示:

时间: 2024-07-28 17:53:53

IIPP迷你项目(四)"Pong"的相关文章

IIPP迷你项目(三)“Stopwatch: The Game”

0 本周项目说明 这一次博客是Coursera的IIPP课程第三周迷你项目的实现,基础要求是做一个秒表,能start能stop能reset,更高的要求是在此秒表的基础上完成两个小游戏,但是鉴于这两个小游戏全部牵扯到“按下键盘的某一个键则frame会立即反应”,而这一步怎么实现课程还没讲,所以本次博客暂且先不实现这两个小游戏,单纯实现靠button控制的秒表. 1 canvas简介 为了方便后续过程中我自己的查阅,我将canvas整理如下.本文内容除过参考Coursera的视频之外,还有simpl

android 实践项目四

android 实践项目四 本周主要是开发android baidumap实现公交的查询 1.权限的取得和对屏幕的支持 1 <uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE" > 2 </uses-permission> 3 <uses-permission android:name="android.permission.ACCESS_NETWORK

16周(项目四 动态数组)

/* *copyright(c) 2014,烟台大学计算机学院 *All rights reserved. *文件名称:16周(项目四 动态数组) *作者:王忠 *完成日期:2014.12.15 *版本号:v1.0 * *问题描述:新增一个恰当长度的动态数组,将原数组中的数据"复制"到新数组,接着再输入新的数据.增加新数据后的数组,成为保存数据的新数组. *输入描述:输入成绩,学生数 *程序输出:新增的学生数 成绩 #include <iostream> using nam

MVC4商城项目四:应用Bundle捆绑压缩技术

从MVC4开始,我们就发现,项目中对Global.asax进行了优化,将原来在MVC3中使用的代码移到了[App_Start]文件夹下,而Global.asax只负责初始化.其中的BundleConfig类就有个很牛X的功能:合并与压缩.想到以前做ASP.NET的时候要通过工具压缩,手动合并,很麻烦.通过BundleConfig可以大大的提高工作效率和项目性能. 一.基本的使用 1.1.Global.asax文件的初始化 protected void Application_Start() {

docker 运行jenkins及vue项目与springboot项目(四.docker运行nginx)

docker 运行jenkins及vue项目与springboot项目: 一.安装docker 二.docker运行jenkins为自动打包运行做准备 三.jenkins的使用及自动打包vue项目 四.docker运行nginx 五.jenkins打包springboot服务且在docker中运行 准备配置 创建 /home/jenkins/docker/nginx/nginx.conf 文件及/home/docker/nginx/log文件夹 其nginx.conf 文件为在原nginx.co

P2P理财项目四个月开发总结

目前项目情况 这个项目从元旦开始开发到现在已经有四个多月的时间了,上线期限也是一拖再拖,从整个项目开发情况来看造成项目延期的原因有很多,简单分析和总结一下这个项目的优缺点,以及在这个项目中的成长. 项目进展分析 需求方面 需求变动在原因里面占用20%,通过个人感觉这个项目需求变动造成的时间浪费在20%左右,一般项目在代码写了一部分后基本上需求是不会再变了,可是这个项目再开发了两个月之后,需求又大变了一次,导致很多代码重新开发或者从新编译,开发重复劳动情绪也收到影响,当然项目慢也不能完全推给需求,

项目四:Java秒杀系统方案优化-高性能高并发实战

技术栈 前端:Thymeleaf.Bootstrap.JQuery 后端:SpringBoot.JSR303.MyBatis 中间件:RabbitMQ.Redis.Druid 功能模块 分布式会话,商品列表页,商品详情页,订单详情页,系统压测,缓存优化,消息队列,接口安全. 一.项目框架搭建 1.Spring Boot环境搭建 2.集成Thymeleaf,Result结果封装 3.集成Mybatis+Druid 4.集成Jedis+Redis安装+通用缓存Key封装 二.实现登录功能 1.数据库

第十一周 项目四 类族的设计】

项目4 - 类族的设计] 按以下的提示,由基类的设计和测试开始,逐渐地完成各个类的设计,求出圆格柱体的表面积.体积并输出并且完成要求的计算任务: (1)先建立一个Point(点)类,包含数据成员x,y(坐标点),实现需要的成员函数,并设计main函数完成测试: (2)以Point为基类,派生出一个Circle(圆)类,增加数据成员r(半径),以及求面积的成员函数area,实现其他需要的成员函数,设计main函数完成测试: (3)再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类

第11周 项目四-类族的设计

按以下的提示,由基类的设计和测试开始,逐渐地完成各个类的设计,求出圆格柱体的表面积.体积并输出并且完成要求的计算任务: (1)先建立一个Point(点)类,包含数据成员x,y(坐标点),实现需要的成员函数,并设计main函数完成测试: (2)以Point为基类,派生出一个Circle(圆)类,增加数据成员r(半径),以及求面积的成员函数area,实现其他需要的成员函数,设计main函数完成测试: (3)再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,再增加数据成员h(高),