using Assets.Scenes.Ride.Scripts.Model.CyclingModels; using Assets.Scripts.Apis.Models; using GeoJSON.Net.Geometry; using Mapbox.Unity.Map; using Mapbox.Utils; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TurfCS; using UnityEngine; namespace Assets.Scenes.Ride.Scripts { public abstract class AbstractPlayer: MonoBehaviour { [Header("Character")] [SerializeField] GameObject character; [SerializeField] Animator characterAnimator; [SerializeField] AbstractMap map; //AbstractMap map; #region 动画控制参数 Vector3 nextPos; Vector3 prePos = Vector3.zero; float timer = 1.0f;//计时器 #endregion #region 选手骑行数据 protected Vector2d nextlatlong; //下一个点的坐标 protected bool isStart;//开始或者暂停 protected bool isQuit;//true 中途退出 或者到达终点 protected bool isMajor;//是否是主人公 protected MapDataModel mapData; protected int userId; protected DateTime startTime;//开始骑行时间 protected DateTime endTime;//结束骑行时间 protected double weight;//体重 protected double bicycleWeight;//车重 protected double speed; protected double power; protected double elevation; protected double cadance; protected int heartRate; protected int ticks; protected double totalDistance; protected double currentSlope; protected double nextSlope; protected double nextSlopeDistance; protected double distance; protected double currentSlopeDistance; protected double lastEndDistance; public int UserId { get => userId; } public bool IsStart { get => isStart; } public double Speed { get => speed; } public double Power { get => power; } public double Cadance { get => cadance; } public double HeartRate { get => heartRate; } public int TotalTicks { get => ticks; } public double TotalDistance { get => totalDistance; } public double CurrentSlope { get => currentSlope; } public double NextSlope { get => nextSlope; } public double NextSlopeDistance { get => nextSlopeDistance; } public double CurrentSlopeDistance { get => currentSlopeDistance; } public double Elevation { get => elevation; } public double LastEndDistance { get => lastEndDistance; } public Vector2d Nextlatlong { get => nextlatlong; } #endregion #region 游戏状态控制 //开始骑行 public void SetStart() { isStart = true; startTime = DateTime.Now; } //继续骑行 public void SetContinue() { isStart = true; } //暂停骑行 public void SetPause() { isStart = false; characterAnimator.SetBool("IsRide", false); } //退出或者完成骑行 public void SetQuit() { isQuit = true; endTime.AddSeconds(ticks);//计算结束时间 } #endregion void Start() { Init(); } void Update() { Excute(); } private void FixedUpdate() { } #region 骑行逻辑 //初始化骑行数据 protected CyclingController mainController; protected BaseCycling cyclingExcutor; protected virtual void Init() { characterAnimator = GetComponentInChildren(); mainController = transform.parent.GetComponent(); //map = FindObjectOfType(); mapData = mainController.GetMapData();//获取路书信息 nextlatlong = new Vector2d(mapData.List[0].Point[0], mapData.List[0].Point[1]);//初始化人物位置 TODO加上之前骑行距离 cyclingExcutor = mainController.cyclingController; } protected virtual void Excute() { //CamControl(); timer -= Time.deltaTime; if (timer <= 0)//定时器 一秒执行一次 { Run(); timer = 1.0f; } } //骑行中 protected virtual void Run() { ComputeNextSlope();//计算下一个坡度相关数据 if (isStart) { ticks++; Compute();//接受蓝牙设备数据计算 characterAnimator.SetBool("IsRide", false);//初始化动画状态 if (totalDistance <= mapData.TotalDistance) { //数据处理 nextlatlong = Along(totalDistance);//下一个坐标 nextPos = map.GeoToWorldPosition(nextlatlong);//下一个点 nextPos.y += 0.5f;//提高y轴让人物站在地图上面 prePos = transform.localPosition;//当前点 thisRotation = transform.localRotation; //动画控制 if (distance > 0) { characterAnimator.SetBool("IsRide", true);//开始移动动画 StartCoroutine(MoveTo());//移动 //transform.localPosition = nextPos; } } else { totalDistance = mapData.TotalDistance; characterAnimator.SetBool("ReachEnd", true);//到达终点 //Task.Run(() => { });//异步上传数据 Upload(); isStart = false; isQuit = true; } } } //计算功率 速度 当前骑行总里程(M)心率 踏频 等 protected virtual void Compute() { //power = 900;//功率 //speed = Helper.CalculateSpeed(elevation, 0, power, 65, 7); //distance = Math.Round(speed / 3600, 6); //totalDistance += distance; } //当前用户调用来上传骑行记录 protected virtual void Upload() { } #endregion #region 工具类 protected string CaptureCamera(Camera camera, Rect rect) { // 创建一个RenderTexture对象 RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0); // 临时设置相关相机的targetTexture为rt, 并手动渲染相关相机 camera.targetTexture = rt; camera.Render(); //ps: --- 如果这样加上第二个相机,可以实现只截图某几个指定的相机一起看到的图像。 //ps: camera2.targetTexture = rt; //ps: camera2.Render(); //ps: ------------------------------------------------------------------- // 激活这个rt, 并从中中读取像素。 RenderTexture.active = rt; Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false); screenShot.ReadPixels(rect, 0, 0);// 注:这个时候,它是从RenderTexture.active中读取像素 screenShot.Apply(); // 重置相关参数,以使用camera继续在屏幕上显示 camera.targetTexture = null; //ps: camera2.targetTexture = null; RenderTexture.active = null; // JC: added to avoid errors GameObject.Destroy(rt); // 最后将这些纹理数据,成一个图片文件 byte[] bytes = screenShot.EncodeToJPG(); string filename = Application.dataPath + "/"+Guid.NewGuid().ToString() +".jpg"; System.IO.File.WriteAllBytes(filename, bytes); //Debug.Log(string.Format("截屏了一张照片: {0}", filename)); return filename; } public int CurrentIndex; //当前距离所在的海拔/坡度/距离 下一个点的坡度以及剩余距离 void ComputeNextSlope() { double sumDistance = 0; var pointList = mapData.List; int index = 0; for (int i = 0; i < pointList.Count; i++) { sumDistance += pointList[i].Distance; if (totalDistance * 1000 <= sumDistance) { index = i; break; } } //计算当前海拔和坡度 elevation = pointList[index].Elevation; currentSlope = pointList[index].Grade; //计算下一个点的坡度和距离 int nextIndex = index == pointList.Count - 1 ? index : index + 1; CurrentIndex = nextIndex; nextSlope = pointList[nextIndex].Grade; nextSlopeDistance = sumDistance - totalDistance * 1000; currentSlopeDistance = totalDistance * 1000 - (sumDistance - pointList[index].Distance); } //根据距离计算坐标 Vector2d Along(double endDistance) { if (mapData != null) { var list = mapData.List.Select(p => new GeoJSON.Net.Geometry.GeographicPosition(p.Point[0], p.Point[1])); LineString lineString = new LineString(list); var pt1 = Turf.Along(lineString, endDistance); var ll = ((GeographicPosition)((GeoJSON.Net.Geometry.Point)pt1.Geometry).Coordinates); return new Vector2d(ll.Latitude, ll.Longitude); } return nextlatlong; } #endregion #region 人物移动与转向控制 Quaternion thisRotation; IEnumerator LookAtNextPos() { Quaternion neededRotation = Quaternion.LookRotation(prePos - nextPos); //Quaternion thisRotation = character.transform.localRotation; float t = 0; while (t < 1.0f) { t += Time.deltaTime / 0.5f; var rotationValue = Quaternion.Slerp(thisRotation, neededRotation, t); character.transform.rotation = Quaternion.Euler(0, rotationValue.eulerAngles.y, 0); yield return null; } } Vector3 deltaPos = Vector3.zero; Vector3 previousPos = Vector3.zero; void CamControl() { deltaPos = transform.position - previousPos; deltaPos.y = 0; Camera.main.transform.position = Vector3.Lerp(Camera.main.transform.position, Camera.main.transform.position + deltaPos, Time.time); previousPos = transform.position; } //人物移动控制 IEnumerator MoveTo() { StartCoroutine(LookAtNextPos());//转向 //让人物移动分点增加动画的流畅度 float t = 0; while (t < 1) { t += Time.deltaTime; Vector3 v = Vector3.Lerp(prePos, nextPos, t); Vector3 nextPosition = new Vector3((float)Math.Round(v.x, 2), (float)Math.Round(v.y, 2), (float)Math.Round(v.z, 2)); if (!nextPosition.Equals(transform.localPosition)) { transform.localPosition = nextPosition; //Camera.main.transform.localPosition = nextPosition; } //控制海拔图的位置 yield return null; } } #endregion } }