【unity實戰】一個通用的FPS槍支不同武器射擊控制腳本

文章目錄

  • 前言
  • 模型素材
  • 文章用到的粒子火光特效
  • 射擊效果
  • 換彈
  • 瞄準
  • 開槍抖動效果
  • 設置顯示文本
  • 最終代碼
  • 不同武器射擊效果
    • 1. 手槍
    • 2. 機槍
    • 3. 狙擊槍
    • 4. 霰彈槍
    • 5. 加特林
  • 其他
  • 感謝
  • 完結

前言

實現FPS槍支不同武器效果,比如手槍,噴子,狙擊槍,機槍,其實我最開始的想法是先做一個基類腳本,寫一些公共屬性和方法,然后再起不同的武器腳本這個基礎基類,實現不同的武器效果。

這樣的實現思路其實是沒什么問題的,直到我看到這個視頻:https://www.youtube.com/watch?v=bqNW08Tac0Y,作者只用一個腳本就實現了不同的武器效果更加方便,下面我就參考一下作者的思路實現一下大致的效果。

順帶說一下,在第一人稱射擊(FPS)游戲中實現子彈射擊效果,可以通過不同的技術和方法來完成。以下是幾種常見的實現方式:

  1. 射線投射(Raycasting):
    這是最常用的方法之一。射線投射意味著從槍口發出一個虛擬的射線,并檢測這個射線與游戲世界中的對象之間的交互。如果射線與某個對象相交,那么就可以認為子彈擊中了該對象。

    實現步驟:

    • 從玩家的攝像機或槍口位置發出一條射線。
    • 使用物理引擎提供的射線投射功能來檢測射線路徑上的碰撞。
    • 如果射線與對象相交,根據交互結果執行相應的邏輯,比如扣除生命值、播放受擊動畫等。
    • 在射擊點顯示擊中效果,如粒子效果或貼圖。
  2. 拋射物模擬(Projectile Simulation):
    對于需要模擬子彈飛行軌跡的情況,比如遠距離狙擊、火箭筒或者拋射武器,可以使用拋射物模擬。

    實現步驟:

    • 創建一個子彈實體,并賦予它初始速度和方向。
    • 通過物理引擎模擬子彈的飛行軌跡,考慮重力、空氣阻力等因素。
    • 檢測子彈與其他對象的碰撞,并在碰撞發生時處理相應的邏輯。
    • 在子彈飛行過程中可以添加軌跡效果,如拖尾。

每種方法都有其適用場景和優缺點。射線投射適合快速射擊和近距離交火,拋射物模擬適合遠距離和弧線射擊。在實際開發中,這些方法可以組合使用,以達到最佳的效果。

模型素材

不會配置模型可以看我之前的文章,進行下載和配置:
unity中導入下載的3D模型及albedo/baseColor、normal 、AO/Occlus、metallic、roughness貼圖紋理設置

文章用到的粒子火光特效

https://assetstore.unity.com/packages/vfx/particles/legacy-particle-pack-73777
在這里插入圖片描述

射擊效果

[Tooltip("是否正在射擊")]
bool shooting;
[Tooltip("是否允許按住射擊")]
public bool allowButtonHold;
[Tooltip("是否可以射擊")]
bool readyToShoot;
[Tooltip("是否在換彈")]
bool reloading;
[Tooltip("彈夾容量")]
public int magazineSize;
[Tooltip("當前彈夾容量")]
public int bulletsLeft;
[Tooltip("儲備彈藥容量")]
public int reservedAmmoCapacity = 300;
[Tooltip("當前剩余射擊發射的子彈數")]
public int bulletsShot;
[Tooltip("槍口火焰特效")]
public ParticleSystem muzzleFlash;
[Tooltip("子彈擊中效果")]
public GameObject bulletHoleGraphic;
[Tooltip("射擊間隔時間")]
public float timeBetweenShooting;
[Tooltip("連發射擊之間的間隔時間")]
public float timeBetweenShots;
[Tooltip("射擊時的散布度")]
public float spread;
[Tooltip("射擊的最大距離")]
public float range;
[Tooltip("每次射擊發射的子彈數")]
public int bulletsPerTap;
[Tooltip("是否允許按住射擊")]
public bool allowButtonHold;
[Tooltip("每次射擊造成的傷害")]
public int damage;  // 傷害public Camera fpsCam;private void Awake()
{bulletsLeft = magazineSize;readyToShoot = true;
}private void Update()
{MyInput();
}private void MyInput()
{if (allowButtonHold)shooting = Input.GetKey(KeyCode.Mouse0);elseshooting = Input.GetKeyDown(KeyCode.Mouse0);// 射擊if (readyToShoot && shooting && !reloading && bulletsLeft > 0){bulletsShot = bulletsPerTap;Shoot();}
}private void Shoot()
{readyToShoot = false;// 散布float x = Random.Range(-spread, spread);float y = Random.Range(-spread, spread);// 計算帶有散布的射擊方向Vector3 direction = fpsCam.transform.forward + new Vector3(x, y, 0);//場景顯示紅線,方便調試查看Debug.DrawRay(fpsCam.transform.position, direction * range, Color.red);// 射線檢測if (Physics.Raycast(fpsCam.transform.position, direction, out RaycastHit rayHit, range)){Debug.Log(rayHit.collider.name);muzzleFlash.Play();//槍口火焰/火光//TODO:相機震動if (rayHit.collider.CompareTag("Enemy")){Debug.Log("擊中敵人");Rigidbody rb = rayHit.transform.GetComponent<Rigidbody>();if (rb != null){rb.constraints = RigidbodyConstraints.None; // 解除剛體約束rb.AddForce(transform.parent.transform.forward * 500); // 給敵人施加一個力}// 擊中敵人特效var res1 = Instantiate(bulletHoleGraphic, rayHit.point, Quaternion.Euler(0, 180, 0));Destroy(res1, 0.5f);//TODO:扣血}}bulletsLeft--;bulletsShot--;Invoke("ResetShot", timeBetweenShooting);if (bulletsShot > 0 && bulletsLeft > 0)Invoke("Shoot", timeBetweenShots);
}private void ResetShot()
{readyToShoot = true;
}

