524 lines
19 KiB
C#
524 lines
19 KiB
C#
using Assets.Scenes.Ride.Scripts;
|
||
using Assets.Scenes.Ride.Scripts.Model;
|
||
using Assets.Scenes.Ride.Scripts.Model.CyclingModels;
|
||
using Assets.Scripts.Apis.Models;
|
||
using Assets.Scripts.UI.Prefab.Device;
|
||
using GeoJSON.Net.Geometry;
|
||
using Mapbox.Utils;
|
||
using RenderHeads.Media.AVProVideo;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using TurfCS;
|
||
using UnityEngine;
|
||
using Assets.Scenes.Ride.Scripts.Model.RiderModels;
|
||
using UnityEngine.EventSystems;
|
||
using UnityEngine.Events;
|
||
using Helper = Assets.Scenes.Ride.Scripts.Helper;
|
||
using System.Collections;
|
||
using Assets.AR;
|
||
using Assets.Core;
|
||
|
||
namespace Assets.Scripts.Scenes.VideoRide
|
||
{
|
||
public class VideoGameManager : DeviceServiceMonoBase
|
||
{
|
||
public ARTrainingController trainingController;
|
||
public AbstractVideoPlayer CurrentPlayer { get; set; }
|
||
private MapDataModel mapData { get; set; }
|
||
private MediaPlayer mediaPlayer { get; set; }
|
||
private bool isStart { get; set; }
|
||
private Route route { get; set; }
|
||
public MapRoute mapRoute { get; set; }
|
||
public RouteResultParam selectParamModel { get; set; }
|
||
public RouteResult routeResult;
|
||
public string recordId { get; set; }
|
||
public DateTime startTime { get; set; }
|
||
public CyclingModel cyclingModel { get; set; }
|
||
public BaseCycling cyclingController { get; set; }
|
||
private double endDistance { get; set; }
|
||
private GameObject infoPanel;
|
||
private GameObject Player;
|
||
private GameObject Player_NV;
|
||
private GameObject OnlinePlayer;
|
||
private GameObject OnlinePlayer_NV;
|
||
|
||
private bool isStop { get; set; }
|
||
VideoLoading videoLoading { get; set; }
|
||
//当前是第一人称还是第三人称
|
||
public ViewMode _viewMode { get; set; }
|
||
//当前是观察者视角还是骑行者视角
|
||
public ARMode _aRMode { get; set; }
|
||
public int RankingId { get; set; }
|
||
public Dictionary<IRider, PlayerRenderer> rideObjs = new Dictionary<IRider, PlayerRenderer>();
|
||
private VideoUIManager _uiManager { get; set; }
|
||
private ARTrainingController _trainingController { get; set; }
|
||
public List<AbstractVideoPlayer> visibleRiders = new List<AbstractVideoPlayer>();//当前线路上的人
|
||
private const int limits = 5;//在线的其他人数
|
||
private double MaxVisibleDistance = 200d;//最大显示距离
|
||
float timer = 0f;
|
||
int ticks = 0;
|
||
MapRouteRankingList rankingList;
|
||
public GameObject videoPlayer;
|
||
public GameObject target;
|
||
public int CurrentUserId { get; set; }
|
||
|
||
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
_uiManager = FindObjectOfType<VideoUIManager>();
|
||
trainingController = GetComponent<ARTrainingController>();
|
||
mediaPlayer = FindObjectOfType<MediaPlayer>();
|
||
DeviceCache.Init(PFConstants.DeviceCacheFolder);
|
||
var check = CheckAnt();//初始化蓝牙设备
|
||
|
||
recordId = Guid.NewGuid().ToString();
|
||
|
||
infoPanel = Resources.Load<GameObject>("UI/Prefab/AR/VideoPlayerHead");
|
||
OnlinePlayer = Resources.Load<GameObject>("UI/Prefab/AR/OnlineVideoPlayer");
|
||
OnlinePlayer_NV = Resources.Load<GameObject>("UI/Prefab/AR/OnlineVideoPlayer_NV");
|
||
Player = Resources.Load<GameObject>("UI/Prefab/AR/VidePlayer");
|
||
Player_NV = Resources.Load<GameObject>("UI/Prefab/AR/VidePlayer_NV");
|
||
|
||
_trainingController = GetComponent<ARTrainingController>();
|
||
StartCoroutine(Init());
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
UIManager.Instance.MainPanel = GetCanvasTransform().GetComponent<PFUIPanel>();
|
||
UIManager.Instance.ModalsPanel = this.transform.Find("Canvas/ModalPanel").GetComponent<PFUIPanel>();
|
||
var routeId = App.RouteIdParam;
|
||
//获取路书
|
||
GetMapRoute();
|
||
GetMapData();
|
||
route = new Route(mapData, mapRoute);
|
||
|
||
if (selectParamModel == null)
|
||
{
|
||
selectParamModel = new RouteResultParam
|
||
{
|
||
CompetitionId = 0,
|
||
ContinueIndex = 0,
|
||
ContinueMark = "",
|
||
GlobalContinue = false,
|
||
EndDistance = 0,
|
||
RankingsId = new List<string>(),
|
||
OnlineUserId = 0,
|
||
RouteId = routeId
|
||
};
|
||
}
|
||
Debug.Log("start");
|
||
endDistance = 0;
|
||
videoLoading = FindObjectOfType<VideoLoading>();
|
||
}
|
||
|
||
private IEnumerator Init()
|
||
{
|
||
yield return null;
|
||
videoLoading.Init();//初始化loading页面
|
||
}
|
||
|
||
protected override void Update()
|
||
{
|
||
timer -= Time.deltaTime;
|
||
while (timer <= 0)
|
||
{
|
||
if (cyclingController == null)
|
||
return;
|
||
|
||
try
|
||
{
|
||
cyclingController.Run(null);//发送数据到tcp
|
||
|
||
var onlineRiders = cyclingController.riders;
|
||
CreateOnlineUser(onlineRiders); //解析tcp返回数据
|
||
|
||
if (isStart)
|
||
{
|
||
ComputePlayerRuntimeData();
|
||
ticks++;
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.Log(e.Message);
|
||
}
|
||
timer += 1f;
|
||
}
|
||
}
|
||
|
||
//计算骑手的数据
|
||
private void ComputePlayerRuntimeData()
|
||
{
|
||
var riders = FindObjectsOfType<OnlineVideoPlayer>();
|
||
foreach (var rider in riders)
|
||
{
|
||
rider.StartAction();
|
||
}
|
||
//解决当前用户setActive(false)时仍能计算数据
|
||
if (CurrentPlayer != null && CurrentPlayer is VideoPlayer)
|
||
{
|
||
CurrentPlayer.StartAction();
|
||
}
|
||
}
|
||
|
||
public MapRouteRankingList GetRankingList(string type = "month")
|
||
{
|
||
var endTime = UIManager.Now == null ? DateTime.Now : UIManager.Now.GetDateTime();
|
||
var startTime = Helper.GetStartTime(endTime, type);
|
||
var list = ConfigHelper.mapApi.GetRouteRanking(App.RouteIdParam, "1", 0, 10, "", startTime, endTime);
|
||
if (list.result)
|
||
{
|
||
rankingList = list.data;
|
||
}
|
||
return rankingList;
|
||
}
|
||
|
||
//创建当前线路其他选手
|
||
private void CreateOnlineUser(List<BaseRider> list)
|
||
{
|
||
list = list.Where(c => ((OnlineRiderModel)c).IsWatcher == false).OrderByDescending(c => c.IsSelf).ToList();
|
||
//断网移除所有用户
|
||
if (list.Count == 0)
|
||
{
|
||
ClearRiders();
|
||
return;
|
||
}
|
||
|
||
//删除离开的用户
|
||
RemovePlayers(list);
|
||
//如果当前为观察者模式且currentPlayerInfo为null随机选择以为用户观察
|
||
var current = DefaultCurrentPlayer(list);
|
||
//更新和新增用户
|
||
UpdateRiders(list, current);
|
||
}
|
||
|
||
//断网清空当前线路所有用户
|
||
private void ClearRiders()
|
||
{
|
||
foreach (var item in visibleRiders)
|
||
{
|
||
DestroyImmediate(item.gameObject);
|
||
}
|
||
rideObjs.Clear();
|
||
visibleRiders.Clear();
|
||
CurrentPlayer = null;
|
||
}
|
||
|
||
//默认当前用户1.当前骑行模式下是当前用户 2.观察者模式下随机第一个用户
|
||
private BaseRider DefaultCurrentPlayer(List<BaseRider> list)
|
||
{
|
||
var current = CurrentUserId == 0 ? list.FirstOrDefault() : list.FirstOrDefault(c => c.UserId == CurrentUserId);
|
||
|
||
if(CurrentUserId == 0 && current != null)
|
||
CurrentUserId = current.UserId;
|
||
|
||
return current;
|
||
}
|
||
|
||
private void UpdateRiders(List<BaseRider> list,BaseRider current)
|
||
{
|
||
//更新和新增用户
|
||
foreach (var item in list)
|
||
{
|
||
var onlineRider = item as OnlineRiderModel;
|
||
var visibleItem = visibleRiders.FirstOrDefault(c => c.UserId == item.UserId);
|
||
if (visibleItem != null)
|
||
{
|
||
visibleItem.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, current.EndDistance, onlineRider.FrameRate.Value);
|
||
if (visibleItem.userId == CurrentUserId)
|
||
{
|
||
CurrentPlayer = visibleItem;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var distance = item.EndDistance % mapData.TotalDistance - current.EndDistance % mapData.TotalDistance;
|
||
if (!(Math.Abs(distance * 1000) <= MaxVisibleDistance)) continue;
|
||
|
||
if (item.IsSelf)
|
||
{
|
||
CreateVideoPlayer(onlineRider,item,current);
|
||
}
|
||
else
|
||
{
|
||
CreateOnlinePlayer(onlineRider,item,visibleItem,current);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateOnlinePlayer(OnlineRiderModel onlineRider,BaseRider item,AbstractVideoPlayer visibleItem,BaseRider current)
|
||
{
|
||
var obj = CreatePlayerGameObject(false, onlineRider.Sex == 1);
|
||
|
||
var online = obj.GetComponentInChildren<OnlineVideoPlayer>();
|
||
var rideObj = obj.GetComponentInChildren<PlayerRenderer>();
|
||
online.SetStartDistance(item.EndDistance);
|
||
|
||
rideObj.Distance = (float)online.StartDistance;
|
||
rideObj.RouteDistance = rideObj.Distance;
|
||
rideObj.UserId = item.UserId;
|
||
|
||
rideObjs.Add(online, rideObj);
|
||
visibleRiders.Add(online);
|
||
|
||
_trainingController.AddRider(onlineRider);
|
||
online.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, current.EndDistance, onlineRider.FrameRate.Value);
|
||
|
||
if (online.userId == CurrentUserId)
|
||
{
|
||
CurrentPlayer = visibleItem;
|
||
}
|
||
}
|
||
|
||
private void CreateVideoPlayer(OnlineRiderModel onlineRider,BaseRider item,BaseRider current)
|
||
{
|
||
videoPlayer = CreatePlayerGameObject(true, App.CurrentUser.Sex == 1);
|
||
CurrentUserId = App.CurrentUser.Id;
|
||
CurrentPlayer = videoPlayer.GetComponent<AbstractVideoPlayer>();
|
||
|
||
var vp = videoPlayer.GetComponent<VideoPlayer>();
|
||
vp.SetEndDistance(item.EndDistance);
|
||
CurrentPlayer.SetStartDistance(item.EndDistance);
|
||
|
||
var rideObj = videoPlayer.GetComponent<PlayerRenderer>();
|
||
rideObj.Distance = (float)CurrentPlayer.StartDistance;
|
||
rideObj.RouteDistance = rideObj.Distance;
|
||
rideObj.IsMain = true;
|
||
rideObj.UserId = item.UserId;
|
||
rideObjs.Add(CurrentPlayer, rideObj);
|
||
visibleRiders.Add(CurrentPlayer);
|
||
CurrentPlayer.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, current.EndDistance, onlineRider.FrameRate.Value);
|
||
}
|
||
|
||
private GameObject CreatePlayerGameObject(bool self,bool isMale)
|
||
{
|
||
return self ? Instantiate(isMale ? Player : Player_NV, transform) : Instantiate(isMale ? OnlinePlayer : OnlinePlayer_NV, transform);
|
||
}
|
||
|
||
//移除退出的选手
|
||
private void RemovePlayers(List<BaseRider> list)
|
||
{
|
||
|
||
var players = FindObjectsOfType<OnlineVideoPlayer>();
|
||
foreach (var item in players)
|
||
{
|
||
var currentItem = list.FirstOrDefault(c => c.UserId == item.UserId);
|
||
if (currentItem != null) continue;
|
||
rideObjs.Remove(item);
|
||
visibleRiders.Remove(item);
|
||
}
|
||
}
|
||
|
||
//设置当前是骑行模式还是观察模式
|
||
public void SetCurrentMode(ARMode aRMode)
|
||
{
|
||
_aRMode = aRMode;
|
||
_uiManager.SetCurrentMode(aRMode);
|
||
if (_aRMode != ARMode.INSPECT)
|
||
{
|
||
CurrentUserId = App.CurrentUser.Id;
|
||
ContinueAsync();
|
||
}
|
||
else
|
||
{
|
||
SetCyclingModel(CyclingModel.Single);
|
||
}
|
||
}
|
||
//切换人物
|
||
public void ChangePlayer(int userId)
|
||
{
|
||
Debug.Log($"切换到{userId}");
|
||
CurrentUserId = userId;
|
||
}
|
||
//获取角色头顶信息预制件
|
||
public GameObject GetHeadInfo()
|
||
{
|
||
return infoPanel;
|
||
}
|
||
//继续骑行
|
||
public void ContinueAsync()
|
||
{
|
||
//骑行结果
|
||
if (App.routeResult != null)
|
||
{
|
||
routeResult = App.routeResult;
|
||
selectParamModel = App.routeResult.ContinueCyclingParam;
|
||
Debug.Log("selectParamModel"+ selectParamModel.ContinueMark);
|
||
SetCyclingModel(CyclingModel.Single);
|
||
endDistance = routeResult.EndDistance;
|
||
App.routeResult = null;
|
||
//mediaPlayer.Control.SeekToFrame(routeResult.LastFrame ?? 0);
|
||
}
|
||
}
|
||
//设置骑行模式
|
||
public void SetCyclingModel(CyclingModel mode)
|
||
{
|
||
this.cyclingModel = mode;
|
||
switch (cyclingModel)
|
||
{
|
||
case CyclingModel.Single:
|
||
cyclingController = new ARSingleModel(route, selectParamModel);
|
||
break;
|
||
case CyclingModel.GameRoom:
|
||
cyclingController = new GameModel(route, selectParamModel);
|
||
break;
|
||
}
|
||
}
|
||
//开始游戏
|
||
public void StartGame()
|
||
{
|
||
//if (startTime != DateTime.MinValue)
|
||
{
|
||
startTime = UIManager.Now.GetDateTime();
|
||
}
|
||
isStart = true;
|
||
}
|
||
//骑行是否开始
|
||
public bool IsStart()
|
||
{
|
||
return isStart;
|
||
}
|
||
//获取UI
|
||
public Transform GetCanvasTransform()
|
||
{
|
||
return transform.Find("Canvas/Panel");
|
||
}
|
||
//设置视频源文件
|
||
public void SetMedia(string path)
|
||
{
|
||
if (mediaPlayer != null)
|
||
{
|
||
mediaPlayer.OpenMedia(new MediaPath(path,MediaPathType.AbsolutePathOrURL),false);
|
||
}
|
||
}
|
||
//是否停止
|
||
public bool IsQuit()
|
||
{
|
||
return isStop;
|
||
}
|
||
|
||
//暂停
|
||
public void Pause()
|
||
{
|
||
isStart = !isStart;
|
||
isStop = !isStop;
|
||
}
|
||
//退出骑行
|
||
public void Quit()
|
||
{
|
||
mediaPlayer?.Pause();//暂停视频
|
||
isStart = false;
|
||
isStop = true;
|
||
mediaPlayer?.Stop();
|
||
}
|
||
//获取当前视频帧数
|
||
public int GetCurrentFrame()
|
||
{
|
||
return mediaPlayer.Control.GetCurrentTimeFrames();
|
||
}
|
||
|
||
//获取AR骑行配置信息
|
||
//获取路书gps信息
|
||
public MapDataModel GetMapData()
|
||
{
|
||
if (mapData == null)
|
||
{
|
||
var mapApi = ConfigHelper.mapApi;
|
||
int routeId = App.RouteIdParam;
|
||
if(routeId > 0)
|
||
mapData = mapApi.GetData(routeId,0);//获取路书地理数据
|
||
}
|
||
return mapData;
|
||
}
|
||
//获取路书信息
|
||
public MapRoute GetMapRoute()
|
||
{
|
||
if (mapRoute == null)
|
||
{
|
||
var mapApi = ConfigHelper.mapApi;
|
||
int routeId = App.RouteIdParam;
|
||
mapRoute = mapApi.GetById(routeId).data;
|
||
}
|
||
return mapRoute;
|
||
}
|
||
|
||
|
||
public void ShowUpRemainTime(double remain)
|
||
{
|
||
_uiManager.ShowUpRemainTime(remain);
|
||
}
|
||
|
||
//保存骑行记录
|
||
public void SaveData(double totalDistance)
|
||
{
|
||
if (cyclingController.recorderData == null || cyclingController.recorderData.Saved)
|
||
return;
|
||
|
||
Quit();
|
||
|
||
cyclingController.recorderData.EndTime = UIManager.Now.GetDateTime();
|
||
var path = PFConstants.MapWorkoutRecordFolder + "/" + recordId;
|
||
Helper.CreateDirectoryIfNotExsit(path);
|
||
var imageFileName = path + "/" + Guid.NewGuid().ToString() + ".png";
|
||
Helper.CaptureCamera(Camera.main, new Rect(Screen.width * 0f, Screen.height * 0f, Screen.width * 0.5f, Screen.height * 0.5f), imageFileName);
|
||
|
||
cyclingController.recorderData.StartTime = startTime;
|
||
cyclingController.recorderData.IsCompleted = totalDistance >= mapData.TotalDistance;
|
||
cyclingController.recorderData.EndDistance = cyclingController.recorderData.IsCompleted ? mapData.TotalDistance : totalDistance;
|
||
cyclingController.recorderData.AntModelId = AntModelId;
|
||
cyclingController.recorderData.ManufacturerId = ManufacturerId;
|
||
cyclingController.recorderData.ManufacturerName = ManufacturerName;
|
||
cyclingController.recorderData.DeviceNumber = DeviceNumber;
|
||
cyclingController.recorderData.LastFrame = GetCurrentFrame();
|
||
|
||
RankingId = cyclingController.recorderData.SaveWithLocalRecordAysnc(cyclingModel, selectParamModel, imageFileName, recordId, path);
|
||
}
|
||
public void AddEvent(GameObject sender, EventTriggerType eventType, UnityAction<BaseEventData> unityAction)
|
||
{
|
||
UIManager.AddEvent(sender, eventType, unityAction);
|
||
}
|
||
public Texture GetCountryImageByCode(string code)
|
||
{
|
||
return UIManager.Instance.loginRegOptions.GetCountryImage(code);
|
||
}
|
||
public Texture GetCountryImageByName(string name)
|
||
{
|
||
return UIManager.Instance.loginRegOptions.GetCountryImageByName(name);
|
||
}
|
||
public 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);
|
||
}
|
||
else
|
||
{
|
||
return new Vector2d(0, 0);
|
||
}
|
||
}
|
||
private void OnDestroy()
|
||
{
|
||
App.gameRoomDetail = null;
|
||
}
|
||
|
||
public enum ARMode
|
||
{
|
||
RIDE,
|
||
INSPECT
|
||
}
|
||
|
||
public enum ViewMode
|
||
{
|
||
THIRD,
|
||
FIRST,
|
||
}
|
||
}
|
||
} |