2018年2月18日星期日

python GUI学习--Tkinter(一)--第一个程序

Tkinter是python自带的GUI库。

教程来源:http://www.tkdocs.com/tutorial

第一个程序:
from tkinter import *
from tkinter import ttk
root = Tk()
ttk.Button(root, text="Hello World").grid()
root.mainloop()

运行结果:
解释说明:
from tkinter import * # 载入tkinter库
from tkinter import ttk # 载入ttk库,一个比较新的库,比较现代化
root = Tk() # 根节点
ttk.Button(root, text="Hello World").grid() # 添加一个按钮,并排列
root.mainloop() # 开启主循环

第一个真实的程序:一个单位转换器
设计:

程序代码:

from tkinter import *
from tkinter import ttk

def calculate(*args):
    try:
        value = float(feet.get())
        meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
    except ValueError:
        pass
    
root = Tk()
root.title("Feet to Meters")

mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)

feet = StringVar()
meters = StringVar()

feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))

ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)

ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)

for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)

feet_entry.focus()
root.bind('', calculate) # here the '' should be '<Return>'

root.mainloop()

结果:
程序说明:

from tkinter import *
from tkinter import ttk

# 载入tk库,和一个新主题库


root = Tk()
root.title("Feet to Meters")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)

# 设置根节点,设置标题,frame位置,frame占窗口尺寸定义


feet = StringVar()
meters = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet) feet_entry.grid(column=2, row=1, sticky=(W, E))
ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E)) ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)

# 定义2个变量,创建 输入框,显示结果的文本框,用于计算的按钮。
# 对每一个元素,需要创建它,然后给出位置。列,行 表示位置,sticky表示伸展(紧靠)方向。


ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W) ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E) ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)

# 显示三个文本框


for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5) feet_entry.focus()
root.bind('', calculate)  ## here the '' should be '<Return>'

# 上面三行:首先为每个main frame中的元素加一层外框。
# 然后设置输入框为默认激活状态
# 最后绑定回车和 计算函数,这样按下回车键就等于按下 计算 按钮




def calculate(*args):
    try:
        value = float(feet.get())
        meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
    except ValueError:
        pass

# 计算函数,转换英尺和米,并将结果赋给 meters
# 之前与赋给元素的变量将会自动更新


root.mainloop()


# 开始主循环


2018年1月14日星期日

音频软件OpenMPT

unity中支持Tracker Module,即一些预先处理的音频包,而它可以利用 OpenMPT 这个开源音频软件制作。

另一款自己用的开源音频软件叫做 Audacity。

关于汽车换档

最佳动力性换挡原则

即获得最快加速性能的换档原则:

换档,使得换档之后的功率或者扭矩大于换档前。

功率 P = F*V,假设换档前后速度一致,则F(扭矩)越大,功率越大。

2018年1月13日星期六

关于婴儿睡眠与扁头

知乎上的问题“https://www.zhihu.com/question/27539492”--"把女儿的头睡扁了……",其中有一个回答值得参考:

龚非4 天前
这个我应该有点发言权。。。我闺女出生后,我就坚持让她侧着睡,当然没敢让趴着,是怕窒息。侧着睡是有讲究的,因为婴儿很软,是无法自己侧着睡稳当的。我会用一个小毯子卷成卷,然后放在女儿后背挡着,这样她就能正侧着睡了。另外,最重要的是换边!每天晚上,孩子需要吃奶的时候,我会把孩子抱出来给我老婆喂奶,喂完后我拍咯,拍完放回小床时,一定是换一边睡。这样下次喂奶再换。因此我能保证在前半年,我闺女没有任何两次睡觉是同一侧挨枕头的(白天上班我不在,不过我也交代家里人了,一定要换边)。现在我闺女的脸就非常小,前后奔头都有,梳马尾不管高低,都很好看。希望准父母们参考一下吧。

希望可以给以后的生活积累一些经验,为下一代创造良好,健康的生活。

2017年11月13日星期一

游戏中的物理(车辆)(五)

游戏中的物理(车辆)(五)

轮胎牵引力

