关于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组件的物体发生碰撞时才调用。
3: 重要方法:
  Move(Vec3 offset): 移动的距离;

  如果一个角色挂载了CharacterController组件。那么要控制这个角色的移动,其实不必改变角色节点的位置,只需对这个组件进行Move操作,角色就会跟着走。

  我把这个组件理解为一个可以牵动节点的可以设置特殊移动属性的胶囊体碰撞器组件Capsule Collider

遥杆编写的基本思路与原理

1:以8个方向为例,将整个圆分为 下,右下,右,右上,上,左上, 左, 左下;
2:当我们的遥感中心点位于某一个方向的范围内,那么就属于这个方向;

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

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

根据摇杆的方向算出当前距离所对应的向量的分解的系数

实例

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组件,调整组件的胶囊体到完全盖住主角,它有碰撞区域但是不受力的影响。

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 = -1,
    UP = 0,
    DOWN = 1,
    LEFT = 2,
    RIGHT = 3,
    RU = 4,
    LU = 5,
    LD = 6,
    RD = 7,
}

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[8] { 0, 0, -1, 1, 0.707f, -0.707f, -0.707f, 0.707f };//cos45=0.707,sin45=0.707
        this.z_set = new float[8] { 1, -1, 0, 0, 0.707f, 0.707f, -0.707f, -0.707f };
        this.rot_set = new float[8] { 0, 180, -90, 90, 45, -45, -135, 135 };

        this.camera_offset = Camera.main.transform.position - this.transform.position;//获取当前摄像机和人物的三维距离
    }

    int get_dir(float r)
    {
        if (r >= -Mathf.PI && r < -7 * Mathf.PI / 8)
        { // 左的一部分
            return (int)DIR.LEFT;
        }
        else if (r >= -7 * Mathf.PI / 8 && r < -5 * Mathf.PI / 8)
        {//左下
            return (int)DIR.LD;
        }
        else if (r >= -5 * Mathf.PI / 8 && r < -3 * Mathf.PI / 8)
        {//下
            return (int)DIR.DOWN;
        }
        else if (r >= -3 * Mathf.PI / 8 && r < -1 * Mathf.PI / 8)
        {//右下
            return (int)DIR.RD;
        }
        else if (r >= -1 * Mathf.PI / 8 && r < 1 * Mathf.PI / 8)
        {//右
            return (int)DIR.RIGHT;
        }
        else if (r >= 1 * Mathf.PI / 8 && r < 3 * Mathf.PI / 8)
        {//右上
            return (int)DIR.RU;
        }
        else if (r >= 3 * Mathf.PI / 8 && r < 5 * Mathf.PI / 8)
        {//上
            return (int)DIR.UP;
        }
        else if (r >= 5 * Mathf.PI / 8 && r < 7 * Mathf.PI / 8)
        {//左上
            return (int)DIR.LU;
        }
        else if (r >= 7 * Mathf.PI / 8 && r < 8 * Mathf.PI / 8)
        {//左的另一部分
            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], 0, 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.运行效果

时间: 2024-08-24 19:00:09

关于Unity中ARPG游戏人物移动的相关文章

在Unity中使用事件/委托机制(event/delegate)进行GameObject之

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 一对多的观察者模式机制有什么缺点? 如果你对如何在Unity中使用事件/委托机制还不太了解,建议您查看我的前一篇文章:[Unity3D技巧]在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 在前一篇博客里面,我们写到

unity中三种调用其他脚本函数的方法

第一种,被调用脚本函数为static类型,调用时直接用  脚本名.函数名().很不实用-- 第二种,GameObject.Find("脚本所在物体名").SendMessage("函数名");  此种方法可以调用public和private类型函数 第三种,GameObject.Find("脚本所在物体名").GetComponent<脚本名>().函数名();此种方法只可以调用public类型函数 unity中三种调用其他脚本函数的

关于Unity中的NGUI和UGUI

用Unity开发2D游戏,有三套关系 1.GUI:Unity本身的对象 2.NGUI:以前在Unity中广泛来做2D的,是第三方的包,需要安装 3.UGUI:Unity5.X后,Unity找到NGUI的作者,开发了UGUI,变成内置于Unity中的包,官方主推 所有的元素都在Unity的UI工具栏 3D做2D游戏的方法: 1: 使用正交摄像机;2: 使用透视摄像机,将2D元素移动到合适的距离. 例如设计分辨率为 960x640, 得到在3D世界里面一个图片的大小w*h米,将这个图片移动到一定的距

Unity中使用协程进行服务端数据验证手段

近期在做项目中的个人中心的一些事情,用户头像上传,下载,本地缓存,二级缓存,压缩,这些都要做,麻雀虽小五脏俱全啊,也是写的浑浑噩噩的, 当我们在上传用户头像的时候,向服务端发送上传头像请求之前,一般都会做一次验证,向服务端获取token验证信息,来确保非法上传,如果不做这个那么会有非法用户上传非法图像,使你的服务器 带来未知的灾难. 而验证的逻辑很好写,并没有什么难度,比如: Server.SendMessage("获取token"); Client.Receive(string to

C#中的yield return与Unity中的Coroutine(协程)(下)

Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image 1 using UnityEngine; 2 using System.Collections; 3 using System.Threading; 4 using UnityEngine.UI; 5 6 public class CoroutineDemo : MonoBehaviour { 7 8 //

【Unity技巧】Unity中的优化技术

写在前面 这一篇是在Digital Tutors的一个系列教程的基础上总结扩展而得的~Digital Tutors是一个非常棒的教程网站,包含了多媒体领域很多方面的资料,非常酷!除此之外,还参考了Unity Cookie中的一个教程.还有很多其他参考在下面的链接中. 这篇文章旨在简要地说明一下常见的各种优化策略.不过对每个基础有非常深入地讲解,需要的童鞋可以自行去相关资料. 还有一些我认为非常好的参考文章: Performance Optimization for Mobile Devices

在Unity中定义统一的对象搜索接口

我们经常要在Unity中以各种方式搜索对象.比如按名字搜索.按tag.layer或者是查找名字为xxx开头的对象. 本文是介绍以一种统一的接口来搜索对象. 1.定义统一的搜索接口 /// <summary> /// 游戏对象搜索接口 /// </summary> public interface IGameObjectFinder { /// <summary> /// 搜索 /// </summary> /// <param name="r

Unity中实现播放视频

突然想着在一个cube物体上播放视频会是怎样的情景.今天终于有时间来尝试下了.结果=>成功 下面来说说详细的步骤吧 准备阶段: 1.unity pro 专业版 =>  需正版(当然破解版也ok,你懂的). 2.安装QuickTime Player.必须要安装,否则导入movie资源时,unity会自动报错提醒的. 3.安装格式化工厂软件=>movie格式转换.其他工具也ok.我这里默认转换为MOV格式.100M的avi转换后大概7M. ====================== uni

unity中mesh属性的uv坐标讨论

http://blog.sina.com.cn/s/blog_427cf00b0102vp0j.html 之前在做连连看游戏中,也用到贴图坐标,当时我们讲到,不管是平铺(Tiling)还是偏移(Offset),我们参考的基准都是原始的那张图,Tiling配合Offset,Tiling负责截取,Offset负责移动,最终实现截取贴图的任一部分?,但是这种方法弄出的图形形状都是方块的,无法实现任意的贴图 而下面要讨论的方法和上面的方法会大不一样,会从UV坐标的角度去讨论,从而实现想怎么贴就怎么贴的效