(1.这里写的移动系统包括角色的移动以及摄像机的移动 2.不包括动画部分 3.本人是根据b站“傅老师”的黑魂复刻视频写的这个移动系统,所以高度相似)

动作控制器

输入输出模块做完后我们新建一个脚本开始做动作控制器了

//定义
public PlayerInput pi;//获取
void Awake()
{pi = GetComponent<PlayerInput>();
}

首先我们要获得之前的输入输出模块,考虑到动作控制器和输入输出模块应该是挂在同一物体上,我们直接在Awake里面获取。然后我们就可以开始调整角色的朝向了。

//获取人物模型
public GameObject model;//让模型转向
void Update()
{model.transform.forward = pi.Dright * transform.right + pi.Dup * transform.forward;
}

这里有一个要注意的点,你的脚本不能挂在角色模型上,不然你的角色模型的坐标就会转动,比方说角色模型收到的指令是转向它的右手边,可是它的右手在它转动的时候也在转动,那么就会出现“小狗追尾巴的效果”,会鬼畜的大旋转。
好的现在我们的转向还需要处理两个问题:1.运行后我们会发现,在我们松开按键之后一会儿角色的朝向会回到初始的方向,这是由于角色的Dup或Dright值此时开始衰减,两者都为零之后公式算出的model.transform.forward值就变成了0,也就是初始方向。2.当我们一个一个按下方向键时,会看到角色的转向会突变,让人看起来很不爽。
那么我们现在来解决这两个问题。
问题一的解法很简单,既然是衰减到零惹得祸,那么我们只要让转向只在Dup或Dright的值大于0时执行就好了,所以我们可以这样做:

if (Mathf.Sqrt((pi.Dup * pi.Dup) + (pi.Dright * pi.Dright)) > 0.1f)
{model.transform.forward = pi.Dright * transform.right + pi.Dup * transform.forward;
}

问题二呢,则需要我们进一步更改一下代码:

if (Mathf.Sqrt((pi.Dup * pi.Dup) + (pi.Dright * pi.Dright)) > 0.1f)
{Vector3 Dvec = pi.Dright * transform.right + pi.Dup * transform.forward;model.transform.forward = Vector3.Slerp(model.transform.forward, Dvec,0.5f);
}

Slerp是用于Vector3中的插值函数,其特点是会使两个向量在球面上进行插值。

好的现在呢我们开始做模型的位移部分,这一部分我们还是用刚体来实现。
所以先定义并且在Awake里面获取吧。

private Rigidbody rigid;void Awake()
{rigid = GetComponent<Rigidbody>();
}

由于Rigidbody无法在Updata里面调用,所以我们对它的操作将在FixedUpdata里面进行。(物理引擎是每秒50次模拟,与Updata函数的运行速度不一样)

public float walkSpeed = 2.0f;
private Vector3 movingVec;void Updata()
{movingVec = Mathf.Sqrt((pi.Dup * pi.Dup) + (pi.Dright * pi.Dright)) * model.transform.forward * walkSpeed;
}void FixedUpdate()
{//这里两种方式,方法一:rigid.position += movingVec * Time.fixedDeltaTime;//方法二:rigid.velocity = new Vector3(movingVec.x, rigid.velocity.y, movingVec.z);
}

这里说一下为什么方法二中我们不直接设置 rigid.velocity = movingVec * walkSpeed 而要让其 y 轴速度保持原本速度,因为我们的 movingVec 的运算中实际上是没有给出 y 轴的速度的,也就是 y 轴速度为0,如果就这么设置,那么运行时角色 y 轴速度会被抹去,跳跃或下落等有 y 轴速度的动作就会出差错。
在这么处理后角色就能开始移动了,然而这个写法仍有一个问题。
我们看到movingVec的公式中包含Mathf.Sqrt((pi.Dup * pi.Dup) + (pi.Dright * pi.Dright))这条,只要稍一注意就会发现这将导致单按下某个方向按键与按下两个按键时的速度不同,这要如何解决?

答案是通过公式把坐标转化为“一个圆”。
这里要对我们的输入模块进行改动:

 void Updata(){Dup = Mathf.SmoothDamp(Dup, targetDup, ref velocityDup, 0.1f);Dright = Mathf.SmoothDamp(Dright, targetDright, ref velocityDright, 0.1f);Vector2 tempDAxis = SquareToCircle(new Vector2(Dup, Dright));}private Vector2 SquareToCircle(Vector2 input){Vector2 output = Vector2.zero;output.x = input.x * Mathf.Sqrt(1 - (input.y * input.y) / 2.0f);output.y = input.y * Mathf.Sqrt(1 - (input.x * input.x) / 2.0f);return output;}

