游戏中,我们经常会有这样的操作,点击场景中某个位置,角色自动移动到那个位置,同时角色一直是朝向那个位置移动的,而且相机也会一直跟着角色移动。有些游戏,鼠标滑动屏幕,相机就会围绕角色旋转。
看似很简单的操作,那么到底是怎么实现的呢?
 
我们把上述操作分解为以下几个步骤
 
角色的移动
1. 移动到下一个路点,线性插值、曲线插值
2. 角色朝向,一直面朝下一个路点
 
相机跟随角色
1. 相机俯视角度,决定相机的高度
2. 相机跟随距离,前向距离或者直线距离(就是三角形的水平边长或者斜边长)
3. 相机一直看角色的后背(Y轴旋转角度和角色一致)
4. 相机围绕角色旋转
 
技术点:
1. 向量
2. 旋转
 
先来看效果,请原谅我未注册屏幕录像orz
 
角色移动
  包括位移和方向,就是移动角色的同时角色一直要朝向移动的方向。
 
 
 
左边的图,角色从A移动到B,朝向却一直是向前方的,明显不符合跑动的显示逻辑。正确的表现是右图所展示那样,角色面朝移动方向。
 
那么我们要怎么做才能实现这个效果呢?位移很简单,A到B的坐标插值。
 
其次是旋转角色,Unity提供了一个方法Quaternion.LookRotation。关于这个方法,官方的解释如下:

Quaternion.LookRotation 注视旋转

static function LookRotation (forward : Vector3, upwards : Vector3 = Vector3.up) : Quaternion

Description描述

Creates a rotation that looks along forward with the the head upwards along upwards

创建一个旋转,沿着forward(z轴)并且头部沿着upwards(y轴)的约束注视。也就是建立一个旋转,使z轴朝向view  y轴朝向up。

Logs an error if the forward direction is zero.

如果forward方向是0,记录一个错误。

光看描述,是不是比较难理解。网上对这个方法的解释也挺多的,但是各说纷纭,没个简单明了的说法,更容易误导人。

我们知道向量,包含大小和方向。大小很容易得到,那么方向怎么获得呢?常规来说,可以通过把向量分解为x、y、z三个分量,然后通过三角函数依次求得个分量的夹角。
Unity提供了更简单的方法,就是Quaternion.LookRotation,这个方法就是获得传入向量的方向,即旋转值,是个四元数。
 
代码实际上很简单,就几行。主要是要理解为什么
             //计算当前位置到下一个坐标点的向量
var vector = (posB - posA).normalized;
//取得向量的方向
var rotation = Quaternion.LookRotation(vector).eulerAngles;
//将物体旋转到指向下一个坐标点的方向
transform.rotation = Quaternion.Euler(, rotation.y, );
//设置物体的坐标
transform.position = posB;
想想为什么Quaternion.Euler(0, rotation.y, 0)这里x和z方向都是填的0?
因为角色的朝向是根据偏转角Yaw,也就是Y轴决定的,x和z轴是没有发生偏转的,倘若改变x轴z轴旋转值,就会发现角色会有俯仰、翻滚的效果。
 
相机跟随角色
好了,角色的朝向解决了。那么,如果我要让相机一直跟着角色走,同时相机一直看到角色的后背,也就是角色旋转时,相机要跟着转动,同时保持固定距离,该如何实现?
 