之前的假设是轮胎不会打滑,现实中,如果汽车停止,全油门加速,车胎将会先打滑然后再前进。如果汽车以过高的速度经过一个弯道,或许会侧滑出去。
回忆此章的开头,汽车能向前运动,是因为轮胎和地面间的摩擦力。这个摩擦力叫做牵引力。它等于垂直于汽车的压力乘以摩擦系数:
式8.32的牵引力,是轮胎不打滑的最大摩擦力。一辆车的牵引力一般是通过“滑轨测试(skidpad test)”得到的。车辆围绕一个平的圆形轨道行驶,车辆的速度不断增加,直到侧向加速度与轮胎的牵引力相等。
式8.33的r是轨道的半径。如果车速超过某点,向心力比牵引力大,车辆开始向外侧滑动。滑轨测试的结果通常表示为车辆不滑动的最大加速度。在干燥路面上, 2004 Porsche Boxster S 的最大轮胎加速度是0.91g,g是重力加速度。
这个加速度限制也适用于直线状况。如果轮胎上施加的扭力大于最高加速度,则轮胎开始打滑。所以最大轮胎加速度会限制汽车的加速。无论轮胎上施加了多大的扭力,汽车的加速不会超过轮胎的最大加速度。
对游戏而言,使用轮胎牵引力效果很直观。首先计算施加到轮胎上的扭力:
然后计算最大摩擦力(式8.32).如果轮上扭力低于最大摩擦力,则可用于汽车运动,如果轮上扭力大于最大摩擦力,则轮胎打滑,应使用最大摩擦力计算汽车运动。
式8.32的系数取决于轮胎和路面的条件。光头胎会比日常胎有更低的系数。在冰面上会比干地上有更低的系数。
最后的注意点是最大轮胎加速度用于汽车最终加速度。围绕曲线行驶的车辆将会有向心加速度。最终加速度等于向心和直线加速度的和的平方根:
从式8.35可得,一辆加速进入一个弯道的车辆比用特定速度沿此弯道巡航的车辆更容易打滑。

围绕曲线行驶

到目前为止,只讨论了车辆沿直线行驶的物理。车子当然不能永远直行,有时还需转弯。围绕曲线行驶可分为两种情况:高速转向和低速转向。
首先讨论低速的情况。低速比高速要容易些,一些因素,比如向心加速度,可以忽略。轮胎可以假定不打滑。考虑如图8-10的车。前轮转过角度为δ,向右转。如果车子以恒定速度行驶,将转过一个半径为 rc的圆。
车子转向的圆心位于右侧前后轮的垂线的交点。圆的半径可以用三角测量得到。前后轮的距离是l,也叫轴距。轴距与半径的比等于sinδ:
另一个重点是转向的速度,即角速度。如果转向时没有摩擦力,则角速度ωt,等于线速度除以半径:
使用式8.36,角速度可由轮距和前轮角度得出:
式8.36和8.38提供了低速转向的所有信息。比如,驾驶Boxster S低速转一个90度的弯,速度为10m/s(36km/h)。为了转这个弯,前轮需要转动10度。Boxster S的轴距为2.41m。半径有多大,需要花多长时间?半径可从式8.36得出:
所需时间等于转过的角度pi/2,除以角速度:

高速转向

模拟高速转向比较复杂,例如,向心力会导致车子向外滑。或者说,轮胎会有垂直于转向方向的速度分量。这个力也产生对汽车质心的扭力,使得汽车围绕质心转动。你可能见过这个效果,当车子高速转向时,汽车的尾部向外甩,出现“甩尾”现象。
最简单的模拟高速转向的方式是计算侧向力,Flateral,它等于向心力和摩擦力的差:

角度θ是汽车行驶的坡道的角度。在式8.41中,正侧向力是向外的。因为摩擦力不可能超过向心力(汽车不可能滑向内侧),侧向力将总是大于或等于0。
式8.41提供了大致的侧向力的计算,但是它没法模拟汽车高速过弯时的甩尾或侧滑效果。要得到更逼真的高速过弯效果,需要考虑每个轮胎上的侧向力。这相当复杂,需要知道轮胎打滑角度等,超出了这本书的范围。

模拟撞车

我们都知道,汽车有时会撞到什么东西。你或许在现实中撞过车。在汽车模拟中,撞向什么东西或撞飞什么看起来很有趣。我们在第六章学习了碰撞的基础,很多相同的理念可以应用到汽车上。汽车不是实心的金属块,当它们撞到什么东西,除非是速度很低,否则车体会变形。这种碰撞是非弹性的,因为汽车运动的能量会损坏车体。
第六章,给出了计算两个物体直线碰撞后的速度的公式8.42a,8.42b。碰撞后的速度v′1 and v′2,是两物体的质量m和碰撞前的速度v,以及返回系数e的函数。其中一个物体是车,另一个则可以是任何东西。
如果汽车的任何部位在碰撞中发生了变形,那么碰撞是非弹性的,则返回系数将小于1.在第六章中,弹性和非弹性的碰撞已经讨论过。一个极端情况是完全非弹性碰撞,这时返回系数为0.这种情况下,汽车和碰撞的物体将挤在一起,会有一个相同的碰撞后速度。(式8.43)
大多数情况下,碰撞不是完全非弹性的,返回系数将会大于0.汽车将会损坏,并撞飞碰到的物体。F1赛车游戏使用0.25的返回系数。

