天津23维预案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

682 lines
28 KiB

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using AX.TrackRecord;
using AX.MessageSystem;
using System.Linq;
using UnityEngine.AI;
public class XiaoFangYuanDrawLine : MonoBehaviour
{
// Use this for initialization
public GameObject cloneObj;
public GameObject nullobject;
private GameObject prlineObj;
public GameObject Line;//管线模型
public GameObject Zhaomingxian;//照明线模型
public GameObject Guanxian;//管线模型
private Vector3 placementPos;//第一碰撞点
private Vector3 placementPos2;//第二碰撞点
private Vector3[] nowpath;
private Vector3[] newpath;
private float timer = 0;
private bool IsFirstPFFlag = false;//该记录的第一次寻路标志,开始记录时赋值true
private UnityEngine.AI.NavMeshPath NavMeshPath;
public List<Vector3> Allpath = new List<Vector3>();//关键点
public List<string> AllLine = new List<string>();//水带、照明线
public List<float> AllLineDistance = new List<float>();//水带长度
private int pointIndex = 1;
private bool flag;
float time;
float allLineDistance;//可用管线长度(管线总长减别人已用的长度)
float drawLineDistance;//已用管线长度
float DifferenceLine;//管线超出长度
private int MultipleSpeed=1;//回放播放倍数
void Awake()
{
NavMeshPath = new NavMeshPath();
TheBackView.instance.SpeedChangeEvent += OnSpeedChangeEvent;
MultipleSpeed = LoadManager.Instance.speedFactor;
}
void Start()
{
//string name = this.name + "drawline";
string name_ = "TeamName-drawline-Zhaomingxian-" + this.name;
if (!GameObject.Find(name_))
{
prlineObj = Instantiate(nullobject) as GameObject;
prlineObj.name = name_;
prlineObj.transform.parent = GameObject.Find("pdrawline").transform;
prlineObj.AddComponent<DestroyObj>();//用来记录删除消防管线
}
else
{
prlineObj = GameObject.Find(name_);
}
}
void OnDestroy()
{
TheBackView.instance.SpeedChangeEvent -= OnSpeedChangeEvent;
}
/// <summary>
/// 找到当前最靠近的Index点
/// </summary>
/// <param name="nowpath"></param>
/// <param name="point"></param>
/// <returns></returns>
private int GetNearest(List<Vector3> nowpath, Vector3 point)
{
int index = 0;
var result = (from x in nowpath
select new { Key = x, Value = Vector3.Distance(point, x), Index = index++ })
.OrderBy(x => x.Value).Take(Mathf.Min(1, nowpath.Count)); // 太多了,按照接近程度 take 10 个。
index = result.ToList()[0].Index;
return index;
}
private bool IsPointOnSegment(Vector3 Pi, Vector3 Pj, Vector3 Q)
{
if ((Q.x - Pi.x) * (Pj.z - Pi.z) == (Pj.x - Pi.x) * (Q.z - Pi.z) //叉乘
&& Mathf.Min(Pi.x, Pj.x) <= Q.x && Q.x <= Mathf.Max(Pi.x, Pj.x)//保证Q点坐标在pi,pj之间
&& Mathf.Min(Pi.z, Pj.z) <= Q.y && Q.y <= Mathf.Max(Pi.z, Pj.z))
return true;
else
return false;
}
// Update is called once per frame
void /*Fixed*/Update()
{
if (!HasLine())
{
nowpath = null;
return;
}
drawLine();
time += Time.deltaTime;
if (time >= 0.5f/ MultipleSpeed)//间隔0.5秒重新规划下管线
{
time = 0.0f;
if (nowpath != null && pointIndex < nowpath.Length&&GetComponent<UnityEngine.AI.NavMeshAgent>().velocity.magnitude>0)//只有移动的时候需要纠正路线
{
changeLine();
}
else if (flag)//寻路停止后再纠正一下管线位置
{
changeLine();
flag = false;
}
}
}
private void drawLine()
{
if (nowpath != null)
{
if (Allpath.Count == 0)
{
Allpath.Add(nowpath[0]);
}
for (int i = pointIndex; i < nowpath.Length; i++)
{
if (Vector3.Distance(transform.position, nowpath[i]) < 1.0f)
{
placementPos = nowpath[i - 1];
placementPos2 = nowpath[i];
pointIndex = i + 1;
Allpath.Add(placementPos2);
}
}
}
}
private void changeLine()
{
//float dis = Allpath.Count == 0 ? 0.0f : Vector3.Distance(transform.position, Allpath[Allpath.Count - 1]);
if (!getDistance())
{
if (this.GetComponent<AgentControl>().enabled)
{
this.GetComponent<AgentControl>().StopAllCoroutines();
this.GetComponent<AgentControl>().enabled = false;
this.GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;
this.transform.position = correctLine();
//this.GetComponent<XiaoFangYuanMessage>().positionjiuzheng = true;
this.GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = true;
this.GetComponent<AgentControl>().enabled = true;
nowpath = null;//停止画线
return;
}
else
{
this.GetComponent<AgentControl>().enabled = true;
this.GetComponent<AgentControl>().StopAllCoroutines();
this.GetComponent<AgentControl>().enabled = false;
this.GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;
this.transform.position = correctLine();
//this.GetComponent<XiaoFangYuanMessage>().positionjiuzheng = true;
this.GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = true;
nowpath = null;//停止画线
}
}
if (Allpath.Count == 0)
{
if (GetComponent<UnityEngine.AI.NavMeshAgent>().velocity.magnitude>0)
{
MessageDispatcher.SendMessage("Operatinghints", (object)"水带长度不足,请装备水带");
}
return;
}
else if (Allpath.Count == 1)
{
for (int i = AllLine.Count - 1; i >= 0; i--)
{
if (GameObject.Find(AllLine[i]))
{
Destroy(GameObject.Find(AllLine[i]));
//NetworkManager.Instance.Send("ENTITY_DESTROY", AllLine[i]);
}
AllLine.RemoveAt(i);
//if(i< AllLineDistance.Count - 1)
//{
AllLineDistance.RemoveAt(i);
//}
}
NavMeshPath.ClearCorners();
try
{
//计算范围外距离最近的关键点和当前位置的平滑路径
UnityEngine.AI.NavMesh.CalculatePath(Allpath[0], transform.position, -1, NavMeshPath);
}
catch (Exception e)
{
System.Diagnostics.Trace.TraceError(e.Message);
}
//根据生成的关键点画线
newpath = NavMeshPath.corners;
for (int k = 1; k < newpath.Length; k++)
{
placementPos = newpath[k - 1];
placementPos2 = newpath[k];
Vector3 tempPos = (placementPos + placementPos2) / 2;//计算两个点的中点坐标,
cloneObj = Instantiate(Line, tempPos, Quaternion.identity) as GameObject;
var LineMsg = cloneObj.GetComponent<BandLineMessage>();
//LineMsg.MessageInit();
//LineMsg.userID = DeptList.UserID;
//LineMsg.roleName = DeptList.RoleName;
LineMsg.objectNum = BandLineMessage.Num;
LineMsg.objectType = "drawline";
//LineMsg.parentName = prlineObj.name;
cloneObj.GetComponent<CengID>().cengID = this.GetComponent<CengID>().cengID;
cloneObj.GetComponent<CengID>().CengIDBuildType = this.GetComponent<CengID>().CengIDBuildType;
//cloneObj.name = LineMsg.objectType + LineMsg.objectNum;
cloneObj.name = "TeamName-" + LineMsg.objectType + "-" + "Zhaomingxian-" + LineMsg.objectNum;
cloneObj.transform.parent = prlineObj.transform;
cloneObj.transform.forward = (cloneObj.transform.position - placementPos).normalized;//改变线条的朝向
float distance = Vector3.Distance(placementPos, placementPos2);//计算两点的距离
cloneObj.transform.localScale = new Vector3(6f, 6f, distance * 10.75f);//延长线条,连接两点。
//cloneObj.AddComponent("DrawLineSync");
Allpath.Add(placementPos2);
AllLine.Add(cloneObj.name);
AllLineDistance.Add(distance);
}
}
else if (Allpath.Count >= 2)
{
float dis = Vector3.Distance(transform.position, Allpath[Allpath.Count - 1]);
for (int i = Allpath.Count - 1; i >= 1; i--)
{
//实际有效点是 i-1
dis += Vector3.Distance(Allpath[i], Allpath[i - 1]);
if (dis > 10.0f)
{
//倒序删除范围内的活动关键点
for (int j = Allpath.Count - 1; j >= i; j--)
{
Allpath.RemoveAt(j);
}
for (int j = AllLine.Count - 1; j >= i - 1; j--)//这里分开循环是因为Allpath,AllLine的长度并不是一直相同的
{
if (GameObject.Find(AllLine[j]))
{
Destroy(GameObject.Find(AllLine[j]));
//NetworkManager.Instance.Send("ENTITY_DESTROY", AllLine[j]);
}
AllLine.RemoveAt(j);
//if (j < AllLineDistance.Count - 1)
//{
AllLineDistance.RemoveAt(j);
//}
}
NavMeshPath.ClearCorners();
try
{
//计算范围外距离最近的关键点和当前位置的平滑路径
UnityEngine.AI.NavMesh.CalculatePath(Allpath[i - 1], transform.position, -1, NavMeshPath);
}
catch (Exception e)
{
System.Diagnostics.Trace.TraceError(e.Message);
}
//根据生成的关键点画线
newpath = NavMeshPath.corners;
for (int k = 1; k < newpath.Length; k++)
{
placementPos = newpath[k - 1];
placementPos2 = newpath[k];
Vector3 tempPos = (placementPos + placementPos2) / 2;//计算两个点的中点坐标,
cloneObj = Instantiate(Line, tempPos, Quaternion.identity) as GameObject;
var LineMsg = cloneObj.GetComponent<BandLineMessage>();
//LineMsg.MessageInit();
//LineMsg.userID = DeptList.UserID;
//LineMsg.roleName = DeptList.RoleName;
LineMsg.objectNum = BandLineMessage.Num;
LineMsg.objectType = "drawline";
//LineMsg.parentName = prlineObj.name;
cloneObj.GetComponent<CengID>().cengID = this.GetComponent<CengID>().cengID;
cloneObj.GetComponent<CengID>().CengIDBuildType = this.GetComponent<CengID>().CengIDBuildType;
//cloneObj.name = LineMsg.objectType + LineMsg.objectNum;
cloneObj.name = "TeamName-" + LineMsg.objectType + "-" + "Zhaomingxian-" + LineMsg.objectNum;
cloneObj.transform.parent = prlineObj.transform;
cloneObj.transform.forward = (cloneObj.transform.position - placementPos).normalized;//改变线条的朝向
float distance = Vector3.Distance(placementPos, placementPos2);//计算两点的距离
cloneObj.transform.localScale = new Vector3(6f, 6f, distance * 10.75f);//延长线条,连接两点。
//cloneObj.AddComponent("DrawLineSync");
Allpath.Add(placementPos2);
AllLine.Add(cloneObj.name);
AllLineDistance.Add(distance);
}
break;
}
else if (i == 1)//从起点到现在位置都没超过限定距离
{
for (int j = Allpath.Count - 1; j > 0; j--)
{
Allpath.RemoveAt(j);//删除除起点外的所有点
}
for (int j = AllLine.Count - 1; j >= 0; j--)
{
if (GameObject.Find(AllLine[j]))
{
Destroy(GameObject.Find(AllLine[j]));
//NetworkManager.Instance.Send("ENTITY_DESTROY", AllLine[j]);
}
AllLine.RemoveAt(j);//删除所有线
//if (j < AllLineDistance.Count - 1)
//{
AllLineDistance.RemoveAt(j);
//}
}
NavMeshPath.ClearCorners();
try
{
//计算范围外距离最近的关键点和当前位置的平滑路径
UnityEngine.AI.NavMesh.CalculatePath(Allpath[0], transform.position, -1, NavMeshPath);
}
catch (Exception e)
{
System.Diagnostics.Trace.TraceError(e.Message);
}
//根据生成的关键点画线
newpath = NavMeshPath.corners;
for (int k = 1; k < newpath.Length; k++)
{
placementPos = newpath[k - 1];
placementPos2 = newpath[k];
Vector3 tempPos = (placementPos + placementPos2) / 2;//计算两个点的中点坐标
cloneObj = Instantiate(Line, tempPos, Quaternion.identity) as GameObject;
var LineMsg = cloneObj.GetComponent<BandLineMessage>();
//LineMsg.MessageInit();
//LineMsg.userID = DeptList.UserID;
//LineMsg.roleName = DeptList.RoleName;
LineMsg.objectNum = BandLineMessage.Num;
LineMsg.objectType = "drawline";
//LineMsg.parentName = prlineObj.name;
cloneObj.GetComponent<CengID>().cengID = this.GetComponent<CengID>().cengID;
cloneObj.GetComponent<CengID>().CengIDBuildType = this.GetComponent<CengID>().CengIDBuildType;
//cloneObj.name = LineMsg.objectType + LineMsg.objectNum;
cloneObj.name = "TeamName-" + LineMsg.objectType + "-" + "Zhaomingxian-" + LineMsg.objectNum;
cloneObj.transform.parent = prlineObj.transform;
cloneObj.transform.forward = (cloneObj.transform.position - placementPos).normalized;//改变线条的朝向
float distance = Vector3.Distance(placementPos, placementPos2);//计算两点的距离
cloneObj.transform.localScale = new Vector3(6f, 6f, distance * 10.75f);//延长线条,连接两点。
//cloneObj.AddComponent("DrawLineSync");
Allpath.Add(placementPos2);
AllLine.Add(cloneObj.name);
AllLineDistance.Add(distance);
}
}
}
}
setLineXiaoHao();
}
public void setLine()
{
var task = GetComponent<ObjMessage>().TaskName;
if (task.Contains("灭火") || task.Contains("掩护") || task.Contains("铺设水带") || task.Contains("洗消"))
{
Line = Guanxian;
}
else if (task.Contains("铺设照明线"))
{
Line = Zhaomingxian;
}
}
public void setPath(Vector3[] path)
{
setLine();
Debug.Log(Line.name);
nowpath = path;
pointIndex = 1;
flag = true;
}
/// <summary>
/// 判断是否携带了管线和照明线
/// </summary>
/// <returns></returns>
public bool HasLine()
{
float disLine = 0.0f;//携带管线长
float disZhaoMingXian = 0.0f;//携带照明线长
GameObject obj;
//List<GameObject> AllMembers = this.GetComponent<XiaoFangYuanToShiNei>().AllMembers;
//List<GameObject> AllMembers = InputManager.Instance_.GetSelectedCharacters();
List<GameObject> AllMembers = GetComponent<AgentRecord>().xfyList;
for (int i = 0; i < AllMembers.Count; i++)
{
obj = AllMembers[i];
if (obj && obj.name.Contains("xiaofangyuan"))
{
disLine += obj.GetComponent<XiaoFangYuanDrawLine>().getHaveLine();
disZhaoMingXian += obj.GetComponent<XiaoFangYuanDrawLine>().getHaveZhaoMingXian();
}
}
if (Line.name.Equals(Guanxian.name))
{
if (disLine < 0.5f)
{
return false;
}
}
else if (Line.name.Equals(Zhaomingxian.name))
{
if (disZhaoMingXian < 0.5f)
{
return false;
}
}
return true;
}
/// <summary>
/// 判断消防员携带水带是否还有剩余
/// </summary>
/// <returns></returns>
private bool getDistance()
{
bool flag = true;
allLineDistance = getAllLine();
drawLineDistance = getDrawLine();
if (allLineDistance < 0)//allLineDistance < drawLineDistance
{//可用管线<0
flag = false;
//DifferenceLine = drawLineDistance - allLineDistance;//超出可用范围长度
DifferenceLine = Mathf.Abs(allLineDistance);//超出可用范围长度
}
return flag;
}
//获取该消防员可用的管线、照明线长度
private float getAllLine()
{
float dis = 0.0f;
float disLine = 0.0f;//携带管线长
float disZhaoMingXian = 0.0f;//携带照明线长
float disDraw = 0.0f;//已用长度
GameObject obj;
List<GameObject> AllMembers = this.GetComponent<XiaoFangYuanToShiNei>().AllMembers;
for (int i = 0; i < AllMembers.Count; i++)
{
obj = AllMembers[i];
disLine += obj.GetComponent<XiaoFangYuanDrawLine>().getHaveLine();
disZhaoMingXian += obj.GetComponent<XiaoFangYuanDrawLine>().getHaveZhaoMingXian();
disDraw += obj.GetComponent<XiaoFangYuanDrawLine>().getDrawLine();
}
//dis = disLine > disZhaoMingXian ? disZhaoMingXian : disLine;//取最短值作为管线可用长度
//dis -= disDraw;
//dis += this.GetComponent<XiaoFangYuanDrawLine>().getDrawLine();
//if (dis>getHaveZhaoMingXian())
//{
// dis = getHaveZhaoMingXian();
// MessageDispatcher.SendMessage("Operatinghints", (object)"水带长度不足,请装备水带");
//}
//Debug.Log("可用照明线长度为:" + dis+"携带照明线的长度为:"+getHaveZhaoMingXian());
if (Line.name.Equals(Guanxian.name))
{
dis = disLine - disDraw;
}
else if (Line.name.Equals(Zhaomingxian.name))
{
dis = disZhaoMingXian - disDraw;
}
return dis;
}
//获取该消防员已用的管线长度
public float getDrawLine()
{
float dis = 0.0f;
Debug.Log("AllLineDistance.Count" + AllLineDistance.Count);
for (int i = 0; i < AllLineDistance.Count; i++)
{
dis += AllLineDistance[i];
}
Debug.Log(dis);
return dis;
}
//获取该消防员携带的管线长度
public float getHaveLine()
{
float dis = 0.0f;
Dictionary<string, CostEquip> costSelectedEquips = this.GetComponent<Bag>().costSelectedEquips;
foreach (var item in costSelectedEquips)
{
if (item.Key.Contains("消防高压水带"))
{
dis = item.Value.selectedEquipNum * item.Value.unit;
}
}
return dis;
}
//获取该消防员携带的照明线长度
public float getHaveZhaoMingXian()
{
float dis = 0.0f;
Dictionary<string, CostEquip> costSelectedEquips = this.GetComponent<Bag>().costSelectedEquips;
foreach (var item in costSelectedEquips)
{
if (item.Key.Contains("救生照明线"))
{
dis = item.Value.selectedEquipNum * item.Value.unit;
}
}
return dis;
}
//管线超出可用管线范围纠正方法
private Vector3 correctLine()
{
//int k = 0;
Vector3 pos = new Vector3();
float dis = 0;
for (int i = AllLineDistance.Count - 1; i >= 0; i--)
{
//倒序找出应该回退到第几条线上
dis += AllLineDistance[i];
if (dis >= DifferenceLine)
{
float ab = dis - DifferenceLine;
float x = Allpath[i].x + (Allpath[i + 1].x - Allpath[i].x) * ab / AllLineDistance[i];
float y = Allpath[i].y + (Allpath[i + 1].y - Allpath[i].y) * ab / AllLineDistance[i];
float z = Allpath[i].z + (Allpath[i + 1].z - Allpath[i].z) * ab / AllLineDistance[i];
pos = new Vector3(x, y, z);//算出回退后消防员所在位置
//倒序删除多出的关键点和线
for (int j = Allpath.Count - 1; j >= i + 1; j--)
{
Allpath.RemoveAt(j);
}
for (int j = AllLine.Count - 1; j >= i; j--)//这里分开循环是因为Allpath,AllLine的长度并不是一直相同的
{
if (GameObject.Find(AllLine[j]))
{
Destroy(GameObject.Find(AllLine[j]));
//NetworkManager.Instance.Send("ENTITY_DESTROY", AllLine[j]);
}
AllLine.RemoveAt(j);
//if(j< AllLineDistance.Count - 1)
//{
AllLineDistance.RemoveAt(j);
//}
}
//将删除后最后一个点和消防员新位置连点成线
placementPos = Allpath[i];
placementPos2 = pos;
Vector3 tempPos = (placementPos + placementPos2) / 2;//计算两个点的中点坐标
cloneObj = Instantiate(Line, tempPos, Quaternion.identity) as GameObject;
var LineMsg = cloneObj.GetComponent<BandLineMessage>();
//LineMsg.MessageInit();
//LineMsg.userID = DeptList.UserID;
//LineMsg.roleName = DeptList.RoleName;
LineMsg.objectNum = BandLineMessage.Num;
LineMsg.objectType = "drawline";
//LineMsg.parentName = prlineObj.name;
cloneObj.GetComponent<CengID>().cengID = this.GetComponent<CengID>().cengID;
cloneObj.GetComponent<CengID>().CengIDBuildType = this.GetComponent<CengID>().CengIDBuildType;
cloneObj.name = LineMsg.objectType + LineMsg.objectNum;
cloneObj.transform.parent = prlineObj.transform;
cloneObj.transform.forward = (cloneObj.transform.position - placementPos).normalized;//改变线条的朝向
float distance = Vector3.Distance(placementPos, placementPos2);//计算两点的距离
cloneObj.transform.localScale = new Vector3(6f, 6f, distance * 10.75f);//延长线条,连接两点。
//cloneObj.AddComponent("DrawLineSync");
Allpath.Add(placementPos2);
AllLine.Add(cloneObj.name);
AllLineDistance.Add(distance);
break;
}
}
return pos;
}
/// <summary>
/// 消耗为0时,执行该方法即可将消耗重置,已使用数量标记为0
/// 消耗不为0时,即为计算消耗
/// </summary>
private void setLineXiaoHao()
{
float dis = 0.0f;
float disLine = 0.0f;//管线长
float disZhaoMingXian = 0.0f;//照明线长
GameObject obj;
//List<GameObject> AllMembers = this.GetComponent<XiaoFangYuanToShiNei>().AllMembers;
List<GameObject> AllMembers = GetComponent<AgentRecord>().xfyList;//使用该数组计算管线消耗,确保室外寻路也会消耗管线
for (int i = 0; i < AllMembers.Count; i++)//计算出总消耗量
{
obj = AllMembers[i];
dis += obj.GetComponent<XiaoFangYuanDrawLine>().getDrawLine();
}
Debug.Log(dis);
if (Line.name.Equals(Guanxian.name))
{
disLine = dis;
}
else if (Line.name.Equals(Zhaomingxian.name))
{
disZhaoMingXian = dis;
}
for (int i = 0; i < AllMembers.Count; i++)//按照顺序将消耗分配给成员
{
obj = AllMembers[i];
Dictionary<string, CostEquip> costSelectedEquips = obj.GetComponent<Bag>().costSelectedEquips;
foreach (var item in costSelectedEquips)
{
if (item.Key.Contains("消防高压水带"))
{
item.Value.useNum = 0;
if (disLine >= item.Value.selectedEquipNum * item.Value.unit)
//如果消耗管线总数大于此人选择的管线,那么此人管线全部标记为已消耗,再从下一个人身上继续扣除
{
item.Value.useNum = item.Value.selectedEquipNum;
disLine -= item.Value.selectedEquipNum * item.Value.unit;
}
else
{
//如果剩余消耗管线总数小于此人选择的管线,那么此人管线向上取整标记为已消耗,无需再从下一个人身上继续扣除了
item.Value.useNum =(int) Math.Ceiling(disLine / item.Value.unit);//向上取整
disLine = 0.0f;
}
}
else if (item.Key.Contains("救生照明线"))
{
item.Value.useNum = 0;
if (disZhaoMingXian >= item.Value.selectedEquipNum * item.Value.unit)
{
item.Value.useNum = item.Value.selectedEquipNum;
disZhaoMingXian -= item.Value.selectedEquipNum * item.Value.unit;
}
else
{
item.Value.useNum = (int)Math.Ceiling(disZhaoMingXian / item.Value.unit);//向上取整
disZhaoMingXian = 0.0f;
}
}
}
}
}
//收起管线
public void destoryLine()
{
for (int i = 0; i < AllLine.Count; i++)
{
if (GameObject.Find(AllLine[i]))
{
Destroy(GameObject.Find(AllLine[i]));
//NetworkManager.Instance.Send("ENTITY_DESTROY", AllLine[i]);
}
}
Allpath.Clear();
AllLine.Clear();
AllLineDistance.Clear();
nowpath = null;
setLineXiaoHao();
}
private void OnSpeedChangeEvent(SpeedChangeEventArgs e)
{
if (e.speed == 0)
return;
MultipleSpeed = e.speed;
}
}