我们先计算相机的位置,然后在旋转相机朝向角色的后背。
1. 计算相机的旋转值,这里需要指定相机的俯仰角Pitch的值,假定是30度,可以根据具体情况调节
//相机的俯仰角和偏航角,Y方向偏航和目标对象一致
Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y, );
2. 计算指定长度Distance的向量,这个向量是与世界坐标z方向平行
var vector = Vector3.forward * Distance;
3. 用上面的相机旋转值左乘第二步得到的向量,改变这个向量的方向( 四元数左乘向量,改变向量的方向)
vector  = ro * vector;
4. 用目标位置减去vector,得到指向目标位置的坐标点,也就是相机的最终位置。(为什么这样就得到位置了,回去看看向量的知识吧)
var pos = transform.position - vector; 
5. 最后,将旋转值和坐标赋值给相机,相机就完成了跟随效果, 是不是很简单
CameraGo.transform.position = pos;
CameraGo.transform.rotation = ro;
 //相机的俯仰角和偏航角,Y方向偏航和目标对象一致
Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y, );
//给向量赋予旋转
var distanceVector = ro * Vector3.forward * Distance;
var pos = transform.position - distanceVector;
CameraGo.transform.position = pos;
CameraGo.transform.rotation = ro;
 
至于相机围绕角色旋转,我们只需要改变一下Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y, 0) 中transform.rotation.eulerAngles.y这个值
本来这个值是指定相机朝向角色的方向,我们改变这个值,就可以实现相机围绕角色的效果。我们可以这样做
//delta就是围绕角色旋转的旋转角度0~360.
Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y + delta, )
 
最终,上诉代码如下,代码不完整,请各位自行补全:
 
      //角色移动
void SmoothMove()
{
Vector3[] vector3s = _transDataList;// CurvePath.PathControlPointGenerator(_transDataList);
int sample = _transDataList.Length * SampleRate; _movePtg += Time.deltaTime * MoveSpeed; //曲线插值
transform.position = CurvePath.Interp(vector3s, _movePtg / sample); //计算当前位置到下一个坐标点的向量
var vector = (transform.position - _prevPos).normalized;
//取得向量的方向
var rotation = Quaternion.LookRotation(vector, Vector3.right).eulerAngles;
//去处x和z方向的影响,仅作用y方向偏转
rotation.x = ;
rotation.z = ; //将物体旋转到指向下一个坐标点的方向
transform.rotation = Quaternion.Euler(rotation); _prevPos = transform.position;
if (_movePtg >= sample)
{
ResetLocalData();
}
} //相机跟随
void FollowCamera()
{
if (CameraGo == null) return; if(UseFollow != )
{
//相机的俯仰角和偏航角,Y方向偏航和目标对象一致
Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y + Slider, ); //给向量赋予旋转
var distanceVector = ro * Vector3.forward * Distance;
var pos = transform.position - distanceVector;
CameraGo.transform.position = pos;
CameraGo.transform.rotation = ro;
return;
}
}

unity3D:游戏分解之角色移动和相机跟随的更多相关文章

  1. [Unity3D]Unity3D游戏开发之角色控制漫谈

    各位朋友,大家好.我是秦元培,欢迎大家关注我的博客,我的博客地址blog.csdn.net/qinyuanpei.今天呢,我们来说说Unity3D中的角色控制,这篇文章并非关注于Unity3D中的某项 ...

  2. unity3D:游戏分解之曲线

    一提到曲线,很多新手就头疼了,包括我.查了很多资料,终于有个大概的了解.想深入了解曲线原理的,推荐一个链接http://www.cnblogs.com/jay-dong/archive/2012/09 ...

  3. Unity3D 游戏开发构架篇 ——角色类的设计与持久化

    在游戏开发中,游戏角色占了很大的篇幅,可以说游戏中所有的内容都是由主角所带动.这里就介绍一下角色类的设计和持久化. 一.角色类应用场景和设计思想 游戏中的角色类型不一而足,有不同的技能,有不同的属性等 ...

  4. [Unity3D]Unity3D游戏开发之跑酷游戏项目解说

    大家好,我是秦元培.我參加了CSDN2014博客之星的评选,欢迎大家为我投票,同一时候希望在新的一年里大家能继续支持我的博客. 大家晚上好.我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.c ...

  5. [Unity3D]Unity3D游戏开发之伤害数值显示

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.众所周知,在RPG游戏策划中最为重要的一个环节是数值策划.数值策划是一个关于游戏平衡方面的概念 ...

  6. Unity3D游戏开发从零单排(四) - 制作一个iOS游戏

    提要 此篇是一个国外教程的翻译,尽管有点老,可是适合新手入门. 自己去写代码.debug,布置场景,能够收获到非常多.游戏邦上已经有前面两部分的译文,这里翻译的是游戏的最后一个部分. 欢迎回来 在第一 ...

  7. [Unity3D]Unity3D游戏开发3D选择场景中的对象,并显示轮廓效果强化版

    大家好,我是秦培,欢迎关注我的博客,我的博客地址blog.csdn.net/qinyuanpei. 在上一篇文章中,我们通过自己定义着色器实现了一个简单的在3D游戏中选取.显示物体轮廓的实例. 在文章 ...

  8. [Unity3D]Unity3D游戏开发MatchTarget的作用攀登效果实现

    大家好,我是秦培,欢迎关注我的博客.我的博客地址blog.csdn.net/qinyuanpei. 今天我们来一起学习在Unity3D中怎样实现角色攀爬效果. 在RPG游戏中,某些游戏场景经常须要玩家 ...

  9. Unity3D游戏-愤怒的小鸟游戏源码和教程(一)

    Unity愤怒的小鸟游戏教程 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) AngryEva游戏效果: 1 ...