摩托车

摩托车也是一种可以创造刺激的游戏体验的车辆。摩托车更轻,更灵活,加速性更好,但是大部分加速和刹车的物理是和汽车一样的。摩托车的动力传到后轮,趋势它前进。摩托车也受到空阻,滚动摩擦力,牵引力的影响,正如车一样。
表8-4比较了跑车和高性能摩托车的性能参数。车:2004 Porsche Boxster S,摩托车:2004 Honda CBR1000RR。摩托车更轻,汽车有更高的极速,但是摩托车加速更快。它只需要汽车的一半多一点的时间达到100km/h。汽车引擎扭力更高,但是摩托车引擎有更高的红线转速(这也是它加速更快的一个原因)。
如之前所说,汽车和摩托车有很多相似的地方,但是有一个重要的不同之处:摩托车如何转向。

摩托车转向

让汽车转弯很简单,转动轮子到想转的方向。如果你在摩托车上也这么做,除非是速度很低,否则你会摔车。这种现象的原因叫“陀螺进动”。当摩托车的轮子转向一个方向时,一个力会施加到相反的方向上,使得轮子倾斜。比如,如果你把摩托车的前轮向左转,摩托车会向右倾斜,反之亦然。因为这个现象,如果你想把摩托车的前轮转向某方向,你会摔出摩托车。
成功地让摩托车高速转向的关键是向弯道的内部倾斜,如图8.11所示。这种倾斜会稳定摩托车的运动,有几种方法可以让摩托车向弯内倾斜。第一种是利用陀螺进动,叫反转向。为了开始转向,驾驶者必须向相反的方向转动前轮。这看起来奇怪,但是记住向反方向转动前轮会使得摩托车向弯内倾斜。驾驶者也可以倾斜肩部来使得摩托车向合适的方向倾斜。

表示反转向的力和时间的数学公式非常复杂,包含许多惯性和角速度的项。除非你想模拟非常高细节的摩托车运动,否则没有必要考虑那么复杂。反转向更适合作为一种视觉效果。当游戏中的车手转向时,让摩托车向弯内倾斜。

为汽车或摩托车增加高级效果

这章描述了汽车或摩托车的基本物理,可以想象,一些高级的物理效果并没有讨论。我们已经说过,汽车转向的真实描述需要考虑四个轮子上的侧向力。另一个转向的效果是重量会转移到外侧的轮子上。
要增加更逼真的物理效果,请使用和基本模型相同的步骤。首先,创建一个受力分析图,找出力和方向。然后,写出描述这些运动的公式。最后,代码实现。
参考:
1. B. Bowling, “Air Drag Coefficients and Frontal Area Calculation,” www.bgsoflex.com/airdragchart.html. 
2. C.E. Mungan, “Rolling Friction of a Free Wheel,” http://usna.edu/Users/physics/mungan/Scholarship/RollingFriction.pdf. 
3. R. van Gaal, “Car Physics Basics,” www.racer.nl/reference/carphys.htm#enginebraking. 

游戏中的物理(车辆)(四)

游戏中的物理(车辆)(四)

一个汽车模拟器

让我们用已经了解的知识来建立一个汽车模拟器。该模拟器的GUI界面如图8-8所示。界面的上方是显示区域,显示汽车的图片,汽车的上面是两个矩形的标记。当模拟器运行时,汽车的位置保持不变,标记从左边移动到右边,模拟汽车向前运动。标记移动的速度即为汽车运动的速度。

