625 lines
19 KiB
C#
625 lines
19 KiB
C#
using DG.Tweening;
|
|
using RenderHeads.Media.AVProVideo;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using System.IO;
|
|
using Assets.Scripts.Scenes.VideoRide;
|
|
using System.Reflection;
|
|
using UnityEngine.UI;
|
|
using Assets.Scripts;
|
|
using FluffyUnderware.Curvy;
|
|
using FluffyUnderware.Curvy.Controllers;
|
|
using Mapbox.Utils;
|
|
using Mapbox.Unity.Map;
|
|
using Assets.Scripts.Apis.Models;
|
|
using Mapbox.Unity.MeshGeneration.Data;
|
|
|
|
public class TestVideoController : MonoBehaviour
|
|
{
|
|
|
|
public Transform Player;
|
|
|
|
public GameObject QuitBtn;
|
|
|
|
public GameObject PauseBtn;
|
|
|
|
public GameObject CancelBtn;
|
|
|
|
public Transform Quad;
|
|
|
|
public Transform Light;
|
|
|
|
public Transform FrameContent;
|
|
|
|
public GameObject FrameBtnPrefab;
|
|
|
|
public GameObject PreviewBtn;
|
|
|
|
public GameObject SaveBtn;
|
|
|
|
public GameObject ResetBtn;
|
|
|
|
public GameObject DeleteBtn;
|
|
|
|
public MediaPlayer mediaPlayer;
|
|
|
|
public Text Frametext;
|
|
|
|
public TrailRenderer trailRenderer;
|
|
|
|
private Dictionary<int, string> list = new Dictionary<int, string>();
|
|
Vector3 originPos = new Vector3(0, -1, 3);
|
|
Vector3 originRotation = Vector3.zero;
|
|
|
|
// Start is called before the first frame update
|
|
void Start()
|
|
{
|
|
lightRotation = new Vector3(50f,-45,0);
|
|
InitConfig();
|
|
UIManager.AddEvent(QuitBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
Application.Quit();
|
|
});
|
|
UIManager.AddEvent(PauseBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
PlayOrPause();
|
|
});
|
|
UIManager.AddEvent(PreviewBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
BuildList();
|
|
isPlay = true;
|
|
mediaPlayer.Control.SeekFast(0);
|
|
mediaPlayer.Play();
|
|
});
|
|
UIManager.AddEvent(slider.gameObject, UnityEngine.EventSystems.EventTriggerType.Drag, (e) =>
|
|
{
|
|
OnTimeSliderDrag();
|
|
});
|
|
UIManager.AddEvent(SaveBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
Vector3[] TrailRecorded = new Vector3[trailRenderer.positionCount];
|
|
trailRenderer.GetPositions(TrailRecorded);
|
|
var curvy = CurvySpline.Create();
|
|
curvy.Interpolation = CurvyInterpolation.Bezier;
|
|
foreach (var item in TrailRecorded)
|
|
{
|
|
curvy.Add(item);
|
|
}
|
|
DoRecord();
|
|
});
|
|
UIManager.AddEvent(ResetBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
Player.DOMove(originPos,0);
|
|
Player.DORotate(originRotation, 0);
|
|
});
|
|
UIManager.AddEvent(CancelBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
var k = mockRange.Where(c => c.KeyFrame == currentFrame).FirstOrDefault();
|
|
if (k != null)
|
|
{
|
|
Player.DOMove(new Vector3(k.PositionX, k.PositionY, k.PositionZ), 0);
|
|
Player.DORotate(new Vector3(0, k.RotationY, k.RotationZ), 0);
|
|
}
|
|
});
|
|
UIManager.AddEvent(DeleteBtn, UnityEngine.EventSystems.EventTriggerType.PointerClick, (e) =>
|
|
{
|
|
DeleteFrame(currentFrame);
|
|
});
|
|
//默认轨迹1
|
|
switcher = FindObjectOfType<SplineSwitcher>();
|
|
var curve = switcher.GetDefaultController();
|
|
//控制轨迹根据当前运动员旋转
|
|
controller = Controller.GetComponent<SplineController>();
|
|
controller.Spline = curve;
|
|
onlineController = onlinePlayer.GetComponent<SplineController>();
|
|
|
|
}
|
|
SplineSwitcher switcher;
|
|
public GameObject Controller;
|
|
CurvySpline c { get; set; }
|
|
List<Vector3> vlist = new List<Vector3>();
|
|
|
|
|
|
public Vector2d GetCenterCoordinate()
|
|
{
|
|
return new Vector2d(mapData.List[0].Point[0], mapData.List[0].Point[1]);
|
|
}
|
|
|
|
MapDataModel mapData;
|
|
GameObject tracker;
|
|
SplineController controller;
|
|
public GameObject onlinePlayer;
|
|
SplineController onlineController;
|
|
public Text PlayBtnText;
|
|
|
|
public Transform target;
|
|
|
|
float timer = 0;
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
Frametext.text = $"当前视频帧数:{GetCurrentFrame()}";
|
|
//视频播放时间
|
|
TimeRange timelineRange = GetTimelineRange();
|
|
double time = mediaPlayer.Control.GetCurrentTime();
|
|
sliderText.text = $"{ Assets.Scenes.Ride.Scripts.Helper.FormatTicks((int)Math.Floor(time))}/{Assets.Scenes.Ride.Scripts.Helper.FormatTicks((int)Math.Floor(timelineRange.duration))}";
|
|
if (timelineRange.duration != 0)
|
|
{
|
|
slider.value = (float)(time / timelineRange.duration);
|
|
}
|
|
timer -= Time.deltaTime;
|
|
while (timer<0 && isPlay)
|
|
{
|
|
//controller.Position += 0.007f;
|
|
timer += 1f;
|
|
}
|
|
//controller.Position += 0.0001f; ///(GetCurrentFrame() / 41225f)* 47.9f;
|
|
if (controller.Position >= 1)
|
|
{
|
|
controller.Spline = switcher.Next();
|
|
controller.Position = 0;
|
|
onlineController.Position = 0;
|
|
onlineController.Spline = controller.Spline;
|
|
}
|
|
onlineController.Position = controller.Position + 0.015f;
|
|
//轨迹运动
|
|
//tracker.transform.DOLocalMoveZ(Player.localPosition.z-3f, 0f);
|
|
//轨迹旋转
|
|
//tracker.transform.DORotate(new Vector3(0, 0, 1), 1f);
|
|
//键盘输入
|
|
CharacterControl();
|
|
//计算当前帧数在哪个区段
|
|
ComputeCurrentFrame();
|
|
//人物控制
|
|
if (isPlay)
|
|
{
|
|
Turn();
|
|
}
|
|
//暂停或播放
|
|
var isPause = mediaPlayer.Control.IsPaused();
|
|
ResetBtn.SetActive(isPause);
|
|
if (!isPause)
|
|
{
|
|
CancelBtn.SetActive(false);
|
|
DeleteBtn.SetActive(false);
|
|
}
|
|
PlayBtnText.text = isPause ? "播放" : "暂停";
|
|
}
|
|
|
|
public int currentFrame { get; set; }
|
|
|
|
public void PlayToFrame(int frame)
|
|
{
|
|
var config = mockRange.Where(c => c.KeyFrame == frame).FirstOrDefault();
|
|
if (config != null)
|
|
{
|
|
CancelBtn.SetActive(true);
|
|
DeleteBtn.SetActive(true);
|
|
currentFrame = frame;
|
|
SeekToFrame(frame);
|
|
mediaPlayer.Pause();
|
|
isPlay = false;
|
|
var rotation = new Vector3(0, config.RotationY, config.RotationZ);
|
|
Player.DORotate(rotation, 0);
|
|
var pos = new Vector3(config.PositionX, config.PositionY, config.PositionZ);
|
|
//Player.DOMove(pos, 0);
|
|
}
|
|
}
|
|
|
|
private string ConfigPath = Application.streamingAssetsPath + "/newdirection.txt";
|
|
//初始化配置
|
|
private void InitConfig()
|
|
{
|
|
var text = File.ReadAllText(ConfigPath);
|
|
var arr = text.Replace("\r\n", " ").Split(' ');
|
|
foreach (var item in arr)
|
|
{
|
|
if (!string.IsNullOrEmpty(item))
|
|
{
|
|
int key = Convert.ToInt32(item.Split(':')[0]);
|
|
list.Add(key, item);
|
|
}
|
|
}
|
|
BuildList();
|
|
if (mockRange.Count > 0)
|
|
{
|
|
pre = mockRange[0];
|
|
next = mockRange[0];
|
|
}
|
|
}
|
|
private void DeleteFrame(int frame)
|
|
{
|
|
//删除当前帧数
|
|
var s = mockRange.Where(c => c.KeyFrame == frame).FirstOrDefault();
|
|
if (s != null)
|
|
{
|
|
mockRange.Remove(s);
|
|
}
|
|
|
|
if (list.ContainsKey(frame))
|
|
{
|
|
list.Remove(frame);
|
|
}
|
|
|
|
//回到上一帧
|
|
var l = mockRange.OrderBy(c => c.KeyFrame).ToList();
|
|
var btnList = FindObjectsOfType<TestVideoFrameButton>();
|
|
|
|
var needRemove = btnList.Where(c => c.Frame == frame).FirstOrDefault();
|
|
if (needRemove != null)
|
|
{
|
|
needRemove.Destroy();
|
|
}
|
|
|
|
var nextFrame = 0;
|
|
foreach (var item in l)
|
|
{
|
|
if (item.KeyFrame < frame)
|
|
{
|
|
nextFrame = item.KeyFrame;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
var btn = btnList.Where(c => c.Frame == nextFrame).FirstOrDefault();
|
|
if (btn != null)
|
|
{
|
|
btn.SelectFrame(nextFrame);
|
|
}
|
|
//同步到txt
|
|
Save();
|
|
}
|
|
TestVideoFrameButton[] btnList;
|
|
private void BuildList()
|
|
{
|
|
var l = list.OrderBy(c => c.Key);
|
|
mockRange.Clear();
|
|
Utils.DestroyChildren(FrameContent);
|
|
foreach (var item in l)
|
|
{
|
|
mockRange.Add(CustomRange.Read(item.Value));
|
|
var btn = Instantiate<GameObject>(FrameBtnPrefab, FrameContent);
|
|
btn.SetActive(true);
|
|
btn.GetComponent<TestVideoFrameButton>().SetInfo(item.Key);
|
|
}
|
|
btnList = FindObjectsOfType<TestVideoFrameButton>();
|
|
}
|
|
|
|
private bool isPlay { get; set; } = true;
|
|
private List<CustomRange> mockRange = new List<CustomRange>();
|
|
|
|
private CustomRange pre;
|
|
private CustomRange next;
|
|
private void ComputeCurrentFrame()
|
|
{
|
|
var currentFrame = GetCurrentFrame();
|
|
var config = mockRange;
|
|
if (config.Count == 0)
|
|
return;
|
|
|
|
for (int i = 0; i < config.Count; i++)
|
|
{
|
|
if (config[i].KeyFrame >= currentFrame)
|
|
{
|
|
pre = i > 0 ? config[i - 1] : config[i];
|
|
next = config[i];
|
|
break;
|
|
}
|
|
}
|
|
if (mediaPlayer.Control.IsPlaying())
|
|
{
|
|
foreach (var item in btnList)
|
|
{
|
|
item.SetBg(item.Frame == pre.KeyFrame);
|
|
}
|
|
}
|
|
}
|
|
private void Turn()
|
|
{
|
|
var currentFrame = GetCurrentFrame();
|
|
//控制人物的转向
|
|
var p = new Vector3(0, pre.RotationY, pre.RotationZ);
|
|
var q = new Vector3(0, next.RotationY, next.RotationZ);
|
|
var t = next.KeyFrame - pre.KeyFrame == 0? 1 : (float)(currentFrame - pre.KeyFrame) / (float)(next.KeyFrame - pre.KeyFrame);
|
|
var rt = Vector3.Lerp(p, q, t);
|
|
//Player.DORotate(rt, 0, RotateMode.Fast);
|
|
//控制人物的前后左右上下
|
|
var l = new Vector3(pre.PositionX, pre.PositionY, pre.PositionZ);
|
|
var s = new Vector3(next.PositionX, next.PositionY, next.PositionZ);
|
|
var pos = Vector3.Lerp(l, s, t);
|
|
//Player.DOMove(pos, 0); //控制光线
|
|
var z = new Vector3(50, pre.LightY, 0);
|
|
var c = new Vector3(50, next.LightY, 0);
|
|
var zc = Vector3.Lerp(z, c, t);
|
|
//Light.DORotate(zc, 0);
|
|
}
|
|
public Slider slider;
|
|
public Text sliderText;
|
|
private void OnTimeSliderDrag()
|
|
{
|
|
if (mediaPlayer && mediaPlayer.Control != null)
|
|
{
|
|
TimeRange timelineRange = GetTimelineRange();
|
|
double time = timelineRange.startTime + ( slider.value*timelineRange.duration);
|
|
mediaPlayer.Control.Seek(time);
|
|
}
|
|
}
|
|
|
|
private TimeRange GetTimelineRange()
|
|
{
|
|
if (mediaPlayer.Info != null)
|
|
{
|
|
return Helper.GetTimelineRange(mediaPlayer.Info.GetDuration(), mediaPlayer.Control.GetSeekableTimes());
|
|
}
|
|
return new TimeRange();
|
|
}
|
|
|
|
private void SeekToFrame(int frame)
|
|
{
|
|
mediaPlayer.Control.SeekToFrame(frame);
|
|
}
|
|
private int GetCurrentFrame()
|
|
{
|
|
return mediaPlayer.Control.GetCurrentTimeFrames();
|
|
}
|
|
|
|
private int GetPreFrame(int frame)
|
|
{
|
|
return mediaPlayer.Control.GetCurrentTimeFrames();
|
|
}
|
|
private Vector3 rotation = Vector3.zero;
|
|
private Vector3 lightRotation;
|
|
private void CharacterControl()
|
|
{
|
|
var delta = 0.2f;
|
|
var zdelta = 0.1f;
|
|
//控制太阳
|
|
if (Input.GetKey(KeyCode.Z))
|
|
{
|
|
//lightRotation.x -= delta;
|
|
lightRotation.y += zdelta;
|
|
Light.DORotate(lightRotation, 0);
|
|
isPlay = false;
|
|
}
|
|
if (Input.GetKey(KeyCode.C))
|
|
{
|
|
// lightRotation.x += delta;
|
|
lightRotation.y -= zdelta;
|
|
Light.DORotate(lightRotation, 0);
|
|
isPlay = false;
|
|
}
|
|
//控制人物方向
|
|
if (Input.GetKey(KeyCode.Q))
|
|
{
|
|
rotation.y -= delta;
|
|
Player.DORotate(rotation, 0);
|
|
Player.parent.DORotate(rotation, 0);
|
|
isPlay = false;
|
|
}
|
|
if (Input.GetKey(KeyCode.E))
|
|
{
|
|
rotation.y += delta;
|
|
Player.DORotate(rotation, 0);
|
|
Player.parent.DORotate(rotation, 0);
|
|
isPlay = false;
|
|
}
|
|
//控制人物左右倾斜
|
|
if (Input.GetKey(KeyCode.J))
|
|
{
|
|
rotation.z += zdelta;
|
|
Player.DORotate(rotation, 0);
|
|
Player.parent.DORotate(rotation, 0);
|
|
isPlay = false;
|
|
}
|
|
if (Input.GetKey(KeyCode.K))
|
|
{
|
|
rotation.z -= zdelta;
|
|
Player.DORotate(rotation, 0);
|
|
Player.parent.DORotate(rotation, 0);
|
|
isPlay = false;
|
|
}
|
|
//空格键记录当前人物数据
|
|
if (Input.GetKeyDown(KeyCode.Space))
|
|
{
|
|
PlayOrPause();
|
|
}
|
|
//人物前后左右
|
|
if (Input.GetKey(KeyCode.S))
|
|
{
|
|
setHeroState(HERO_DOWN); //下
|
|
}
|
|
else if (Input.GetKey(KeyCode.W))
|
|
{
|
|
setHeroState(HERO_UP); //上
|
|
}
|
|
if (Input.GetKey(KeyCode.D))
|
|
{
|
|
setHeroState(HERO_RIGHT); //右
|
|
}
|
|
else if (Input.GetKey(KeyCode.A))
|
|
{
|
|
setHeroState(HERO_LEFT); //左
|
|
}
|
|
//控制视频播放进度
|
|
if (Input.GetKey(KeyCode.LeftArrow))
|
|
{
|
|
var frame = GetCurrentFrame()-1;
|
|
SeekToFrame(frame);
|
|
}
|
|
if (Input.GetKey(KeyCode.RightArrow))
|
|
{
|
|
var frame = GetCurrentFrame() + 1;
|
|
SeekToFrame(frame);
|
|
}
|
|
//控制人物上下
|
|
if (Input.GetKey(KeyCode.UpArrow))
|
|
{
|
|
setHeroState(UP);
|
|
}
|
|
if (Input.GetKey(KeyCode.DownArrow))
|
|
{
|
|
setHeroState(DOWN);
|
|
}
|
|
}
|
|
private void PlayOrPause()
|
|
{
|
|
if (mediaPlayer.Control.IsPaused())
|
|
{
|
|
isPlay = true;
|
|
mediaPlayer.Play();
|
|
}
|
|
else
|
|
{
|
|
isPlay = false;
|
|
mediaPlayer.Pause();
|
|
}
|
|
}
|
|
private void DoRecord()
|
|
{
|
|
Save();
|
|
BuildList();
|
|
//回到上一个节点
|
|
if (pre != null)
|
|
{
|
|
mediaPlayer.Control.SeekToFrame(pre.KeyFrame);
|
|
}
|
|
isPlay = true;
|
|
mediaPlayer.Play();
|
|
}
|
|
|
|
private void Save()
|
|
{
|
|
var key = GetCurrentFrame();
|
|
//获取人物inpector面板的rotation值
|
|
Vector3 vect3 = Vector3.zero;
|
|
Vector3 vect = Vector3.zero;
|
|
MethodInfo mth = typeof(Transform).GetMethod("GetLocalEulerAngles", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
PropertyInfo pi = typeof(Transform).GetProperty("rotationOrder", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
object rotationOrder = null;
|
|
object lightRotationOrder = null;
|
|
if (pi != null)
|
|
{
|
|
rotationOrder = pi.GetValue(Player, null);
|
|
lightRotationOrder= pi.GetValue(Light, null);
|
|
}
|
|
if (mth != null)
|
|
{
|
|
object retVector3 = mth.Invoke(Player, new object[] { rotationOrder });
|
|
vect3 = (Vector3)retVector3;
|
|
|
|
object retVector = mth.Invoke(Light, new object[] { lightRotationOrder });
|
|
vect = (Vector3)retVector;
|
|
}
|
|
//保存记录
|
|
var s = $"{key}:{ Math.Round(vect3.y, 3)},{ Math.Round(vect3.z, 3)},{Math.Round(Player.position.x,3)},{Math.Round(Player.position.y,3)},{Math.Round(Player.position.z,3)},{Math.Round(vect.y,3)}";
|
|
if (list.ContainsKey(key))
|
|
{
|
|
list[key] = s;
|
|
}
|
|
else
|
|
{
|
|
list.Add(key, s);
|
|
}
|
|
var coll = list.OrderBy(c => c.Key);
|
|
StringBuilder sb = new StringBuilder();
|
|
foreach (var item in coll)
|
|
{
|
|
sb.AppendLine(item.Value);
|
|
}
|
|
File.WriteAllText(ConfigPath, sb.ToString());
|
|
}
|
|
//人物状态
|
|
public const int HERO_UP = 0;
|
|
public const int HERO_RIGHT = 1;
|
|
public const int HERO_DOWN = 2;
|
|
public const int HERO_LEFT = 3;
|
|
public const int UP = 4;
|
|
public const int DOWN = 5;
|
|
|
|
//人物当前行走的方向状态
|
|
public int state = 0;
|
|
//人物移动速度
|
|
public int moveSpeed = 2;
|
|
void setHeroState(int newState)
|
|
{
|
|
isPlay = false;
|
|
//根据当前人物方向与上一次备份的方向计算出模型旋转的角度
|
|
Vector3 transformValue = new Vector3();
|
|
//模型移动的位置数值
|
|
switch (newState)
|
|
{
|
|
case HERO_UP:
|
|
transformValue = Vector3.forward * Time.deltaTime;
|
|
break;
|
|
case HERO_DOWN:
|
|
transformValue = (-Vector3.forward) * Time.deltaTime;
|
|
break;
|
|
case HERO_LEFT:
|
|
transformValue = Vector3.left * Time.deltaTime;
|
|
break;
|
|
case HERO_RIGHT:
|
|
transformValue = (-Vector3.left) * Time.deltaTime;
|
|
break;
|
|
case UP:
|
|
transformValue = (Vector3.up) * Time.deltaTime;
|
|
break;
|
|
case DOWN:
|
|
transformValue = (Vector3.down) * Time.deltaTime;
|
|
break;
|
|
}
|
|
////移动人物
|
|
Player.Translate(transformValue * moveSpeed, Space.World);
|
|
Player.parent.Translate(transformValue * moveSpeed, Space.World);
|
|
state = newState;
|
|
|
|
}
|
|
public class CustomRange
|
|
{
|
|
public int KeyFrame { get; set; }//帧数
|
|
public int Start { get; set; }//起始帧
|
|
public int End { get; set; }//结束帧
|
|
public float PositionX { get; set; }
|
|
public float PositionY { get; set; }
|
|
public float PositionZ { get; set; }
|
|
public float RotationY { get; set; }
|
|
public float RotationZ { get; set; }
|
|
public float LightY { get; set; }
|
|
|
|
|
|
|
|
|
|
private const float defaultRotationY = 0;
|
|
private const float defaultRotationZ = 0;
|
|
private const float defaultPositionX = 0;
|
|
private const float defaultPositionY = -1;
|
|
private const float defaultPositionZ = 3;
|
|
private const float defaultLightY = 0;
|
|
|
|
public static CustomRange Read(string s)
|
|
{
|
|
// - 代表默认值
|
|
//KeyFrame:RotationY,RotationZ,PositionX,PositionY,PositionZ,LightY
|
|
var result = s.Split(':');
|
|
var v = result[1].Split(',');
|
|
CustomRange r = new CustomRange()
|
|
{
|
|
KeyFrame = Convert.ToInt32(result[0]),
|
|
RotationY = v[0].Equals("-") ? defaultRotationY : (float)Convert.ToDouble(v[0]),
|
|
RotationZ = v[1].Equals("-") ? defaultRotationZ : (float)Convert.ToDouble(v[1]),
|
|
PositionX = v[2].Equals("-") ? defaultPositionX : (float)Convert.ToDouble(v[2]),
|
|
PositionY = v[3].Equals("-") ? defaultPositionY : (float)Convert.ToDouble(v[3]),
|
|
PositionZ = v[4].Equals("-") ? defaultPositionZ : (float)Convert.ToDouble(v[4]),
|
|
LightY = v[5].Equals("-") ? defaultLightY : (float)Convert.ToDouble(v[5]),
|
|
};
|
|
return r;
|
|
}
|
|
}
|
|
}
|