1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 项目实训(十一)——FPS游戏(第一人称射击游戏)初步开发

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

时间:2018-09-25 08:21:24

相关推荐

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

一、前言

我与另外两个组员合作进行了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();

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。