爆肝一周,完成了一款第一人称3D射击游戏,现在把源代码分享给大家,适合新手跟着学习

一、项目背景

大家好,我是小飞

我之前给大家分享了一些网上现成的游戏模板资源,但是很多小伙伴后来反馈说网上的资源有些不能用了,导入进去就会报错等等的问题。

还有一些小伙伴私信问我,有没有什么3D类的游戏项目可以分享的,最好是3D类的FPS游戏。我找了很长时间,但是都没有合适的。所以小飞就花了大概一周的时间,自己写了一个简单的3D FPS游戏。

我在写这个游戏的时候,秉承简单直观的原则。在底层架构的时候,也没有太多复杂的结构。基本上每一个类就对应着游戏中的一个实体,然后有相关的管理类去统筹的两层结构。所以这个项目是非常适合新手学习的。如果你是一个苦于寻找练手项目的新手,对网上的资源又很难争辩优劣的话,小飞这个项目非常适合你。

我接下来跟大家分享下我这个项目的主要思路,可以更好的帮助大家理解这个项目。

这个游戏设定是在一片废墟中,有随机数量的敌人,你需要控制玩家,在规定的时间内找到所有的敌人并将其击杀,即可获得游戏的胜利。超时或者先被敌人击杀,视为游戏失败。每局游戏中,敌人生成的数量和位置都是随机的。

注意:把UnityPackage下载成功,导入到自己的新项目后,需要按照下图所示,增加4个层级

爆肝一周,完成了一款第一人称3D射击游戏,现在把源代码分享给大家,适合新手跟着学习_第1张图片

 

二、项目架构

我这里把项目架构分为两个部分来阐述,场景资源和代码。场景资源是外在一面,每个资源有什么具体的作用,为什么要这样子设定等;代码是内核,针对每一个具体的类,有哪些比较难理解的,怎么才能减少耦合,类之间怎么交互等。

2.场景资源

爆肝一周,完成了一款第一人称3D射击游戏,现在把源代码分享给大家,适合新手跟着学习_第2张图片

 上面的图片是整个场景的结构图,我们需要关注一下几个方面:

2.1 Map

Map下面是放着整个场景的地图资源,包括河流,废墟,墙壁等等。这个下面并没有加上任何的代码。需要注意的就是地图资源需要有碰撞体,这样子玩家或敌人才可以检测到物体碰撞。还有一些是可以阻挡子弹的路径的,需要给它们设定成具体的Layer

2.2 GameInfo

GameInfo是一个空物体,只挂载了GameInfo.cs脚本。它的主要目的是提供一个游戏全局属性配置的窗口。玩家属性和敌人属性可以直接配置到玩家和敌人的预制体上,游戏全局属性就可以配置到GameInfo上。比如说,我在这上面就配置了全局游戏的时长,敌人数量生成最小值和最大值

2.3 EnemyMgr

EnemyMgr是一个空物体,挂载了EnemyManager.cs脚本。该脚本的主要作用是管理敌人。我主要是通过这个脚本来生成、保存、销毁敌人。游戏开始或者重开的时候,通过这个脚本来生成敌人,将所有的敌人都保存到一个对应的字典中,游戏其他地方可以直接通过该脚本获得到所有的敌人信息。给销毁敌人提供的一个统一的接口,方便日后在销毁敌人的之后的一些后处理事件

2.4 AudioMgr

AudioMgr是一个空物体,挂载了AudioManager.cs脚本。该脚本的主要作用是管理音效。游戏中的音效分两大类,一个是UI上的音效,玩家射击声、脚步声和被击中的声音,这些声音我暂时是把它们当成了2D音效来处理,音量不会跟着远近距离的改变而改变;另一个是敌人身上的音效,比如说敌人的射击声和死亡的声音,这些声音是3D音效,如果我站在很远的地方,就听不到这些声音。AudioManager主要是处理2D声音的。现在里面是处理了4种类型的2D音效,大家可以到AudioManager.cs中的AudioType里面查看。这里要强调一个,声音资源必须要直接放在Audio文件夹下才能识别出来,不能Audio下嵌套另外一个文件夹

2.5 UI

UI下面是3个UI界面,MainUI、GameOverUI和GameSuccessUI。每个UI界面上都挂载这对应的脚本文件,比如说MainUI上就挂载这MainUI.cs。UI相关的部分主要是打开关闭的时机,相对应的信息获取和更新,这里就不细说了,可以到项目中直接看代码

2.6 pfb_player_first_perspective

这个就是我们的玩家预制体,和其他的游戏不同,在这个游戏中,我把游戏中的摄像机放到了玩家预制体下。这样子,我们不需要去考虑摄像机的位置更新和旋转角度。在经过我之前的尝试之后,我发现如果你把摄像机放到玩家预制体外面,在玩家旋转角度的时候,会出现不同程度的视野的变化,从而可能可以看到玩家的身体的的问题

