美文网首页python自制小工具
python游戏开发中的数学和物理--Apple的学习笔记

python游戏开发中的数学和物理--Apple的学习笔记

作者: applecai | 来源:发表于2021-04-30 20:03 被阅读0次

    一,前言

    最近看了《游戏开发中的数学和物理》,至于为什么突然要看这本书,只是看了北京卫视的<新闻大求真>里面正好说到光线闪烁后一帧帧看图片后,变成动画的效果。处于出于好奇,人家是什么做游戏的,因为我绘图或GUI引擎基本都知道原理,但是做不出游戏,所以我要探秘。我已经全部看完了,后面的章节只是快速过一下,前面的章节做了下实验。

    二,游戏中的数学笔记

    首先一个游戏中的运动要呈现的就是每一帧有图像变化。而每一帧可以理解为周期调用移动函数。我已经说明了框架哦。

    2.1 第一章第一节 物体的匀速直线运动

    1. 关于匀速直线运动的物体碰壁回弹

    a.关于移动物体,比如从左边出发,移动到右边,遇到右边边框,这个向右碰到判断的位置是viewWidth-objWidth。为什么要减去objWidth呢!原因就是物体坐标从左上角开始。这个依据view和obj的坐标系,设计代码的时候注意即可。
    b.碰到后可能obj面积有超过view边框,所以要重置位置值。比如x=viewWidth-objWidth。
    c.关于回弹就是速度使用负值。

    2.2 关于按键控制匀速直线运动

    这个看起来和自动每一帧运动类似,只是周期调用前判断上下左右按键是否按下。没想要里面也有技巧,就是2个按键一起按下后的效果,比如向右和向上一起按下后,它的运动方向变成x和y都增加,最后是斜向上方向运行。它的速度会变成原来的\sqrt 2倍。这是勾股定理,因为匀速运动速度和距离成正比。我同样是周期运行,1帧的时间,一个上一个右2个按钮按下后,物体运动的距离是一个斜边s。斜边s的长度比a和b直角边长要长吧,长就说明速度不同了。
    所以解决方法就是判断按右键后,继续判断是否上或下键也同时按下了,此时移动的距离向右增加的少些,变成增加v/1.414。

    2.3 第一章第二节 物体的各种方向运动

    三角函数中几乎都试用弧度,很少使用角度,主要是关系到微积分的一些问题。所以游戏中将角的单位统一为弧度。此案例中让我领悟了沿不同角度移动,其实就是要修改x和y移动增加的delta,而只要delta的数学关系满足数学公式,那么物体移动的效果就满足数学公式。突然感觉这个积分的处理有点像,积分将断拆分为小段进行累加,而此运动可以看做一帧帧中物体的一点点的变动。

        def __init__(self):
            #...略
            self.mult = 3                                       # 调速倍数
    
            self.angle = math.pi/6.0                            # 移动角度
            self.moveSpeedX = self.mult * math.cos(self.angle)  # x移动增量
            self.moveSpeedY = self.mult * math.sin(self.angle)  # y移动增量
    
        def birdUpdate(self):
            # 直线移动
            self.birdX += self.moveSpeedX
            self.birdY += self.moveSpeedY
            #self.moveSpeedY += 1                               # 重力加速度
            # 移动到边框则重中心点开始,每次角度添加30度的方向开始直线移动
            if( self.birdX <= 0 or self.birdX >= view_w - self.birdrect.width or self.birdY <= 0 or self.birdY >= view_h - self.birdrect.height):
                # 重置物体位置到中心点
                self.birdX = (view_w - self.birdrect.width)/2.0
                self.birdY = (view_h - self.birdrect.height)/2.0
                # 角度增加30度
                self.angle += 2.0 * math.pi/10.0
                # 角度值控制在2 pi内
                if(self.angle > 2.0 * math.pi):
                    self.angle -= 2.0 *math.pi
                # delta移动增量按角度更新
                self.moveSpeedX = self.mult * math.cos(self.angle)
                self.moveSpeedY = self.mult * math.sin(self.angle)
    

    2.4 第一章第5节 圆周运动

    之前小节有写重力加速度,就是速度每帧也累加,这个比较简单。另外一节就是说随机值,里面提到c语言的rand是均匀分布的随机数,不是正态分布的随机数。并且给了没有详细解释的正态分布随机值的算法,所以我没有去尝试。接着说到了圆周运动,此时我发现和速度没有关系了,直接计算x和y的位置了。不是都在速度上做文章吗?

        def birdUpdate_cycle(self):
            # 圆周移动
            self.birdX = 60 * math.cos(self.angle) + (view_w - self.birdrect.width)/2.0
            self.birdY = 60 * math.sin(self.angle) + (view_h - self.birdrect.height)/2.0
            self.angle += 2.0*math.pi/120.0
    

    我改成和速度相关,运行结果非预期,它不是在图像中心点开始运动的,另外关于这个r*cos(x)中的r取值也不好定义了。虽然运动起来也是一个圆。主要原因我想了下就是这个r是围绕图像中心为圆心。而不是运动的物体中每个点的圆心。所以次例子中再用delta增量的方式不太好。直接对obj对象进行处理,在定位方面会比较好。

        def birdUpdate_cycle(self):
            # 圆周移动
            # self.birdX = 60 * math.cos(self.angle) + (view_w - self.birdrect.width)/2.0
            # self.birdY = 60 * math.sin(self.angle) + (view_h - self.birdrect.height)/2.0
            # self.angle += 2.0*math.pi/120.0
            self.birdX += self.moveSpeedX
            self.birdY += self.moveSpeedY
            self.moveSpeedX = 5 * math.cos(self.angle)
            self.moveSpeedY = 5 * math.sin(self.angle)
            self.angle += 2.0 * math.pi / 120.0
    

    三,学以致用

    理论学习中物体的运动,只是对移动对象的局部操作,想要运用到游戏中,那么我需要用一个框架来实现下。本书自带的example已经下载不到了,而且很古老。所以我可以选择在之前的guilite中实现,可以选择在SDL2框架实现,但是我想了下,我期望再简单点,目的是要验证书中描述的物体运动。于是我找了个更简单的框架,就在python的pygame上实现吧。小游戏就是通过上下左右按键来控制小鸟的直线运动。框架我是参考网上其它博主分享的,结合自己的按键验证场景进行的修改。至于pygame的api一学就会,基于游戏或GUI的开发思路都是基于事件驱动后进行渲染,所以这方面的设计思想真的是一通百通呢~
    按键直接控制小鸟直线运动的效果图

    image.png
    python小游戏源码:
    '''
    ******************************************************************************
    | Project                      : AppleGame
    | Description                  : pygame project
    | CPU and Compiler             : win10 python 3.7
    |               R E V I S I O N   H I S T O R Y
    |-------------------------------------------------------------------------------
    | Date        Version   Author     Description
    | ----------  --------  ------     ---------------------------------------------
    | 2020-04-29  01.00.00  AppleCai   First version
    ******************************************************************************
    '''
    import pygame
    import sys
    import random
    
    view_w = 628
    view_h = 393
    
    class Bird(object):
        """定义一个鸟类"""
    
        def __init__(self):
            """定义初始化方法"""
            # 定义鸟的3种状态列表
            self.birdStatus = pygame.image.load("bird.png")
            self.birdrect = self.birdStatus.get_rect()  # 获取矩形区域
            self.birdX = 10     # 鸟所在X轴坐标,即是向右飞行的速度
            self.birdY = 30     # 鸟所在Y轴坐标,即上下飞行高度
            self.bLeftKey = False   
            self.bRightKey = False   
            self.bUpKey = False   
            self.bDownKey = False          
            self.moveSpeed = 10  # 移动速度
    
        def birdUpdate(self):
            # 左键操作
            if(self.bLeftKey):
                if(self.bUpKey or self.bDownKey):
                    self.birdX -= self.moveSpeed/1.414
                else:
                    self.birdX -= self.moveSpeed
                if(self.birdX < 0):
                    self.birdX = 0
            # 右键操作
            if(self.bRightKey):
                if(self.bUpKey or self.bDownKey):
                    self.birdX += self.moveSpeed/1.414
                    #self.birdX += self.moveSpeed
                else:
                    self.birdX += self.moveSpeed
                if(self.birdX  >= view_w - self.birdrect.width):
                    self.birdX = view_w -self.birdrect.width
            # 上键操作
            if(self.bUpKey):
                if(self.bLeftKey or self.bRightKey):
                    self.birdY -= self.moveSpeed/1.414
                    #self.birdY -= self.moveSpeed
                else:
                    self.birdY -= self.moveSpeed
                if(self.birdY < 0):
                    self.birdY = 0
            # 下键操作
            if(self.bDownKey):
                if (self.bLeftKey or self.bRightKey):
                    self.birdY += self.moveSpeed/1.414
                else:
                    self.birdY += self.moveSpeed
                if(self.birdY  >= view_h - self.birdrect.height):
                    self.birdY = view_h -self.birdrect.height
    
    def createMap():
        """定义创建地图的方法"""
        screen.fill((255, 255, 255))     # 填充颜色
        screen.blit(background, (0, 0))  # 填入到背景
        # 显示小鸟,设置小鸟的坐标
        screen.blit(Bird.birdStatus, (Bird.birdX, Bird.birdY))
        Bird.birdUpdate()                # 小鸟移动
        # 更新显示
        pygame.display.update()
    
    
    def check_keydown_events(event, rocket):
        """响应按键"""
        if event.key == pygame.K_RIGHT:
            rocket.bRightKey = True
        elif event.key == pygame.K_LEFT:
            rocket.bLeftKey = True
        elif event.key == pygame.K_UP:
            rocket.bUpKey = True
        elif event.key == pygame.K_DOWN:
            rocket.bDownKey = True
            
    def check_keyup_events(event, rocket):
        """响应松开"""
        if event.key == pygame.K_RIGHT:
            rocket.bRightKey = False
        elif event.key == pygame.K_LEFT:
            rocket.bLeftKey = False
        elif event.key == pygame.K_UP:
            rocket.bUpKey = False
        elif event.key == pygame.K_DOWN:
            rocket.bDownKey = False
    
    if __name__ == '__main__':
        """主程序"""
        pygame.init()                                        # 初始化pygame
        pygame.display.set_caption("AppleCai's pygame")
        size = view_w, view_h                                # 设置窗口
        screen = pygame.display.set_mode(size)               # 显示窗口
        clock = pygame.time.Clock()                          # 设置时钟
        Bird = Bird()                                        # 实例化鸟类
        background = pygame.image.load("background.png")     # 加载背景图片
        while True:
            clock.tick(60)                                   # 每秒执行60次
            # 轮询事件
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    check_keydown_events(event, Bird)
                elif event.type == pygame.KEYUP:
                    check_keyup_events(event, Bird)
    
            createMap()                                      # 创建地图
            
        pygame.quit()
    

    四,总结

    还真是学到不少,不看这本书的话,让我自己做我是想不到这些问题的。并且学习了些设计思路。有些东西自己去想这个实现思路会比较难,但是直接看过了解过,就简单了。这是否和做数学题一样,有时候没有解题思路,参考了别人的解题思路就会了。没事儿做看看闲书,就是就和知道,了解下方法论,需要用的时候可以知道去哪里找,不会没有方向,目的就达到了,哈哈~

    相关文章

      网友评论

        本文标题:python游戏开发中的数学和物理--Apple的学习笔记

        本文链接:https://www.haomeiwen.com/subject/lzhorltx.html