今天研究模型控制器,探寻下怎么实现基本的控制模型方法
首先,我随便拉了几个小模型
这就是猪脚了。先添加常用的前后左右,就是WSAD,按wsad就使角色的transform组件变化下位置,
private float MoveSpeed = 3f; void Start() { } void Update() { if(Input.GetKey(KeyCode.A)) { //改变角色X轴 transform.Translate(Vector3.right * -MoveSpeed * Time.deltaTime, Space.World); } if(Input.GetKey(KeyCode.D)) { transform.Translate(Vector3.right * MoveSpeed * Time.deltaTime, Space.World ); } if (Input.GetKey(KeyCode.W)) { //改变角色Y轴 transform.Translate(Vector3.forward * MoveSpeed * Time.deltaTime, Space.World); } if (Input.GetKey(KeyCode.S)) { transform.Translate(Vector3.forward * -MoveSpeed * Time.deltaTime,Space.World); } }
啊,现在那个兽人应该可以前后左右移动了,这里是通过改变角色的transform的position来实现的(其实是废话,都是通过改变这个的,大家懂我的意思就好),
换种思路,我先给个目标点,让角色平移过去
private float MoveSpeed = 6f; void Update() { Vector3 targetPos = transform.position; if(Input.GetKey(KeyCode.A)) { targetPos.Set(targetPos.x-MoveSpeed * Time.deltaTime,targetPos.y,targetPos.z); } if(Input.GetKey(KeyCode.D)) { targetPos.Set(targetPos.x+MoveSpeed * Time.deltaTime,targetPos.y,targetPos.z); } if (Input.GetKey(KeyCode.W)) { targetPos.Set(targetPos.x,targetPos.y,targetPos.z+MoveSpeed * Time.deltaTime); } if (Input.GetKey(KeyCode.S)) { targetPos.Set(targetPos.x,targetPos.y,targetPos.z-MoveSpeed * Time.deltaTime); } transform.position = Vector3.Lerp(transform.position, targetPos, MoveSpeed * Time.deltaTime); }
这是两种移动的方式,暂时只想到两种移动方式,若有其他的回复我。
除了移动方式,方向也是要考虑的,在第一种移动方式中,如何设置角色的朝向呢? 我是这样考虑的,得到移动前的位置和移动后的位置,相减获得方向,啊,我竟聪明如斯,动手
private float MoveSpeed = 3f; void Start() { } void Update() { //获取移动前位置 Vector3 lastPosation = transform.position; if(Input.GetKey(KeyCode.A)) { transform.Translate(Vector3.right * -MoveSpeed * Time.deltaTime); } if(Input.GetKey(KeyCode.D)) { transform.Translate(Vector3.right * MoveSpeed * Time.deltaTime); } if (Input.GetKey(KeyCode.W)) { transform.Translate(Vector3.forward * MoveSpeed * Time.deltaTime); } if (Input.GetKey(KeyCode.S)) { transform.Translate(Vector3.forward * -MoveSpeed * Time.deltaTime); } //设置方向 transform.LookAt(transform.position+ transform.position-lastPosation); }
然后,老鸟该呵呵一笑了
截图看不出效果,如果按照我的代码,这个小人是会原地转圈,看上去很白痴。
........
省略号代表我想了很长时间,然后看了unityAPI
public class example : MonoBehaviour { void Update() { transform.Translate(Vector3.forward * Time.deltaTime); transform.Translate(Vector3.up * Time.deltaTime, Space.World); } }
原来是坐标系的问题,Space.World ,不过我原来一直没考虑这个问题啊,好像也能实现移动?
想了会,原来移动的时候,这兽人脸是不变方向的。所以他移动的时候不考虑方向也行。现在兽人的朝向要变了,自身坐标系就一直在转变,所以要加上世界坐标系
这样这个兽人终于不用走太空步了。
那移动的第二个方法如何做方向,应该只要看向目标点就行了吧,回顾下这个移动的代码,不像自身坐标系,添加
transform.LookAt(targetPos + targetPos-transform.position);
这里的获取awsd的按键事件可以通过unity的API ,Input.GetAxis()来代替
private float MoveSpeed = 3f; void Start() { } void Update() { //获取移动前位置 Vector3 lastPosation = transform.position; float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); transform.Translate(new Vector3(h, 0, v) * MoveSpeed * Time.deltaTime,Space.World); /* if(Input.GetKey(KeyCode.A)) { transform.Translate(Vector3.right * -MoveSpeed * Time.deltaTime, Space.World); } if(Input.GetKey(KeyCode.D)) { transform.Translate(Vector3.right * MoveSpeed * Time.deltaTime, Space.World ); } if (Input.GetKey(KeyCode.W)) { transform.Translate(Vector3.forward * MoveSpeed * Time.deltaTime, Space.World); } if (Input.GetKey(KeyCode.S)) { transform.Translate(Vector3.forward * -MoveSpeed * Time.deltaTime,Space.World); } * */ //设置方向 transform.LookAt(transform.position+ transform.position-lastPosation); }
瞬间感觉清爽了,处女座的福音,而且可以发现角度不像原来的只能45度角变化,移动也平滑了,总之腰不痛,腿不酸,能上六楼了
Input.GetKey()方法通过参数的不同也能获得鼠标与触屏的输入类容,实际上我对这种方法,还有类似的invoke()方法,通过字符串调用其他方法的方式我很有兴趣,以后会去看看这种方法的实现原理与优劣。常用的pc玩游戏的操作方式还有鼠标,我来看看鼠标点击是怎么移动的,鼠标移动监听他右击时间,这个点是一个三维坐标,但屏幕是2d的,我这想了一会,结合我多年游戏经验,他么鼠标点的地方最后都是在地面上有木有,所以这里应该是将这个点给弄到地面上,想不明白鼠标点击点是2d的怎么转换为3D呢,首先排除添加默认Y=0 (x,0,z),然后大家请看
虽然有点抽象,但透露着浓浓的后现代艺术气息,A是屏幕,B是虚拟的地面,C是鼠标点,做过C于A面的法线交C面的点应该就是点击在地面上的点了,无论是平行还是交叉的游戏,法线应该都适用.先看看鼠标右击会得到什么吧。
结果,什么玩意儿都没得到,坑爹。看看API怎么说的
- C#
- JavaScript
using UnityEngine; using System.Collections; public class example : MonoBehaviour { public float horizontalSpeed = 2.0F; public float verticalSpeed = 2.0F; void Update() { float h = horizontalSpeed * Input.GetAxis("Mouse X"); float v = verticalSpeed * Input.GetAxis("Mouse Y"); transform.Rotate(v, h, 0); } }
// Performs a mouse look. //执行一个鼠标观察 var horizontalSpeed : float = 2.0; var verticalSpeed : float = 2.0; function Update () { // Get the mouse delta. This is not in the range -1...1 //获取鼠标增量,范围不在-1...1 var h : float = horizontalSpeed * Input.GetAxis ("Mouse X"); var v : float = verticalSpeed * Input.GetAxis ("Mouse Y"); transform.Rotate (v, h, 0); }
javascript才有注释 ,才是亲儿子。 看到注释没,获取鼠标增量。然后我用鼠标划了下屏幕。然后看到参数和模型角度的变化
这个值是有时候能看到 有事后看不到的,本着科研的精神,我进行了细致的控制变量法研究,发现要想看到X和Y有数据得鼠标划的快,而且有数据后会调用update三次左右。事情的真相如何,请看今晚的unity的不归路 OK,现在揭秘,这个XY确实是鼠标在一帧中的滑动向量,而调用update三次是因为手抖了:d 各位看官,我也是受害者,别吐槽。虽然这里花了点时间,但也不是做无用功,至少以后做镜头的旋转什么的就有方法了。 我觉得这里的向量获得方式也是获取一帧前的鼠标位置和一帧后的鼠标位置,然后获取的向量,一帧的时间很短,可以认为在一帧内几乎不可能双击造成误判,当然也可以在其中进行判断鼠标时候双击。 在有的游戏中鼠标点击即可能触发的是点击事件也肯能是拖动时间,就像我想点击文件时,如何判定是拖动还是单击,1 判断鼠标点击和放开的位置 2.判断鼠标点击和放开的时间想了会 这里显然是时间比较合理啊,比如鼠标拖出去再拖回原地这个显然1不能满足。暂时只能想到时间。 至于我为什么提出这两个问题,因为拖动和单机的区别就在于鼠标的位置和时间,请叫我 柯南.道尔.本。 说到这里,前面获取键盘的Input.GetAxis方法显然也是获取增量,键盘总不能得到在屏幕上的位置吧,这里估计是为了统一所以鼠标也获得的是增量。 扯了半天,还是没找到鼠标单击时的点。既然Input.GetAxis("Mouse Y")这个方法能获得向量,那应该也有获取位置的方法,总不能叫我们监听串口去吧。 在找inputAPI,我看到了这个Input.mousePosition,以我四级430的高分段选手来看,这一定是鼠标的位置,我们Debug.Log(Input.mousePosition)出鼠标的位置看看
这些点貌似都是Z轴为0的 屏幕的位置,我再点几个点,四角和中间的试试
可以看出,这个点的位置是以左下角为原点,以像素为坐标,比如我是1920*1080的屏幕,就和这个坐标系很吻合。这样就算获得了鼠标在屏幕上的位置,如何投射到scene中呢?再次有请抽象一号和二号
第一幅图中A是显示器 B是场景 。 第二幅图中红色框是显示器,注意那个相机,屏幕相当于在中间截取了一面,那个A点就相当于鼠标点,屏幕上显示的就是摄像机与A点的射线,看到的东西,A点坐标我们获取到了就是mouseposition,但这个坐标是相对坐标,是相对于左下角的二维坐标,根据相机的位置可以获得相机的世界坐标点
在更具第二排的角度,rotation, 便可获得一个锥形,可以看上面的抽象2,屏幕应该是在固定位置中间或者1/3或者其他, 结合鼠标点计算出这个点的世界坐标系,然后两点一线做出射线,再判断撞击点。这个便是我们点在屏幕上的投射到场景中的位置。一口气说了这么多表示我就不去写轮子了,unityAPI中是有这样的处理的
if( Input.GetMouseButton(0) ) { Debug.Log(Input.mousePosition); // 获取屏幕上的点与相机的射线 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; //获取碰撞点 if(Physics.Raycast(ray,out hit)) { //debug Debug.Log(hit.point); } //让角色看向这个点 transform.LookAt(hit.point); }
这个ScreenPointToRay方法便是获取相机与鼠标点的射线。具体效果就不截图了