unity基于用户输入的对象移动
这里讲一下向量位置Vector3,它表示物体在三维世界里的位置。
在Unity三维坐标系,分为全局坐标系和相对坐标系。
全局坐标系
也叫世界坐标系
:默认起始点是(0,0,0). 当一个物体在世界坐标系(1,1,1)位置的时候,我们就知道它是在世界坐标系的右上方。相对坐标系
也叫模型坐标系
:它以对象自身位置为中心点,比如上面的对象位置(1,1,1)。
假设模型位置叫做A, 当我们说物体B在模型坐标系的(1,1,1)的时候,那么它在世界坐标系位置,是A + B,即真实位置是(2,2,2)。
用户操作对象移动,通常有两种方式:
1. 通过c#中的Input对象,改变对象transform的position来达到。
2. 通过添加刚体Rigidbody,模拟重力方式,给对象增加一个推力AddForce。
1. 用户键盘输入Input
获取用户输入的方式,通常只有前后、左右箭头、和aswd键盘,用户可以在项目设置的InputManager里设置。
InputManager设置,以macOS unity为例子:
选中unity项目,顶部菜单栏 > Edit > Project Settings > InputManager,点开Axes自行修改对应的key。
修改完后,我们就可以通过Input获取InputManager里的设定内容.
1.1 Input.GetAxis方式获取水平、垂直方向
//方式一:通过GetAxis的方式
//获取水平方向
float Horizontal = Input.GetAxis("Horizontal");
//获取前后方向
float Vertical = Input.GetAxis("Vertical");
通过GetAxis方式,在设置按键被按下时,即可获得对应的返回。 GetAxis返回是一个浮点数,范围在[-1,1]
之间,表示用户按下力度的大小偏移量。
1.2 Input.GetKeyDown方式获取键盘按下
//方式2:通过获取键盘按下GetKeyDown的方式
Boolean isMoveLeft = Input.GetKeyDown(KeyCode.LeftArrow);
Boolean isMoveRight = Input.GetKeyDown(KeyCode.RightArrow);
Boolean isMoveForward = Input.GetKeyDown(KeyCode.UpArrow);
Boolean isMoveBackground = Input.GetKeyDown(KeyCode.DownArrow);
通过GetKeyDown/GetKeyUp检测按键按下和弹起,按哪个按键可以通过KeyCode.xx 来指定。 KeyCode是Unity内置的按键枚举,比如空白按键KeyCode.Space。
2. 对象移动
对象的移动,可以通过修改postion大小来改变;也可以通过给对象增加推力,让其自行调整postion位置。
2.1 postion大小修改
float x = 1;
float y = 1;
float z = 1;
Vector3 newPostion = new Vector3(x,y,z);
transform.position = newPostion;
//移动指定向量偏移量
float speed = 30.0f;
float Vertical = Input.GetAxis("Vertical");
transform.Translate(Vector3.forward * Time.deltaTime * speed * Vertical);
直接修改postion的方式,比较简单。
- 通过提供一个新的Vector3 向量位置
- 通过Unity的Translate方法,给位置增加偏移向量。
2.2 AddForce添加推力
给对象添加一个推力,我们需要给对象添加一个刚体Rigidbody组件,它表示物理世界的重力属性。
Boolean isMoveLeft = Input.GetKeyDown(KeyCode.LeftArrow);
Boolean isMoveRight = Input.GetKeyDown(KeyCode.RightArrow);
Boolean isMoveForward = Input.GetKeyDown(KeyCode.UpArrow);
Boolean isMoveBackground = Input.GetKeyDown(KeyCode.DownArrow);
float Horizontal = Input.GetAxis("Horizontal");
float Vertical = Input.GetAxis("Vertical");
float speed = 10;
float zBound = 4.5f;
// GetAxis方式
GetComponent<Rigidbody>().AddForce(Vector3.right * Horizontal * speed);
GetComponent<Rigidbody>().AddForce(Vector3.forward *Vertical*speed);
//keydown方式
if (isMoveLeft || isMoveRight) {
float force = isMoveLeft ? 10 : 0;
force = isMoveRight ? -10 : force;
GetComponent<Rigidbody>().AddForce(Vector3.left * Horizontal * speed, ForceMode.Impulse);
}
if (isMoveForward || isMoveBackground) {
float force = isMoveForward ? 10 : 0;
force = isMoveBackground ? -10 : force;
GetComponent<Rigidbody>().AddForce(Vector3.forward *Horizontal*speed, ForceMode.Impulse);
}
上面AddForce例子里,force 10/-10表示一个正向反向的推力,推力方向是Vector3.right和Vector3.forward,模式是ForceMode.Impulse。
ForceMode
是 Unity 中的一个枚举类型,用于指定在施加力或作用力时的力的模式。它定义了四种不同的模式:
Force:在刚体上施加一个连续的力,使用刚体的质量。这意味着力将持续作用于物体,直到另一个力或相反方向的力抵消它。通常用于模拟持续的力,比如重力或者推力。
Impulse:在刚体上施加一个瞬时冲量,使用刚体的质量。这意味着力将一次性作用于物体,然后立即停止。通常用于模拟瞬时的力,比如碰撞或爆炸。
VelocityChange:在刚体上施加一个瞬时速度变化,忽略刚体的质量。这意味着物体将立即改变其速度,而不考虑其质量。通常用于直接改变物体的速度,而不考虑惯性。
Acceleration:在刚体上施加一个连续的加速度,忽略刚体的质量。这意味着物体将以恒定的加速度持续加速,直到另一个力或相反方向的力抵消它。通常用于模拟持续的加速度,比如风或推力。
这些不同的模式允许开发者根据场景的需求来选择合适的力的作用方式,从而实现更精确的物理模拟和游戏行为。
3. 优缺点
这两种方式各有优劣,具体取决于你的需求和场景。
1. 直接修改位置 (transform.position
):
- 优点:
- 简单直接:直接修改位置参数,代码量少,容易理解和实现。
- 精确控制:可以精确地将物体移动到指定的位置,不受物理系统的影响。
- 缺点:
- 不受物理系统约束:直接修改位置不受物理引擎的约束,可能会绕过碰撞检测,导致物体穿过其他物体或产生意外的行为。
- 不适合动态场景:如果物体需要受到力的影响,例如重力、摩擦力等,直接修改位置可能无法满足需求。
2. 施加力 (Rigidbody.AddForce())
:
- 优点:
- 物理仿真:通过施加力的方式,物体会受到物理系统的影响,可以模拟真实世界中的物体运动行为,例如惯性、摩擦力、碰撞等。
- 自然流畅:施加力可以使物体的运动更自然、流畅,更符合真实物理规律。
- 缺点:
- 复杂性:与直接修改位置相比,使用物理引擎需要更多的代码和配置来控制物体的移动,尤其是在需要调整力的大小和方向时。
- 相对性能较低:物理仿真需要消耗额外的计算资源,可能会对性能产生一定的影响。
综合来说,如果你的场景需要模拟真实物理行为,或者需要让物体受到力的影响,那么使用 Rigidbody.AddForce()
更为合适。但如果你只是简单地需要将物体移动到某个位置,且不需要考虑物理因素,那么直接修改位置可能更简单和有效。