256 lines
6.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
AbstractMap map;
#region
Vector3 nextPos;
Vector3 prePos;
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; }
#endregion
#region
//开始骑行
public void SetStart()
{
isStart = true;
startTime = DateTime.Now;
}
//继续骑行
public void SetContinue()
{
isStart = true;
}
//暂停骑行
public void SetPause()
{
isStart = false;
}
//退出或者完成骑行
public void SetQuit()
{
isQuit = true;
endTime.AddSeconds(ticks);//计算结束时间
}
#endregion
void Start()
{
Init();
}
void Update()
{
Excute();
}
#region
//初始化骑行数据
protected virtual void Init()
{
characterAnimator = GetComponentInChildren<Animator>();
var mainController = transform.parent.GetComponent<CyclingController>();
map = FindObjectOfType<AbstractMap>();
mapData = mainController.GetMapData();//获取路书信息
nextlatlong = new Vector2d(mapData.List[0].Point[0], mapData.List[0].Point[1]);//初始化人物位置 TODO加上之前骑行距离
}
protected virtual void Excute()
{
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.3f;//提高y轴让人物站在地图上面
prePos = transform.localPosition;//当前点
//动画控制
if (distance > 0)
{
characterAnimator.SetBool("IsRide", true);//开始移动动画
StartCoroutine(LookAtNextPos());//转向
StartCoroutine(MoveTo());//移动
}
}
else
{
totalDistance = mapData.TotalDistance;
characterAnimator.SetBool("ReachEnd", true);//到达终点
Task.Run(() => { Upload(); });//异步上传数据
isStart = false;
isQuit = true;
}
}
else
{
characterAnimator.SetBool("IsRide", false);
}
}
//计算功率 速度 当前骑行总里程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
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
IEnumerator LookAtNextPos()
{
Quaternion neededRotation = Quaternion.LookRotation(transform.localPosition - nextPos);
Quaternion thisRotation = character.transform.localRotation;
float t = 0;
while (t < 1.0f)
{
t += Time.deltaTime / 0.25f;
var rotationValue = Quaternion.Slerp(thisRotation, neededRotation, t);
character.transform.rotation = Quaternion.Euler(0, rotationValue.eulerAngles.y, 0);
yield return null;
}
}
//人物移动控制
IEnumerator MoveTo()
{
//让人物移动分点增加动画的流畅度
float t = 0;
while (t < 1)
{
t += Time.deltaTime;
Vector3 v = Vector3.Lerp(prePos, nextPos, t);
transform.localPosition = v;
//控制海拔图的位置
yield return null;
}
}
#endregion
}
}