题目
思路
- 一个方块多种颜色:可以通过建模贴不同颜色的材质,或者shader实现
- 随机位置和角度:使用随机数,生成随机向量,赋给position和eulerAngles
- 位置误差:两个面的中点的position的差值
- 旋转误差:用自身各个轴和要对齐的平面的夹角表示。旋转顺序应该为将X轴转到要对齐的平面,再将Y轴转到要对其的平面,使得两个面在同一平面内;然后旋转Z轴,使两个面完全重合。
我的解答
-
把方块作为Quad的子类,移动Quad吸附要对齐的面,得到面的位姿
-
设定平移和旋转两种交互模式,勾选切换后,通过键盘操作平移和旋转,并且复用按钮减少操作复杂度
-
强制设定了交互顺序,先平移再旋转
-
绿方块按照自身轴旋转和平移,只需要将误差调到指定的数,即可对齐。
代码
- 随机位置和角度
public GameObject Cube;
public float RandomRadius; //限制随机出现的范围,使红色方块一定出现在摄像机视野内
void Start()
{
Cube.transform.position = RandomPosi(RandomRadius);
Cube.transform.eulerAngles = RandomRot();
}
private Vector3 RandomPosi(float radius)//随机位置
{
Vector3 pos;
float x= Random.Range(-radius, radius);
float y= Random.Range(-radius, radius);
float z= Random.Range(-radius, radius);
return pos;
}
private Vector3 RandomRot()//随机角度
{
Vector3 rot;
float x = Random.Range(0.0f, 360.0f);
float y= Random.Range(0.0f, 360.0f);
float z= Random.Range(0.0f, 360.0f);
return rot;
}
- 平移、旋转、显示误差
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MoveCube : MonoBehaviour
{
public bool IsMove = false ;//移动模式
public bool IsRot = false ;//旋转模式
//移动、旋转的速度
private float MoveXspeed;
private float MoveYspeed;
private float MoveZspeed;
private float RotXspeed;
private float RotYspeed;
private float RotZspeed;
//设置最快速度和最慢速度,接近对齐时使用慢速微调
public float FastMoveSpeed;
public float SlowMoveSpeed;
public float FastRotSpeed;
public float SlowRotSpeed;
//显示误差
public GameObject RedQuad;
public GameObject GreenQuad;
public Text TextBoard;
void Update()
{
TextBoard.text = showError();
if (IsMove) Move();
if (IsRot) Rot();
}
//平移方法
private void Move()
{
//Y轴,上下移动
if (Input.GetKey(KeyCode.W)
this.transform.Translate(Vector3.up * Time.fixedTime * MoveYspeed);
if (Input.GetKey(KeyCode.S) )
this.transform.Translate(-Vector3.up * Time.fixedTime * MoveYspeed);
//X轴,左右移动
if (Input.GetKey(KeyCode.A) )
this.transform.Translate(Vector3.left * Time.fixedTime * MoveXspeed);
if (Input.GetKey(KeyCode.D) )
this.transform.Translate(-Vector3.left * Time.fixedTime * MoveXspeed);
//Z轴,前后移动
if (Input.GetKey(KeyCode.Q) )
this.transform.Translate(Vector3.back * Time.fixedTime *MoveZspeed);
if (Input.GetKey(KeyCode.E) )
this.transform.Translate(-Vector3.back * Time.fixedTime * MoveZspeed);
}
//旋转方法
private void Rot()
{
//绕Y轴
if (Input.GetKey(KeyCode.W))
this.transform.Rotate(Vector3.down * Time.fixedTime * RotYspeed);
if (Input.GetKey(KeyCode.S))
this.transform.Rotate(-Vector3.down * Time.fixedTime * RotYspeed);
//绕X轴
if (Input.GetKey(KeyCode.A))
this.transform.Rotate(Vector3.left * Time.fixedTime * RotXspeed);
if (Input.GetKey(KeyCode.D))
this.transform.Rotate(-Vector3.left * Time.fixedTime * RotXspeed);
//绕Z轴
if (Input.GetKey(KeyCode.Q))
this.transform.Rotate(Vector3.back * Time.fixedTime * RotZspeed);
if (Input.GetKey(KeyCode.E))
this.transform.Rotate(-Vector3.back * Time.fixedTime * RotZspeed);
}
//是否平移
public void MoveGo()
{
IsMove = true;
IsRot = false;
}
//是否旋转
public void RotGo()
{
IsRot = true;
IsMove = false;
}
//显示误差
private string showError()
{
string posError = PosError();
string rotError = RotError();
return "先平移:"+"\r\n" + posError
+ "\r\n" + "后旋转:" + "\r\n" + rotError;
}
//位置误差
private string PosError()
{
float GreenX = GreenQuad.transform.position.x;
float GreenY = GreenQuad.transform.position.y;
float GreenZ = GreenQuad.transform.position.z;
float x = RedQuad.transform.position.x - GreenX;
float y = RedQuad.transform.position.y - GreenY;
float z = RedQuad.transform.position.z - GreenZ;
//根据误差大小控制速度
if (Mathf.Abs(y) > 1.0f)
MoveYspeed = FastMoveSpeed;
else MoveYspeed = SlowMoveSpeed;
if (Mathf.Abs(x) > 1.0f)
MoveXspeed = FastMoveSpeed;
else MoveXspeed = SlowMoveSpeed;
if (Mathf.Abs(z) > 1.0f)
MoveZspeed = FastMoveSpeed;
else MoveZspeed = SlowMoveSpeed;
return "X轴方向误差(操作AD使误差归0):"+x+"\r\n"
+ "Y轴方向误差(操作WS使误差归0):" + y+"\r\n"
+ "Z轴方向误差(操作QE使误差归0):" + z+"\r\n";
}
//角度误差
private string RotError()
{
float XZ = Angle(GreenQuad.transform.right,RedQuad.transform.forward);
float YZ = Angle(GreenQuad.transform.up, RedQuad.transform.forward);
float ZZ = Angle(GreenQuad.transform.forward, RedQuad.transform.forward);
float XX = Angle(GreenQuad.transform.right, RedQuad.transform.right);
根据误差大小控制速度
if (YZ > 95.0f || YZ < 85.0f)
RotXspeed = FastRotSpeed;
else RotXspeed = SlowRotSpeed;
if (XZ > 95.0f || XZ < 85.0f)
RotYspeed = FastRotSpeed;
else RotYspeed = SlowRotSpeed;
if (0.0f <= XX && XX < 5.0f)
RotZspeed = SlowRotSpeed;
else if (175.0f <= XX && XX < 185.0f)
RotZspeed = SlowRotSpeed;
else RotZspeed = FastRotSpeed;
return "操作WS按钮,使误差接近90\r\n"
+ "绿方块x轴与红方块xy平面的夹角(操作WS):" +XZ+ "\r\n" + "\r\n"
+ "操作AD按钮,使误差接近90\r\n"
+ "绿方块y轴与红方块xy平面的夹角(操作AD):" + YZ + "\r\n" + "\r\n"
+ "180代表相对,0代表重合\r\n"
+ "绿方块z轴与红方块z轴的夹角:" + ZZ + "\r\n" + "\r\n"
+ "操作QE按钮,使误差接近0或180\r\n"
+ "绿方块x轴与红方块x轴的夹角(操作QE):" + XX + "\r\n";
}
//求两向量夹角
private float Angle(Vector3 red, Vector3 green)
{
float dot = Vector3.Dot(red.normalized, green.normalized);
float angle = Mathf.Acos(dot) * Mathf.Rad2Deg;
return angle;
}
}