解决相机抖动和人物移动动画不流畅的问题

This commit is contained in:
lishuo committed 2021-03-30 17:29:39 +08:00
1 parent 0ab0e99597
commit 42fa59d103
24 files changed
+154640 -457

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

+104
View File
@@ -0,0 +1,104 @@
fileFormatVersion: 2
guid: 941b43407750edb46a7532221b274dfd
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large. Load diff
-40
View File
@@ -1,40 +0,0 @@
using GeoJSON.Net.Geometry;
using Mapbox.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using TurfCS;
using UnityEngine.Networking;
using Assets.Scripts.Apis.Models;
namespace Assets.Scenes.Ride.Scripts
{
public static class GameManger
{
public static double totaldistance;
public static List<Vector2d> vl;
public static int routeId;
public static bool IsStart = true;
public static MapDataModel MapData;
//记录当前游戏一些全局数据
public static Vector2d Along(double distance)
{
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, distance);
var ll = ((GeographicPosition)((GeoJSON.Net.Geometry.Point)pt1.Geometry).Coordinates);
return new Vector2d(ll.Latitude, ll.Longitude);
}
return new Vector2d(0, 0);
}
}
}
+22
View File
@@ -6,6 +6,28 @@ namespace Assets.Scenes.Ride.Scripts
{
public class Helper
{
public static string FormatTicks(int seconds)
{
int h, m, s;
h = seconds / 3600;
m = (seconds - (3600 * h)) / 60;
s = seconds - (3600 * h + 60 * m);
string H, M, S;
H = M = S = string.Empty;
if (h < 10)
H = "0" + h;
else
H = h.ToString();
if (m < 10)
M = "0" + m;
else
M = m.ToString();
if (s < 10)
S = "0" + s;
else
S = s.ToString();
return $"{H}:{M}:{S}";
}
/// <summary>
/// 计算速度
/// 参考 http://bikecalculator.com/index.html
@@ -0,0 +1,56 @@
using Assets.Scripts.Apis;
using Assets.Scripts.Apis.Models;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainController : MonoBehaviour
{
private MapDataModel mapData;//当前路书数据
private double[] coordiantes;//当前地图中心
private int currentUserId;//当前选中的用户id
private bool isStart;//当前游戏是否开始
private string gameType;//当前骑行模式
public MapDataModel GetMapData()
{
return mapData;
}
public double[] GetCenterCoordinate()
{
return coordiantes;
}
// Start is called before the first frame update
void Awake()
{
//获取路书信息
MapApi mapApi = new MapApi();
//var result = mapApi.GetData(5492);
var result = GetTestData();
if (result != null && result.List.Count > 0)
{
mapData = result;
coordiantes = result.List[0].Point;
}
else
{
throw new System.Exception("fail to get route data");
}
//TODO:
//获取当前用户信息
//获取当前udp信息
//获取蓝牙设备信息
}
/// <summary>
/// 获取模拟的骑行记录
/// </summary>
/// <returns></returns>
public MapDataModel GetTestData()
{
string json = "{'Type':'LineString','TotalDistance':19.17906,'List':[{'Point':[26.092100000000002,119.33686000000002],'Elevation':7.6198},{'Point':[26.09211,119.33749000000002],'Elevation':7.5859},{'Point':[26.092170000000003,119.33840000000001],'Elevation':7.421},{'Point':[26.092260000000003,119.33921000000001],'Elevation':7.3133},{'Point':[26.092270002098761,119.33999000005943],'Elevation':7.2394},{'Point':[26.092280000000002,119.34077],'Elevation':7.2701},{'Point':[26.092240000956789,119.34129500009136],'Elevation':7.3416},{'Point':[26.092200000000002,119.34182000000001],'Elevation':7.4177},{'Point':[26.092083338752424,119.34270666844074],'Elevation':7.5033},{'Point':[26.09196667208499,119.34359333511317],'Elevation':7.2596},{'Point':[26.09185,119.34448],'Elevation':6.8727},{'Point':[26.091680000000004,119.34505000000001],'Elevation':6.4546},{'Point':[26.091536672044878,119.34593333550309],'Elevation':6.0312},{'Point':[26.091393338710645,119.34681666884185],'Elevation':5.751},{'Point':[26.091250000000002,119.3477],'Elevation':5.6373},{'Point':[26.091230000000003,119.34794000000001],'Elevation':5.6052},{'Point':[26.091225001411136,119.3485800001182],'Elevation':5.5997},{'Point':[26.091220000000003,119.34922000000002],'Elevation':5.6907},{'Point':[26.091330000000003,119.34997000000001],'Elevation':6.0231},{'Point':[26.091440000000002,119.35021],'Elevation':6.4916},{'Point':[26.09157,119.35095000000001],'Elevation':7.0092},{'Point':[26.091600000000003,119.3516],'Elevation':7.3641},{'Point':[26.091767507390937,119.35244499640774],'Elevation':7.4909},{'Point':[26.091935009859512,119.353289995235],'Elevation':6.9736},{'Point':[26.092102507405667,119.35413499648182],'Elevation':6.7797},{'Point':[26.092270000000003,119.35498000000001],'Elevation':6.5711},{'Point':[26.092405001867032,119.35571999903352],'Elevation':6.4206},{'Point':[26.092540000000003,119.35646000000001],'Elevation':6.3653},{'Point':[26.09269,119.35732000000002],'Elevation':7.251},{'Point':[26.092710000000004,119.35761000000001],'Elevation':8.2263},{'Point':[26.092703339253426,119.35853666675888],'Elevation':9.8464},{'Point':[26.092696672586847,119.35946333341218],'Elevation':11.8545},{'Point':[26.09269,119.36039000000001],'Elevation':13.6159},{'Point':[26.092665001414368,119.36103000007358],'Elevation':15.1102},{'Point':[26.092640000000003,119.36167],'Elevation':16.3984},{'Point':[26.0925,119.36225],'Elevation':17.1179},{'Point':[26.092270000000003,119.36289000000001],'Elevation':17.3805},{'Point':[26.092200000000002,119.36334000000001],'Elevation':17.3022},{'Point':[26.092180000000003,119.36363000000001],'Elevation':17.2282},{'Point':[26.092190000000002,119.36396],'Elevation':17.2224},{'Point':[26.092290000000002,119.36435000000002],'Elevation':17.1729},{'Point':[26.092100000000002,119.36453000000002],'Elevation':17.1065},{'Point':[26.092000000000002,119.36473000000001],'Elevation':17.0503},{'Point':[26.091910000000002,119.36502000000002],'Elevation':17.1392},{'Point':[26.09193,119.36525],'Elevation':17.2636},{'Point':[26.092150000000004,119.36569000000001],'Elevation':17.4486},{'Point':[26.09233,119.36581000000001],'Elevation':17.7034},{'Point':[26.092540000000003,119.36588],'Elevation':18.1077},{'Point':[26.092750000000002,119.36589000000001],'Elevation':18.5083},{'Point':[26.092950000000002,119.36582000000001],'Elevation':18.892},{'Point':[26.093110000000003,119.36572000000001],'Elevation':19.2643},{'Point':[26.09335,119.36544],'Elevation':19.6256},{'Point':[26.094033333311039,119.36542333352864],'Elevation':20.1707},{'Point':[26.094716666620165,119.36540666686258],'Elevation':21.2487},{'Point':[26.0954,119.36539],'Elevation':22.396},{'Point':[26.09605,119.36548],'Elevation':23.9715},{'Point':[26.09615,119.36567000000001],'Elevation':25.3392},{'Point':[26.096753333417059,119.36562333380944],'Elevation':26.626},{'Point':[26.097356666819095,119.36557666713746],'Elevation':28.1709},{'Point':[26.09796,119.36553],'Elevation':30.077},{'Point':[26.098260000000003,119.36556000000002],'Elevation':32.1094},{'Point':[26.09888000013564,119.36572999910875],'Elevation':34.3101},{'Point':[26.099500000000003,119.36590000000001],'Elevation':36.7362},{'Point':[26.099970000000003,119.36599000000001],'Elevation':39.7763},{'Point':[26.100720000000003,119.36591000000001],'Elevation':43.1691},{'Point':[26.101160000000004,119.36591000000001],'Elevation':46.6581},{'Point':[26.10181,119.36598000000001],'Elevation':50.4232},{'Point':[26.10208,119.36621000000001],'Elevation':53.9898},{'Point':[26.102210000000003,119.36674000000001],'Elevation':57.5845},{'Point':[26.101960000000002,119.36725000000001],'Elevation':61.2459},{'Point':[26.101530000000004,119.36721000000001],'Elevation':64.7154},{'Point':[26.100900000000003,119.36697000000001],'Elevation':68.1881},{'Point':[26.100415000136522,119.36697500001934],'Elevation':71.7923},{'Point':[26.09993,119.36698000000001],'Elevation':75.4172},{'Point':[26.099330000000002,119.36702000000001],'Elevation':79.066},{'Poin Line truncated
return Newtonsoft.Json.JsonConvert.DeserializeObject<MapDataModel>(json);
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ec3c835a32499e84e8d2f93d713d461a
guid: 904fddf6d736a004a969cdfa63f14076
MonoImporter:
externalObjects: {}
serializedVersion: 2
+168 -76
View File
@@ -4,6 +4,13 @@ using Mapbox.Unity.Map;
using Mapbox.Utils;
using Assets.Scripts.Apis.Models;
using static Assets.Scripts.Apis.Models.MapDataModel;
using System;
using Random = UnityEngine.Random;
using Assets.Scripts.Apis;
using GeoJSON.Net.Geometry;
using TurfCS;
using System.Linq;
using System.Collections.Generic;
namespace Assets.Scenes.Ride.Scripts
{
@@ -13,106 +20,177 @@ namespace Assets.Scenes.Ride.Scripts
[SerializeField]
GameObject character;
[SerializeField]
float characterSpeed;
[SerializeField]
Animator characterAnimator;
[SerializeField]
AbstractMap map;
Vector3 nextPos;
#region 动画控制参数
Vector3 nextPos;
Vector3 prePos;
private Vector2d currentlatlong; //当前坐标
private Vector2d nextlatlong; //下一个点的坐标
private double totalDistance;
private int ticks;//秒数
public float timer = 1.0f;//计时器
Vector2d currentlatlong; //当前坐标
Vector2d nextlatlong; //下一个点的坐标
float timer = 1.0f;//计时器
#endregion
#region 选手骑行数据
bool isStart;
MapDataModel mapData;
int userId;
double speed;
double power;
double gradev;
double elevation;
double cadance;
double heartRate;
int ticks;
double totalDistance;
double currentSlope;
double nextSlope;
double nextSlopeDistance;
double distance;
public int UserId { get => userId; }
public bool IsStart { get => isStart; }
public double Speed { get => speed; }
public double Power { get => power; }
public double Cadance { get => cadance; }
public double HeartRate { get => heartRate; }
public int TotalTicks { get => ticks; }
public double TotalDistance { get => totalDistance; }
public double CurrentSlope { get => currentSlope; }
public double NextSlope { get => nextSlope;}
public double NextSlopeDistance { get => nextSlopeDistance; }
public double Gradev { get => gradev; }
public double Elevation { get => elevation; }
#endregion
void Start()
{
characterAnimator = GetComponentInChildren<Animator>();
InitializePlayer();
var mainController = transform.parent.GetComponent<MainController>();
mapData = mainController.GetMapData();//获取路书信息
InitializePlayer(mainController.GetCenterCoordinate());//初始人物
}
//初始化人物
void InitializePlayer()
{
//获取玩家初始距离
currentlatlong = map.WorldToGeoPosition(transform.localPosition);
nextlatlong = currentlatlong;
totalDistance = 0;
ticks = 0;
}
void Update()
{
timer -= Time.deltaTime;
if (timer <= 0 && GameManger.IsStart)//定时器
if (timer <= 0)//定时器 一秒执行一次
{
ticks++;
Riding();
Run();
timer = 1.0f;
}
}
//计算当前玩家高度和坡度
Item find(double totalDistance)
#region 骑行逻辑
//当前人物骑行状态 true 开始 false 暂停
public void SetStart(bool start)
{
isStart = start;
}
//初始化玩家距离/朝向
void InitializePlayer(double[] coordinates)
{
ticks = 0;//当前骑行时间
//初始化人物位置
totalDistance = 10;//TODO:根据骑行模式动态取值
currentlatlong = Along(totalDistance);//new Vector2d(coordinates[0], coordinates[1]);//当前坐标
nextlatlong = currentlatlong;//下一秒坐标
////初始化人物转向
//var secondPlace = mapData.List[10].Point;
//var secondVect3d = map.GeoToWorldPosition( new Vector2d(secondPlace[0], secondPlace[1]));
//Quaternion firstRotation = Quaternion.LookRotation(transform.localPosition - secondVect3d);
//character.transform.rotation = Quaternion.Euler(0, firstRotation.eulerAngles.y, 0);
}
//骑行中
void Run()
{
if (IsStart)
{
//CamControl();
ComputeMapData();//计算海拔&坡度&下一个点信息
power = 300;//功率
speed = Helper.CalculateSpeed(elevation, gradev, power, 65, 7);
distance = Math.Round(speed / 3600, 5);
totalDistance += distance;
characterAnimator.SetBool("IsRide", false);//初始化动画状态
if (totalDistance <= mapData.TotalDistance)
{
ticks++;
if (distance > 0)
{
characterAnimator.SetBool("IsRide", true);//开始移动动画
nextlatlong = Along(totalDistance);//下一个坐标
nextPos = map.GeoToWorldPosition(nextlatlong);//下一个点
prePos = transform.localPosition;//当前点
StartCoroutine(LookAtNextPos());//转向
StartCoroutine(MoveTo());//移动
}
}
else
{
//TODO保存骑行数据
}
}
else
{
characterAnimator.SetBool("IsRide", false);
}
}
//TODO:骑行结束
void Finish()
{
//MapInterruptRecordApi api = new MapInterruptRecordApi();
//api.Add(null, null);
}
#endregion
#region 工具类
//当前距离所在的海拔/坡度/距离 下一个点的坡度以及剩余距离
void ComputeMapData()
{
double sumDistance = 0;
MapDataModel mapDataModel = GameManger.MapData;
foreach (var item in mapDataModel.List)
var pointList = mapData.List;
int index = 0;
for (int i = 0; i < pointList.Count; i++)
{
sumDistance += item.Distance;
if (totalDistance < sumDistance)
sumDistance += pointList[i].Distance;
if (totalDistance >= sumDistance)
{
return item;
index = i;
break;
}
}
return mapDataModel.List[0];
//计算当前海拔和坡度
elevation = pointList[index].Elevation;
gradev = pointList[index].Grade;
//计算下一个点的坡度和距离
int nextIndex = index == pointList.Count - 1 ? index : index + 1;
nextSlope = pointList[nextIndex].Grade;
nextSlopeDistance = sumDistance + pointList[nextIndex].Distance - totalDistance;
}
void Riding()
//根据距离计算坐标
Vector2d Along(double endDistance)
{
//yield return new WaitForSeconds(1.0f);
////读取当前速度以及骑行距离
MapDataModel mapDataModel = GameManger.MapData;
Item nextRange = find(totalDistance);
double elevation = nextRange.Elevation;
double gradev = nextRange.Grade;
double power = Random.Range(700, 2000);//TODO
double distance = Helper.CalculateSpeed(elevation, gradev, power, 65, 7) / 3600;
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);
}
return nextlatlong;
}
#endregion
characterAnimator.SetBool("IsRide", false);
totalDistance += distance;
if (totalDistance <= mapDataModel.TotalDistance)
{
if (distance > 0)
{
var v = GameManger.Along(totalDistance);
StartCoroutine(CamControl());
//设定动画状态
characterAnimator.SetBool("IsRide", true);
nextPos = map.GeoToWorldPosition(v);
prePos = transform.localPosition;
//转向
StartCoroutine(LookAtNextPos());
//移动
StartCoroutine(MoveTo());
}
}
}
IEnumerator MoveTo()
{
//让人物移动分点增加动画的流畅度
float t = 0;
while (t < 1)
{
t += Time.deltaTime;
Vector3 v = Vector3.Lerp(transform.localPosition, nextPos, t);
transform.localPosition = v;
yield return null;
}
}
#region Character : Rotation
IEnumerator LookAtNextPos()
#region 人物移动与转向控制
IEnumerator LookAtNextPos()
{
Quaternion neededRotation = Quaternion.LookRotation(transform.localPosition - nextPos);
Quaternion thisRotation = character.transform.localRotation;
@@ -126,16 +204,30 @@ namespace Assets.Scenes.Ride.Scripts
yield return null;
}
}
//人物移动控制
IEnumerator MoveTo()
{
//让人物移动分点增加动画的流畅度
float t = 0;
while (t < 1)
{
t += Time.deltaTime;
Vector3 v = Vector3.Lerp(prePos, nextPos, t);
transform.localPosition = v;
yield return null;
}
}
#endregion
#region CameraControl
#region 相机控制
[Header("CameraSettings")]
[SerializeField]
Camera cam;
Vector3 previousPos = Vector3.zero;
Vector3 deltaPos = Vector3.zero;
IEnumerator CamControl()
IEnumerator CamControl()//TODO 替换成cinemachine
{
if (cam != null)
{
@@ -26,6 +26,7 @@ namespace Assets.Scenes.Ride.Scripts
private int _counter;
GameObject _directionsGO;
MainController mainCotroller;
protected virtual void Awake()
{
@@ -39,6 +40,7 @@ namespace Assets.Scenes.Ride.Scripts
public void Start()
{
mainCotroller = transform.parent.GetComponent<MainController>();
foreach (var modifier in MeshModifiers)
{
modifier.Initialize();
@@ -66,14 +68,14 @@ namespace Assets.Scenes.Ride.Scripts
var meshData = new MeshData();
var dat = new List<Vector3>();
var mapData = GameManger.MapData;
var mapData = mainCotroller.GetMapData();
if (mapData != null)
{
foreach (var mapDataItem in mapData.List)
{
var point = mapDataItem.Point;
Vector3 item = _map.GeoToWorldPosition(new Vector2d(point[0], point[1]));
item.y += 0.4f;
item.y += 0.2f;
dat.Add(item);
}
var feat = new VectorFeatureUnity();
+18
View File
@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StartGame : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1fb28883cdccb754f96b10ee3509d5ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+72
View File
@@ -0,0 +1,72 @@
using UnityEngine;
using UnityEngine.UI;
namespace Assets.Scenes.Ride.Scripts
{
public class UIManager : MonoBehaviour
{
[SerializeField]
Button startBtn;
[SerializeField]
Text speedTxt;
[SerializeField]
Text powerTxt;
[SerializeField]
Text timerTxt;
[SerializeField]
Text countDownTxt;
PlayerController playerController;
private float timeRemaining = 1f;
private int count = 0;
// Start is called before the first frame update
void Start()
{
startBtn.onClick.AddListener(StartRide);
}
private void StartRide()
{
playerController = transform.parent.Find("Player").GetComponent<PlayerController>();
//加个5秒钟倒计时
count = 5;
startBtn.gameObject.SetActive(false);
countDownTxt.gameObject.SetActive(true);
countDownTxt.text = count.ToString();
}
// Update is called once per frame
void Update()
{
if (playerController != null)
{
speedTxt.text = $"{playerController.Speed}";
powerTxt.text = $"{playerController.Power}";
timerTxt.text = Helper.FormatTicks(playerController.TotalTicks);
if (count > 0)
{
timeRemaining -= Time.deltaTime;
if (timeRemaining <= 0)//定时器
{
count--;
if (count == 0)
{
playerController.SetStart(true);
countDownTxt.gameObject.SetActive(false);
}
timeRemaining = 1.0f;
}
}
countDownTxt.text = count.ToString();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86aa3e408146cb248a4a5eff052ffdaa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: