1.前言
在我们个人开发自己的游戏的Demo的时候肯定会遇到这种情况,如果在一个Player类中实现的功能过多,就会使得整个代码的耦合性大幅度上升,其他地方需要某个功能,而这个功能在Player类中已经实现过时,代码的依赖关系就会不断变强,且后续开发其他功能时难以拓展。我们来根据一个实际情况看看这种写法带来的糟糕情况。
现在有一个2D射击游戏,直观的逻辑来看,我们需要使得player类能执行我们的移动,射击(需要武器)等功能。那如果我们这些功能全部都写在player类这个脚本时会发生什么情况呢?当我们需要制造这个游戏中的敌人时,而敌人也需要射击这个功能时,我们就会遇到非常尴尬的情况了,这就是代码没有模块化的原因,我们没有履行好单一职责原则。
那我们该如何根据现在的情景去编写一个Player类呢,先来看下面这张图
我们无需在player中实现所有我们想要的功能,我们创建PlayerController类与GunController将Player类中的多数功能下放给两个组件类去完善,我们只需要在Player类中去实现,这就好比乐高积木,我们只需要拿到我们想要的零件,然后将零件拼装成我们想要的模型。
[RequireComponent(typeof(GunController))]
[RequireComponent(typeof(PlayerController))]
public class Player : LivingEntity
{
//[控制器] 组件类
public GunController gunController;
public PlayerController Controller;
//[输入参数]
private float moveH, MoveV;
public Vector2 mousePos;
[Header("PlayMoveSpeed")]
public float moveSpeed = 5f;
public float ClearRange = 2f;
public override void Start()//获取到我们的组件类
{
base.Start();
Controller = GetComponent<PlayerController>();
gunController = GetComponent<GunController>();
}
void Update()//通过拿到的输入直接去调用组件类的方法
{
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
moveH = Input.GetAxisRaw("Horizontal")*moveSpeed;
MoveV = Input.GetAxisRaw("Vertical") * moveSpeed;
if (Input.GetMouseButton(0))
{
gunController.Shoot();
}
if (Input.GetKeyDown(KeyCode.R))
{
gunController.Reload();
}
if (Input.GetKeyDown(KeyCode.Q))
{
gunController.ChangeGun();
}
if (Input.GetKeyDown(KeyCode.Space))
{
Controller.Roll();
}
}
void FixedUpdate()//通过拿到的输入直接去调用组件类的方法
{
Controller.Move(moveH, MoveV);
gunController.GunPointTo(mousePos);
Controller.Look(mousePos);
}
}
上述代码是我从我的个人项目中删减出来的一部分代码,我们不需要关注太多代码本身的问题,只需要关注思路,我们在Player类中只负责拿到玩家的输入(键盘鼠标操控)然后将具体的实现下放给PlayerController和GunController。这样我们Player类的职责就比较单一了,在后续我们需要实现我们的Enemy类时,也可以直接将GunController类当成自己的组件类来使用了。