这上面挂载了PlayerManager.cs核心脚本。这个脚本的主要作用就是玩家的一切逻辑都在这个脚本中。玩家是支持移动、旋转、开枪、换弹等行为,具体的我在代码部分去讲讲。我也开放了一些相关的属性的配置,比如说玩家的移动速度、射程等,你调整这些数值就能得到不同的效果

2.7 pfb_enemy_barnes

这个预制体是敌人的,放在了Prefab文件夹下,没有展示在游戏场景中,上面挂载了Enemy.cs的脚本。和玩家脚本一样,给大家开放了一些简单属性的接口,比如说玩家的射击速率,最大射程等

2.8 Resources文件目录

爆肝一周,完成了一款第一人称3D射击游戏,现在把源代码分享给大家,适合新手跟着学习_第3张图片

整个项目分为两个大文件夹,Scenes和Resources。Scenes里面就只有一个场景文件。Resources是各种资源文件。Animator是动画资源,Audio是音效,Map是我从网上下载的地图资源,Material是材质球资源,Model下面是玩家、敌人、武器的模型资源,Prefab是玩家、敌人和武器的预制体,UI是各种图片资源

3.代码解析

 爆肝一周,完成了一款第一人称3D射击游戏,现在把源代码分享给大家,适合新手跟着学习_第4张图片

 3.1 AnimationEventBroadcast

此类代码的主要作用是广播动画的事件。有时候,我需要去知道一个动画是不是播放完成了。Unity原生的接口并不是那么友好,所以我写了这个脚本,然后在动画窗口添加一个事件广播,在需要的地方去监听相应的事件,就能够非常准确的实现逻辑了。

爆肝一周,完成了一款第一人称3D射击游戏,现在把源代码分享给大家,适合新手跟着学习_第5张图片

 3.2 EventCenter 和 XFEvent

这两个类是相辅相成的。我们的设计模式是监听者模式。在涉及到不同类之间的交互的时候,经常性的直接引用是非常痛苦的事情。万一其中的一个类已经消亡了,但是你还在引用它,就会得到空值,从而抛出异常。

这个时候,比较好的设计就是你去增加一个监听事件 XFEvent。当发生这个事情的时候,广播出来这个事件,任何监听这个事件的地方都能够收到这个信息。再去执行相关的代码。

XFEvent是具体的事件类型,可以带着0-4个参数。EventCenter是事件中心。所有的事件都是通过事件中心来转发传播的

3.3 PlayerManager

PlayerManager里面涉及的内容相对比较多。我们的玩家支持移动、射击、换弹,旋转等操作。在具体的代码中,都是有相对应的逻辑实现的。并不是很复杂。

移动的时候,如果玩家面对的方向是Z轴的正方向,那么就直接增加它的移动量;但是如果玩家已经旋转了一定的角度,就需要经过一个坐标轴的变化,将之前世界坐标轴里的向量,转换成本地坐标轴的,然后才能正确,具体查看UpdateMove()。

射击的时候,屏幕中心会有一个瞄准点。如果前方有敌人,并且敌人是在射程范围内,那么瞄准点的颜色会变成红色,否则变成灰色,方便玩家查看。

换弹操作不复杂,需要注意的是,我们从网上下载的很多资源,玩家和武器的模型是分开的。为了处理方便,一般要把武器放到玩家的左手或者右手节点下。但是换弹的动画,武器和玩家是分开表现的,所以这个时候就要代码里将武器从玩家节点下拿下来,换弹完成之后,再重新放回去,具体查看 StartLoad()。

旋转的问题是去考虑两个,一个检测玩家现在是否是在拖动操作,一个是检测玩家是上下拖动还是左右拖动。第一个检测,在代码里面是检测玩家是否是点击了鼠标右键,然后前后的鼠标位置是否发生改变,如果是在手机等移动端,需要另外写方法。第二个中,上下拖动是改变枪口位置,左右拖动是改变玩家角度。用户在玩游戏的时候,拖动肯定是上下左右都会有偏移,所以要设置好偏移量,一次拖动只改变一种,这样子玩家体验会好一些,具体查看 OnSwipe()。

3.4 Enemy

敌人主要是AI。这次我并没有制定很复杂的敌人行为。现在只包括三种行为,Idle,Aim和Fire。在一定的范围内,没有检测到玩家,是Idle;当检测到玩家,转变为Aim;Aim了一定的时长之后,转变为Fire。Fire之后再重新检测,是否玩家还在范围内,如果是就转变为Aim,以此循环。这次我是直接写代码,没有构建类似状态机的AI结构,也没有给敌人添加寻路。

三、总结

本次FPSDemo游戏主要是给新手一个练手的项目。它是一个3D项目,网上一般的新手项目都是2D。因为3D项目相对要复杂些。

但是本次项目在代码上是相对简单的,所以理解起来并没有太大的难度。

如果你有什么问题的话,可以评论给我。

你可能感兴趣的:(项目分享,Unity,游戏,学习)