換彈

private void MyInput()
{//。。。if (Input.GetKeyDown(KeyCode.R) && bulletsLeft < magazineSize && !reloading)Reload();
}//換彈
private void Reload()
{reloading = true;Invoke("ReloadFinished", reloadTime);
}private void ReloadFinished()
{if (reservedAmmoCapacity <= 0) return;//計算需要填裝的子彈數=1個彈匣子彈數-當前彈匣子彈數int bullectToLoad = magazineSize - bulletsLeft;//計算備彈需扣除子彈數int bullectToReduce = (reservedAmmoCapacity >= bullectToLoad) ? bullectToLoad : reservedAmmoCapacity;reservedAmmoCapacity -= bullectToReduce;//減少備彈數bulletsLeft += bullectToReduce;//當前子彈數增加bulletsLeft = magazineSize;reloading = false;
}

瞄準

private void MyInput()
{//。。。//瞄準DetermineAim();
}void DetermineAim()
{Vector3 target = normalLocalPosition; // 默認目標位置為正常瞄準時的本地位置if (Input.GetMouseButton(1)) target = aimingLocalPosition; // 如果按下鼠標右鍵,目標位置為瞄準時的本地位置Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing); // 使用插值平滑過渡到目標位置transform.localPosition = desiredPosition; // 更新槍支的本地位置
}

效果
在這里插入圖片描述

開槍抖動效果

如果你的槍模型沒有開槍動畫的話,這個方法就很方便了

private void Shoot()
{transform.localPosition -= Vector3.forward * 0.1f; // 后坐力使槍支向后移動//。。。
}

設置顯示文本

private void Update()
{//。。。SetUI();
}// 設置文本
private void SetUI()
{text.SetText(bulletsLeft + " / " + reservedAmmoCapacity);
}

最終代碼

