使用Unity实现简单第一人称射击游戏

github项目地址:GitHub - lababababidu/My-U3D-FPS-Assests(只包含素材脚本,项目结构较乱)

FPS With CrossBow 自用

第一人称组件

第一人称基本框架

一个PlayerInputHandler获取玩家的控制输入,再传给PlayerCharacterController玩家角色控制器对玩家所控制的角色的各种属性进行更改。或是传入WeaponManager武器管理器来操控WeaponConroller武器控制器控制武器。

输入从键盘传入后大致的流向如下类图所示:

基本移动

一个正常的FPS游戏应当允许玩家控制角色在地图上移动。通常使用键盘或手柄(控制器)进行控制。对于键盘,更常见的使用wasd控制角色移动,空格键控制角色跳跃(部分游戏没有这个功能)。

要实现这个功能,主要的逻辑在于获取玩家键盘输入。Unity中内置了一个很方便的输入检测的功能,我们可以通过Input.GetAxisRaw的函数获取一个水平或是竖直的输入量,将些输入量放入一个Vector3中,使用ClampMagnitude规范其每个分量的最大值为1,这样就得到了一个移动向量,这个向量表示了玩家期望当前角色想要往哪个方向移动。

对于跳跃,只需检测空格键是否被按下。

之后,将获取的玩家输入按一定的逻辑转化为速度,赋值给Unity组件Character Controller。Character Controller是一个非常强大的组件,给予他速度之后,它就能自行在world space中移动,同时,它也提供了碰撞体,以及isgrounded的布尔值变量。将输入转化为速度的逻辑如下:先将move转化为worldspacemove,然后判断角色是否在地面上(空中转体不符合科学,但其实大部分游戏都允许),如果在地上,则直接将worldspacemove乘一个speed系数获取目标速度,使用lerp插值方法将Character Controller的速度逐渐转化为目标速度。

如果角色处于地面,且跳跃被按下,则让Character Controller获得一个向上的速度分量,模拟跳跃。

如果角色不在地面,则不对x和z轴速度进行操作,而是更新Y轴速度,让Character Controller获得一个下降的速度。由于内置的Gravity系数所导致的自由落体在视觉效果上看略慢,所以使用自己定义的Gravity系数。

视角转动

目前市面上绝大多数FPS游戏都允许玩家使用鼠标操控角色进行视角的转动,以达到更好的瞄准效果。

这部分的实现逻辑是,获取用户鼠标的纵向与横向位移,将其按一定的逻辑转化为旋转量,应用到摄像机(或是整个角色)上。

获取鼠标纵向与横向位移仍是通过Input.GetAxisRaw的函数来实现,获取输入后,将其乘上一些系数,以免值过大。

对于水平的转动,直接乘上相机旋转速度后直接应用到整个角色对象上即可,但对于抬头低头的转动,我们不希望角色的身体跟着转动,只转动摄像头。同时,也不能直接将旋转应用到摄像头上,因为我们不希望角色的头整个调转(这很恐怖),因此需要使用Clamp函数对竖直方向的旋转角度进行限制,然后再对摄像头应用旋转。

枪械组件

目前市面上绝大多数FPS游戏,都会在屏幕的右下角显示出当前所使用的武器,并且武器随着开火状态播放不同的的动画。

本次使用的武器模型来自于Unity Assets Store,使用的是免费的十字弩模型。

武器显示

本人在屏幕上显示出武器的方法为:直接往角色的根节点下,主摄像机旁创建一个新节点,用于挂载武器,被挂载的武器的position就在主摄像机旁边,这样摄像机就能一直拍到武器。

但是,这样会导致一个问题,武器并没有设置碰撞体,当角色靠近墙体时,武器的一部分会因穿模埋在墙体里而看不见,这并不是我们希望的。

对此,解决方法是:为武器设置一个layer,同时新建一个摄像头,对这个摄像头的各项参数进行调整,使其只看着武器的layer,这样无论武器如何穿模,都不会被截断。这样做有一个好处,后续做子弹发射和子弹碰撞检测时,可以直接避开武器的layer。

