首页 > 其他分享 >【Unity项目实践】FPS项目复盘及关键技术要点

【Unity项目实践】FPS项目复盘及关键技术要点

时间:2022-11-13 22:01:36浏览次数:86  
标签:zombie 摄像机 transform zb hitInfo Unity FPS 武器 复盘

概述

【Unity项目实践】FPS项目复盘及关键技术要点_实例化

之前做过一个小型的FPS项目,基本实现了以下这些功能点:

  • 人物移动:前进后退、鼠标调整视角、右键瞄准;模拟后坐力、初步处理武器穿模的问题。
  • 怪物生成:在地图上放置怪物生成点,实现怪物随机从这些生成点上生成;并通过对象池实现怪物的回收利用。
  • 武器系统:实现了武器切换、换弹,目前的武器包括手枪、狙击枪、刀等;运用了继承,通过继承武器基类提高了开发效率。
  • 武器交互:实现了伤害判定和UI的更新。


人物移动

Unity自带的FirstPersonController可以实现基本的人物移动功能,我们自己撰写脚本的时候只需要补充一些细节。

(1)后坐力

后坐力 = 镜头抖动 + 弹道偏移

这里我们先简单模拟一下镜头抖动,镜头抖动是指开枪之后先左右小幅度抖动+向上移位一段时间,再缓慢复位,代码如下:

IEnumerator ShootRecoil_Camera(float recoil)
{
float xOffset = Random.Range(0.3f, 0.6f) * recoil;//开枪之后会有一个向上抬的效果
float yOffset = Random.Range(-0.15f, 0.15f) * recoil;
firstPersonController.xRotOffset = xOffset;
firstPersonController.yRotOffset = yOffset;
//模拟停留一下之后又往下偏
for (int i=0; i<6; i++)
{
yield return null;
}
firstPersonController.xRotOffset = 0;
firstPersonController.yRotOffset = 0;
}

(2)处理对象穿模

常见的有以下三种处理方式:

  • 添加碰撞体
  • 碰到墙的时候把枪竖起来或者背起来
  • 利用第二个摄像机制造一种没有穿墙的假象

这个项目中使用了第三种,这种方式主要是利用摄像机的层级选择。我们将武器设置成一个单独的层级,在主摄像机中取消勾选这个武器的层级,同时我们在主摄像机的位置再创建第二个摄像机,使其只拍摄武器这个层级,并且将第二个摄像机的层级设置在主摄像机之上。这样就算穿模了,武器的图像还是显示在别的物体之上,视觉上没有穿模。


怪物生成

(1)随机生成

创建一个GameController脚本,用来管理场景中的怪物生成点,生成怪物的时候在这些生成点中随机选择位置。

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

public class GameManager : MonoBehaviour
{
public static GameManager Instance;
public Transform[] Points;
void Start()
{
Instance = this;
}

public Vector3 GetPoints()
{
return Points[Random.Range(0, Points.Length)].position;
}
}

(2)对象池管理

生成的时候如果池子里有,就从池子里拿,这里用到了队列,代码如下:

void Start()
{
StartCoroutine(CheckZombie());
}

// 检查僵尸
IEnumerator CheckZombie()
{
while (true)
{
yield return new WaitForSeconds(1);
// 僵尸数量不够,产生僵尸
if (zombies.Count<3)
{
// 池子里面有,从池子拿
if (zombiePool.Count>0)
{
ZombieController zb = zombiePool.Dequeue();//出队
zb.transform.SetParent(transform);
zb.transform.position = GameManager.Instance.GetPoints();
zombies.Add(zb);
zb.gameObject.SetActive(true);
zb.Init();
yield return new WaitForSeconds(2);
}
// 池子没有,就实例化
else
{
GameObject zb = Instantiate(prefab_Zombie, GameManager.Instance.GetPoints(), Quaternion.identity, transform);
zombies.Add(zb.GetComponent<ZombieController>());
}
}
}
}

怪物死亡的时候就加入到对象池中:

public void ZombieDead(ZombieController zombie)
{
zombies.Remove(zombie);
zombiePool.Enqueue(zombie);//入队
zombie.gameObject.SetActive(false);
zombie.transform.SetParent(Pool);
}


武器系统

武器系统的核心点在于:为了提升开发效率,我们使用一个武器基类来实现所有的武器共性的逻辑。

比如我们会有不同的枪存在,那么枪的基类中主要包括如下部分:

  • 数值:包括最大子弹数、当前子弹数、备用子弹数、伤害数值、后坐力数值等
  • 初始化:进入游戏的时候需要先给武器初始赋值
  • 拿到武器:初始化数值、播放拿起武器的动画、播放音效等
  • 退出武器:播放退出动画、音效等
  • 效果:包含音效和视觉特效的播放时间点
  • 开枪效果:一些共性的开枪效果,比如弹坑、音效、射线检测等

下面详细记录一下一些细节:开镜+关键帧事件。

(1)开镜

主要用于狙击枪,狙击枪射程远、伤害高,一般是右键开镜之后获得一个放大的视野进行瞄准再射击。主要流程如下:

【Unity项目实践】FPS项目复盘及关键技术要点_实例化_02

(2)添加关键帧事件

