572 lines
22 KiB
C#
572 lines
22 KiB
C#
using Assets.Scenes.Ride.Scripts;
|
|
using Assets.Scenes.Ride.Scripts.Model;
|
|
using Assets.Scenes.Ride.Scripts.Model.CyclingModels;
|
|
using Assets.Scripts.Apis;
|
|
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 System.Threading.Tasks;
|
|
using TurfCS;
|
|
using UnityEngine;
|
|
using DG.Tweening;
|
|
using Assets.Scenes.Ride.Scripts.Model.RiderModels;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.Events;
|
|
using Helper = Assets.Scenes.Ride.Scripts.Helper;
|
|
using System.Collections;
|
|
|
|
namespace Assets.Scripts.Scenes.VideoRide
|
|
{
|
|
public class CustomRange
|
|
{
|
|
public int Start { get; set; }//起始帧
|
|
public int End { get; set; }//结束帧
|
|
public int PositionX { get; set; }
|
|
public int PositionY { get; set; }
|
|
public int PositionZ { get; set; }
|
|
public int RotationY { get; set; }
|
|
public int RotationZ { get; set; }
|
|
public int ShadowDirection { get; set; }
|
|
|
|
public static CustomRange Read(string s)
|
|
{
|
|
//243~573:-15,13,12
|
|
var result = s.Split(':');
|
|
var range = result[0].Split('~');
|
|
var v = result[1].Split(',');
|
|
CustomRange r = new CustomRange()
|
|
{
|
|
Start = Convert.ToInt32(range[0]),
|
|
End = Convert.ToInt32(range[1]),
|
|
RotationY = Convert.ToInt32(v[0]),
|
|
RotationZ = Convert.ToInt32(v[1]),
|
|
PositionX = Convert.ToInt32(v[2]),
|
|
};
|
|
return r;
|
|
}
|
|
}
|
|
public class VideoGameManager : DeviceServiceMonoBase
|
|
{
|
|
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;
|
|
public RouteResult routeResult;
|
|
public string recordId { get; set; }
|
|
public DateTime startTime { get; set; }
|
|
public CyclingModel cyclingModel;
|
|
public BaseCycling cyclingController;
|
|
public List<CustomRange> mockDirection = new List<CustomRange>();
|
|
private double endDistance { get; set; }
|
|
public List<float> slots = new List<float>();
|
|
GameObject infoPanel;
|
|
GameObject OnlinePlayer;
|
|
GameObject OnlinePlayer_NV;
|
|
private bool isStop { get; set; }
|
|
public enum ARMode
|
|
{
|
|
RIDE,
|
|
INSPECT
|
|
}
|
|
//当前是观察者视角还是骑行者视角
|
|
public ARMode _aRMode { get; set; }
|
|
public int RankingId { get; set; }
|
|
private int currentOnlineCount = 0;
|
|
|
|
private void Awake()
|
|
{
|
|
base.Awake();
|
|
mediaPlayer = FindObjectOfType<MediaPlayer>();
|
|
DeviceCache.Init(PFConstants.DeviceCacheFolder);
|
|
var check = CheckAnt();//初始化蓝牙设备
|
|
recordId = Guid.NewGuid().ToString();
|
|
MockDirection();
|
|
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");
|
|
StartCoroutine(Init());
|
|
}
|
|
void Start()
|
|
{
|
|
InitSlots();
|
|
|
|
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
|
|
};
|
|
}
|
|
endDistance = 0;
|
|
videoLoading = FindObjectOfType<VideoLoading>();
|
|
}
|
|
private IEnumerator Init()
|
|
{
|
|
yield return null;
|
|
videoLoading.Init();//初始化loading页面
|
|
}
|
|
VideoLoading videoLoading { get; set; }
|
|
// Update is called once per frame
|
|
float timer = 0f;
|
|
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.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)
|
|
{
|
|
//观察者模式随机选择当前骑行的人作为观察对象
|
|
if (_aRMode == ARMode.INSPECT && CurrentPlayer == null)
|
|
{
|
|
var currentPlayer = list.FirstOrDefault();
|
|
if (currentPlayer != null)
|
|
{
|
|
var onlineRider = currentPlayer as OnlineRiderModel;
|
|
GameObject obj;
|
|
if (onlineRider.Sex == 1)
|
|
{
|
|
obj = Instantiate(OnlinePlayer, transform);
|
|
}
|
|
else
|
|
{
|
|
obj = Instantiate(OnlinePlayer_NV, transform);
|
|
}
|
|
var online = obj.GetComponent<OnlineVideoPlayer>();
|
|
online.SetPlayer(onlineRider.NickName, onlineRider.EndDistance-onlineRider.PreDistance, onlineRider.EndDistance, onlineRider.Cadence, onlineRider.HeartRate, onlineRider.TotalTicks, onlineRider.UserId, onlineRider.Power, onlineRider.EndDistance,onlineRider.FrameRate.Value);
|
|
obj.transform.DOMoveX(0, 1);
|
|
ChangePlayer(currentPlayer.UserId);
|
|
CurrentPlayer = online;
|
|
}
|
|
}
|
|
//list = list.Where(c => c.UserId != CurrentPlayer?.UserId).ToList();
|
|
var onlinelist = MapUDPService.GetOnlineUsers(App.RouteIdParam);//最新列表
|
|
var currentPlayerInfo = onlinelist.Where(c => c.Id == CurrentPlayer.UserId).FirstOrDefault();
|
|
|
|
var players = FindObjectsOfType<OnlineVideoPlayer>();
|
|
//移除
|
|
foreach (var item in players)
|
|
{
|
|
var currentItem = list.Where(c => c.UserId == item.UserId).FirstOrDefault();
|
|
if (currentItem == null)
|
|
{
|
|
item.Destroy();
|
|
if (currentOnlineCount > 1) {
|
|
currentOnlineCount--;
|
|
}
|
|
}
|
|
}
|
|
//新增/更新
|
|
var pagedList = list.Take(5).ToList();
|
|
foreach (var item in pagedList)
|
|
{
|
|
var onlineRider = item as OnlineRiderModel;
|
|
var exsit = players.Where(c => c.UserId == item.UserId).FirstOrDefault();
|
|
if (exsit != null)
|
|
{
|
|
var online = exsit.GetComponent<OnlineVideoPlayer>();
|
|
|
|
online.SetPlayer(onlineRider.NickName, onlineRider.EndDistance - onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value);
|
|
}
|
|
else
|
|
{
|
|
if (currentPlayerInfo != null)
|
|
{
|
|
var diff = item.EndDistance % mapData.TotalDistance - currentPlayerInfo.EndDistance % mapData.TotalDistance;
|
|
if (Math.Abs(diff * 1000) <= 50)
|
|
{
|
|
GameObject obj;
|
|
if (currentPlayerInfo.Sex == 1)
|
|
{
|
|
obj = Instantiate(OnlinePlayer, transform);
|
|
}
|
|
else
|
|
{
|
|
obj = Instantiate(OnlinePlayer_NV, transform);
|
|
}
|
|
var online = obj.GetComponent<OnlineVideoPlayer>();
|
|
online.SetPlayer(onlineRider.NickName, onlineRider.EndDistance - onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value);
|
|
obj.transform.DOMoveX(slots[currentOnlineCount], 1);
|
|
currentOnlineCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//设置当前是骑行模式还是观察模式
|
|
public void SetCurrentMode(ARMode aRMode)
|
|
{
|
|
_aRMode = aRMode;
|
|
var uimanager = FindObjectOfType<VideoUIManager>();
|
|
uimanager.SetCurrentMode(aRMode);
|
|
if (_aRMode != ARMode.INSPECT)
|
|
{
|
|
InitCurrentPlayer();
|
|
ContinueAsync();
|
|
}
|
|
}
|
|
//初始化人物模型
|
|
public void InitCurrentPlayer()
|
|
{
|
|
GameObject videoPlayer;
|
|
if (App.CurrentUser.Sex == 1)
|
|
{
|
|
videoPlayer = Instantiate(Resources.Load<GameObject>("UI/Prefab/AR/VidePlayer"),transform);
|
|
}
|
|
else
|
|
{
|
|
videoPlayer = Instantiate(Resources.Load<GameObject>("UI/Prefab/AR/VidePlayer_NV"), transform);
|
|
}
|
|
CurrentPlayer = videoPlayer.GetComponent<VideoPlayer>();
|
|
}
|
|
|
|
Vector3 origin = new Vector3(0, -1, 3);
|
|
//切换人物
|
|
public void ChangePlayer(int userId)
|
|
{
|
|
var players = FindObjectsOfType<OnlineVideoPlayer>();
|
|
if (players != null)
|
|
{
|
|
CurrentPlayer = players.Where(c => c.UserId == userId).FirstOrDefault();
|
|
if (CurrentPlayer != null) {
|
|
var currentFrames = DistanceToFrames(CurrentPlayer.totalDistance);
|
|
//获取当前人物的帧数
|
|
SetCurrentFrame(currentFrames);
|
|
//设置人物的位置
|
|
CurrentPlayer.transform.position = origin;
|
|
|
|
}
|
|
else
|
|
{
|
|
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<OnlineVideoPlayer>();
|
|
online.SetPlayer(onlineRider.NickName, onlineRider.EndDistance-onlineRider.PreDistance, onlineRider.EndDistance, onlineRider.Cadence, onlineRider.HeartRate, 0, onlineRider.UserId, onlineRider.Power, onlineRider.EndDistance, onlineRider.FrameRate.Value);
|
|
obj.transform.position = origin;
|
|
CurrentPlayer = online;
|
|
var currentFrames = DistanceToFrames(CurrentPlayer.totalDistance);
|
|
//获取当前人物的帧数
|
|
SetCurrentFrame(currentFrames);
|
|
}
|
|
var clearList = players.Where(c => c.UserId != userId);
|
|
foreach (var item in clearList)
|
|
{
|
|
item.Destroy();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//初始化骑行选手横向插槽
|
|
private void InitSlots()
|
|
{
|
|
for (float i = -2f; i <= 2; i+=0.5f)
|
|
{
|
|
if (i != 0)
|
|
{
|
|
slots.Add(i);
|
|
}
|
|
}
|
|
slots = slots.OrderBy(c => Math.Abs(c)).ToList();
|
|
}
|
|
//获取角色头顶信息预制件
|
|
public GameObject GetHeadInfo()
|
|
{
|
|
return infoPanel;
|
|
}
|
|
//骑行记录
|
|
public void ContinueAsync()
|
|
{
|
|
//骑行结果
|
|
if (App.routeResult != null)
|
|
{
|
|
routeResult = App.routeResult;
|
|
selectParamModel = App.routeResult.ContinueCyclingParam;//继续骑行
|
|
SetCyclingModel(CyclingModel.Single);
|
|
endDistance = routeResult.EndDistance;
|
|
SetCurrentFrame(routeResult.LastFrame ?? 0);
|
|
var v = FindObjectOfType<VideoPlayer>();
|
|
v.SetEndDistance(endDistance);
|
|
}
|
|
}
|
|
|
|
private void MockDirection()
|
|
{
|
|
var text = Resources.Load<TextAsset>("UI/direction");
|
|
var arr = text.text.Replace("\r\n", " ").Split(' ');
|
|
foreach (var item in arr)
|
|
{
|
|
if (string.IsNullOrEmpty(item))
|
|
continue;
|
|
var c = CustomRange.Read(item);
|
|
mockDirection.Add(c);
|
|
}
|
|
}
|
|
//设置骑行模式
|
|
public void SetCyclingModel(CyclingModel mode)
|
|
{
|
|
startTime = UIManager.Now.GetDateTime();
|
|
this.cyclingModel = mode;
|
|
switch (cyclingModel)
|
|
{
|
|
case CyclingModel.Single:
|
|
cyclingController = new SingleModel(route, selectParamModel);
|
|
break;
|
|
case CyclingModel.GameRoom:
|
|
cyclingController = new GameModel(route, selectParamModel);
|
|
break;
|
|
}
|
|
}
|
|
//模拟登录
|
|
private async Task Login()
|
|
{
|
|
var result = await new UserApi().Login("anyway2019@163.com", "123456", "");
|
|
App.CurrentUser = result.data;
|
|
}
|
|
//开始游戏
|
|
public void StartGame()
|
|
{
|
|
if (startTime == null)
|
|
{
|
|
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 Play(float playbackRate = 1f)
|
|
{
|
|
if (mediaPlayer != null)
|
|
{
|
|
mediaPlayer.PlaybackRate = playbackRate;
|
|
mediaPlayer.Play();
|
|
}
|
|
if (startTime == null)
|
|
{
|
|
startTime = UIManager.Now.GetDateTime();
|
|
}
|
|
isStart = true;
|
|
}
|
|
//暂停
|
|
public void Pause()
|
|
{
|
|
isStart = !isStart;
|
|
isStop = !isStop;
|
|
if (isStop)
|
|
{
|
|
mediaPlayer?.Pause();
|
|
}
|
|
else
|
|
{
|
|
mediaPlayer?.Play();
|
|
}
|
|
}
|
|
//退出骑行
|
|
public void Quit()
|
|
{
|
|
mediaPlayer?.Pause();//暂停视频
|
|
isStart = false;
|
|
isStop = true;
|
|
mediaPlayer?.Stop();
|
|
}
|
|
//获取当前视频帧数
|
|
public int GetCurrentFrame()
|
|
{
|
|
return mediaPlayer.Control.GetCurrentTimeFrames();
|
|
}
|
|
//距离换算成视频帧数
|
|
public int DistanceToFrames(double distance)
|
|
{
|
|
var frames = mediaPlayer.Info.GetMaxFrameNumber(); //视频打开后生效
|
|
var TotalDistance = route?.TotalDistance ?? 0;
|
|
distance %= TotalDistance;
|
|
return TotalDistance > 0 ? Convert.ToInt32(frames / TotalDistance * distance) : 0;
|
|
}
|
|
public int GetFrameOffSet(double distance)
|
|
{
|
|
var currentFrame = GetCurrentFrame();
|
|
var frames = mediaPlayer.Info.GetMaxFrameNumber(); //视频打开后生效
|
|
var TotalDistance = route?.TotalDistance ?? 0;
|
|
TotalDistance *= 1000;
|
|
distance %= TotalDistance;
|
|
var offset = TotalDistance > 0 ? Convert.ToInt32(frames / TotalDistance * distance) : 0;
|
|
return currentFrame + offset;
|
|
}
|
|
//设置当前视频播放进度
|
|
public void SetCurrentFrame(int seq)
|
|
{
|
|
mediaPlayer?.Control.SeekToFrame(seq);
|
|
}
|
|
//获取路书gps信息
|
|
public MapDataModel GetMapData()
|
|
{
|
|
if (mapData == null)
|
|
{
|
|
var mapApi = ConfigHelper.mapApi;
|
|
int routeId = App.RouteIdParam;
|
|
mapData = mapApi.GetData(routeId);//获取路书地理数据
|
|
}
|
|
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<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);
|
|
}
|
|
//截图
|
|
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;
|
|
}
|
|
}
|
|
} |