武器管理

武器管理器被挂载到Player对象上,与角色控制器和输入检测器属于同一级

使用一个WeaponManager对武器进行初始化和管理,这个WeaponManager有一个武器列表,如果有需要,可以通过这个列表切换武器,控制武器是否启用,玩家也是通过输入其与武器管理器交互,再调用武器的开火、换弹等接口。

武器控制器

武器控制器脚本,被挂载到武器对象的根上,它有一个tryfire接口,当用户鼠标左键被摁下时,如果武器管理器的fireability为true,则会调用武器的tryfire接口,如果武器满足开火条件,则会开火。若是不满足开火条件,则会尝试换弹或其他操作。

此外武器控制器也有一个换弹接口,当玩家摁下R键时,武器管理器会调用这个换弹接口。

武器开火

本次游戏使用的武器是一把十字弩,武器开火时,射出的子弹速度较低,故直接采用生成实体的方式创造子弹。当武器开火时,生成弓箭实体对象,并赋予其初速度,生成的弓箭对象带有刚体组件,会随时间下落。

箭控制脚本

一个抛物体基类用于调用箭的发射函数,同时搭桥将箭的owner设置,这样再碰撞检测是也可以使用owner变量避开某些特定对象。抛物体基类和箭的控制类同时挂载到箭的预制体上,打开箭的box collider。

箭有一个公共函数onshoot,这个函数用于给箭的刚体赋值速度,同时。这个函数会在箭控制类被启用是挂载到抛物体基类的一个UnityAction  OnShoot上。

WeaponController脚本需要挂载子弹的预制件的抛物体基类。当武器控制器的fire函数被调用时,会通过抛物体基类的Shoot函数启动动作OnShoot,动作OnShoot中又包含箭控制器的onShoot,箭控制器的onShoot为箭的刚体赋予速度和方向,箭就被射出去了。

武器动画

在武器控制器的里,获取武器预制体的animator,然后在各处函数中,如fire、reload函数中,设置武器animator的变量,通过这些变量的值控制使得animator转换动画状态,以播放不同的动画。

箭命中后效果

许多游戏,比如minecraft,在弓箭命中目标,或是物体后,会将弓箭插在击中点。这个效果也可由脚本实现。

通过实现oncollision回调函数,当碰撞发生时,collision会记录碰撞点以及被碰撞物体。将箭的速度清空,设置IsKinematic为true避免后续碰撞和重力对箭的影响。并移到碰撞点上,加上一些偏置,使得箭的大部分躯体暴露在外,同时将箭指向碰撞法线方向,这样视觉效果更好。随后将箭设置为被碰撞物的子物体。

计分类设计

用一个简单的脚本实现一个计分类,这个脚本仅被挂载到游戏空间中的一个计分器空对象上,当箭命中标靶时,标靶从计分器空对象获取脚本对象,然后调用脚本的接口进行加分。

标靶调用计分器加分示例:

固定靶制作

从Assets Store上找到一些免费的标靶模型,并导入。

为标靶添加标靶控制器,所有标靶控制器关联一个计分器。当标靶的碰撞发生时,如果检测到被碰撞物体为箭,则说明箭集中了标靶,标靶控制器调用计分器的函数执行加分操作。

移动靶制作

移动靶与固定靶制作基本没有区别。但是需要标靶控制器控制移动靶移动。同时,在箭击中移动靶时,标靶控制器做出一个向后倒伏的动画。

其他

地形

使用Unity内置的地形编辑器编辑地形,添加地形纹理,种植树和草。

天空盒

使用了一个网上找到的动态天空盒的shader。把这个shader放到一个新的material上,添加好噪声图和星空图。在Unity项目设置中将环境里的天空盒改成新的material。再添加一个脚本,随着时间推移更改项目中模拟太阳光的直射光的角度。

天空效果:

音效

为游戏添加背景音,在计分器脚本的Start函数中启动背景音播放,设置循环。

为十字弩添加射击音效。在开火时播放音效。为弩箭添加音效,在弩箭击中物体时播放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值