public class GunSystem : MonoBehaviour
{public Camera fpsCam;[Header("槍械狀態")][Tooltip("是否正在射擊")]bool shooting;[Tooltip("是否可以射擊")]bool readyToShoot;[Tooltip("是否在換彈")]bool reloading;[Header("彈夾")][Tooltip("彈夾容量")]public int magazineSize;[Tooltip("當前彈夾容量")]public int bulletsLeft;[Tooltip("儲備彈藥容量")]public int reservedAmmoCapacity = 300;[Tooltip("當前剩余射擊發射的子彈數")]public int bulletsShot;[Header("射擊")][Tooltip("射擊間隔時間")]public float timeBetweenShooting;[Tooltip("射擊時的散布度")]public float spread;[Tooltip("射擊的最大距離")]public float range;[Tooltip("每次射擊發射的子彈數")]public int bulletsPerTap;[Tooltip("是否允許按住射擊")]public bool allowButtonHold;[Tooltip("每次射擊造成的傷害")]public int damage;  // 傷害[Tooltip("裝填彈藥的時間")]public float reloadTime;[Tooltip("連發射擊之間的間隔時間")]public float timeBetweenShots;[Header("瞄準")][Tooltip("正常情況的本地位置")]public Vector3 normalLocalPosition;[Tooltip("瞄準時的本地位置")]public Vector3 aimingLocalPosition;[Tooltip("瞄準過程的平滑度")]public float aimSmoothing = 10;[Header("效果")][Tooltip("槍口火焰特效")]public ParticleSystem muzzleFlash;[Tooltip("子彈擊中效果")]public GameObject bulletHoleGraphic;[Header("UI")]public TextMeshProUGUI text;  // 彈藥顯示文本private void Awake(){bulletsLeft = magazineSize;readyToShoot = true;}private void Update(){MyInput();SetUI();}// 設置文本private void SetUI(){text.SetText(bulletsLeft + " / " + reservedAmmoCapacity);}private void MyInput(){if (allowButtonHold)shooting = Input.GetKey(KeyCode.Mouse0);elseshooting = Input.GetKeyDown(KeyCode.Mouse0);// 射擊if (readyToShoot && shooting && !reloading && bulletsLeft > 0){bulletsShot = bulletsPerTap;Shoot();}//換彈if (Input.GetKeyDown(KeyCode.R) && bulletsLeft < magazineSize && !reloading)Reload();//瞄準DetermineAim();}private void Shoot(){readyToShoot = false;transform.localPosition -= Vector3.forward * 0.1f; // 后坐力使槍支向后移動// 散布float x = Random.Range(-spread, spread);float y = Random.Range(-spread, spread);// 計算帶有散布的射擊方向Vector3 direction = fpsCam.transform.forward + new Vector3(x, y, 0);//場景顯示紅線,方便調試查看Debug.DrawRay(fpsCam.transform.position, direction * range, Color.red);// 射線檢測if (Physics.Raycast(fpsCam.transform.position, direction, out RaycastHit rayHit, range)){Debug.Log(rayHit.collider.name);muzzleFlash.Play();//槍口火焰/火光//相機震動if (rayHit.collider.CompareTag("Enemy")){Debug.Log("擊中敵人");// Rigidbody rb = rayHit.transform.GetComponent<Rigidbody>();// if (rb != null)// {//     rb.constraints = RigidbodyConstraints.None; // 解除剛體約束//     rb.AddForce(transform.parent.transform.forward * 500); // 給敵人施加一個力// }// 擊中敵人特效var res = Instantiate(bulletHoleGraphic, rayHit.point, Quaternion.Euler(0, 180, 0));res.transform.parent = rayHit.transform;//設置父類//TODO:扣血}}bulletsLeft--;bulletsShot--;Invoke("ResetShot", timeBetweenShooting);if (bulletsShot > 0 && bulletsLeft > 0)Invoke("Shoot", timeBetweenShots);}void DetermineAim(){Vector3 target = normalLocalPosition; // 默認目標位置為正常瞄準時的本地位置if (Input.GetMouseButton(1)) target = aimingLocalPosition; // 如果按下鼠標右鍵,目標位置為瞄準時的本地位置Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing); // 使用插值平滑過渡到目標位置transform.localPosition = desiredPosition; // 更新槍支的本地位置}private void ResetShot(){readyToShoot = true;}//換彈private void Reload(){reloading = true;Invoke("ReloadFinished", reloadTime);}private void ReloadFinished(){if (reservedAmmoCapacity <= 0) return;//計算需要填裝的子彈數=1個彈匣子彈數-當前彈匣子彈數int bullectToLoad = magazineSize - bulletsLeft;//計算備彈需扣除子彈數int bullectToReduce = (reservedAmmoCapacity >= bullectToLoad) ? bullectToLoad : reservedAmmoCapacity;reservedAmmoCapacity -= bullectToReduce;//減少備彈數bulletsLeft += bullectToReduce;//當前子彈數增加bulletsLeft = magazineSize;reloading = false;}
}

不同武器射擊效果

注意:這里為了方便,我就用一把槍做演示了

1. 手槍

參數配置
在這里插入圖片描述
效果
在這里插入圖片描述

2. 機槍

參數
在這里插入圖片描述
效果
在這里插入圖片描述

3. 狙擊槍

參數,狙擊槍其實和手槍參數差不多,可以就需要修改射擊間隔時間、換彈時間和傷害
在這里插入圖片描述
效果
在這里插入圖片描述

4. 霰彈槍

參數
在這里插入圖片描述

效果
在這里插入圖片描述

5. 加特林

參數
在這里插入圖片描述

效果
在這里插入圖片描述

其他

可以看到其實還有很多功能沒有實現,比如后座力或者放大鏡等等效果,這篇文章說的已經夠多了,后面我再單獨做其他內容的探究吧!

感謝

【視頻】https://www.youtube.com/watch?v=bqNW08Tac0Y