GUi界面的左边是三个圆形按钮,分别表示汽车加速,定速巡航,刹车。这些按钮是单选的。下面是五个按钮,start按钮启动或重启模拟,shift up 和 shift down控制换档,stop停车并换到一档,限制引擎转速为1000rpm。reset按钮做stop按钮相同的事情,并重置距离和时间为0.
界面的右边显示当前速度,引擎转速,当前档位,行驶距离,经过时间。界面的底部显示警告信息。如果引擎转速超过红线,将会显示信息。如果引擎转速超过8000转,你将“炸掉”引擎,模拟将停止。
这里的GUI界面比较原始,但是基本的物理是非常逼真的。模型包含空阻,滚动摩擦力,但是还是做了一些简化。车辆假定行驶在平直路上。刹车时,刹车加速度是-5.0m/s^2的常量。我们也没有模拟倒档,所以车辆只能前进或停止。
这里模拟的轮胎不会打滑。现实中的轮胎如果扭力太高则会打滑。稍后我们将会讨论如何模拟“烧胎”效果。
模拟车辆需要两种类:一种表示汽车,另一种定义GUI。首先讨论表示车的类。这里有两个类:一个叫Car,描述所有车的特性。它是DragProjectile类的子类。

/*接下来的部分是游戏物理的代码实现,由于我的重点是汽车的物理,这里就不再介绍*/

注意这里的模拟器使用的是式8.20的最大加速度(即油门按下即是最大)。

游戏中的物理(车辆)(三)

游戏中的物理(车辆)(三)

空气阻力

运动的汽车会受到空气阻力。空阻与速度方向相反,减慢汽车的运动。如式8.3所示,空阻与空气密度,车速的平方,迎风面积,以及空阻系数相关。
为了计算式8.3,我们需要知道空阻系数和迎风面积。

汽车的空阻系数

空阻系数与车辆的形状有关。跑车的空阻系数比卡车要低。一些典型车辆的空阻系数如表8-3所示。
尽管因为雷诺数和其他因素,汽车的空阻系数会发生变化,但对游戏而言,你可以假设空阻系数是一个常量。2004 Porsche Boxster S 的空阻系数是0.31.

迎风面积

式8.3中有迎风面积。最简单的描述迎风面积的方式是汽车的宽和高的乘积。这里假设汽车的前视横截面是矩形,实际上很多汽车的侧面是倾斜的,所以迎风面积要小于宽与高的乘积。更准确的方法是宽和高的乘积再乘以一个0到1之间的系数,对Boxster S而言,这个系数是0.85.
Boxster S的宽是1.78m,高1.28m,用式8.16,迎风面积为1.94平方米。

滚动摩擦力

滚动摩擦力是由物体和滚动的面之间的变形而引起的力。由式8.4可知,滚动摩擦力可由垂直于车辆向下的力FN乘以滚动摩擦系数µr得到。如果车辆在平地上行驶,向下的力为mg。
滚动摩擦系数远比静摩擦系数小。汽车轮胎的滚动摩擦系数一般在0.01到0.02之间。

计算加速度和速度

为了模拟汽车的运动,需要知道在任意时刻的汽车的加速度和速度。我们从式8.11开始。前面已经知道了滚动摩擦系数和空阻系数,如果坡度,迎风面积,空气密度已知,唯一未知的量是轮上扭力Tw。
由式8.10,轮上扭力是引擎扭力Te,当前齿比 gk,终传比G的乘积。引擎扭力Te可由引擎扭力曲线得到。对游戏而言,扭力曲线需要用数学的方式表示。最简化的方式是用一些线段表示扭力曲线。
比如,图8.2的Boxster S的扭力曲线可以用三条线段表示。第一条是转速从1000rpm到4600rpm,扭力从220Nm到309.2Nm,第二条是转速从4600rpm到红线7200rpm,扭力则掉到227Nm,当引擎转速低于1000rpm,扭力假定为220Nm。简化的扭力曲线如图8-7所示。

使用简化的曲线,Boxster S的扭力可由三个公式表达。扭力单位为Nm。
所有8.17的式子都是如下直线公式的特殊形式:
式8.18的b是直线的斜率。当然,直线不是扭力曲线的唯一数学模型,根据曲线形状的不同,抛物线或指数函数也可用来表示扭力曲线。
为了计算加速度,我们需要将轮上扭力表达为当前车速的函数。这个函数成立的假设是轮胎不会打滑。这时,车速v可以表达为轮胎半径rw和轮胎角速度ωw的乘积。在式8.12中,角速度与引擎转速,齿比,终传比有关:
 这里的60是将每分钟的转速转换为秒。将式8.18和8.19代入8.11,可得加速度与当前速度的关系:

