using Assets.Scenes.Ride.Scripts; using Assets.Scripts.Apis.Models; using DG.Tweening; using Mapbox.Utils; using System; using System.Collections; using System.Linq; using UnityEngine; using UnityEngine.UI; namespace Assets.Scripts.Scenes.VideoRide { public abstract class AbstractVideoPlayer : MonoBehaviour { protected Animator animator; public GameObject head { get; set; } protected Image ftpImage { get; set; } protected Text headName { get; set; } protected Text headWkg { get; set; } public int UserId; public string UserName; public double weight;//体重 protected double bicycleWeight;//车重 protected double preSpeed; public double speed; public double power; protected double elevation; public double cadance; public double wkg; public int? heartRate { get; set; } public int ticks; public double totalDistance; public double currentSlope; protected double nextSlope; protected double nextSlopeDistance; public double distance; protected double currentSlopeDistance; protected double lastEndDistance; public double totalClimb; public Vector2d currentlatLon { get; set; } public int currentIndex; public float bearing = 0f; protected MapDataModel mapData; protected bool isHit = false; protected RaycastHit hit; float timer = 1f; protected bool start = true; protected Sequence sequence; protected VideoGameManager manager { get; set; } Camera camera; float currenPlayerHeight; Transform bone_bottle_2 { get; set; } protected virtual void Start() { animator = GetComponent(); manager = FindObjectOfType(); mapData = manager.GetMapData(); ComputeNextSlope();//初始化坡度等 if (speed > 0) { animator.Play("rideLoop"); } else { animator.Play("idle"); } camera = Camera.main; //bone_bottle_2 bone_bottle_2 = transform.Find("bone_cable_20"); } protected virtual void Update() { timer -= Time.deltaTime; CreateHeadImage(); while (timer <= 0) { try { ComputeNextSlope();//计算下一个坡度 ComputePlayer();//计算人物属性 if (GetStart()) { ticks++; Forward(); ComputeRecord(); ComputeVideo(); RayCastHit(); Turn(); } ComputeAnimator();//控制动画 timer += 1f; } catch (Exception e) { power = 0; speed = 0; Debug.LogError(e.Message); } } } //人物碰撞 void OnCollisionEnter(Collision collision) { } void RayCastHit() { Vector3 pos = transform.position; Ray ray = new Ray(pos, new Vector3(0, 0, 1)); isHit = Physics.Raycast(ray, out hit, 1f, 1 << 0, QueryTriggerInteraction.Collide); } protected virtual bool GetStart() { return true; } //动画状态机 protected virtual void ComputeAnimator() { if (animator != null) { animator.SetFloat("preSpeed", (float)preSpeed); animator.SetFloat("speed", (float)speed); animator.SetFloat("grade", (float)currentSlope); animator.SetFloat("power", (float)power); animator.SetFloat("bearing", bearing); } } protected virtual int GetCurrentFrame() { return manager.GetCurrentFrame(); } private bool animated = false; private float offset = 0; //控制角色进行向左或向右 protected virtual void Turn() { var currentFrame = GetCurrentFrame(); var result = manager.mockDirection.Where(c => c.Start < currentFrame && c.End > currentFrame).FirstOrDefault(); if (result != null) { bearing = result.Value; } else { bearing = 0; } animator.SetFloat("bearing", bearing); var headBack = ticks % 60 == 0 && speed > 0 && bearing == 0; var drink = ticks % 125 == 0 && speed > 0 && bearing == 0; animator.SetBool("headBack", headBack); animator.SetBool("drinking", drink); var waiting = ratio == 0 ? 1 : 1 / ratio; if (Math.Abs(bearing) > 30) { if (!animated) { animated = true; var tween = transform.DORotate(new Vector3(0, bearing, -bearing/5), waiting); tween.onComplete += () => { var zoffset = bearing / 10.5f; var doMoveX = transform.DOMoveX(transform.position.x + zoffset, waiting); doMoveX.onComplete += () => { offset = -zoffset; }; }; tween.SetEase(Ease.InOutSine).SetLoops(2, LoopType.Incremental); } } else { if (offset != 0) { var cpoffset = offset; transform.DORotate(new Vector3(0, bearing, 0), 1.2f * waiting).onComplete += () => { transform.DOMoveX(transform.position.x + cpoffset, 1.2f * waiting).onComplete += () => { animated = false; }; }; offset = 0; } else { transform.DORotate(new Vector3(0, bearing, -bearing), waiting); } } } //计算人物当前属性 protected virtual void ComputePlayer() { if (power > 0) { preSpeed = speed; speed = Helper.CalculateSpeed(elevation, currentSlope, power, weight, bicycleWeight); } else { speed = 0; distance = 0; } //一旦有功率就开始骑行、否则暂停 if (!manager.IsQuit() && manager.CurrentPlayer.UserId == UserId && !manager.IsQuit() && manager.cyclingModel == Assets.Scenes.Ride.Scripts.Model.CyclingModel.Single) { if (power > 0) { manager.StartGame(); } } } protected virtual void Forward() { try { if (mapData == null) mapData = manager.GetMapData(); currentlatLon = manager.Along(totalDistance % mapData.TotalDistance); ////根据人物速度设置人物距离摄像头远近 //if (speed > 20 && speed < 30) //{ // transform.DOMoveZ(3, 1f); //} //else if (speed > 30 && speed < 40) //{ // transform.DOMoveZ(3.5f, 1f); //} //else if (speed > 40) //{ // transform.DOMoveZ(4, 1f); //} //else //{ // transform.DOMoveZ(3, 1f); //} } catch (Exception e) { Debug.LogError(e); } } protected float ratio = 1; protected virtual void ComputeVideo() { mapData = manager.GetMapData(); if (currentIndex + 1 < mapData.List.Count) { ratio = (float)(speed / mapData.List[currentIndex + 1].Speed); } else { ratio = (float)(speed / mapData.List[currentIndex].Speed); } if (manager.CurrentPlayer != null && manager.CurrentPlayer.UserId != UserId) return; if (ratio > 1) { ratio = Math.Min(ratio, 1.2f); } if (ratio < 1) { ratio = Math.Max(ratio, 0.6f); } var info = animator.GetCurrentAnimatorClipInfo(0); var currentClip = info.FirstOrDefault(); if (currentClip.clip != null && currentClip.clip.isLooping) { animator.speed = ratio; } manager.Play(ratio); } protected virtual void ComputeRecord() { } //计算当前区段属性下一个区段属性 void ComputeNextSlope() { double sumDistance = 0; mapData = manager.GetMapData(); if (mapData == null) return; var pointList = mapData.List; int preIndex = 0; for (int i = 0; i < pointList.Count; i++) { sumDistance += pointList[i].Distance; //decimal left = (decimal)totalDistance * 1000; decimal left = (decimal)totalDistance % (decimal)mapData.TotalDistance;//处理多圈的情况 left *= 1000; decimal right = (decimal)sumDistance; if (left <= right) { currentIndex = i; break; } } var DOUBLE_DELTA = 1E-6; if (Math.Abs(totalDistance - mapData.TotalDistance) < DOUBLE_DELTA) { currentIndex = pointList.Count - 1; } preIndex = currentIndex > 0 ? currentIndex - 1 : 0;//前一个索引 int nextIndex = currentIndex == pointList.Count - 1 ? currentIndex : currentIndex + 1; //计算下一个点的坡度和距离 elevation = pointList[currentIndex].Elevation; currentSlope = pointList[currentIndex].Grade; //CurrentDistance = pointList[currentIndex].Distance; //计算下一个海拔和坡度&当前区间距离 nextSlope = pointList[nextIndex].Grade; nextSlopeDistance = sumDistance - totalDistance * 1000; //NextSlopeTotalDistance = pointList[nextIndex].Distance; currentSlopeDistance = (totalDistance * 1000 - (sumDistance - pointList[currentIndex].Distance)); //计算累计爬升 totalClimb = 0; for (int i = 1; i <= currentIndex; i++) { var diff = mapData.List[i].Elevation - mapData.List[i - 1].Elevation; if (diff > 0) { totalClimb += diff; } } } public void CreateHeadImage() { if (head == null) { if (manager.GetHeadInfo() != null) { head = Instantiate(manager.GetHeadInfo(), manager.GetCanvasTransform()); ftpImage = head.transform.Find("ftp").GetComponent(); headName = head.transform.Find("name").GetComponent(); headWkg = head.transform.Find("wkg").GetComponent(); } } if (head != null) { //它们的乘积就是高度 Vector3 worldPosition = new Vector3(bone_bottle_2.position.x, bone_bottle_2.position.y+0.8f, bone_bottle_2.position.z); var playerScreenPos = Camera.main.WorldToScreenPoint(worldPosition); head.transform.position = playerScreenPos; ftpImage.fillAmount = (float)(wkg / 6); headName.text = UserName; headWkg.text = $"{wkg}W/KG"; } } public void Destroy() { if (manager.CurrentPlayer != null && manager.CurrentPlayer.UserId == UserId) { manager.Pause(); } head?.Destroy(); gameObject.Destroy(); } } }