[Unity3D]巧妙利用父级子级实现Camera场景平面漫游
本文系作者原创,转载请注明出处
入门级的笔者想了一上午才搞懂那个欧拉角的Camera旋转..=.=
在调试场景的时候,每次都本能的按下W想前进,但是这是不可能的(呵呵)
于是便心血来潮想顺便添加个KeyMove事件给摄像机,来实现 伪”漫游“场景 吧。
笔者之前看到过一个叫First Person Controller的Prefab,直接就实现了第一人称的场景漫游(即是不能到处乱飞,只能在一个固定高度进行场景浏览,模拟人行走的意思)
盗张图嘿嘿
但是介于刚刚入门不知道哪儿去找,所以只能自己嗨几个脚本出来自己测....勿喷...
进入正题吧
众所周知 transfrom.Translate平移 里面提供了一个函数
• function Translate (x : float, y : float, z : float, relativeTo : Space = Space.Self) : void Description
描述 Moves the transform by x along the x axis, y along the y axis, and z along the z axis. 移动变换
x沿着x轴,y沿着y轴,z沿着z轴 If relativeTo is left out or set to Space.Self the movement is applied relative to the transform's local axes.
(the x, y and z axes shown when selecting the object inside the Scene View.)
If relativeTo is Space.World the movement is applied relative to the world coordinate system. 如果relativeTo留空或者设置为Space.Self,移动被应用相对于变换的自身轴(当在场景视图选择物体时,x、y和z轴显示)
如果相对于Space.World 移动被应用相对于世界坐标系统
函数的第四个形参relativeTo可以不加,默认为Space.Self
--------------------------------------------
那么什么是Space.World和Space.Self?
官方文档已经说了,Space.World使实体相对于世界坐标轴进行平移变换,Space.Self使实体相对于自己的坐标轴进行平移变换
举个栗子:
当不填写relativeTo(使用Space.Self)的时候,用以下移动一个物体
if (Input.GetKey(KeyCode.W)) { transform.Translate(, , * Time.deltaTime * moveSpeedForDebug); } if (Input.GetKey(KeyCode.S)) { transform.Translate(, , - * Time.deltaTime * moveSpeedForDebug); } if (Input.GetKey(KeyCode.A)) { transform.Translate(- * Time.deltaTime * moveSpeedForDebug, , ); } if (Input.GetKey(KeyCode.D)) { transform.Translate( * Time.deltaTime * moveSpeedForDebug, , ); }
会以物体当前的Z轴正方向作为”前面“,即向着Z轴的实时朝向进行平移变换(前进后退左移右移等)。如果你朝向正前面按下W,就会往前面平移;向天上按下W就会向天上平移
即你可以到达三维空间中任何一个点
但是使用Space.World的时候不一样了
我们假设世界轴Z轴朝向北方
你继续以上的动作你会发现,不管你的视角面向哪儿,你按下W向着世界轴Z轴进行平移变换,你始终是往北边移动的
这个感觉就像你坐在汽车上,你可以踩油门但是不能摸方向盘,于是你踩着油门一直往前开。当前面遇到一个十字路口你想左转,于是你本能地看向左边
但是你只能踩油门,于是虽然你看向左边了,但是汽车还是开向了前方(如果还不懂的话就去自己试一试吧moew)
--------------------------------------------
于是我想到,可以新建一个camera,用GetComponent获取,然后直接用不写relativeTo的Translate函数对相机进行平移变换实现这种二维平面的移动
但是问题来了,就像上面说的,Space.Self平移变换是使用物体当前的Z轴正方向作为”前面“的,也就是说要实现在一定高度的场景预览,摄像机的X轴不能旋转
但是这不现实啊,哪儿有人去看风景的时候一直盯着前面不看天上不看地下的=.=这样的话Space.Self平移变换就不能实现二维平面的移动
用Space.World呢?也不行!因为实体的平移变换不会根据你的视角发生变化,也就是说实体一直往一个方向平移,不会”看哪儿走哪儿“,所以不能实现有指向的二维平面的移动
但是也只有Space.World能够控制实体不在空间的Y轴上乱动了,这个怎么办呢?
如果相机的移动朝向一直有左右没有上下(只有Yaw旋转没有Pitch旋转),但是相机的查看却能有左右和上下(包含Yaw与Pitch),那就可以直接用relativeTo Space.Self参数
进行一个有指向的二维平面移动了!
于是乎,利用父级子级的方法来实现!
也就是说可以将Camera绑在一个Cube上面。
给Cube添加只有Yaw旋转的查看以及relativeTo Space.Self平移变换,那么Cube只能在xOz平面内进行平移,而因为相机是Cube的子级,平移和旋转照样适用
也就是说我们需要做的,只是在给相机添加一个只有Pitch旋转的查看就行了!
这样的话,相机能够实现”到处看“的查看,也能实现只在xOz平面内进行的平移
于是首先建个简单的场景吧
然后建立一个Cube实体,并在Cube的子级建立一个Camera,我把这个起导向作用的Cube实体命名为了GuideCube
向导方块2333
接下来做的是把Cube移到地面上来,再把相机放进Cube中间,关闭Cube的渲染
建立一个脚本(我的是MouseLook)在Update()函数里面添加如下片段(变量的定义我就不说了,详细点这里,另一篇文章里面给出了MouseLook的源码)
把脚本添加到Cube上,实现只有Yaw旋转的查看
if (axes == RotationAxes.MouseX) { //获取鼠标的X移动增量 //希望摄像机移动Yaw即Y轴 deltaMouseRotationX += Input.GetAxis("Mouse X") * sensitivityX * Damping; //比较X旋转角度与最大、最小旋转角度限制 deltaMouseRotationX = Mathf.Clamp(deltaMouseRotationX, minimumX, maximumX); transform.localEulerAngles = , deltaMouseRotationX, ); Debug.Log("左右看!"); }
再将刚刚的代码写入另一个脚本(我的是KeyMove)添加上去
(并没有写完,但是具有基本功能,比如private enum movementLimit与mainCamera = GetComponentInChildren<Camera>();都还用不上)
using System.Collections; using System.Collections.Generic; using UnityEngine; [AddComponentMenu("Camera-Control/Key Move")] public class KeyMove : MonoBehaviour { private Camera mainCamera; private enum movementLimit { noLimit =, limitYaxisMovement = } private movementLimit isMovementLimited = movementLimit.limitYaxisMovement; public float moveSpeedForDebug = 0.5f; // Use this for initialization void Start () { mainCamera = GetComponentInChildren<Camera>(); if (mainCamera == null) Debug.LogWarning("Warning:\nError Finging camera!!"); } // Update is called once per frame void Update () { if (isMovementLimited == movementLimit.limitYaxisMovement) { if (Input.GetKey(KeyCode.W)) { transform.Translate(, , * Time.deltaTime * moveSpeedForDebug); } if (Input.GetKey(KeyCode.S)) { transform.Translate(, , - * Time.deltaTime * moveSpeedForDebug); } if (Input.GetKey(KeyCode.A)) { transform.Translate(- * Time.deltaTime * moveSpeedForDebug, , ); } if (Input.GetKey(KeyCode.D)) { transform.Translate( * Time.deltaTime * moveSpeedForDebug, , ); } } } }
之后给相机添加如下,源码还是在MouseLook里面,实现只有Pitch旋转的查看
if (axes == RotationAxes.MouseY) { //获取鼠标的Y移动增量 //希望摄像机移动Pitch即X轴 deltaMouseRotationY += Input.GetAxis("Mouse Y") * sensitivityY * Damping; //比较Y旋转角度与最大、最小旋转角度限制 deltaMouseRotationY = Mathf.Clamp(deltaMouseRotationY, minimumY, maximumY); transform.localEulerAngles = , ); Debug.Log("上下看!"); }
这样的话,鼠标的X轴偏移会变成Cube的Yaw旋转,鼠标的Y轴偏移变成Camera的Pitch旋转,又Camera跟着父级GuideCube进行Yaw旋转
那么在我们眼中看起来就只是Camera在作”四处查看“的动作啦,而GuideCube也能实现只在xOz平面上的漫游
。。是不是有点麻烦。。
注,我写的MouseLook源码里面能设置如下
也就是规定添加了此Component的实体能够XY旋转还是只能X还是只能Y旋转,方便了这个文章的实现
[Unity3D]巧妙利用父级子级实现Camera场景平面漫游的更多相关文章
- delphi 选中的展开0级 子级不展开
TreeView1.Selected.Expand(False); //选中的展开0级 子级不展开 TreeView1.Selected.Expand(True); //全部展开 来自为知笔记(Wiz ...
- JS获取节点的兄弟,父级,子级元素的方法(js获取子级获取到换行与空格元素-FF)
先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比. JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素 < ...
- mysql oracle sql获取树 父级 子级 及自己
select * from ( select t.*,d.TABLE_NAME,d.QUERY_SQL,d.data_control_col,d.id table_id,d.where_sql fro ...
- 递归方式---通过子级id,获取子级和父级Name
#region 递归--返回 父级|子级 名称 #region --返回 父级|子级 名称 public string RetrurnTypeNames(string TypeId) { String ...
- vue结合Ant Design实现后台系统的权限分配(支持无限子级嵌套)
最近公司的业务需要,要做一个后台管理系统的管理系统类似于这样子 功能需求如下: 左边是权限菜单,右边对应的是具体权限. 1.父级权限菜单选中,父级权限菜单的权限包括其中所有子级权限菜单的权限也要选中, ...
- WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象
原文:WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象 简介 本文将完整叙述我利用VisualTreeHelper实现题述功能的全部过程,想直接看函数实现的朋友可以跳到函数 ...
- ThinkPHP 关联模型中查询某条记录的父级(非查询子级)
数据表 id cat_name cat_pid 76 手机.数码 0 84 手机配件 76 86 蓝牙耳机 84 从属关 ...
- 子级Repeater获取 父级Repeater
第一种方法,子级Repeater中绑定父级的某个字段: <%# DataBinder.Eval((Container.NamingContainer.NamingContainer as Rep ...
- <转载>如何解决子级用float浮动父级div高度不能自适应的问题
转载:http://www.kwstu.com/ArticleView/divcss_2013101582430202 解决子级对象使用css float浮动 而父级div不能自适应高度,不能被父级内 ...
随机推荐
- 00.Web大前端时代之:HTML5+CSS3入门系列~Bug反馈文章
感谢广大网友的热心提醒,现已发现如下错误: 感谢 “ ”对画布笔记系列的反馈(QQ:350223285) 这个是失误,strokeStyle和stroke对应 待续.... 欢迎提出更多问题,感谢大家 ...
- JavaScript高级程序设计--对象,数组(栈方法,队列方法,重排序方法,迭代方法)
1.使用对象字面量定义对象 var person={}; 使用这种方式创建对象时,实际上不会调用Object构造函数. 开发人员更喜欢对象字面量的语法. 2.有时候需要传递大量可选参数的情形时,一 ...
- Android动画效果之Tween Animation(补间动画)
前言: 最近公司项目下个版本迭代里面设计了很多动画效果,在以往的项目中开发中也会经常用到动画,所以在公司下个版本迭代开始之前,抽空总结一下Android动画.今天主要总结Tween Animation ...
- ASP.NET Core管道深度剖析(4):管道是如何建立起来的?
在<管道是如何处理HTTP请求的?>中,我们对ASP.NET Core的请求处理管道的构成以及它对请求的处理流程进行了详细介绍,接下来我们需要了解的是这样一个管道是如何被构建起来的.这样一 ...
- 用spm2构建seajs项目的过程
前言 Javascript模块化规范有CommonJs规范,和主要适用于浏览器环境的AMD规范,以及国内的CMD规范,它是SeaJs遵循的模块化规范.因为以前项目中用SeaJs做过前端的模块管理工具, ...
- 设计模式(十三):从“FQ”中来认识代理模式(Proxy Pattern)
我们知道Google早就被墙了,所以FQ才能访问Google呢,这个“FQ”的过程就是一个代理的过程.“代理模式”在之前的博客中不止一次的提及过,之前的委托回调就是代理模式的具体应用.今天我们就从“F ...
- CentOS7安装iptables防火墙
CentOS7默认的防火墙不是iptables,而是firewalle. 安装iptable iptable-service #先检查是否安装了iptables service iptables st ...
- c 小工具的使用
1. 这是一个gps 数据过滤的小工具,目的是过滤到gps数据中不符合要求的数据,然后转为json 数据 需要两个小工具 bermuda.c ------> 过滤一定范围的数据 geo2j ...
- php数据库访问及增删改
利用PHP访问由MySQL构建的数据库 连接到数据库 //1.造连接对象 $db = new MySQLi("localhost","root","1 ...
- 一个前端所需具备的PS能力
前端网页设计+静态实现案例 放一个2天半内给某公司完成的(设计 + 静态实现)的案例吧,静态阴影用CSS3实现的http://www.cnblogs.com/MuYunyun/p/5693615.ht ...