目录
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-玩家的创建&移动
在之前基于Game Kit的学习就涉及到了Tilemap,它是用来绘制2D游戏地图的一个很方便的工具。
关于瓦片地图的学习,由于内容比较多我另开了两个博客专门讲了讲Tilemap:
【Unity入门计划】基本概念(8)-瓦片地图 TileMap 01_flashinggg的博客-CSDN博客
【Unity入门计划】基本概念(8)-瓦片地图 TileMap 02_flashinggg的博客-CSDN博客
教程中介绍的是基于Unity自带的功能,我进行了补充,也找到了另外的处理这个问题的方法,也总结成了博客:【Unity入门计划】2D游戏中遮挡问题的处理方法&伪透视_flashinggg的博客-CSDN博客
想要游戏交互更加真实,加入碰撞是必须的!
先把玩家Ruby和加入到场景中的一个盒子,都做成预制件Prefab,以方便接下来重复使用,分别
直接查看效果,会出现一些怪异的BUG:
这个简单,直接编辑对应预制件碰撞体的范围就行。
这里直接给Ruby预制件的属性中 Constraints冻结Z轴旋转即可。
抖动问题出在移动脚本和碰撞体之间的问题,挂了碰撞体组件后:
先检测Ruby移动进入了箱子碰撞体的范围内 -> 物理引擎生效 -> 把Ruby挤出去碰撞体范围 -> Ruby再靠近盒子 -> 物理引擎再生效...这样不断重复,就造成了抖动。
解决办法也很直接:在我们的移动脚本中,直接移动刚体本身而非游戏对象的变换组件,让物理系统将游戏对象位置同步到刚体的位置。这样,物理系统就可以在进入箱子前停止移动,也就不会在进入箱子的碰撞范围后再移动Ruby。
参考:从零手写游戏引擎21:物理引擎基础 - 知乎 (zhihu.com)
摘抄至参考文章:由于物理引擎中存在大量微积分运算,所以物理引擎一般会要求物理更新的时间步长,也就是dt,保持恒定。而游戏引擎的更新帧率却是不确定的,可能会根据程序运行的情况或者硬件设备的性能不同而产生波动。这就意味着,游戏引擎的更新帧率,与物理引擎的更新帧率是不一致的。假设物理引擎的更新间隔为0.02s,如果游戏引擎某一帧因为某些原因卡顿,更新耗费了0.04s,那么下一帧物理引擎有可能在一次逻辑更新之前进行了2次更新,这完全是有可能的。
用官方教程中的话来描述,就是:每次游戏计算新一帧图像时都会调用Update(),但调用速度是由电脑的计算处理速度决定的,有可能调用速度是每秒20帧,也有可能是每秒3000帧。
为了保持物理计算的稳定, 需要定期更新,这就需要用到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();
}
// 每帧都会执行一次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;
}
}
Tilemap有专门的碰撞体: Tilemap Collider 2D,单纯挂上一个碰撞,会发现每个格子都被约束了。
需要到Tiles文件中修改Default Collider,实现局部赋予碰撞体
问题出在哪儿呢?当游戏世界很大,Tilemap范围非常大的时候,物理系统计算量变大,游戏运行会被减慢。速度如果很快,遇到带有碰撞体的Tilemap会出现直接“卡过去”的情况。
如果改变?Unity为我们提供了复合碰撞体组件。
之前我写过一篇总结2D碰撞体的博客,里面有对复合碰撞体组件组成的介绍:
【Unity入门计划】基本概念(3)-2D碰撞体Collider 2D
如何使用呢?
给Tilemap游戏对象添加一个Composite Collider 2D组件,同时会自动加入一个2D刚体组件,接着让Tilemap Collider 2D中选择:Used By Composite
此时,场景中有碰撞体的Tile会组成一个整体,不再是单独的一个一个小格子了,可以看看前后对比:
简单建立一个场景
在搭建场景时,跟着教程会把每个素材都做成一个预制件,减少重复操作。
范围的位置是根据精灵的pivot变化而变化的,因此编辑顺序应该是:修改精灵的pivot -> 调整碰撞体的范围
例如,给游戏对象House一个碰撞体,并挂上伪透视脚本,勾选Static,就有如下效果