随机推荐

  1. ArrayList 线程安全

    都说ArrayList是线程不安全的,那为什么不安全呢.根据官方提供的源码, 我是这样理解的,ArrayList的成员方法都不是原子操作的,比如add(E)方法,该方法是在集合的尾部加入一个一个元素. ...

  2. QuartusII13.0使用教程详解(一个完整的工程建立)

    好久都没有发布自己的博客了,因为最近学校有比赛,从参加到现在都是一脸懵逼,幸亏有bingo大神的教程,让我慢慢走上了VIP之旅,bingo大神的无私奉献精神值得我们每一个业界人士学习,向bingo致敬 ...

  3. IDEA第五章----Git常用技能

    前几篇已经介绍了idea的环境搭建及基础配置常用模板等,这一章我们介绍下idea中git的一些常用技能,包括提交文件,排除提交文件,合并分支,解决冲突,还原代码等等等. 第一节:Git常用技能 Git ...

  4. 使用jquery的load方法设计动态加载,并解决浏览器前进、后退、刷新等问题

    继上一篇 使用jquery的load方法设计动态加载,并解决被加载页面JavaScript失效问题 解决了后台业务系统的部分动态加载问题,然而该框架离正常的用户体验还存在一些问题,如:浏览器的前进.后 ...

  5. [ext4]06 磁盘布局 - 特殊inode

    Ext4预留了一些inode做特殊特性使用,见下表: inode Purpose 0 不存在,Ext4中不存在inode 0. 1 存放损坏的数据块链表 2 根目录 3 User quota. 用户q ...

  6. js中面向对象编程

    一.理解对象: 第一种:基于Object对象 var person = new Object(); person.name = 'My Name'; person.age = 18; person.g ...

  7. POJ1006: 中国剩余定理的完美演绎(非原创)

    问题描述 人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天.一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好.通常这三个周期的峰值不会是同一天.现在给出 ...

  8. js获取一组不重复的随机数的方法

    一.基本思路: 建立一个数组存放所有可以取到的值,每次从该数组中随机取走一个,放到新的数组中,直到完成. 二.实现方法 1.方法一: (1)创建一个数组arr,数组元素为所有可能出现元素的集合: (2 ...

  9. Apple本地认证(密码+Touch id)

    转载请注明原文链接:http://www.cnblogs.com/zhanggui/p/6839554.html 前言 本片博客主要介绍如何在自己的APP中添加指纹解锁/密码解锁技术.主要是对苹果的L ...

  10. PHP 中级内容

    1.面向对象编程(OOP) 2.模板引擎(smarty) 3.MYSQL(中级操作) 数据库抽象层(PDO): 4.Ajax(异步刷新) 5.Js框架(jQuery) Xml+JSON数据       ...