zl程序教程

您现在的位置是:首页 >  其他

当前栏目

【Unity入门计划】制作RubyAdventure02-处理瓦片地图&碰撞

amp入门 处理 制作 Unity 计划 地图 碰撞
2023-09-11 14:22:30 时间

目录

3 使用TileMap瓦片地图创建世界

4 处理游戏对象的前后遮挡关系

5 实现碰撞

5.1 解决碰撞BUG-碰撞范围

5.2 解决碰撞BUG-玩家旋转

5.3 解决碰撞BUG-碰撞抖动

游戏引擎与物理引擎的更新帧率

FixedUpdate() 

处理完BUG的效果

6 实现Tilemap的碰撞

6.1 局部赋予碰撞体

6.2 解决Tilemap碰撞体BUG

Composite Collider 2D 复合碰撞体

7 伪透视2D下碰撞和遮罩的关系

7.1 使用素材时要有建立Prefab的习惯

7.2 明确碰撞体范围的中心点


已进行步骤

制作RubyAdventure01-玩家的创建&移动

3 使用TileMap瓦片地图创建世界

在之前基于Game Kit的学习就涉及到了Tilemap,它是用来绘制2D游戏地图的一个很方便的工具。

关于瓦片地图的学习,由于内容比较多我另开了两个博客专门讲了讲Tilemap:

【Unity入门计划】基本概念(8)-瓦片地图 TileMap 01_flashinggg的博客-CSDN博客

【Unity入门计划】基本概念(8)-瓦片地图 TileMap 02_flashinggg的博客-CSDN博客

4 处理游戏对象的前后遮挡关系

教程中介绍的是基于Unity自带的功能,我进行了补充,也找到了另外的处理这个问题的方法,也总结成了博客:【Unity入门计划】2D游戏中遮挡问题的处理方法&伪透视_flashinggg的博客-CSDN博客

5 实现碰撞

想要游戏交互更加真实,加入碰撞是必须的!

先把玩家Ruby和加入到场景中的一个盒子,都做成预制件Prefab,以方便接下来重复使用,分别

  • 给Ruby加上一个Rigidbody 2D + Box Collider 2D
  • 给箱子加上一个Box Collider 2D 用于实现碰撞(因为盒子是静止的因此不需要刚体组件)

直接查看效果,会出现一些怪异的BUG: 

5.1 解决碰撞BUG-碰撞范围

这个简单,直接编辑对应预制件碰撞体的范围就行。

 

5.2 解决碰撞BUG-玩家旋转

这里直接给Ruby预制件的属性中 Constraints冻结Z轴旋转即可。

5.3 解决碰撞BUG-碰撞抖动

抖动问题出在移动脚本和碰撞体之间的问题,挂了碰撞体组件后:

先检测Ruby移动进入了箱子碰撞体的范围内 -> 物理引擎生效 -> 把Ruby挤出去碰撞体范围 -> Ruby再靠近盒子 -> 物理引擎再生效...这样不断重复,就造成了抖动。

解决办法也很直接:在我们的移动脚本中,直接移动刚体本身而非游戏对象的变换组件,让物理系统将游戏对象位置同步到刚体的位置。这样,物理系统就可以在进入箱子前停止移动,也就不会在进入箱子的碰撞范围后再移动Ruby。

游戏引擎与物理引擎的更新帧率

参考:从零手写游戏引擎21:物理引擎基础 - 知乎 (zhihu.com)

摘抄至参考文章:由于物理引擎中存在大量微积分运算,所以物理引擎一般会要求物理更新的时间步长,也就是dt,保持恒定。而游戏引擎的更新帧率却是不确定的,可能会根据程序运行的情况或者硬件设备的性能不同而产生波动。这就意味着,游戏引擎的更新帧率,与物理引擎的更新帧率是不一致的。假设物理引擎的更新间隔为0.02s,如果游戏引擎某一帧因为某些原因卡顿,更新耗费了0.04s,那么下一帧物理引擎有可能在一次逻辑更新之前进行了2次更新,这完全是有可能的。

用官方教程中的话来描述,就是:每次游戏计算新一帧图像时都会调用Update(),但调用速度是由电脑的计算处理速度决定的,有可能调用速度是每秒20帧,也有可能是每秒3000帧。

FixedUpdate() 

为了保持物理计算的稳定, 需要定期更新,这就需要用到FixedUpdate()来实现固定时间间隔执行更新。FixedUpdate()默认是0.02次/秒,也就是每秒更新50次,也可以在Project Settings里自定。 

修改后的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RubyController : MonoBehaviour
{
    //声明刚体对象
    Rigidbody2D rigidbody2D;
    //在方法外声明水平和数值量
    float horizontal;
    float vertical;
    private void Start()
    {
        //游戏运行前,获取当前游戏对象的刚体组件
        //这里用到了GetComponent获取当前所在对象的吗某个组件 - GetComponent<>() 
        rigidbody2D = GetComponent<Rigidbody2D>();
    }
    // 每帧都会执行一次Update函数
    void Update()
    {

        //声明新变量
        //获取水平轴并储存在新变量中
        horizontal = Input.GetAxis("Horizontal");
        //获取垂直轴
        vertical = Input.GetAxis("Vertical");
    }
    void FixedUpdate()
    {

        Vector2 position = transform.position;
        //对x轴移动距离做了细微的更改
        position.x += horizontal * 3.0f * Time.deltaTime;
        //对y轴也做相应更改
        position.y += vertical * 3.0f * Time.deltaTime;
        rigidbody2D.position = position;
    }
}

处理完BUG的效果

6 实现Tilemap的碰撞

6.1 局部赋予碰撞体

Tilemap有专门的碰撞体: Tilemap Collider 2D,单纯挂上一个碰撞,会发现每个格子都被约束了。

 

需要到Tiles文件中修改Default Collider,实现局部赋予碰撞体

  • None——不赋予碰撞体
  • Sprite——赋予碰撞体

6.2 解决Tilemap碰撞体BUG

问题出在哪儿呢?当游戏世界很大,Tilemap范围非常大的时候,物理系统计算量变大,游戏运行会被减慢。速度如果很快,遇到带有碰撞体的Tilemap会出现直接“卡过去”的情况。

如果改变?Unity为我们提供了复合碰撞体组件。

Composite Collider 2D 复合碰撞体

 之前我写过一篇总结2D碰撞体的博客,里面有对复合碰撞体组件组成的介绍:

【Unity入门计划】基本概念(3)-2D碰撞体Collider 2D

 如何使用呢?

给Tilemap游戏对象添加一个Composite Collider 2D组件,同时会自动加入一个2D刚体组件,接着让Tilemap Collider 2D中选择:Used By Composite

此时,场景中有碰撞体的Tile会组成一个整体,不再是单独的一个一个小格子了,可以看看前后对比:

7 伪透视2D下碰撞和遮罩的关系

7.1 使用素材时要有建立Prefab的习惯

简单建立一个场景

在搭建场景时,跟着教程会把每个素材都做成一个预制件,减少重复操作。

7.2 明确碰撞体范围的中心点

范围的位置是根据精灵的pivot变化而变化的,因此编辑顺序应该是:修改精灵的pivot -> 调整碰撞体的范围

例如,给游戏对象House一个碰撞体,并挂上伪透视脚本,勾选Static,就有如下效果