一、前言

我与另外两个组员合作进行了FPS游戏(第一人称射击游戏)的开发,这个游戏对应于我们在项目开始设想的PVP玩家对战游戏。玩家之间的之间对战会让游戏变得更加紧张刺激,还能够增强玩家之间的感情。
我在这个游戏中主要负责的工作是枪械特效、枪械声音、射击反馈震屏、子弹散射、枪械射击弹孔、ui子弹数量、pun控制输入同步、remote开枪效果同步。

二、实现枪械射击

首先,我们是在weapon文件夹下完成对枪械的相关脚本的创建和编写的。

创建IWeapon脚本用来管理接口,命名空间归类到Scripts.Weapon下,防止出现冲突:

namespace Scripts.Weapon
{public interface IWeapon{void DoAttack();}
}

然后编写Firearms脚本,这是枪械整体共用的部分。其中把Firearms枪械类抽象掉,因为这不是具体的枪械,并且可以挂在game object上:
获取枪口的位置,还要知道子弹抛出的位置。抛出弹壳使用粒子变量,避免太多的实例化过程。
需要一个弹夹AmmoInMag,设置容纳的子弹数。并且设置每把枪最大的子弹携带数。此外开枪需要设置动画。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace Scripts.Weapon
{public abstract class Firearms : MonoBehaviour, IWeapon{public GameObject BulletPrefab;public Camera EyeCamera;public Camera GunCamera;public Transform MuzzlePoint;public Transform CasingPoint;public ParticleSystem MuzzleParticle;public ParticleSystem CasingParticle;public AudioSource FirearmsShootingAudioSource;public AudioSource FirearmsReloadAudioSource;public FirearmsAudioData FirearmsAudioData;public ImpactAudioData ImpactAudioData;public GameObject BulletImpactPrefab;public float FireRate;public int AmmoInMag = 30;public int MaxAmmoCarried = 120;public float SpreadAngle;[SerializeField] internal Animator GunAnimator;public List<ScopeInfo> ScopeInfos;public ScopeInfo BaseIronSight;protected ScopeInfo rigoutScopeInfo;public int GetCurrentAmmo => CurrentAmmo;public int GetCurrentMaxAmmoCarried => CurrentMaxAmmoCarried;protected int CurrentAmmo;protected int CurrentMaxAmmoCarried;protected float LastFireTime;protected AnimatorStateInfo GunStateInfo;protected float EyeOriginFOV;protected float GunOriginFOV;protected bool IsAiming;protected bool IsHoldingTrigger;private IEnumerator doAimCoroutine;private Vector3 originalEyePosition;protected Transform gunCameraTransform;
        protected virtual void Awake(){CurrentAmmo = AmmoInMag;CurrentMaxAmmoCarried = MaxAmmoCarried;GunAnimator = GetComponent<Animator>();EyeOriginFOV = EyeCamera.fieldOfView;GunOriginFOV = GunCamera.fieldOfView;doAimCoroutine = DoAim();gunCameraTransform = GunCamera.transform;originalEyePosition = gunCameraTransform.localPosition;rigoutScopeInfo = BaseIronSight;}
        public void DoAttack(){Shooting();}protected abstract void Shooting();protected abstract void Reload();//protected abstract void Aim();protected bool IsAllowShooting(){return Time.time - LastFireTime > 1 / FireRate;}protected Vector3 CalculateSpreadOffset(){float tmp_SpreadPercent = SpreadAngle / EyeCamera.fieldOfView;return tmp_SpreadPercent * UnityEngine.Random.insideUnitCircle;}protected IEnumerator CheckReloadAmmoAnimationEnd(){while (true){yield return null;GunStateInfo = GunAnimator.GetCurrentAnimatorStateInfo(2);if (GunStateInfo.IsTag("ReloadAmmo")){if (GunStateInfo.normalizedTime >= 0.9f){int tmp_NeedAmmoCount = AmmoInMag - CurrentAmmo;int tmp_RemainingAmmo = CurrentMaxAmmoCarried - tmp_NeedAmmoCount;if (tmp_RemainingAmmo <= 0){CurrentAmmo += CurrentMaxAmmoCarried;}else{CurrentAmmo = AmmoInMag;}CurrentMaxAmmoCarried = tmp_RemainingAmmo <= 0 ? 0 : tmp_RemainingAmmo;yield break;}}}}protected IEnumerator DoAim(){while (true){yield return null;float tmp_EyeCurrentFOV = 0;EyeCamera.fieldOfView =Mathf.SmoothDamp(EyeCamera.fieldOfView,IsAiming ? rigoutScopeInfo.EyeFov : EyeOriginFOV,ref tmp_EyeCurrentFOV,Time.deltaTime * 2);float tmp_GunCurrentFOV = 0;GunCamera.fieldOfView =Mathf.SmoothDamp(GunCamera.fieldOfView,IsAiming ? rigoutScopeInfo.GunFov : GunOriginFOV,ref tmp_GunCurrentFOV,Time.deltaTime * 2);Vector3 tmp_RefPosition = Vector3.zero;gunCameraTransform.localPosition = Vector3.SmoothDamp(gunCameraTransform.localPosition,IsAiming ? rigoutScopeInfo.GunCameraPosition : originalEyePosition,ref tmp_RefPosition,Time.deltaTime * 2);}}internal void Aiming(bool _isAiming){IsAiming = _isAiming;GunAnimator.SetBool("Aim", IsAiming);if (doAimCoroutine == null){doAimCoroutine = DoAim();StartCoroutine(doAimCoroutine);}else{StopCoroutine(doAimCoroutine);doAimCoroutine = null;doAimCoroutine = DoAim();StartCoroutine(doAimCoroutine);}}internal void SetupCarriedScope(ScopeInfo _scopeInfo){rigoutScopeInfo = _scopeInfo;}internal void HoldTrigger(){DoAttack();IsHoldingTrigger = true;}internal void ReleaseTrigger(){IsHoldingTrigger = false;}internal void ReloadAmmo(){Reload();}}[System.Serializable]public class ScopeInfo{public string ScopeName;public GameObject ScopeGameObject;public float EyeFov;public float GunFov;public Vector3 GunCameraPosition;}
}

三、枪械特效配置

首先在Assets里面找到之前以及导入的资源包,将其中的Bullet_GoldFire_Small_MuzzleFlare预制体拖拽到场景中。这个预制体是开火的特效实现。然后将它移动到枪械的Components物体里面作为子物体。

随后将其拖拽到枪口的位置,点击restart,即可看到开火的效果。

此外还需要将它的layer设置为Gun。
在Hierachy面板打开枪,也就是Assault_Rifle_01_FPSController,然后找到Bullet_GoldFire_Small_MuzzleFlare:

在旁边的inspector面板可以对这个开火的特效进行一些设置。

点击AK47,将枪焰效果物体拖到相应的位置,之前编写好的脚本就可以按照程序执行这个开火效果了,这个效果的播放次数和播放时间也将由脚本进行控制。

对于子弹射出的效果,需要将Particle System物体移动到出弹口的位置。然后就会有弹壳弹出的效果。

同样的,这个效果的layer也要设置为gun。其属性也可以在inspector面板进行更改。
后来发现弹壳的朝向是错误的,于是将rotation进行了修改,这样就没有问题了。

四、枪械声音

首先找到AssultRife的节点,然后打开AssultRife脚本,跳转到Fireams枪械脚本,在其中加入两个和枪械声音相关的变量。

         public AudioSource FirearmsShootingAudioSource;//射击public AudioSource FirearmsReloadAudioSource;//换弹夹

新建一个脚本,命名为FirearmsAudioData枪械声音。然后将audio都编写进来。


namespace Scripts.Weapon
{[CreateAssetMenu(menuName = "FPS/Firearms Audio Data")]public class FirearmsAudioData : ScriptableObject{public AudioClip ShootingAudio;public AudioClip ReloadLeft;//换子弹的声音public AudioClip ReloadOutOf;//弹夹打空,换一个全新的弹夹}
}

[CreateAssetMenu(menuName = “FPS/Firearms Audio Data”)]
这个类继承ScriptableObject。
会发现在create菜单的最上方出现了刚才新建的选项。

新建后,就得到了一个可以播放的声音对象,可以在旁边进行音频的赋值。

然后在Firearms里面新增一个公开的变量。把枪械音源写到里面去,使用public进行修饰,这样才能给它进行赋值。

public FirearmsAudioData FirearmsAudioData;

找到枪械,就可以为它赋上Firearms Audio Data值。
在AssultRife脚本里完成播放开枪音源的逻辑的编写。

     FirearmsShootingAudioSource.clip = FirearmsAudioData.ShootingAudio;FirearmsShootingAudioSource.Play();

同样地,实现换弹夹的声音播放。需要注意的是,要防止换弹夹的声音把开枪的声音掐断。由于是有两种音源,所以要进行一下判断。

     protected override void Reload(){GunAnimator.SetLayerWeight(2, 1);GunAnimator.SetTrigger(CurrentAmmo > 0 ? "ReloadLeft" : "ReloadOutOf");FirearmsReloadAudioSource.clip =CurrentAmmo > 0? FirearmsAudioData.ReloadLeft: FirearmsAudioData.ReloadOutOf;FirearmsReloadAudioSource.Play();

项目实训(十一)——FPS游戏(第一人称射击游戏)初步开发相关推荐

  1. Unity3D FPS Game:第一人称射击游戏(一)

    耗时一周制作的第一人称射击游戏,希望能帮助到大家! 由于代码较多,分为三篇展示,感兴趣的朋友们可以点击查看! Unity3D FPS Game:第一人称射击游戏(一) Unity3D FPS Game ...

  2. Unity3D FPS Game:第一人称射击游戏(二)

    耗时一周制作的第一人称射击游戏,希望能帮助到大家! 由于代码较多,分为三篇展示,感兴趣的朋友们可以点击查看! Unity3D FPS Game:第一人称射击游戏(一) Unity3D FPS Game ...

  3. Unity3D FPS Game:第一人称射击游戏(三)

    耗时一周制作的第一人称射击游戏,希望能帮助到大家! 由于代码较多,分为三篇展示,感兴趣的朋友们可以点击查看! Unity3D FPS Game:第一人称射击游戏(一) Unity3D FPS Game ...

  4. FPS - 第一人称射击游戏

    第一人称射击类游戏,FPS(First-person shooting game), 严格来说第一人称射击游戏属于ACT类游戏的一个分支,但和RTS类游戏一样,由于其在世界上的迅速风靡,使之发展成了一 ...

  5. 【UE4 第一人称射击游戏】01-真实的第一人称相机

    步骤: 1.首先在虚幻商城中下载动画初学者内容包 2.创建一个工程,命名为"FPSTutorial",然后将内容包添加到该工程中 大约20M 3.双击打开"ThirdPe ...

  6. 【历史上的今天】12 月 10 日:世界上第一位程序员诞生;Ada 语言发布;第一人称射击游戏的开拓者

    整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来. 今天是 2021 年 12 月 10 日,在 120 年前的今天,瑞典国王和挪威诺贝尔基金会首次颁发了诺贝尔奖.根据诺贝尔 ...

  7. linux游戏object怎么玩,用Object Detection玩第一人称射击游戏

    在本文中,我将解释如何使用tensorflow的对象检测模型来玩经典的FPS游戏"CS". 不久前,我遇到了这个非常有趣的项目,文章作者使用网络摄像机播放经典的格斗游戏,真人快打. ...

  8. unity3D第一人称射击游戏(推荐)

    unity3d第一人称射击游戏(推荐) 第一部分:简介   这个教程中,我们详细了解下如何制作一个简单的第一人称射击游戏(FPS).其中将介绍一些基本的3D游戏编程的概念和一些关于怎样如游戏程序员般思 ...

  9. 始于20200613关于第一人称射击游戏猿粪计划开发日志

    始于20200613关于第一人称射击游戏猿粪计划开发日志 关于第一人称射击游戏的游戏脚本分析 脚本逻辑图 脚本大纲及关联图 关于第一人称射击游戏的游戏脚本分析 前言:这款FPS单机生存游戏是我独立开发 ...

最新文章

  1. 如何用命令将本地项目上传到git
  2. cisco stp技术应用
  3. VC++调用UpdateLayeredWindow实现半透明窗体【转】
  4. web desktop在线演示
  5. QUIC技术创新 让视频和图片分发再提速
  6. 网络编程中的常见陷阱之 0x十六进制数(C++字面值常量)
  7. 面向计算机体系结构,面向计算机体系结构的程序优化.ppt
  8. MySql笔记之数据备份与还原
  9. 微信小程序(1)-简单答题小程序
  10. 3DMAX渲染了很久还是黑的或有部分黑​屏?
  11. HTTP代理是什么意思?
  12. PeopleSoft 快捷键
  13. win7配置计算机失败还原更改,win7系统更新失败 卡在还原更改处的解决方法
  14. mysql 美东时间格式_C#/.NET怎么样将UTC时间转换成美国东部时间(EST)
  15. Arduino之干接点控制继电器取反实例
  16. CodeForces 869A The Artful Expedient
  17. 安装win10,刻录U盘,还原刻录的U盘
  18. springboot中使用freemarker根据flt模板导出word、pdf文档
  19. MATLAB的RTL-SDR硬件支持包使用详细教程
  20. Linux tcpdump 命令详解

热门文章

  1. python读取dicom序列_用原生Python解析DICOM文件
  2. 每周全球科技十大新闻(2021.7.5-7.11)
  3. 视频、音频文件格式大全
  4. TED x Brixton
  5. qprocess终止其它程序
  6. PMP-项目整合管理的内容
  7. 全网首发,大众奥迪领驭帕萨特DIY数码碟盒增加USB和蓝牙播放音乐功能使用原车接口无损改装
  8. mysql5.5异常: java.sql.SQLException: Packet for query is too large (1055975 > 1048576).
  9. 【编程语言】Go 程序设计教程 / 禅与计算机程序设计艺术
  10. C/C++程序员简历模板(转载)