完結

贈人玫瑰,手有余香!如果文章內容對你有所幫助,請不要吝嗇你的點贊評論和關注,以便我第一時間收到反饋,你的每一次支持都是我不斷創作的最大動力。當然如果你發現了文章中存在錯誤或者有更好的解決方法,也歡迎評論私信告訴我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奮斗的開發者,出于興趣愛好,于是最近才開始自習unity。如果你遇到任何問題,也歡迎你評論私信找我, 雖然有些問題我可能也不一定會,但是我會查閱各方資料,爭取給出最好的建議,希望可以幫助更多想學編程的人,共勉~
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/212650.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/212650.shtml
英文地址,請注明出處:http://en.pswp.cn/news/212650.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《使用ThinkPHP6開發項目》 - 創建應用

《使用ThinkPHP6開發項目》 - 安裝ThinkPHP框架-CSDN博客 《使用ThinkPHP6開發項目》 - 設置項目環境變量-CSDN博客 《使用ThinkPHP6開發項目》 - 項目使用多應用開發-CSDN博客 根據前面的步驟&#xff0c;我們現在就可以開發我們的項目開發了&#xff0c;根據項目開發的需要…

【數據挖掘】國科大蘇桂平老師數據庫新技術課程作業 —— 第四次作業

云數據庫研究 云計算與云數據庫背景 云計算&#xff08;cloud computing&#xff09;是 IT 技術發展的最新趨勢&#xff0c;正受到業界和學術界的廣泛關注。云計算是在分布式處理、并行處理和網格計算等技術的基礎上發展起來的&#xff0c;是一種新興的共享基礎架構的方法。它…

Django多對多ManyToManyField字段

Django是一個支持多對多關系的Web框架&#xff0c;可以在模型中定義多對多關系。多對多關系通常涉及兩個實體之間的復雜交互&#xff0c;例如用戶和組之間的關系&#xff0c;或者課程和學生之間的關系。在Django中&#xff0c;可以使用ManyToManyField字段來定義多對多關系。 …

[足式機器人]Part4 南科大高等機器人控制課 Ch05 Instantaneous Velocity of Moving Frames

本文僅供學習使用 本文參考&#xff1a; B站&#xff1a;CLEAR_LAB 筆者帶更新-運動學 課程主講教師&#xff1a; Prof. Wei Zhang 南科大高等機器人控制課 Ch05 Instantaneous Velocity of Moving Frames 1.Instantanenous Velocity of Rotating Frames2.Instantanenous Veloc…

機器學習基礎入門

機器學習 引言 介紹機器學習的重要性和應用領域。簡要說明機器學習與人工智能的關系。 在當今迅速發展的技術世界中&#xff0c;機器學習已經成為一項不可或缺的技術&#xff0c;它正在改變我們解決問題和理解世界的方式。機器學習&#xff0c;作為人工智能&#xff08;AI&a…

最新Redis7持久化(權威出版)

首先我們要知道什么是持久化&#xff1a;持久化是指將數據保存到磁盤上&#xff0c;以確保在Redis服務器重啟時數據不會丟失。 Redis支持兩種主要的持久化方式&#xff1a;RDB持久化和AOF持久化 下面讓我依次給你介紹一下&#xff1a; RDB持久化 作用 這是將Redis數據保存…

Java8新特性 - Stream

一、特性 Java 8引入的Stream API為集合&#xff08;Collections&#xff09;提供了一種聲明式的處理方式&#xff0c;支持豐富的操作&#xff0c;包括篩選、映射、歸約等。以下是一些Stream的主要功能和使用方式的案例&#xff1a; 創建Stream&#xff1a; List<String&…

Java語言概述及保姆級入門教程(JDK 17版本)

筆記來自尚硅谷老師-康老師 學習教程&#xff1a;https://www.bilibili.com/video/BV1PY411e7J6/?spm_id_from333.337.search-card.all.click 1、Java基礎全程脈絡圖 1.1 本章專題與脈絡 2. 抽絲剝繭話Java 2.1 當前大學生就業形勢 麥可思研究院發布了《2022年中國大學生就業…

TCP 和UDP 到底有啥區別

TCP&#xff08;傳輸控制協議&#xff09;和UDP&#xff08;用戶數據報協議&#xff09;是互聯網上常用的兩種傳輸層協議&#xff0c;它們在數據傳輸方式和特性上有顯著的區別。下面是TCP和UDP的主要區別&#xff1a; 連接性: TCP 是一種面向連接的協議。在數據傳輸前&#xf…

C#圖像處理OpenCV開發指南(CVStar,09)——邊緣識別之Scharr算法的實例代碼

