Python从零模仿我的世界(十一)

窗口类

这篇文章我们来看两个和3维矢量(vector3)有关的函数。由于我们的游戏是3维的,所以当我提到“矢量”时没有特殊说明都指的是“3维矢量”。先来围观代码:

class Window(...):
    ...
    def get_sight_vector(self):
       # rotation 是画面旋转的角度,等我们讲到鼠标移动时再说
        x, y = self.rotation
        # 这里是一些算法,看看就行了
        # 感兴趣的可以评论区讨论
        m = math.cos(math.radians(y))
        dy = math.sin(math.radians(y))
        dx = math.cos(math.radians(x - 90)) * m
        dz = math.sin(math.radians(x - 90)) * m
        return (dx, dy, dz)

    def get_motion_vector(self):
        # strafe 是用于记录移动状态的,还记得吗?
        # 等到我们讲到键盘事件之后再说
        # 如果 strafe 都为0,那么不在移动,就把移动矢量设为0
        if any(self.strafe):
            # 这里又是一些算法
            # 感兴趣的可以评论区讨论
            x, y = self.rotation
            strafe = math.degrees(math.atan2(*self.strafe))
            x_angle = math.radians(x + strafe)
            dx = math.cos(x_angle)
            dz = math.sin(x_angle)
        else:
            dx = 0.0
            dz = 0.0
        return (dx, 0.0, dz)

这两个函数主要都是算法,我们只要知道它们是怎么使用的就行了。get_sight_vector是获取画面旋转的矢量的。当玩家移动鼠标时,画面会随着鼠标的移动而旋转,旋转的角度就存储在rotation属性中。get_motion_vector是获取移动矢量的。只有在玩家按下移动的按键(WSAD)时,才会移动。移动的方向也取决于rotation属性。剩下的就是一些算法了。

接着我们来讲讲collide函数是怎么回事。collide函数长这样:

class Window(...):
    ...
    def collide(self, position, height):
        # pad 指的是”陷进地里“能”陷”多少
        # 如果为 0.5 那么碰撞体积就是半个方块
        # 如果为 0 那就是完全站在方块上
        pad = 0.25
        # list 让 position 可变
        p = list(position)
        # normalize 函数还记得吗?忘了的话看一眼第二篇
        np = normalize(position)
        # 以下循环的本质就是挨个坐标尝试过去,看看会不会发生碰撞
        for face in Settings.faces:
            # 遍历 x y z 三个值
            for i in range(3):
                if not face[i]:
                    continue
                # 看看现在的坐标和整数坐标差了多少
                d = (p[i] - np[i]) * face[i]
                # 小于 pad,不满足碰撞条件,跳过
                if d < pad:
                    continue
                # 再按高度挨个尝试过去
                for dy in range(height):
                    # list 是为了修改它
                    op = list(np)
                    # 把高度减去,这样可以达到逐个尝试的效果
                    op[1] -= dy
                    op[i] += face[i]
                    # 如果方块不存在,那就不可能发生碰撞了,跳过
                    # 注意,list 不能作为键使用
                    # TypeError: unhashable type: 'list'
                    if tuple(op) not in self.model.world:
                        continue
                    # 发生碰撞了,那么修正坐标
                    p[i] -= (d - pad) * face[i]
                    # 如果方块在头顶上或者在脚底,那么重力和跳跃的速度就置为0
                    if face == (0, -1, 0) or face == (0, 1, 0):
                        self.dy = 0
                    # 既然已经碰撞了,剩下的高度就不必再尝试了
                    break
        # 复原数据类型
        return tuple(p)

我们这篇文章就讲到这里啦。代码比较复杂,不过配合注释应该是能看懂的,也欢迎评论区讨论哦~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值