基于《游戏-01_2D-开发》,
继续制作游戏:
首先给人物添加一个2D重力效果
在编辑的项目设置中,
可以看出unity默认给的2D重力数值是-9.81,模拟现实社会中的重力效果
下方可以设置帧率
而Gravity Scale代表 这个数值会 * 重力
还需要将玩家添加碰撞器Collider,而一般人物均添加胶囊碰撞器Capsule Collider 2D
在编辑场景中人物身上的绿色圆圈就是碰撞范围,我们进行修改
修改成与人物差不多大小
Shift + F 可以快速帮我们找到需要用到的物体
在场景中找到这个物体
添加不规则复合碰撞器有三步
勾选合成为1块 Used By Composite
最后将场景重力效果设置为静态
我们在运行测试前拖动玩家位置
运行可见玩家通过重力落在了地面
我们避免人物因为场景碰撞体的不均匀而摔倒,需要冻结玩家屏幕z坐标
我们还可以通过设置Mass来设定玩家的质量,如果玩家的质量大于怪物就可以撞开怪物
在重力设置中可以在碰撞检测方式上不选间歇性Discrete 而选择持续Continuous
运行即下落
接下来我们开始配置新输入系统
在编写代码之前,我们首先在项目管理中创建两个文件夹,
表示脚本下的玩家文件夹
在玩家管理文件夹中创建一个代码
命名为PlayerController
旧输入系统已经淘汰,因为移植性不好,跨平台性差,例如移植到手机或xbox平台很复杂
所以我们需要用到新输入系统
打开项目设置
找到Other Settings
我们可以修改Api,.NET Framework可以让我们利用更多的c#特性
【切记】:接下来我们要保存好项目,因为接下来的设置新输入系统会自动重启unity项目
我们在Player 的 Other Settings 的 Active Input Handing 中将输入管理Old设置为Both
注意:在点击Apply之前一定要先保存好项目
更新成新输入系统后我们开始使用新输入系统
我们在Windows下的Package Manager下找到新输入系统
选择Unity Registry 在右侧输入Input 即可看到新输入系统点击下载
创建文件夹
创建Input Actions
命名为InputControls
双击我们就可以打开新输入系统了
将新输入系统放置Scene右侧便于操作,创建一个Action map
Action Maps提供选择控制哪些物品操作的途径,
命名为运动Movement
设置
添加 上/下/左/右 绑定
删除无功能选项
设置
重命名WASD
键盘设置完成之后如果还想设置手柄操作的话
可以继续设置
这样就成功实现了两种输入系统
当然除了手动设置新操作系统也可以系统默认生成
首先在Player下增加组件Player Input
点击新建新输入系统
选择刚刚设置好的路径
选择替换
再次双击打开就可以看见系统为我们创建的新输入系统了
节省了很多设置操作
当然我们需要修改这些系统生成的设置比如,
确认设置成了Any 后面会修改它的设置
创建好新输入系统后我们就可以把Player Input这个组件删除了 ,因为我们想通过生成代码的方式实现
要求系统自动生成代码
双击打开代码
编写代码,
这里InputControls 类型 应与自定义新输入系统名字相符合
注意:
函数周期表,
awake > enable > start > physicsUpdate > Update > fixedUpdate > diable > destroy
人物在编辑场景取消右上角显示勾选时,就会执行OnDisable()函数
勾选启动时就会执行OnEnable()这个函数
编写代码,
代码中的inputDirection可以存储一个新输入系统中设定的Vector2变量,从而代码控制新输入系统
编写代码:
定义公开变量inputControl用来存储我们在
下的【InputControls【自定义新输入系统类型】】,
定义公开变量rb存储用来控制玩家移动的【Rigidbody2D【刚体类型】】,
定义公开变量inputDirection存储用来二维转向的【Vector2【二维向量类型】】,
定义公开变量speed存储用来控制移动速度的【float【字符类型】】,
最先调用Awake()函数创建new新输入系统类型内存,再获取刚体组件分别分配给inputControl与rb变量,
然后调用OnEnable()函数与OnDisable()函数中的inputControl的Enabe()与Disable区别是否持续按键,
然后调用Update()函数,获取新输入系统中的二维向量读值,
最后调用FixedUpdate()函数中的Moved函数
Moved()函数中(int)transform.locakScale.x是将transform变量转换成int值
其.locakScale.x即
语句int faceDir = (int)transform.localScale.x; 即将x的缩放比例转换成值存储到faceDir变量中
因为键盘判断左方向与右方向是通过1与-1设定的所以通过
transform.localScale = new Vector3(facwDir,1,1);
其中
是根据
而设定的
根据逻辑判断设定转向
if(inputDirection.x > 0)
faceDir = 1;
if(inputDirection.x < 0)
faceDir = -1;
最后设定刚体的速度
rb.velocity = new Vector2(inputDirection.x * speed * Time.deltaTime,rb.velocity.y);
using UnityEngine;
public class PlayerController : MonoBehaviour{
public InputControls inputControl;
public Rigidbody2D rb;
public Vector2 inputDirection;
public float speed;
private void Awake(){
inputControl = new InputControls();
rb = GetComponent
}
private void OnEnable(){
inputControl.Enable();
}
private void OnDisable(){
inputControl.Disable();
}
private void Update(){
inputDirection = inputControl.Player.Move.ReadValue
}
private void FixedUpdate(){
Moved();
}
private void Moved() {
int faceDir = (int)transform.localScale.x;
if (inputDirection.x > 0)
faceDir = 1;
if (inputDirection.x < 0)
faceDir = -1;
transform.localScale = new Vector3(faceDir, 1, 1);
//键盘
rb.velocity = new Vector2(inputDirection.x * speed * Time.deltaTime,rb.velocity.y);
}
}
注意这里
先判断转向,再进行翻转
运行即完成了翻转及水平移动
接下来要完成跳跃同样,我们需要在新输入系统中自己设定
修改代码,为代码在unity中易读,可在代码中添加特性
保存代码我们在unity中即可看到显示中文
我们首先添加一个 float类型 的 跳跃力 字段
我们想对纵轴施加一个 jumpForce跳跃力
我们需要修改代码:
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour{
public InputControls inputControl;
public Rigidbody2D rb;
public Vector2 inputDirection;
[Header("基本参数")]
public float speed;
public float jumpForce;
private void Awake(){
inputControl = new InputControls();
rb = GetComponent
inputControl.Player.Jump.started += Jump;
}
private void Jump(InputAction.CallbackContext obj){
rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
}
private void OnEnable(){
inputControl.Enable();
}
private void OnDisable(){
inputControl.Disable();
}
private void Update(){
inputDirection = inputControl.Player.Move.ReadValue
}
private void FixedUpdate(){
Moved();
}
private void Moved() {
int faceDir = (int)transform.localScale.x;
if (inputDirection.x > 0)
faceDir = 1;
if (inputDirection.x < 0)
faceDir = -1;
transform.localScale = new Vector3(faceDir, 1, 1);
rb.velocity = new Vector2(inputDirection.x * speed * Time.deltaTime,rb.velocity.y);
}
}
【解析】:
玩家输入系统中我们添加了公开的float类型字段用来存储一个跳跃时纵方向获取的数值,
在调用Awake()函数时 首先获取新输入系统的Jump 然后 打点. 获取 Jump下的 started,
注意:按住可以执行 performed ,为了快速很精准执行一次 我们采取用started 表示按键按下的那一刻 执行了
一般对于单次执行的函数我们放进started中进行,因为started是一个事件方法,所以我们需要添加一个事件注册函数,而注册的内容 就用 += 加号等号 这个符号进行注册,
inpitControl.Player.Jump.started += Jump;
意思就是把 Jump这个函数 添加到 started 按键按下的那一刻来执行,
然后我们可以看到Jump报红,
我们选中Jump 按Alt + Enter 键即可弹出选项我们点击生成Jump方法
即可生成一个带参数的Jump函数我们修改函数中的内容
表示这个Jump函数在按键按下要被执行时 利用刚体rb 打点. 添加一个力,因为这个rb刚体的类型是 Rigidbody2D 所以括号中有两个参数,其中transform.up 表示 世界坐标的上方向,我们通过 * 乘以这个跳跃数值,第二个参数ForceMode2D.Impulse 代表 这个力是瞬时的
Impulse 瞬时力
写好代码,我们通过unity场景中的Player公开的跳跃力字段输入合适的值进行设定找到一个舒服合理的跳跃程度
运行实现跳跃
但这其中还有很多不合理的地方,比如跳跃后松手就会垂直下落,跳跃中前方有障碍物会卡住,在跳跃中可以持续跳跃等,
接下来我们在代码中进行修改,完善成合理的跳跃逻辑
首先我们先解决连续跳跃的问题:
我们新建脚本 物理检查PhysicsCheck.cs
编写代码:
using UnityEngine;
public class PhysicsCheck : MonoBehaviour{
public bool isGround;
public float checkRadius;
public LayerMask groundLayer;
private void Update(){
Check();
}
public void Check(){
isGround = Physics2D.OverlapCircle(transform.position, checkRadius, groundLayer);
}
}
【解析】:
定义一个公开bool类型变量存储到 isGround 变量中,用来判断是否接触到地面,
定义一个公开float类型变量存储到 checkRadius 变量中,用来表示碰撞范围,
定义一个公开 LayerMask层级面具变量存储到 groundLayer 变量中,用来表示对哪个层进行操作,
这里需要在unity场景中手动添加Layer 层:
保存代码后,在unity场景中可见
这两部分的层级是相同的,
我们首先添加层级
设置层级
设置作用层级
这样通过代码就可以影响 被设置的Ground层级的 地面了
语句表示 将进行物理2D 的 OverlapCircle 叠层圆形 检测
检测三个方面
transform.position 检测点
checkRadius 检测范围
groundLayer 检测层级
这样我们回到unity中将检测半径设为 0.2
再将监测点设为脚下
运行即可看到 跳跃前 接触地面的选项被自动 勾选
跳跃后 接触地面的选项被自动 取消
PhysicsCheck脚本写好之后我们进行组合,
用到写好的类PhyisicsCheck脚本这个类型 就可以拿到这个类的所有公开变量与公开方法
【很重要】:拿到之后需要在Awake()函数中激活,
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour{
public InputControls inputControl;
public Rigidbody2D rb;
public Vector2 inputDirection;
public PhysicsCheck physicsCheck;
[Header("基本参数")]
public float speed;
public float jumpForce;
private void Awake(){
inputControl = new InputControls();
rb = GetComponent
inputControl.Player.Jump.started += Jump;
physicsCheck = GetComponent
}
private void Jump(InputAction.CallbackContext obj){
if(physicsCheck.isGround)
rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
}
private void OnEnable(){
inputControl.Enable();
}
private void OnDisable(){
inputControl.Disable();
}
private void Update(){
inputDirection = inputControl.Player.Move.ReadValue
}
private void FixedUpdate(){
Moved();
}
private void Moved() {
int faceDir = (int)transform.localScale.x;
if (inputDirection.x > 0)
faceDir = 1;
if (inputDirection.x < 0)
faceDir = -1;
transform.localScale = new Vector3(faceDir, 1, 1);
rb.velocity = new Vector2(inputDirection.x * speed * Time.deltaTime,rb.velocity.y);
}
}
我们回到unity场景中运行游戏,即可发现连续跳跃问题解决了
当然我们的触碰范围 = 0.2 没有在unity中显示,我们可以自己用代码画出来
using UnityEngine;
public class PhysicsCheck : MonoBehaviour{
public bool isGround;
public float checkRadius;
public LayerMask groundLayer;
public Vector2 bottomOffset;
private void Update(){
Check();
}
public void Check(){
isGround = Physics2D.OverlapCircle(
(Vector2)transform.position + bottomOffset, checkRadius, groundLayer);
}
private void OnDrawGizmosSelected(){
Gizmos.DrawWireSphere(
(Vector2)transform.position + bottomOffset, checkRadius
);
}
}
调用OnDrawGizmosSelected()函数将以
为中心点 以
为半径在人物脚下显示碰撞范围
【解析】
定义一个公开 Vector2二维向量类型的变量存储到 bottomOffset变量中,用作偏移量
在Check()检测函数中 将偏移量bottomOffset 与 检测点位置相加,
注意:因为检测点是三维向量 所以 二维向量 与 三维向量相加需要用到强制转换 (Vector2) 强制转换为二维向量Vector2类型
最后通过OnDrawGizmosSelected()函数将 检测点画出来
注意:Gizmos就是辅助线等小控件可以选择是否显示
这里调用OnDrawGizmosSelected()函数就是选择性将小控件的哪个控件画出来,
显而易见
Gizmos.DrawWireSphere(
(Vector2)transform.position + bottomOffset, checkRadius
);
我们画出来的是 检测范围
在unity场景中通过改变位移差值x/y可以改变检测范围的位置
接下来我们优化跳跃中不会贴在前方障碍物这个问题,
首先在unity场景中创建一个文件夹PhysicsMaterials,
然后创建一个光滑的材质,
起名为Normal
这里表示摩擦力是0.4
我们只需要把摩擦力改为0,就创建了一个光滑的材质
将光滑材质放进玩家的 胶囊碰撞器组件 的 Material框选中
即解决了跳跃中贴前方障碍物的问题
最后运行
实现完整的逻辑跳跃
End