动作游戏制作
动作游戏制作
ZHY开个新坑,最近瓶颈期,我觉得需要多敲代码,让自己更熟悉unity.
教程原链接:
https://www.udemy.com/course/project-little-adventurer-learn-to-create-a-3d-action-game/
b站视频链接:
【UNITY教程 | 学习使用高质量的游戏资产创建 3D 动作游戏(更新完毕)】https://www.bilibili.com/video/BV1B14y1E7SW?p=6&vd_source=b702db14148b48ad87406aaf674e1744
- 付费教程且看且珍惜,是生肉,但是勉强硬啃.(编辑,发现b站有自动生成英文和翻译功能,机翻可以啃的更舒服了)
- 下面内容是我边查资料,边尝试理解作者的操作意图所作,如有不对欢迎指出.
导入资源包
首先,项目设置里,设置渲染为线性渲染.以下内容为转载
线性渲染
Linear Rendering 和 Gamma Rendering的区别
Linear Rendering就是在shader中所有计算会在线性空间下进行,Gamma Rendering就是在shader中不进行转换到线性空间下,直接计算。然就是计算方程式不同,也就意味例如光照表面会有不同的响应曲线和图片效果,表现不相同。
1.Light Falloff
光照表现一般受光源的距离和法线两个因素影响(在同等光强下)。首先当我们用Linear Rendering时,执行Gamma矫正将会使光照范围变大。第二种会使边缘模糊,分不清界限。这更准确的表现了表面光照强度下降。
2.表面响应强度
随着光强的增加,非线性方式计算的表面会更亮一些。这导致了光照在表面很多地方曝光过度,而且给场景模型一个褪色(变白色了)的感觉。当你用线性渲染时,表面颜色仍然随着光照强度线性增加的,这样就使表面材质和颜色更接近现实.
3.混合
混合是在帧缓冲区发生的,当使用Gamma Rendering,这表示颜色之间混合是在非线性空间下计算的。然而这是不正确的。
上图是在Linear Space中混合结果,颜色之间过度不是很明显。
上图是Gamma Space中混合结果,颜色交界处出现了明显的其它颜色,颜色更亮,出现褪色的现象。
4.Mipmaps
计算纹理Mipmap是种线性计算,需要对某个方形区域内像素取平均值,如果纹理存储在非线性空间,那么计算时也是在非线性空间里计算,这样就会得到错误的结果。正确的做法是先转换到线性空间在计算mipmap。
5.Lightmapping
切换linear 和gamma方式,需要重新烘焙相关的Lightmapping。
关于渲染我了解的很少,具体资料可以参考:
————————————————
版权声明:本文为CSDN博主「追风者t」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/k46023/article/details/52489363/
回到项目,设置渲染为线性渲染:
导入包
刚导入时是一片粉色
Package Manager中选择注册表
安装Universal RP
安装完成后打开项目设置,
再安装一个这个
这个
添加包
com.unity.progrids
设置游戏场景
创建一个新空白场景,找到场景预制体拖入场景,并且重置位置属性
新建相机
设置tag为MainCamera
位置可以参考视频里的位置
后处理要打开,虽然我打开之后画面非常模糊,接着往下做看看吧.
新建和配置角色
新建空物体,位置重置为0,0,0
拖入对象
移除动画器
添加灯光
需要设置角色Mesh的layer层级为player
设置完就可以看到灯光
设置虚拟摄像机
注意图里圈出来的地方改一下
添加角色控制器组件
注意数值变化
玩家行走
功能实现写在代码注释中
新建俩脚本添加到player上
玩家输入类PlayerInput.cs
public class PlayerInput : MonoBehaviour |
角色控制类character
using System.Collections; |
动画控制器
创建动画控制器
新建AnimatorController,双击打开.
添加idle状态
新建状态,命名为idle,附加上idle资源,顺便检查下有没有开启循环播放动画.
给角色添加武器
打开角色骨骼,找到左手,将剑资源拖入
设置旋转和位置
右手同上操作,右手剑的位置信息如下:
运动动画
新建float参数speed,新建状态Run,附加上动画,通过make Transition建立状态过渡连线,两端都建一条箭头.
选中Idle->Run的箭头,接下来看图,关闭Has Exit Time
接着选中Run->Idle箭头,关闭Has Exit Time,设置状态过渡用时和过渡时机.
回到character.cs脚本中,添加一个动画控制器变量,CalculatePlayerMovement方法中,为Speed赋值.
下落动画
动画控制器中新建一个bool变量airBorne
确保动画是循环播放
新建状态Fall,由Any State指向Fall
选中该箭头,注意has Exit Time不选中,因为我们要立即执行
拉到最下,连接AirBorne参数为true时进行下落状态
同理Fall->Idle状态设置如下:
接下来回到character脚本,CalculatePlayerMovement方法中添加一条代码控制AirBorne参数.
回到编辑器运行测试,我发现下落和落地后的动作过于僵硬,所以把上面的两个状态之间的过渡都调成了0.1;
脚步视觉特效
新建一个空对象命名为VFX,然后资产文件中找到脚步特效prefab,拖入其中
调整位置
现在奔跑烟雾特效一直显示在角色脚下,我们要做的是将特效改为奔跑时触发.
首先取消自动播放,其次在相应状态动画中创建脚本进行控制.
阻止特效动画自动播放
Initial Event name:初始事件名称
特效管理脚本:PlayerVFXManager
using UnityEngine; |
拖入特效
打开Player动画控制器,选中Run状态,在下面新建脚本Player_Run
状态脚本Player_Run.cs
进入状态时启动特效管理器中的Update_FootStep(true)
,播放特效
退出状态时关闭特效Update_FootStep(false);
using UnityEngine; |
敌人对象
创建敌人对象
在目前项目还不复杂的时候创建敌人对象,可以使用同样的动画控制器
和角色脚本
.
新建对象命名为Enemy_01,拖入npc模型
新建一个重载动画控制器Animator Override Controller
将player拖入
为敌人添加新的动画来重写原主角的动画.
敌人对象添加animator
敌人ai
依次打开Window->AI->Navigation,菜单栏选Bake,更改参数如下
slope斜坡设置为0度,确保ai不会上坡
Step Height设为0.1只覆盖平面,效果图如下
给敌人ai添加碰撞体,并更改参数
添加Nav Mesh Agent
(Agent:代理人)
更改Stopping Distance为2 ai距离人类2时停下进行攻击
敌人脚本
修改Character.cs
增加[SerializeField] bool IsPlayer = true;//是否玩家
Awake()中添加敌人定义
private void Awake() |
添加敌人行动方法CalculateEnemyMovement()
,跟随玩家且播放动画
/// <summary> |
FixedUpdate()中新增判断,来区分玩家和ai
private void FixedUpdate() |
敌人VFX
新建空对象->改名->拖入预制体
删除Initial Event Name防止自动播放特效动画
AI踩踏时触发特效
添加事件
找到npc移动动画
在脚落地的那一帧分别添加事件
创建敌人特效管理脚本EnemyVFXManager
添加命名空间using UnityEngine.VFX;
using System.Collections; |
回到unity,给enemy附加脚本和特效
效果
修改玩家输入脚本
新增部分:添加变量mouseButtonDown代表鼠标左键
,判断是否按下?若未按下且游戏正常运行,则将它设置为当前鼠标左键状态
using UnityEngine; |
状态机
创建状态枚举
打开Character.cs
,声明一个类:CharacterState
,并且创建该类变量
|
状态转换
同一脚本中,创建一个方法SwitchStateTo
进行状态更新
/// <summary> |
在FixedUpdate()
方法中添加代码,判断何时切换状态
switch (CurrentState) |
在计算玩家运动的CalculatePlayerMovement()
方法中添加下面一段判断:玩家在地上且鼠标左键按下时,状态切换成攻击
if (playerInput.mouseButtonDown && cc.isGrounded) |
修改SwitchStateTo方法,在开头清理缓存,在最后log查看状态
private void SwitchStateTo(CharacterState newState) |
测试:运行后点击左键正常触发log内容,但是视频中行动中切换到attacking状态会无法控制角色行走,我做出来的内容依然可以控制 不知道什么原因.
第二天编辑:昨天之所以攻击状态还能移动,是FixedUpdate()
函数中,写状态相关代码之前,没有注释之前调用的玩家移动函数
玩家攻击动画
创建攻击动画
动画器中创建trigger变量,命名为Attack
新建Sub-State Machine 子类状态机命名为Attack
右键添加箭头,这俩箭头配置如下图
Attack状态转idle是灰色箭头,后面修改.
双击点进Attack子状态机,添加combo01状态
箭头参数设置:意思是在攻击动画播完就去下一个动画,并且无过渡部分,动画不与下一个混合
给combo01状态添加动画:
做完当前内容,在游戏中进行攻击,攻击动画播放完成后无法返回idle,要解决这个问题最简单的方式是发送动画事件,在组合动画的最后一帧添加事件
找到攻击动画,并在下方events中快结束的地方添加关键帧,命名为AttackAnimationEnds
脚本部分
来到SwitchStateTo()
函数,新增部分:
接着创建动画事件同名函数AttackAnimationEnds
public void AttackAnimationEnds() |
刀光粒子
找到资源,拖入角色下的visual下的vfx对象
打开PlayerVFXManager.cs
玩家特效管理器脚本,新增刀光粒子相关代码
玩家攻击前滑行(瞬移)代码
定义攻击开始时间,攻击时长,攻击速度等变量
|
在SwitchStateTo
状态更新函数的新状态(newState)分支中添加代码,
判定为玩家后保存当前时刻.
在FixedUpdate()
中更新代码
测试:点击左键角色会往前瞬移一段然后发出攻击.
敌人攻击
设置敌人攻击动画
找到enemy01,添加攻击动画
通过点击动画可跳转到资源
找到敌人攻击动画,在末尾添加关键帧,命名为AttackAnimationEnds
脚本部分
敌人到达主角位置时攻击SwitchStateTo(CharacterState.Attacking);//切换到攻击状态
,具体代码如下:
/// <summary> |
测试发现有报错,原因是SwitchStateTo()
开头有个玩家输入操作代码,加一个判断语句即可
再次测试出现的问题是敌人攻击前不会转向玩家
来到SwitchStateTo()
,找到newState
部分.新加代码:
if (!IsPlayer) |
整体代码如下:
设置敌人攻击特效
找到特效拖入
调整位置
在特效脚本中添加敌人部分