【Unity俯视角射击】我们来做一个《元气骑士》的完整Demo(一)

作者:Yumir


Hi~我是Yumir。

今天开始一起把之前做的俯视角射击整合成一个完整的游戏Demo吧~

目前计划完成的内容有:人物控制系统、怪物AI逻辑、地图元素、游戏UI等等。先不做动态生成(以后有机会的),虽然之前已经写过相关功能,在做Demo的时候还是有不少需要改动的地方,为了更加随心所欲的控制怪物所以自己写了寻路脚本。

本篇分享我的人物控制系统是如何实现的,其他内容后面也会慢慢整理出来,预计四篇。试着使用了Unity的新功能,把Demo上传到网站,后面新的内容完成也会持续更新:

https://connect.unity.com/mg/other/untitled-9864


一、前期准备

写这篇文章的时候想着是讲人物控制系统但是没有场景也不太好看,确实也需要做一些交代,元气骑士的素材包是以前在某个学习群看到下载的,不清楚是哪位大佬解出来的,这里把包分享出来:

链接:https://pan.baidu.com/share/init?surl=ndEqFLc_1nRDaHwi5ax1ww

提取码:pkxq

我自己整合的图比较随性(混乱)等Demo做完再整理分享吧・ᴗ・。

地图的绘制还是用之前用过的那个方法:

老师!我想用Tilemap做元气骑士款地图!


场景中还需要一些其他元素:

1、宝箱:

将素材中的宝箱贴图拼接成一个完整的箱子,并制作相应的动画,因为宝物每次不同但是都有一样的动画,所以新建一个空游戏物体用来制作上升动画并在使用时装上宝箱持有的宝物。

2、告示牌:

告示牌比较简单,碰撞中调用游戏管理脚本显示或者隐藏场景中的提示板就行了,因为摄像机都是一直跟随人物的,所以我把提示板设置在画面中心就可以了。

3、门:

门稍稍有点复杂,主要是因为侧面的门和前后的墙之间有遮挡关系,而门又是由很多很多个小柱子组成的,我是这样处理的(结合TileMap绘制的层级划分):

墙体TileMap绘制的层级划分


门柱的层级和布局

计划里还有各种不同功能的箱子,但是还没有做。

二、人物控制系统

关于人物控制我希望他能够有以下功能:

------为了可以制作玩家预制体首先要有一个测试用的人物和一个测试用的武器------

1、人物

游戏中的人物和怪物动画基本上就三个:待机、行动、死亡。而且都是精灵图动画,状态机也基本是一样的,但是由于是精灵图动画所以并不能复用,角色状态中还有一个被攻击状态,我直接用了颜色动画。


2、武器

由于加入了武器拾取更换的功能,枪的动画就不能使用位移动画了,所以枪的位移动画是自己做了前后抖动的精灵图。

我新建了一个空物体作为玩家父物体,用来挂载玩家控制系统和物理碰撞系统。

注意:我的Tag和Layer也进行了相应的更改

在未运行的状态下该物体底下只有一个角色阴影,其他元素都是运行时动态生成,这个阴影除了使角色看起来立体之外,该位置还承担如角色Buff显示和选中状态显示这种功能,所以其实这个阴影也应该是动态生成的(只是我偷懒了- -)。

玩家持有的人物是在脚本中动态生成准备好的角色预制体到上述游戏物体中,枪则是到游戏中拾取。

myPlayer = Instantiate(playerPrefab, transform);

 

---------------------------准备完毕之后是相关功能实现--------------------------------

1、人物移动

人物的移动依旧是利用在Update中获取键盘输入的"Horizontal"和"Vertical"的值,在FixedUpdate中更新角色的位置。


private void Update()

{

   movement.x = Input.GetAxis("Horizontal");

   movement.y = Input.GetAxis("Vertical");

   if (movement == new Vector2(0, 0)){

      playerAnima.SetBool("run", false);

   }

    else{

        playerAnima.SetBool("run", true);

   }

}

private void FixedUpdate(){

    rigidbody.MovePosition(rigidbody.position + movement * moveSpeed * Time.fixedDeltaTime);

}

 

2、人物朝向

