汽车右侧的网格包含两种,一种是弧形,另一种是矩形,二者均通过计算坐标位置、顶点个数和UV坐标参数生成所需要的网格,同时对网格进行了适配,根据不同的屏幕分辨率自动缩放网格的大小。
//更新弧形网格
protected override void UpdateShape()
{
int vertexCount = segment*2 + 2;
vertices=new Vector3[vertexCount];
float angle = _angleBegin*Mathf.Deg2Rad;
float wHalf = ringWidth*0.5f;
float sin = Mathf.Sin(angle);
float cos = Mathf.Cos(angle);
float minRingRadius = _ringRadius - wHalf;
float maxRingRadius = _ringRadius + wHalf;
Vector3 localPos = offset;
float x = cos*minRingRadius + localPos.x;
float y = localPos.y;
float z = sin*minRingRadius + localPos.z;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = z;
x = cos*maxRingRadius + localPos.x;
z = sin*maxRingRadius + localPos.z;
vertices[1].x = x;
vertices[1].y = y;
vertices[1].z = z;
float singleAngle = (_angleEnd - _angleBegin)/segment*Mathf.Deg2Rad;
for (int i = 0; i < segment; i++)
{
angle += singleAngle;
sin = Mathf.Sin(angle);
cos = Mathf.Cos(angle);
x = cos*minRingRadius + localPos.x;
y = localPos.y;
z = sin*minRingRadius + localPos.z;
vertices[i*2+2]=new Vector3(x,y,z);
x = cos*maxRingRadius + localPos.x;
y = localPos.y;
z = sin*maxRingRadius + localPos.z;
vertices[i*2+3]=new Vector3(x,y,z);
}
UpdateMesh();
}
//更新矩形网格
protected override void UpdateShape()
{
Vector3 localPos = offset;
float w2 = m_Width*0.5f;
float l2 = m_Length*0.5f;
vertices=new Vector3[4];
float x0, z0, x1, z1, x2, z2, x3, z3;
x0 = z0 = x1 = z1 = x2 = z2 = x3 = z3 = 0;
switch (widthAlign)
{
case PivotAlign.Left:
x0 = 0f;
x1 = m_Width;
x2 = 0;
x3 = m_Width;
break;
case PivotAlign.Center:
x0 = -w2;
x1 = w2;
x2 = -w2;
x3 = w2;
break;
case PivotAlign.Right:
x0 = -m_Width;
x1 = 0f;
x2 = -m_Width;
x3 = 0f;
break;
}
switch (lengthAlign)
{
case PivotAlign.Left:
z0 = 0;
z1 = 0;
z2 = m_Length;
z3 = m_Length;
break;
case PivotAlign.Center:
z0 = -l2;
z1 = -l2;
z2 = l2;
z3 = l2;
break;
case PivotAlign.Right:
z0 = -m_Length;
z1 = -m_Length;
z2 = 0f;
z3 = 0f;
break;
}
vertices[0].x = localPos.x + x0;
vertices[0].y = localPos.y;
vertices[0].z = localPos.z + z0;
vertices[1].x = localPos.x + x1;
vertices[1].y = localPos.y;
vertices[1].z = localPos.z + z1;
vertices[2].x = localPos.x + x2;
vertices[2].y = localPos.y;
vertices[2].z = localPos.z + z2;
vertices[3].x = localPos.x + x3;
vertices[3].y = localPos.y;
vertices[3].z = localPos.z + z3;
UpdateMesh();
}
标尺左侧的主要功能是用来显示汽车的长、宽和高,并且标尺上带有相关的数据,以方便用户对汽车有一个直观的认识。
//初始化矩形网格
protected override void InitMesh()
{
if (cacheTransform == null || meshFilter == null)
{
Init();
}
triangles =new int[] {0,2,3,0,3,1};
uvs=new Vector2[4];
uvs[0].x = 0;
uvs[0].y = 0;
uvs[1].x = 1;
uvs[1].y = 0;
uvs[2].x = 0;
uvs[2].y = 1;
uvs[3].x = 1;
uvs[3].y = 1;
UpdateShape();
}
//初始化弧形网格
protected override void InitMesh()
{
if (cacheTransform==null||meshFilter==null)
{
Init();
}
segment = segment > 0 ? segment : 1;
triangles=new int[segment*2*3];
for (int i = 0; i < segment; i++)
{
int k = i*6;
int j = i*2;
triangles[k] = j;
triangles[k + 1] = j + 2;
triangles[k + 2] = j + 3;
triangles[k + 3] = j;
triangles[k + 4] = j + 3;
triangles[k + 5] = j + 1;
}
int vertexCount = segment*2 + 2;
uvs=new Vector2[vertexCount];
float singleUV = 1f/segment;
float uvY = 0f;
for (int i = 0; i < vertexCount; i+=2)
{
uvs[i].x = 0f;
uvs[i + 1].x = 1f;
uvs[i].y = uvY;
uvs[i + 1].y = uvY;
uvY += singleUV;
}
UpdateShape();
}
通过场景的旋转,汽车左右侧的网格会产生动画,并且有淡入和淡出的效果,通过网格的动画可以吸引客户的注意力,并且能注意到网格上的数据。
//动画正常播放
private void PlayForward()
{
float duration;
float delay;
for (int i = 0; i < count; i++)
{
duration = Random.Range(minDuration, maxDuration);
delay = Random.Range(minDelay, maxDelay);
textTf[i].DOScale(scales[i], duration).SetDelay(delay);
}
}
//动画倒序播放
private void PlayBackward()
{
float duration;
float delay;
for (int i = 0; i < count; i++)
{
duration = Random.Range(minDuration, maxDuration);
delay = Random.Range(minDelay, maxDelay);
textTf[i].DOScale(Vector3.zero, duration).SetDelay(delay);
}
}
当点击LIGHT、EXPLOD和汽车车身的时候,会播放不同的声音,同时汽车分解、车灯移动、汽车变色功能实现时会播放相对应功能的声音。
public class SoundManager : MonoBehaviour
{
public static SoundManager Instance;
public AudioSource audioSource;
public AudioClip lightOpen;
public AudioClip ligthClose;
public AudioClip explode;
public AudioClip colorWheel;
public AudioClip carColorChange;
void Awake()
{
Instance = this;
}
void Play()
{
audioSource.Play();
}
public void PlayLightOpen()
{
audioSource.clip = lightOpen;
Play();
}
public void PlayLightClose()
{
audioSource.clip = ligthClose;
Play();
}
public void PlayExplode()
{
audioSource.clip = explode;
Play();
}
public void PlayColorWheelShow()
{
audioSource.clip = colorWheel;
Play();
}
public void PlayCarColorChange()
{
audioSource.clip = carColorChange;
Play();
}
}
按下鼠标左键进行左右和上下拖动时,摄像机可以进行左右和上下旋转,实现汽车在场景中旋转的效果,当滚动鼠标的滚轮键时,摄像机视角可以拉近拉远,实现汽车变大变小的效果。
private void Oribit()
{
if (Input.GetMouseButtonDown(0))
{
lastMousePos = Input.mousePosition;
}
if (Input.GetMouseButton(0))
{
targetEulerAngle.x += (-Input.mousePosition.y + lastMousePos.y)*cureentCameraParameter.mouseMoveRatio;
targetEulerAngle.y += (Input.mousePosition.x - lastMousePos.x) * cureentCameraParameter.mouseMoveRatio;
if (cureentCameraParameter.limitXAngle)
{
targetEulerAngle.x = Mathf.Clamp(targetEulerAngle.x, cureentCameraParameter.minXAngle,
cureentCameraParameter.maxXAngle);
}
if (cureentCameraParameter.limitYAngle)
{
targetEulerAngle.y = Mathf.Clamp(targetEulerAngle.y, cureentCameraParameter.minYAngle,
cureentCameraParameter.maxXAngle);
}
lastMousePos = Input.mousePosition;
}
if (Input.touchCount<2)
{
eulerAngle = Vector3.Lerp(eulerAngle, targetEulerAngle,
Time.fixedDeltaTime*cureentCameraParameter.orbitSensitive);
cameraRootTf.rotation = originalRotate*Quaternion.Euler(eulerAngle);
}
FireEvent(cameraRootTf.localEulerAngles.y);
}
该效果使得摄像机无论旋转到任何角度,UI界面都能够把正面面向摄像机,让用户能够完全看到UI界面,该功能也可以用在3D游戏中的血条效果上。
private void SetBillBoardTarget(Transform[] targettfs)
{
this.targetTfs = targettfs;
count = targettfs.Length;
billBoardItems=new BillBoardItem[count];
GameObject tempGo;
for (int i = 0; i < count; i++)
{
tempGo = Instantiate(itemObject);
billBoardItems[i] = tempGo.GetComponent<BillBoardItem>();
billBoardItems[i].uiText.text = targettfs[i].gameObject.name.Replace("Billboard_", "");
billBoardItems[i].transform.SetParent(cacheTransform);
billBoardItems[i].transform.localScale=Vector3.one;
}
}
当点击车身时,颜色面板会显示出来,点击颜色面板上的某个色块后,汽车的颜色就会变成所点击色块的颜色。
private void InitBodyChildren()
{
Transform[] children = gameObject.GetComponentsInChildren<Transform>();
int count = children.Length;
List<ColorItem> colorItems=new List<ColorItem>();
for (int i = 0; i < count; i++)
{
Transform child = children[i];
if (child!=cacheTransform)
{
if (child.name.StartsWith("Body"))
{
child.gameObject.AddComponentIfNotHave<MeshCollider>();
EventTriggerListener.Get(child.gameObject).onClick += OnClickBody;
ColorItem item = child.gameObject.AddComponent<ColorItem>();
colorItems.Add(item);
}
}
}
items = colorItems.ToArray();
this.count = items.Length;
}
private void OnClickBody(GameObject go, PointerEventData eventdata)
{
Debug.Log("点击了"+go.name);
Vector2 delta = eventdata.position - eventdata.pressPosition;
if (delta.x<dragData&&delta.y<dragData)
{
EventCenter.ConfigEvent.RaiseClickBody(true);
}
}
当点击屏幕右下角的LIGHT按钮时,按钮上的文字会显示ON,此时车灯会在距车头前面的一定距离显示出来,并移动到汽车头部车灯所在的位置。当再一次点击LIGHT按钮,按钮上的文字显示OFF,此时车灯会从汽车头部移动到车头前面指定的距离并隐藏。
public void ClickButton()
{
if (isOpened)
{
EventCenter.UIEvent.RaiseLightFlare(false);
anim.Close();
isOpened = false;
SoundManager.Instance.PlayLightClose();
}
else
{
EventCenter.UIEvent.RaiseLightFlare(true);
anim.Open();
isOpened = true;
SoundManager.Instance.PlayLightOpen();
}
MouseLock.Instance.Lock(1.5f);
}
当点击屏幕右下角的EXPLOD按钮时,汽车外壳隐藏,只显示内部零件的构造,同时按钮上的文字显示为ON,当再一次点击EXPLOD按钮后,内部零部件隐藏,汽车外壳显示,按钮上的文字显示为OFF。
public void ClickButton()
{
if (isOpened)
{
Close();
anim.Close();
isOpened = false;
MouseLock.Instance.Lock(1.5f);
}
else
{
Open();
anim.Open();
isOpened = true;
MouseLock.Instance.Lock(1.5f);
}
SoundManager.Instance.PlayExplode();
}