式8.20看起来复杂,可以表达为一些常量与当前速度的乘积:
其中常量c1,c2,c3分别为:
由式8.20,可以得知是何种因素在影响车辆的加速度。明显可知,车辆越重,加速度越低。如果齿比和终传比增大,加速度也增大。降低滚动摩擦力,加速度将增加。
记住式8.20表示的是给定速度下的最大加速度,这时油门始终处于最大。现实中,始终地板油是一种极端的情况。如果油门不是最大,那么轮上扭力也不是最大。在游戏中,如果油门是最大,则扭力最大,如果油门只有一半,则扭力也是一半。
式8.20假设轮胎不会打滑,在很多情况下,最大扭力会大于轮胎和地面间的最大摩擦力,这时轮胎将会打滑,出现“烧胎”现象。稍后在“轮胎牵引力”一节将会讨论。
另一个需要注意的是,式8.20的加速度公式只是一种理想化的情况,它假设引擎的扭力在通过变速器和差速器时没有损失。实际上因为机械部件的摩擦,会有一些损失。而直线的引擎扭力曲线也不能表示真实情况。这两种假设会互相抵消,对游戏来说,式8.20足够精确。
式8.20或8.21可以计算汽车的速度。可以证明,式8.21有解析解,但是非常复杂,如果用我们的ODE算子,将会简化它的计算。
式8.21可以计算汽车理论上的最大速度。最大速度出现在合力为0时。但是在这之前,低档位时的转速就会达到红线,这时最大车速就由红线转速决定:
 在更高档位(齿比更低),最大车速由阻力决定。阻力会限制车辆加速到红线转速。回忆一下,阻力与车速的平方成正比。当车速上升时,空阻也上升,直到轮上扭力和空阻以及滚动摩擦力平衡。这时加速度为0:

最大速度可以由此式的根得出:
我们用式8.25计算Porsche Boxster S位于第六档时的最大速度。空阻系数是0.31,车重是1323kg,前轮半径0.3186m,假定滚动摩擦系数是0.015,迎风面积1.94m^2,驾驶者重70kg,空气密度1.2kg/m^3,在平地上行驶,则坡度θ为0.
最大速度会出现在引擎转速较高时,所以引擎扭力会由式8.17c得到。此时b为-0.032,d为457.2.在第六档,最大速度由阻力决定,所以用式8.25计算。
另一个解是负值,所以忽略。厂家给出的最大速度为266km/h,考虑到计算中的假设和简化,这是一个相当不错的结果。
271.5km/h是阻力限制下的最大速度,对比一下红线转速限制下的最高速度(式8.23):
所以如果没有空阻和滚动摩擦力,Boxster S可以达到299km/h。为了感受一下这些力的大小,这里比较一下当Boxster S达到271.5km/h时的空阻和滚动摩擦力的大小。空阻可以由式8.3得到:
滚动摩擦力可由式8.4得到:
可以看到当车辆达到271.5km/h时,空阻是滚动摩擦力的10倍。滚动摩擦力与速度无关。如果汽车速度是10km/h,滚动摩擦力依然是205N,而空阻只有2.8N。

制动

开车当然不能总是加速,偶尔也需要减速。这里我们将讨论两种减速的方式(并不包含直接撞到树上)。可以证明,引擎会自然减慢活塞运动的速度。这种现象叫做“发动机制动”。发动机制动的扭力(Teb),由一个叫做发动机制动系数(µeb)的常量,乘以发动机的转速(每秒):
获得一辆车的发动机制动系数比较困难。对一辆F1赛车来说,这个系数是0.74,如果把这个系数用到Boxster S上,则引擎在6000rpm时的发动机制动力是74Nm,加速度为-0.17m/s^2。如果你想在游戏中模拟发动机制动效果,但又不知道发动机系数的精确值,那么0.74会是一个比较合理的数字。
另一个减速的方式是踩下刹车。这时刹车片会夹紧刹车盘,产生摩擦力,使得汽车减速。这个力与轮子转动的方向相反。
获得一辆车的刹车力度也有点难。这个信息一般表达为将车辆从特定速度完全刹停需要的距离。比如,Boxster S 从26.8m/s完全刹停需要34米长。如果刹车距离x已知,则刹车加速度, ab,可由牛顿定律得到:
记住式8.31表示的是最小刹车距离,所以驾驶者是踩满刹车,因此-10.4这个数字应视为最大刹车加速度。
对游戏来说,如果一辆车的刹车力度未知,你可以从刹车距离上计算它。记住刹车距离表示最大刹车力度。更柔和的刹车对应更小的刹车力度。