人物朝向其实附带功能还有武器朝向,我写了一个Target字段现在赋值为鼠标位置,有需要也可以修改(比如改为自瞄),考虑到武器种类不同的情况下瞄准方式也会不一样,所以人物的朝向和武器的朝向是各自管理的。

3、鼠标左键操作逻辑

这个按键需要判断四种状态:一种是玩家在可互动物体周围时左键操作为“互动”,比如现在做的是捡起枪。另外则是长按、短按和抬起,不同武器在长按、短按、抬起这三个状态下的操作是不一样的。

为了判断玩家是否在可互动物体的周围,我在Update中每帧由玩家向周围发射射线检测是否碰撞到可互动物体,这里因为只有枪就只做了枪的判断未进一步优化。

weaponInFloor = null;

Collider2D[] cols = Physics2D.OverlapCircleAll(transform.position, 1);

if (cols.Length > 0){

   for (int i = 0; i < cols.Length; i++){

       if (cols[i].CompareTag("Weapon")){

            weaponInFloor = cols[i].gameObject;

       }

    }

}

 

根据射线检测的结果和按键的情况分别执行对应的操作:

if (weaponInFloor != null && fireKeyDown){

    GetWeapon();

}

else{

     if (fireKeyDown){

        if (weapon != null){ weapon.ShootButtonDown(); }

        else{ Debug.Log("没有武器只能手刀撒"); }

     }

     else if(fireKeyPressed){

        if (weapon != null){ weapon.ShootButtonPressed();}

     }

     if(fireKeyUp){

        if (weapon != null){ weapon.ShootButtonUp(); }

     }

}

 

武器的拾取需要根据玩家手上是否持有武器做不同动作,相应的武器身上也要有被捡起放下的两个对应方法:

void GetWeapon(){

    if (weaponInFloor != null){

        //地上有枪就换枪

        if (weapon != null){

            myWeapon.transform.SetParent(GameManager.instance.weaponRecycle);

            weapon.PickDown();

        }

            myWeapon = weaponInFloor;

            weapon = myWeapon.GetComponent<Weapon>();

            weapon.Pickup();

            myWeapon.transform.SetParent(transform);

            myWeapon.transform.localPosition = new Vector3(0, 0, 0);

            myWeapon.transform.localRotation = Quaternion.identity;

            //注册

            weapon.Initialization(gameObject.tag, gameObject.layer);

    }

}

 

不同武器在对应的状态方法中编辑该状态下的操作即可。

//例:Gun

public override void ShootButtonDown(){

    if (Time.time - timing >=CD){

        timing = Time.time;

        GameObject bullet = Instantiate(bulletPrefab, pos.position, pos.rotation*Quaternion.AngleAxis(Random.Range(0,shake),Vector3.forward));

        bullet.GetComponent<Bullet>().Initialization(attack, role, bulletForce);

        GetComponent<Animator>().Play("Shoot");

     }

}

public override void ShootButtonPressed(){

     if (Time.time - timing >=CD){

       timing = Time.time;

       GameObject bullet = Instantiate(bulletPrefab, pos.position, pos.rotation*Quaternion.AngleAxis(Random.Range(0,shake),Vector3.forward));

       bullet.GetComponent<Bullet>().Initialization(attack, role, bulletForce);

       GetComponent<Animator>().Play("Shoot");

      }

}

 

4、镜头跟随

镜头跟随这块直接用了Cinemachine,跟着马老师的视频设置就可以啦:

【简明UNITY教程】不用写代码的高级2D摄像机 Cinemachine


三、凑一个小标题(有感而发)

由于中间跑去学ShaderGraph再回头看俯视角射击有种恍若隔世的感觉,慢慢找回写代码的状态思路也更清晰了一些,但其实对自己现在写的这个Demo并不是太满意,大概会有漫长的打磨吧。

同时认识到以前对俯视角射击看得太简单了,又或者说其实我写的确实是俯视角射击,但他离一个完整的游戏还是太远了。还需要更加努力,了解更多同质类型的游戏,也需要学习更多类型的游戏。

望:与君共勉。


——分割线——

欢迎加入游戏开发群欢乐搅基:1082025059

对游戏开发感兴趣的童鞋可戳这里进一步了解:levelpp.com/

本文为我原创

本文禁止转载或摘编

-- --
  • 投诉或建议
评论