1 邊緣識別之Scharr算法 算法文章很多&#xff0c;不再論述。 1.1 函數原型 void Cv2.Scharr(src,dst,ddepth,dx,dy,scale,delta,borderType&#xff09; 1.2 參數說明 src 代表原始圖像。dst 代表目標圖像。ddepth 代表輸出圖像的深度。CV_16Sdx 代表x方向上的求導階數…

uniApp應用軟件在運行時,不符合華為應用市場審核標準。解決方案合集!

&#xff08;暫時用不到的也建議收藏一下&#xff0c;因為文章持續更新中&#xff09; 最新更改時間&#xff1a;20023-12-10 第一次做App應用開發相信大家一定都遇到過華為應用市場審核的“駁回”&#xff01; 有些問題一看就明白可以立馬修改&#xff0c;而有一些問題修改意…

Dubbo入門直接上手,結合微服務詳解

Dubbo 高性能、輕量級的 Java RPC 框架 RPC&#xff1a; Remote Procedure Call 遠程過程調用&#xff0c;簡單來說就是它允許一個計算機程序通過網絡請求調用另一個計算機上的程序&#xff0c;就像本地調用一樣。有非常多的協議和技術來都實現了RPC的過程&#xff0c;比如&a…

Elasticsearch 8.9 refresh刷Es緩沖區的數據到Lucene,更新segemnt,使數據可見

一、相關API的handler1、接受HTTP請求的hander(RestRefreshAction)2、往數據節點發送刷新請求的action(TransportRefreshAction)3、數據節點接收主節點refresh傳輸的action(TransportShardRefreshAction) 二、在IndexShard執行refresh操作1、根據入參決定是使用lucene提供的阻塞…

【華為數據之道學習筆記】3-8以確保合規遵從為核心的外部數據管理

一、以確保合規遵從為核心的外部數據管理 外部數據是指華為公司引入的外部組織或者個人擁有處置權利的 數據&#xff0c;如供應商資質證明、消費者洞察報告等。外部數據治理的出發點是合規遵從優先&#xff0c;與內部數據治理的目的不同。 外部數據的治理主要遵循以下原則。 1&…

【設計模式--創建型--原型模式】

設計模式--創建型--原型模式 原型模式概述結構實現結果 案例代碼結果使用場景 擴展&#xff08;深\淺克隆&#xff09;淺克隆演示&#xff1a;結果&#xff1a;使用深克隆&#xff08;利用對象流&#xff09;結果 原型模式 概述 用一個已經創建的實例作為原型&#xff0c;通過…

Go簡單了解

0.一直很好奇,go是不是像傳說中的速度快,解決了多線程問題,快速進行了解了解,和java進行對比,他是怎么解決語言發展的問題的…,所有語言都是差不多的,只是熟練程度不同而已 1.go圖標是土撥鼠,2009發行 docker使用go,解決了并發問題 google facebook 騰訊 百度 七牛云 京東 小米…

Spring Cloud Gateway + Nacos + LoadBalancer實現企業級網關

1. Spring Cloud Gateway 整合Nacos、LoadBalancer 實現企業級網關 前置工作&#xff1a; 創建 SpringBoot 多模塊項目創建網關&#xff08;gateway-service&#xff09;、用戶&#xff08;user-service&#xff09;模塊用戶模塊添加 Nacos discovery 支持以及 Spring Web&am…

gitbash下載安裝

參考教程 零、下載 官網地址 2.43.0win64 鏈接&#xff1a;https://pan.baidu.com/s/16urs_nmky7j20-qNzUTTkg 提取碼&#xff1a;7jaq 一、安裝 圖標組件&#xff08;Additional icons&#xff09;&#xff1a;選擇是否創建桌面快捷方式&#xff1b;桌面瀏覽&#xff08;Win…

設計模式--命令模式的簡單例子

引入&#xff1a;以一個對數組的增刪改查為例。通過命令模式可以對數組進行增刪改查以及撤銷回滾。 一、基本概念 命令模式有多種分法&#xff0c;在本文中主要分為CommandMgr、Command、Receiver. CommandMgr主要用于控制命令執行等操作、Command為具體的命令、Receiver為命…

逸迅科技丁紅陽:三種能力幫助企業打造GBI “護城河”

大數據產業創新服務媒體 ——聚焦數據 改變商業 近日&#xff0c;由上海市經濟和信息化委員會、上海市科學技術委員會指導&#xff0c;數據猿與上海大數據聯盟聯合主辦的“2023企業數智化轉型升級發展論壇”在上海舉行。本次論壇以“釋放數字價值驅動智能升級”為主題&#xf…