关于Unity中ARPG游戏人物移动(专题十一)
ARPG:动作型角色扮演类游戏
大多数的ARPG游戏都是使用摇杆操作,以第三人称摄像机的方式来跟随主角,实际上人物只走八个方向,上,下,左,右,左上,左下,右下,右上
控制角色移动的思路
1: 在ARPG游戏中,主角人物在摇杆下控制行走;
2: 主角人物遇到障碍物(碰撞器)将不会穿越过去;
3: 摇杆控制主角人物8个方向的行走;
4: 使用CharacterController 角色控制器组件: 让你在受制于碰撞的情况下很容易的进行运动,而不用处理刚体,实际上没有刚体的物理特性。角色控制器不受力的影响,仅当你调用Move函数时才运动。它执行运动,但是受制于其他碰撞器。
本来以前都是在角色上面挂载刚体(用里面的重力)和碰撞器组件,如果碰到其他的刚体还会受力会受到一些不好的影响,用了CharacterController 就不会有这种不相关的物理力的影响了。
5: 调用角色控制器的Move函数移动角色;
6: 根据摇杆的方向旋转人物动画;
CharacterController组件
1: 属性面板属性:
Slope Limit: 角色碰撞器只能爬比这个指定角度低的斜坡:(单位是degree)
Step Offset: 上楼梯模式,小于Step Offset 的台阶,可以直接上去;
Skin Width: 两个碰撞器可以互相渗透深入皮肤宽度,一般设置成radius的10%;
Min Move Distance: 调用Move函数移动的最小移动量,如果移动距离比这个小,将不移动;
center: 相对与transform的位置角色叫胶囊体中心;
height: 胶囊体高度;
Radius: 胶囊体的半径;
2: 碰撞检测:
void OnControllerColliderHit(ControllerColliderHit hit) {},和一般的碰撞器一样。有碰撞后会调用这个接口。只会在和其他带有CharacterController组件的物体发生碰撞时才调用。
目前已知这个角色控制器的碰撞接口只有这个,如果要持续碰撞,我会加一个BoxCollider组件或者Capsule之类的碰撞器,调用三个碰撞接口
3: 重要方法:
Move(Vec3 offset): 移动的距离;
如果一个角色挂载了CharacterController组件。那么要控制这个角色的移动,其实不必改变角色节点的位置,只需对这个组件进行Move操作,角色就会跟着走。
我把这个组件理解为一个可以牵动节点的可以设置特殊移动属性的胶囊体碰撞器组件Capsule Collider
遥杆编写的基本思路与原理
1:以8个方向为例,将整个圆分为 下,右下,右,右上,上,左上, 左, 左下;
2:当我们的遥感中心点位于某一个方向的范围内,那么就属于这个方向;

3.排除一个无效的摇杆区域,在这个区域内主角不会跟着移动

4.角色移动的距离是一个标量,等于速度乘于时间,而角色移动的整个行为是一个向量,所以还要考虑方向,获得摇杆的角度得知运动方向后还要把角色到最终目的地的标量距离分解成X和Z轴方向上的距离。
根据摇杆的方向算出当前距离所对应的向量的分解的系数

5.前面都是摇杆的坐标轴解析,这里是从人物的Y轴的角度看各个欧拉角,也就是编辑器上的Transform组件的Rotation里面的Y的值对应的该主角节点的旋转方向角度,0度是角色面朝前方

实例
1.创建Unity工程项目和文件目录
2.导入人物模型资源和地图资源,以及摇杆包(79)
3.人物模型的材质球shader使用Mobile Diffuse,关联好贴图,设置模型---->Rig---->Animation Type---->Legacy---->Apply
4.在人物模型的Animation里添加跑动的动画,136-161帧是跑动的帧,Wrap Mode---->Loop---->Apply,角色配置完毕,拖进场景中
5.创建一个平面Plane,关联材质,放大10倍
6.不需要添加碰撞器,只要给主角添加CharacterController组件,调整组件的胶囊体到完全盖住主角,它有碰撞区域但是不受力的影响,千万别再加Rigidbody组件了,会使得CharacterController组件无效。

