Key snapping

This commit is contained in:
AbstractConcept 2022-10-03 21:45:52 -05:00
parent 5436410162
commit f275ed90ae
101 changed files with 253 additions and 117 deletions

View file

@ -128,6 +128,15 @@ namespace RimWorldAnimationStudio
interactable = true;
base.OnDrag(eventData);
int targetTick = Workspace.FindClosestKeyFrameAtTick(keyframe.atTick.Value, Mathf.CeilToInt(Workspace.StageWindowSize * 0.01f), actorID);
if (Input.GetKey(KeyCode.LeftShift) && Workspace.Instance.DoesPawnKeyframeExistAtTick(Workspace.stageID, actorID, targetTick) == false)
{ value = (float)targetTick; }
// Prevent frames from being moved to tick 1
if (value == 1)
{ value = 2; }
//AnimationController.Instance.stageTick = keyframe.atTick.Value;
Workspace.actorID = actorID;
}

View file

@ -95,8 +95,8 @@ namespace RimWorldAnimationStudio
else
{
stageTick = Workspace.StageWindowSize;
isAnimating = false;
//stageTick = Workspace.StageWindowSize;
//isAnimating = false;
}
}
}
@ -132,10 +132,10 @@ namespace RimWorldAnimationStudio
for (int actorID = 0; actorID < _actorBodies.Count; actorID++)
{
if (Workspace.stageID >= Workspace.animationDef?.animationStages.Count)
{ /*Debug.Log("Waiting for animation stage data to initialize...");*/ return; }
{ return; }
if (actorID >= Workspace.animationDef?.animationStages[Workspace.stageID]?.animationClips.Count)
{ /*Debug.Log("Waiting for animation clip data to initialize...");*/ return; }
{ return; }
Actor actor = Workspace.animationDef.actors[actorID];
PawnAnimationClip clip = Workspace.animationDef?.animationStages[Workspace.stageID]?.animationClips[actorID];
@ -146,6 +146,9 @@ namespace RimWorldAnimationStudio
float clipPercent = (float)(stageTick % clip.duration) / clip.duration;
if (stageTick == clip.duration) clipPercent = 1f;
if (Workspace.animationDef.animationStages[Workspace.stageID].isLooping == false)
{ clipPercent = (float)stageTick / clip.duration; }
AlienRaceDef alienRaceDef = actor.GetAlienRaceDef();
ActorBody actorBody = _actorBodies[actorID];
string bodyType = alienRaceDef.isHumanoid ? actor.bodyType : "None";
@ -155,15 +158,6 @@ namespace RimWorldAnimationStudio
float bodyAngle = clip.BodyAngle.Evaluate(clipPercent);
float headAngle = clip.HeadAngle.Evaluate(clipPercent);
/*if (bodyAngle < 0) bodyAngle = 360 - ((-1f * bodyAngle) % 360);
if (bodyAngle > 360) bodyAngle %= 360;
if (headAngle < 0) headAngle = 360 - ((-1f * headAngle) % 360);
if (headAngle > 360) headAngle %= 360;
bodyAngle = bodyAngle > 180 ? 180 - bodyAngle : bodyAngle;
headAngle = headAngle > 180 ? 180 - headAngle : headAngle;*/
int bodyFacing = (int)clip.BodyFacing.Evaluate(clipPercent);
int headFacing = (int)clip.HeadFacing.Evaluate(clipPercent);
@ -233,7 +227,9 @@ namespace RimWorldAnimationStudio
public void InitializeAnimationTimeline()
{
cyclesNormalField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicks / Workspace.StageWindowSize), 1).ToString();
cyclesFastField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicksQuick / Workspace.StageWindowSize), 1).ToString();
cyclesFastField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicksQuick / Workspace.StageWindowSize), 0).ToString();
Workspace.animationDef.animationStages[Workspace.stageID].isLooping = int.Parse(cyclesNormalField.text) > 1 ? true : false;
for (int actorID = 0; actorID < Workspace.animationDef.actors.Count; actorID++)
{

View file

@ -0,0 +1,26 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class SnapToKeyframe : MonoBehaviour, IDragHandler
{
private Slider slider;
public void Start()
{
slider = GetComponent<Slider>();
}
public void OnDrag(PointerEventData eventData)
{
int targetTick = Workspace.FindClosestKeyFrameAtTick((int)slider.value, Mathf.CeilToInt(Workspace.StageWindowSize * 0.01f));
if (Input.GetKey(KeyCode.LeftShift))
{ slider.value = (float)targetTick; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b19816966eab6a4eba748f04532fb61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -103,7 +103,77 @@ namespace RimWorldAnimationStudio
return null;
}
public bool DoesPawnKeyframeExistAtTick(int stageID, int actorID, int atTick)
{
return animationDef.animationStages[stageID].animationClips[actorID].keyframes.Any(x => x.atTick == atTick);
}
public static void FindAdjacentKeyframes(int atTick, out PawnKeyframe prevKeyframe, out PawnKeyframe nextKeyframe, int actorID = -1, int excludedActorID = -1, bool ignoreSelf = true, int searchDistance = int.MaxValue)
{
prevKeyframe = null;
nextKeyframe = null;
List<PawnKeyframe> keyframesToCheck;
if (actorID >= 0)
{ keyframesToCheck = animationDef.animationStages[stageID].animationClips[actorID].keyframes; }
else
{
keyframesToCheck = animationDef.animationStages[stageID].animationClips.Where(x =>
animationDef.animationStages[stageID].animationClips.IndexOf(x) != excludedActorID).SelectMany(x => x.keyframes)?.ToList();
}
foreach (PawnKeyframe keyframe in keyframesToCheck)
{
if (keyframe.atTick <= atTick && atTick - keyframe.atTick <= searchDistance)
{
if (keyframe.atTick != atTick || ignoreSelf)
{ prevKeyframe = keyframe; }
else
{ prevKeyframe = null; }
}
if (nextKeyframe == null && keyframe.atTick > atTick && keyframe.atTick - atTick <= searchDistance)
{ nextKeyframe = keyframe; }
}
}
public static int FindClosestKeyFrameAtTick(int atTick, int searchDistance = int.MaxValue, int excludedActorID = -1)
{
List<PawnKeyframe> keyframesToCheck;
if (excludedActorID >= 0)
{
keyframesToCheck = animationDef.animationStages[stageID].animationClips.Where(x =>
animationDef.animationStages[stageID].animationClips.IndexOf(x) != excludedActorID).SelectMany(x => x.keyframes)?.ToList();
}
else
{ keyframesToCheck = animationDef.animationStages[stageID].animationClips.SelectMany(x => x.keyframes)?.ToList(); }
keyframesToCheck = keyframesToCheck.Where(x => Mathf.Abs(atTick - x.atTick.Value) <= searchDistance)?.ToList();
if (keyframesToCheck.NullOrEmpty())
{ return atTick; }
int minDist = int.MaxValue;
int bestAtTick = -1;
foreach (PawnKeyframe keyframe_ in keyframesToCheck)
{
if (Mathf.Abs(keyframe_.atTick.Value - atTick) < minDist)
{
minDist = Mathf.Abs(keyframe_.atTick.Value - atTick);
bestAtTick = keyframe_.atTick.Value;
}
}
return bestAtTick;
}
[SerializeField]
public LinkedList<HistoricRecord> pastSnapshots = new LinkedList<HistoricRecord>();
public LinkedList<HistoricRecord> futureSnapshots = new LinkedList<HistoricRecord>();