1. 扩展地图
Game中的场景是摄像机的可视范围,我们用上一节的方法对外部进行绘制,扩展地图,此时Ruby走出可视范围后就看不到了,所以后面会添加相机跟随的功能。
2. 场景美化
在场景中添加树,此时拖拽到场景中后是看不到的,因此需要调整层次。将树添加后选中,添加新的排序层Enviroment,由于希望角色移动到图形背面后依然显示图形,因此层次顺序如下所示。
3. 碰撞检测
给树添加Box Collider 2D组件,点击Edit Collider编辑碰撞区域。
给角色添加Capsule Collider 2D组件,编辑碰撞区域。
由于是俯视角,一般环境的碰撞区域为大约二分之一的位置。
新建Prefabs文件夹存放预制件,将TreeBig1放入文件夹中。通过复制粘贴快速创建多个树木,丰富场景中的元素。
进一步丰富场景,添加不同的树木、房子到场景中。同样地,调整排序层次为Enviroment,添加碰撞检测器,为了管理的方便性,同样存放到Prefabs文件夹中。
4. 相机跟随
添加Cinemachine: Window -》Package Manager -》Cinemachine -》install
创建Virtual Camera
将Aim设为Do nothing,设置Follow为角色,使相机跟随角色移动。设置好后,随着角色的运动,我们看到的场景也在随之变化。
为了使角色在边框内运动,相机可视范围不超出我们地图的边框,因此要分别对相机和角色进行限制。
选择Create -》Empty 添加一个空的对象,重命名为Confiner。添加新的组件Polygon Collider 2D,选中is Trigger,调整碰撞区域至地图的四个角落,相当于将一个多边形渐渐调整成矩形。
将Virtual Camera与Confiner关联起来。选中CM VCAM1,在Extensions里添加CinemachineConfiner,设置Bounding Shape 2D为Confiner,需要注意的是,这里只接受Polygon Collider,且必须勾选is trigger。
要使角色被限制在地图内也并不困难,只需新建一个Tilemap,将地图围起来,并添加碰撞检测器即可。
如图新建Tilemap命名为Bound,在Tile Palette中找到基础图像,把地图的四个边围起来,添加Tilemap的碰撞检测器Tilemap Collider 2D,即完成边框绘制。
5. 加血物品收集
1.将Project文件夹中的加血物品拖到Hierarchy中使其添加进来,此时在场景中是看不到的,依旧是层次的问题。
2.选中,添加新的排序层Item,并移动到Player之上,调整好后设置加血物品的Sorting Layer为Item。最后,调整Scale为0.3使其大小适中。
3.添加碰撞检测器Box Collider 2D,调整边框大小,由于能穿过草莓,因此选中is Trigger。
4.为了使游戏更加灵动,添加动画使草莓动起来。在Hierarchy中选中图片,点击Animation窗口中的Create,在已有的Animation文件夹中新建item文件夹,将文件命名为Item_health_idle。
创建完成后,在Property中找到Scale并添加进来。
打开Enable/Disable keyframe recording mode,即红色按钮,那么针对Scale值的每次变化都将反映到时间轴上来。可以观察到,Inspector中Scale三个值变为红色,表示这三个值正被控制跟踪,修改即能改变对应帧的值。
由于要重新定义帧的值,我们删除最后一帧,将X和Z改为0.4,先让草莓变扁一点。
在第二十帧将X、Z恢复原值,Y设为0.4,使草莓变长。
最后复制第一帧到第四十帧的位置,效果就出来了。将最后一帧拖至35帧的位置,使动画速度加快一点,让整体效果更加精致。
5.添加Item Health脚本,控制加血功能,创建好后将脚本拖至Scripts文件夹。
编辑ItemHealth脚本,在PlayerController脚本中添加生命值相关函数。
ItemHealth
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemHealth : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision)//触发器,collision是与草莓碰撞的物体。
{
PlayerController playerController = collision.GetComponent<PlayerController>();
if (playerController)
{
playerController.ChangeHealth(1);
Destroy(gameObject);
}
}
// Start is called before the first frame update
}
PlayerController(新添加代码)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public int maxHealth = 5;
private int _currentHealth;
public int Health => _currentHealth;//表示外部可以得到 _currentHealth
// Start is called before the first frame update
void Start()
{
_currentHealth = 1;//初始化生命值为1,方便后续观察
}
// Update is called once per frame
public void ChangeHealth(int amount)
{
_currentHealth = Mathf.Clamp(_currentHealth + amount, 0, maxHealth);//clamp返回min和max间的值
print("Current Health: " + _currentHealth);
}
}