游戏中有很多的动画,我们可以在动画的关键帧上添加脚本。

找到相应的动画片段,选择合适的位置,例如动画开始或者结束的时候,点击Events左侧的图标进行事件添加。然后在动画所属的物体上添加脚本撰写同名方法,就会在动画播放到这一帧的时候启动这个事件了。

【Unity项目实践】FPS项目复盘及关键技术要点_实例化_03


武器交互

(1)射线检测

运用了Unity中的Raycast这个API,文档内容如下:

​https://docs.unity3d.com/ScriptReference/Physics.Raycast.html​

使用射线检测的步骤:

  • 从摄像机发射一条射线
  • 如果可以穿墙,返回一个数组;如果不能穿墙,返回碰到的第一个对象
  • 判断打到的物体是不是可以打的怪物
  • 如果是,那么实例化一个命中怪物的效果,并且做数值更新;如果不是,实例化一个普通的弹坑

第一段代码:射线检测

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//从主摄像机发射出一条射线

if (canThroughWall)
{
//Physics.RaycastNonAlloc(ray, hitInfos, 1500f);
RaycastHit[] raycastHits = Physics.RaycastAll(ray, 1500f);
for (int i = 0; i < raycastHits.Length; i++)
{
HitGameObject(raycastHits[i]);
}
}
else
{
if (Physics.Raycast(ray, out RaycastHit hitInfo, 1500f))
{
HitGameObject(hitInfo);
}
}

第二段代码:伤害判定

private void HitGameObject(RaycastHit hitInfo)
{
//判断是不是打到了僵尸
if(hitInfo.collider.gameObject.CompareTag("Zombie"))
{
//实例化一个命中效果
GameObject go = Instantiate(prefab_BulletEF[1], hitInfo.point, Quaternion.identity);
go.transform.LookAt(Camera.main.transform);
//僵尸的逻辑
ZombieController zombie = hitInfo.collider.gameObject.GetComponent<ZombieController>();
if (zombie == null) zombie = hitInfo.collider.gameObject.GetComponent<ZombieController>();
zombie.Hurt(attackValue);
}
else if (hitInfo.collider.gameObject!= player.gameObject)
{
GameObject go = Instantiate(prefab_BulletEF[0], hitInfo.point, Quaternion.identity);
go.transform.LookAt(Camera.main.transform);
}
}


标签:zombie,摄像机,transform,zb,hitInfo,Unity,FPS,武器,复盘
From: https://blog.51cto.com/u_15639010/5847966

相关文章

  • LeeCode 319周赛复盘
    T1:温度转换思路:模拟publicdouble[]convertTemperature(doublecelsius){returnnewdouble[]{celsius+273.15,celsius*1.80+32.00};}T2:最小公倍数......
  • 【unity】ECS
    前言早就听闻ECS框架。今天记录一下相关内容,并尝试使用Unity提供的ECS框架来做一个MiniDemo,体会该框架。ECS的结构ECS分为Entity(实体)-Component(组件)-System(系统),它......
  • 【Unity】利用MagicaCloth的ConnectionMode将骨骼链连接成网格
    最近想把小草神的模型从之前利刃于心大佬的版本换成官方发布的版本,不过用MagicaCloth弄好布料仿真以后发现头发的地方有点问题,可以看到两搓头发在来回摩擦:仔细观察了游戏......
  • Unity之"诡异"的协程
    为什么说是诡异的协程呢?首先从一个案例说起吧,示例如下:游戏目标:让小车进入到对应颜色屋子里,即可获得一分。(转弯的道路可控) 为了让小车能够平滑转弯,小车的前进方向需要......
  • unity3d修改对象属性
    unity3d修改对象属性 #regionvoidloadWorkerModel(Vector3init_position,stringworker_name,stringBDID){GameObjectobj=(GameObject)......
  • Unity一键制作预制体Prefab一键修改Prefab属性
    1.适用于制作多个预制体(一个模型文件下面几百个子物体,都需要制作成预制体,这一个一个拖不是要炸裂)模型资源如下图 2.模型先放到Resources文件夹下面方便读取,制作......
  • Unity 判断UI对象是否在屏幕内,并且把对象移进屏幕
    publicstaticboolJudgmentUiInScreen(GameObjectobj){RectTransformrect=obj.GetComponent<RectTransform>();RectTransformuiRoot=r......
  • 菜鸡学Unity 之 Unity中对游戏物体的常用操作旋转移动放缩
    LZ-Says:愿时光依旧,美好前方~前言本小节,我们一起来看下Unity中对游戏物体的常用操作旋转移动放缩这些基本骚操作吧~基本骚操作全程都可以简单操纵鼠标完成,当然,直接有效是......
  • unity 获取scene整体的bound包围盒以及center
    如下:多场景的情况也适合参考: https://gamedev.stackexchange.com/questions/134675/unity-bounds-includes-the-center-of-the-scene1privateList<Bounds>......
  • unity 对rotation、 localPosition、 localScale 进行修改
    unity对 rotation、localPosition、localScale进行修改 rotation:1、xxx.transform.localEulerAngles=newVector3(0.0f,0.0f,0.0f); 2、xxx.transform.rotat......