7.添加摇杆,Hedgehog Team---->Easy Touch---->Add Easy Touch For C#,Hedgehog Team---->Easy Touch---->Extension---->Adding a new joystick
8.调整摄像机的位置,到可以看见主角运动的最佳位置
9.在主角下面挂载一个脚本Person来通过摇杆控制角色移动
Person.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; enum DIR//定义一个枚举来区分角色移动的八个方向
{
INVALID_DIR = -,
UP = ,
DOWN = ,
LEFT = ,
RIGHT = ,
RU = ,
LU = ,
LD = ,
RD = ,
} public class person : MonoBehaviour
{
float move_speed = 8.0f;//角色移动速度
CharacterController c_ctrl;//角色控制器组件 public EasyJoystick joystick;//摇杆
float[] x_set;//八个方向在X轴上的分解系数
float[] z_set;//八个方向在Z轴上的分解系数
float[] rot_set;//人物面的朝向的角度表
Vector3 camera_offset; // Use this for initialization
void Start()
{
this.c_ctrl = this.GetComponent<CharacterController>(); //按照上,下,左,右,右上,左上,左下,右下的顺序配置
this.x_set = new float[] { , , -, , 0.707f, -0.707f, -0.707f, 0.707f };//cos45=0.707,sin45=0.707
this.z_set = new float[] { , -, , , 0.707f, 0.707f, -0.707f, -0.707f };
this.rot_set = new float[] { , , -, , , -, -, }; this.camera_offset = Camera.main.transform.position - this.transform.position;//获取当前摄像机和人物的三维距离
} int get_dir(float r)
{
if (r >= -Mathf.PI && r < - * Mathf.PI / )
{ // 左的一部分
return (int)DIR.LEFT;
}
else if (r >= - * Mathf.PI / && r < - * Mathf.PI / )
{//左下
return (int)DIR.LD;
}
else if (r >= - * Mathf.PI / && r < - * Mathf.PI / )
{//下
return (int)DIR.DOWN;
}
else if (r >= - * Mathf.PI / && r < - * Mathf.PI / )
{//右下
return (int)DIR.RD;
}
else if (r >= - * Mathf.PI / && r < * Mathf.PI / )
{//右
return (int)DIR.RIGHT;
}
else if (r >= * Mathf.PI / && r < * Mathf.PI / )
{//右上
return (int)DIR.RU;
}
else if (r >= * Mathf.PI / && r < * Mathf.PI / )
{//上
return (int)DIR.UP;
}
else if (r >= * Mathf.PI / && r < * Mathf.PI / )
{//左上
return (int)DIR.LU;
}
else if (r >= * Mathf.PI / && r < * Mathf.PI / )
{//左的另一部分
return (int)DIR.LEFT;
}
return (int)DIR.INVALID_DIR;//无效的区域
} void walk_update()
{
float x = this.joystick.JoystickTouch.x;//摇杆坐标系的X坐标
float y = this.joystick.JoystickTouch.y;//摇杆坐标系的Y坐标
float len = (x * x + y * y);//不开根号是因为开销太大,而且是在Update里面,每帧都开根号受不了
if (len < (0.5f * 0.5f))//摇杆移动到这片区域是无效的
{
return;
} // 获取这个方向
float r = Mathf.Atan2(y, x); // 使用反三角函数, 获取向量的角度, [-PI, PI]
int dir = this.get_dir(r);
if (dir != (int)DIR.INVALID_DIR)
{
float s = this.move_speed * Time.deltaTime;//每一秒要移动的距离
Vector3 offset = new Vector3(s * this.x_set[dir], , s * this.z_set[dir]);//把这个距离分解到X和Z方向上
this.c_ctrl.Move(offset);//每一帧都移动 // 切换人物行走的朝向
Vector3 e_rot = this.transform.eulerAngles;
e_rot.y = this.rot_set[dir];
this.transform.eulerAngles = e_rot;
// end
}
// end
} // Update is called once per frame
void Update()
{
this.walk_update();
Camera.main.transform.position = this.transform.position + this.camera_offset;//保持人物和摄像机的距离不变
}
}
10.运行效果