这里,Dup和Dright的含义发生了改变,所以我们还需要重新设定一组值来代替原来的Dup和Dright,这里可以看出我们设计上出现了漏洞,Dup和Dright已经多次引用,所以为了改动方便,我们讲Dup和Dright使用最频繁的两个公式直接定义出来。

        float Dup2 = tempDAxis.x;float Dright2 = tempDAxis.y;Dmag = Mathf.Sqrt((Dup2 * Dup2) + (Dright2 * Dright2));Dvec = Dright2 * transform.right + Dup2 * transform.forward;

在改动后我们的位移也成功落成,那么剩下的就是跳跃。
跳跃比较简单,并且这里没有加入动画内容,所以我直接把全部代码贴出来吧,跳跃需要注意的点就是如何不空中无限连跳(除非你的游戏就是这么设定的),这个的写法也是多种多样,我这里这个只是贪图个便捷,适用于游戏地图为平面的情况。
现在完成了动作控制器,接下来也就是摄像机了,鉴于Cinemachine这款插件真的太好用了,所以还是去用Cinemachine吧,本系列就此完结。
最后,全部代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerInput : MonoBehaviour
{[Header("===== Key settings =====")]public string keyUp = "w";public string keyDown = "s";public string keyLeft = "a";public string keyRight = "d";public string keyA = "left shift";public string keyB = "space";public string keyC;public string keyD;[Header("===== Output signals =====")]public float Dup;public float Dright;public float Dmag;public Vector3 Dvec;//1.pressing signalpublic bool run;//2.trigger once signalpublic bool jump;public bool lastJump;//3.double trigger[Header("===== Others =====")]public bool inputEnabled = true;private Rigidbody rigid;private float targetDup;private float targetDright;private float velocityDup;private float velocityDright;// Start is called before the first frame updatevoid Awake(){rigid = GetComponent<Rigidbody>();}// Update is called once per framevoid Update(){targetDup = ((Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0));targetDright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0);if (inputEnabled == false){targetDup = 0;targetDright = 0;}Dup = Mathf.SmoothDamp(Dup, targetDup, ref velocityDup, 0.1f);Dright = Mathf.SmoothDamp(Dright, targetDright, ref velocityDright, 0.1f);Vector2 tempDAxis = SquareToCircle(new Vector2(Dup, Dright));float Dup2 = tempDAxis.x;float Dright2 = tempDAxis.y;Dmag = Mathf.Sqrt((Dup2 * Dup2) + (Dright2 * Dright2));Dvec = Dright2 * transform.right + Dup2 * transform.forward;run = Input.GetKey(keyA);bool newJump = Input.GetKey(keyB);if (newJump != lastJump && newJump == true && rigid.velocity.y == 0){jump = true;}else{jump = false;}lastJump = newJump;}private Vector2 SquareToCircle(Vector2 input){Vector2 output = Vector2.zero;output.x = input.x * Mathf.Sqrt(1 - (input.y * input.y) / 2.0f);output.y = input.y * Mathf.Sqrt(1 - (input.x * input.x) / 2.0f);return output;}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ActorController : MonoBehaviour
{public GameObject model;public PlayerInput pi;public float walkSpeed = 2.0f;public float runMultiplier = 2.0f;[SerializeField]private Rigidbody rigid;private Vector3 movingVec;private Vector3 thrustVec;public float jumpVelocity = 5.0f;// Start is called before the first frame updatevoid Awake(){pi = GetComponent<PlayerInput>();rigid = GetComponent<Rigidbody>();}// Update is called once per framevoid Update(){if (pi.jump ==true){thrustVec = new Vector3(0, jumpVelocity, 0);}if (pi.Dmag > 0.1f){model.transform.forward = Vector3.Slerp(model.transform.forward, pi.Dvec,0.2f);}movingVec = pi.Dmag * model.transform.forward * walkSpeed * ((pi.run) ? runMultiplier : 1.0f);}void FixedUpdate(){//rigid.position += movingVec * Time.fixedDeltaTime;rigid.velocity = new Vector3(movingVec.x, rigid.velocity.y, movingVec.z) + thrustVec;thrustVec = Vector3.zero;}
}

在Unity中写一个妥妥贴贴的ARPG移动系统(二)相关推荐

  1. [Unity3D]用C#在unity里面写一个简单的红绿灯

    [Unity3D]用C#在unity里面写一个简单的红绿灯 00.成果展示 01.创建可变颜色的小球 02.编写代码 R1.cs R2.cs G1.cs G2.cs Y1.cs Y2.cs 03.自己 ...

  2. 学习在Unity中创建一个动作RPG游戏

    游戏开发变得简单.使用Unity学习C#并创建您自己的动作角色扮演游戏! 你会学到什么 学习C#,一种现代通用的编程语言. 了解Unity中2D发展的能力. 发展强大的和可移植的解决问题的技能. 了解 ...

  3. 学习用C#在Unity中创建一个2D Metroidvania游戏

    学习用C#在Unity中创建一个2D Metroidvania游戏 你会学到: 构建2D Unity游戏 用C#编程 玩家统计,水平提升,米尔和远程攻击 敌方人工智能系统 制定级别和级别选择 Lear ...

  4. 学会在Unity中创建一个Match-3益智游戏 Learn To Create a Match-3 Puzzle Game in Unity

    MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语言:英语+中英文字幕(根据原英文字幕机译更准确) |时长:48场讲座(6h 38m) |大小解压后:2.8 G ...

  5. 如何在React Native中写一个自定义模块

    前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...

  6. 如何在 React Native 中写一个自定义模块

    前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...

  7. Unity中获取一个物体下所有的子物体的方法

    Unity中获取一个物体下所有的子物体的方法 方法1(获取全部子物体,无论子物体SetActive是否为true): using System.Collections; using System.Co ...

  8. Java IO练习--在程序中写一个“HelloJavaWorld你好世界“输出到操作系统文件Hello.txt文件中

    package com.kj.test;import cn.hutool.core.io.IoUtil;import java.io.File; import java.io.FileOutputSt ...

  9. 在程序中写一个“HelloJavaWorld你好世界“输出到操作系统文件Hello.txt文件中

    import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOExce ...

最新文章

  1. windows下安装nodejs及框架express
  2. 看起来很美 VS. 是你来检阅我的忧伤了吗?
  3. java 创建定时器_SpringBoot创建定时任务
  4. 《C++ Primer 第五版》(第4.11节类型转换) ————关于无符号数和有符号数的运算探究
  5. 从Linux服务器端下载文件Win客户端
  6. 【OpenCV】OpenCV函数精讲之 -- Mat和IplImage之间的相互装换(OpenCV2.0和OpenCV3.0)
  7. Sphinx sphinx_rtd_theme
  8. 转写准确率95%,搜狗开放AI技术实现录音笔行业进化
  9. JAX 是 Google 开发的计算机视觉研究
  10. dnf自动刷图python_dnf卡盟_【python接口自动化】- openpyxl读取excel数据
  11. 多媒体知识,手机电脑设备联用
  12. GB 4208-93 外壳防护等级(IP代码)
  13. 蓝桥ROS机器人之CoppeliaSim_Edu_V4_2_0
  14. 流行音乐混音风格 流行音乐混音的压缩技巧
  15. 本科论文的标准格式是什么样的?
  16. sqlserver 2012实施与管理学习笔记(一):选型和部署之单机部署、故障转移群集与日志传送
  17. 统计b站多p视频正在观看人数和弹幕的变化,制作折线图
  18. 9、刷牛客网SQL题(三)
  19. 转载:“只要3分钟,我就能扒光你的隐私!” | 互联网时代,14亿中国人都在裸奔|你的隐私已不是隐私
  20. 正则表达式、常用的匹配总结

热门文章

  1. 一文教会你如何用Vue开发Chrome插件
  2. 基于Java毕业设计病人跟踪治疗信息管理系统演示2021源码+系统+mysql+lw文档+部署软件
  3. 计算机安全模型研究与应用,基于Web 的数据仓库安全模型分析与探讨 - 计算机应用研究.PDF...
  4. ~4= -5 怎么来的
  5. Java中浅拷贝和深拷贝的区别
  6. iPhone 4S引发排队抢购 周末销量或破400万
  7. 儿童机器人编程入门课程适合几岁孩子学习?
  8. 在CLI中打印表格----gotable使用介绍
  9. .笔记本做无线路由器图像详细教程(转)新加win7 方法:
  10. 第一次完全会玩扫雷,@NK_test