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; } GameObject infoPanel; GameObject Player; GameObject Player_NV; GameObject OnlinePlayer; GameObject OnlinePlayer_NV; private bool isStop { get; set; } public enum ARMode { RIDE, INSPECT } public enum ViewMode { THIRD, FIRST, } VideoLoading videoLoading { get; set; } //当前是第一人称还是第三人称 public ViewMode _viewMode { get; set; } //当前是观察者视角还是骑行者视角 public ARMode _aRMode { get; set; } public int RankingId { get; set; } public Dictionary rideObjs = new Dictionary(); protected override void Awake() { base.Awake(); trainingController = GetComponent(); mediaPlayer = FindObjectOfType(); DeviceCache.Init(PFConstants.DeviceCacheFolder); var check = CheckAnt();//初始化蓝牙设备 recordId = Guid.NewGuid().ToString(); infoPanel = Resources.Load("UI/Prefab/AR/VideoPlayerHead"); OnlinePlayer = Resources.Load("UI/Prefab/AR/OnlineVideoPlayer"); OnlinePlayer_NV = Resources.Load("UI/Prefab/AR/OnlineVideoPlayer_NV"); Player = Resources.Load("UI/Prefab/AR/VidePlayer"); Player_NV = Resources.Load("UI/Prefab/AR/VidePlayer_NV"); StartCoroutine(Init()); } void Start() { UIManager.Instance.MainPanel = GetCanvasTransform().GetComponent(); UIManager.Instance.ModalsPanel = this.transform.Find("Canvas/ModalPanel").GetComponent(); 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(), OnlineUserId = 0, RouteId = routeId }; } Debug.Log("start"); endDistance = 0; videoLoading = FindObjectOfType(); } private IEnumerator Init() { yield return null; videoLoading.Init();//初始化loading页面 } float timer = 0f; protected override void Update() { timer -= Time.deltaTime; while (timer <= 0) { if (cyclingController == null) return; cyclingController.Run(null); var onlineRiders = cyclingController.riders; try { CreateOnlineUser(onlineRiders); } catch (Exception e) { Debug.Log(e.Message); } timer += 1f; } } MapRouteRankingList rankingList; 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; } public List visibleRiders = new List();//当前线路上的人 private const int limits = 5;//在线的其他人数 private double MaxVisibleDistance = 200d;//最大显示距离 //创建当前线路其他选手 private void CreateOnlineUser(List list) { if (list == null || list.Count == 0) { var currentList = FindObjectsOfType(); foreach (var item in currentList) { item.Speed = 0; item.Paused = true; } return; } var trainController = GetComponent(); //移除退出的选手 var players = FindObjectsOfType(); foreach (var item in players) { var currentItem = list.Where(c => c.UserId == item.UserId).FirstOrDefault(); if (currentItem == null) { rideObjs.Remove(item); visibleRiders.Remove(item); //trainController.RemoveRider(item.UserId); } } var currentPlayerInfo = list.Where(c => c.IsSelf).FirstOrDefault(); var needUpdateList = list.OrderByDescending(c=>c.IsSelf).ToList(); foreach (var item in needUpdateList) { var onlineRider = item as OnlineRiderModel; var visibleItem = visibleRiders.Where(c => c.UserId == item.UserId).FirstOrDefault(); //更新 if (visibleItem != null) { visibleItem.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value); } else { if (currentPlayerInfo == null) return; var diff = item.EndDistance % mapData.TotalDistance - currentPlayerInfo.EndDistance % mapData.TotalDistance; if (Math.Abs(diff * 1000) <= MaxVisibleDistance) { GameObject obj = null; if (!item.IsSelf) { if (onlineRider.Sex == 1) { obj = Instantiate(OnlinePlayer, transform); } else { obj = Instantiate(OnlinePlayer_NV, transform); } var online = obj.GetComponentInChildren(); var rideObj = obj.GetComponentInChildren(); online.SetStartDistance(item.EndDistance); rideObj.Distance = (float)online.StartDistance; rideObj.RouteDistance = rideObj.Distance; rideObjs.Add(online, rideObj); visibleRiders.Add(online); trainController.AddRider(onlineRider); online.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value); } else { if (App.CurrentUser.Sex == 1) { var playerprefab = Resources.Load("UI/Prefab/AR/VidePlayer"); videoPlayer = Instantiate(playerprefab, transform); } else { var playerprefabNV = Resources.Load("UI/Prefab/AR/VidePlayer_NV"); videoPlayer = Instantiate(playerprefabNV, transform); } CurrentPlayer = videoPlayer.GetComponent(); var vp = videoPlayer.GetComponent(); vp.SetEndDistance(item.EndDistance); CurrentPlayer.SetStartDistance(item.EndDistance); var rideObj = videoPlayer.GetComponent(); rideObj.Distance = (float)CurrentPlayer.StartDistance; rideObj.RouteDistance = rideObj.Distance; rideObj.IsMain = true; 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, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value); } } } } } //设置当前是骑行模式还是观察模式 public void SetCurrentMode(ARMode aRMode) { _aRMode = aRMode; var uimanager = FindObjectOfType(); uimanager.SetCurrentMode(aRMode); if (_aRMode != ARMode.INSPECT) { //InitCurrentPlayer(); Debug.Log("ContinueAsync"); ContinueAsync(); } else { SetCyclingModel(CyclingModel.Single); } } public GameObject videoPlayer; public GameObject target; //切换人物 TODO:替换写法 public void ChangePlayer(int userId) { var players = FindObjectsOfType(); if (players != null) { CurrentPlayer = players.Where(c => c.UserId == userId).FirstOrDefault(); if (CurrentPlayer == null) { var onlineRiders = cyclingController.riders; var currentPlayer = onlineRiders.Where(c => c.UserId == userId).FirstOrDefault(); if (currentPlayer != null) { var onlineRider = currentPlayer as OnlineRiderModel; var obj = Instantiate(OnlinePlayer, transform); var online = obj.GetComponent(); online.SetPlayer(onlineRider.NickName, onlineRider.Speed,onlineRider.PreDistance, onlineRider.EndDistance, onlineRider.Cadence, onlineRider.HeartRate, 0, onlineRider.UserId, onlineRider.Power, onlineRider.EndDistance, onlineRider.FrameRate.Value); CurrentPlayer = online; } var clearList = players.Where(c => c.UserId != userId); foreach (var item in clearList) { item.Destroy(); } } } } //获取角色头顶信息预制件 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; //mediaPlayer.Control.SeekToFrame(routeResult.LastFrame ?? 0); } } //设置骑行模式 public void SetCyclingModel(CyclingModel mode) { //startTime = UIManager.Now.GetDateTime(); 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 IsReady() { return 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(); } public float ratio = 111.676f; public float startOffset = 0f; //获取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 Save(double totalDistance) { Quit(); cyclingController.recorderData.EndTime = UIManager.Now.GetDateTime(); var path = PFConstants.MapWorkoutRecordFolder + "/" + recordId; Assets.Scenes.Ride.Scripts.Helper.CreateDirectoryIfNotExsit(path); string imageFileName = path + "/" + Guid.NewGuid().ToString() + ".png"; 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 = 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 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); } //截图 protected void CaptureCamera(Camera camera, Rect rect, string fileName) { byte[] bytes = CaptureCameraReturnByte(camera, rect); System.IO.File.WriteAllBytes(fileName, bytes); } private byte[] CaptureCameraReturnByte(Camera camera, Rect rect) { RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0); camera.targetTexture = rt; camera.Render(); RenderTexture.active = rt; Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false); screenShot.ReadPixels(rect, 0, 0); screenShot.Apply(); camera.targetTexture = null; RenderTexture.active = null; GameObject.Destroy(rt); return screenShot.EncodeToJPG(); } //根据距离计算下一个点坐标 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; } } }