关于Unity中ARPG游戏人物移动(专题十一)的更多相关文章
- 关于Unity中的道具拾取(专题六)
原理就是把道具做成触发器,触发器就是当我们有碰撞发生的时候,只会检测碰撞,而不会有任何改变物理运动状态的过程. 触发器非常适合道具拾取,因为它不会改变原本运动物体的任何物理属性,但是依然会检测碰撞,响 ...
- 开发指南专题十一:JEECG微云高速开发平台--基础用户权限
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/zhangdaiscott/article/details/26580037 开发指南专题 ...
- Unity中使用Attribute
Attribute是c#的语言特性 msdn说明如下: The Attribute class associates predefined system information or user-def ...
- 在Unity中使用UGUI修改Mesh绘制几何图形
在商店看到这样一个例子,表示很有兴趣,他们说是用UGUI做的.我想,像这种可以随便变形的图形,我第一个就想到了网格变形. 做法1: 细心的朋友应该会发现,每个UGUI可见元素,都有一个‘Canvas ...
- Unity中使用WebView
Unity中使用WebView @(设计) 需求,最近游戏中需要引入H5直播页面和更新比较频繁的赛事页面,需求包括:加密传参数.和Unity交互,在Unity框架下其实有几种方案: 内置函数Appli ...
- Unity中创建二维码
在网络上发现了一个可以把字符串转换成二维码的dll,但是我们要怎么使用他呢.不废话,直接进入主题. 用到的引用 using UnityEngine;using ZXing;using ZXing.Qr ...
- 在Unity中创建可远程加载的.unity3d包
在一个Unity项目中,发布包本身不一定要包括所有的Asset(译为资产或组件),其它的部分可以单独发布为.unity3d,再由程序从本地/远程加载执行,这部分不在本文讨论范围.虽然Unity并没有直 ...
- 【原创翻译】初识Unity中的Compute Shader
一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位 ...
- 【unity shaders】:Unity中的Shader及其基本框架
shader和Material的基本关系 Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出.绘图单元可以依据这个输出来将图 ...
随机推荐
- Egret 之 消除游戏 开发 PART 6 Egret elimination game development PART 6
Egret 之 消除游戏 开发 PART 6 Egret elimination game development PART 6 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱: ...
- BeautifulSoup库的使用方法
from bs4 import BeautifulSoup import lxml html = ''' <html><head><title>The Dormou ...
- 47. 全排列 II
47. 全排列 II 题意 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2]输出:[ [1,1,2], [1,2,1], [2,1,1]] 解题思路 去重的全排列 ...
- 一些公司的面试题目 U3D
#include <iostream> using namespace std; int main() { int N; while (cin>>N&&N> ...
- Oracle ORA-12541:TNS:无监听程序
背景:自己机子做oracle服务器,其他机子可以ping得通我的机子,但是jdbc就是连不上,后来用plsql连出现无监听程序.... 我昨天重新安装Oracle后,用PL/SQL Developer ...
- [原创]PostMan接口测试神器
[原创]PostMan接口测试神器 1 PostMan是什么? Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件. 2 Postman工具下载及安装 官方网站: htt ...
- java知识思维图解
- java- WatchService监控
java7中新增WatchService可以监控文件的变动信息(监控到文件是修改,新增.删除等事件:) 其中注册事件是需要的: StandardWatchEventKinds.ENTRY_MODIFY ...
- Android性能优化-内存优化
原文链接 Manage Your App’s Memory 前言 在任何软件开发环境中,RAM都是比较珍贵的资源.在移动操作系统上更是这样,因为它们的物理内存通常受限.尽管在ART和Dalvik虚拟机 ...
- PL/SQL学习笔记之记录
一:记录 记录是一种高可以容纳不同数据类型的数据的数据结构. PL/SQL可以处理记录的以下几种类型: 基于数据表 基于游标的记录 用户自定义的记录 二:使用 %ROWTYPE属性 创建基于表格或基于 ...