标签:
在这一步中,首先应该明确小球是如何匀速运动的。它的方法是规定一个列表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列表中元素的大小,我们也的确能够控制小球运动的速度,这就和现实中的“调整速度”是一样的。
这一步我们根据小球球心的坐标来判断。假设小球的当前位置为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-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()
这个程序的运行效果如图所示:
标签:
原文地址:http://www.cnblogs.com/NanShan2016/p/5632016.html