Multi-drag and stretching for keyframes
This commit is contained in:
parent
f449a9b4e2
commit
ab5a2a4c02
Binary file not shown.
|
@ -242,6 +242,8 @@ MonoBehaviour:
|
||||||
maxGhosts: 50
|
maxGhosts: 50
|
||||||
actorID: 0
|
actorID: 0
|
||||||
keyframeID: 0
|
keyframeID: 0
|
||||||
|
linkedSlider: {fileID: 0}
|
||||||
|
linkedOffset: 0
|
||||||
--- !u!1 &8359461402257861397
|
--- !u!1 &8359461402257861397
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
@ -8316,7 +8316,7 @@ MonoBehaviour:
|
||||||
actorCard: {fileID: 3804747680621674853}
|
actorCard: {fileID: 3804747680621674853}
|
||||||
animationTimelines: {fileID: 1100016168}
|
animationTimelines: {fileID: 1100016168}
|
||||||
actorBodies: {fileID: 1828035561}
|
actorBodies: {fileID: 1828035561}
|
||||||
stretchkeyframesToggle: {fileID: 462332576}
|
stretchKeyframesToggle: {fileID: 462332576}
|
||||||
playBackSpeedField: {fileID: 1579799916}
|
playBackSpeedField: {fileID: 1579799916}
|
||||||
playToggleButton: {fileID: 79733375}
|
playToggleButton: {fileID: 79733375}
|
||||||
actorBodyPrefab: {fileID: -4411442180840688308, guid: dc4c8b005322f3b46a2f122a55f38db2,
|
actorBodyPrefab: {fileID: -4411442180840688308, guid: dc4c8b005322f3b46a2f122a55f38db2,
|
||||||
|
@ -17458,7 +17458,7 @@ MonoBehaviour:
|
||||||
m_TargetGraphic: {fileID: 922060210}
|
m_TargetGraphic: {fileID: 922060210}
|
||||||
m_HandleRect: {fileID: 922060209}
|
m_HandleRect: {fileID: 922060209}
|
||||||
m_Direction: 2
|
m_Direction: 2
|
||||||
m_Value: 1
|
m_Value: 0
|
||||||
m_Size: 1
|
m_Size: 1
|
||||||
m_NumberOfSteps: 0
|
m_NumberOfSteps: 0
|
||||||
m_OnValueChanged:
|
m_OnValueChanged:
|
||||||
|
|
|
@ -34,15 +34,14 @@ namespace RimWorldAnimationStudio
|
||||||
HeadBob.Clear();
|
HeadBob.Clear();
|
||||||
GenitalAngle.Clear();
|
GenitalAngle.Clear();
|
||||||
|
|
||||||
|
int keyframePosition = 0;
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
|
|
||||||
|
keyframes[keyframes.Count - 1].tickDuration = 1;
|
||||||
|
|
||||||
foreach (PawnKeyframe frame in keyframes)
|
foreach (PawnKeyframe frame in keyframes)
|
||||||
{ duration += frame.tickDuration; }
|
{ duration += frame.tickDuration; }
|
||||||
|
|
||||||
int keyframePosition = 0;
|
|
||||||
|
|
||||||
keyframes[keyframes.Count - 1].tickDuration = 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < keyframes.Count; i++)
|
for (int i = 0; i < keyframes.Count; i++)
|
||||||
{
|
{
|
||||||
PawnKeyframe keyframe = keyframes[i];
|
PawnKeyframe keyframe = keyframes[i];
|
||||||
|
@ -82,7 +81,7 @@ namespace RimWorldAnimationStudio
|
||||||
quiver.Add(keyframePosition + keyframe.tickDuration - 1, false);
|
quiver.Add(keyframePosition + keyframe.tickDuration - 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyframe.atTick = keyframePosition + 1;
|
keyframe.atTick = keyframePosition + Constants.minTick;
|
||||||
keyframePosition += keyframe.tickDuration;
|
keyframePosition += keyframe.tickDuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
namespace RimWorldAnimationStudio
|
namespace RimWorldAnimationStudio
|
||||||
{
|
{
|
||||||
|
@ -45,5 +46,10 @@ namespace RimWorldAnimationStudio
|
||||||
|
|
||||||
public bool HasValidKeyframeID()
|
public bool HasValidKeyframeID()
|
||||||
{ return keyframeID >= 100000 && keyframeID < 1000000; }
|
{ return keyframeID >= 100000 && keyframeID < 1000000; }
|
||||||
|
|
||||||
|
public KeyframeSlider GetKeyframeSlider()
|
||||||
|
{
|
||||||
|
return Selectable.allSelectablesArray.FirstOrDefault(x => x.GetComponent<KeyframeSlider>()?.keyframeID == keyframeID)?.GetComponent< KeyframeSlider>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,15 @@ namespace RimWorldAnimationStudio
|
||||||
|
|
||||||
private PawnAnimationClip clip;
|
private PawnAnimationClip clip;
|
||||||
private PawnKeyframe keyframe;
|
private PawnKeyframe keyframe;
|
||||||
private float dragTimeStart = -1f;
|
|
||||||
|
|
||||||
public void Initialize(AnimationTimeline timeline, int actorID, int keyframeID)
|
private float dragTimeStart = -1f;
|
||||||
|
private int dragTickStart = -1;
|
||||||
|
|
||||||
|
public KeyframeSlider linkedSlider;
|
||||||
|
public Keyframe pivotKeyframe;
|
||||||
|
public int linkedOffset;
|
||||||
|
|
||||||
|
public void Initialize(AnimationTimeline timeline, int actorID, int keyframeID)
|
||||||
{
|
{
|
||||||
this.timeline = timeline;
|
this.timeline = timeline;
|
||||||
this.clip = Workspace.Instance.GetPawnAnimationClip(actorID);
|
this.clip = Workspace.Instance.GetPawnAnimationClip(actorID);
|
||||||
|
@ -48,8 +54,6 @@ namespace RimWorldAnimationStudio
|
||||||
keyframe.atTick = (int)value;
|
keyframe.atTick = (int)value;
|
||||||
clip.BuildSimpleCurves();
|
clip.BuildSimpleCurves();
|
||||||
|
|
||||||
//AnimationController.Instance.stageTick = keyframe.atTick.Value;
|
|
||||||
|
|
||||||
timeline.InitiateUpdateOfGhostFrames();
|
timeline.InitiateUpdateOfGhostFrames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,52 +103,76 @@ namespace RimWorldAnimationStudio
|
||||||
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftCommand))
|
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftCommand))
|
||||||
{ Workspace.keyframeID.Add(keyframeID); }
|
{ Workspace.keyframeID.Add(keyframeID); }
|
||||||
|
|
||||||
else
|
else if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
|
||||||
{ Workspace.keyframeID = new List<int> { keyframeID }; }
|
{ Workspace.keyframeID = new List<int> { keyframeID }; }
|
||||||
|
|
||||||
if (eventData.clickCount >= 2)
|
if (eventData.clickCount >= 2)
|
||||||
{ AnimationController.Instance.stageTick = keyframe.atTick.Value; }
|
{ AnimationController.Instance.stageTick = keyframe.atTick.Value; }
|
||||||
|
|
||||||
//Workspace.Instance.RecordEvent("Keyframe selected");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnBeginDrag(PointerEventData eventData)
|
public void OnBeginDrag(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
//AnimationController.Instance.stageTick = keyframe.atTick.Value;
|
|
||||||
Workspace.actorID = actorID;
|
Workspace.actorID = actorID;
|
||||||
|
|
||||||
Workspace.keyframeID = new List<int> { keyframeID };
|
|
||||||
|
|
||||||
dragTimeStart = Time.unscaledTime;
|
dragTimeStart = Time.unscaledTime;
|
||||||
|
dragTickStart = keyframe.atTick.Value;
|
||||||
|
|
||||||
|
if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
|
||||||
|
{ Workspace.keyframeID = new List<int> { keyframeID }; }
|
||||||
|
|
||||||
|
List<PawnKeyframe> selectedKeyframes = Workspace.Instance.GetPawnKeyframes(Workspace.keyframeID).Except(new List<PawnKeyframe>() { keyframe })?.ToList();
|
||||||
|
|
||||||
|
// Link other slected keyframes to the movement of this one
|
||||||
|
if (selectedKeyframes.NotNullOrEmpty())
|
||||||
|
{
|
||||||
|
foreach (PawnKeyframe selectedKeyframe in selectedKeyframes)
|
||||||
|
{
|
||||||
|
KeyframeSlider unlinkedSlider = selectedKeyframe.GetKeyframeSlider();
|
||||||
|
|
||||||
|
if (unlinkedSlider != null)
|
||||||
|
{
|
||||||
|
unlinkedSlider.linkedSlider = this;
|
||||||
|
unlinkedSlider.linkedOffset = unlinkedSlider.keyframe.atTick.Value - keyframe.atTick.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pivotKeyframe = keyframe.atTick < selectedKeyframes[0].atTick ? selectedKeyframes.Last() : selectedKeyframes.First();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDrag(PointerEventData eventData)
|
public override void OnDrag(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
if (keyframe.atTick == 1)
|
Workspace.actorID = actorID;
|
||||||
{ value = 1; return; }
|
|
||||||
|
|
||||||
|
// The first keyframe can't be moved
|
||||||
|
if (keyframe.atTick == Constants.minTick)
|
||||||
|
{ value = Constants.minTick; return; }
|
||||||
|
|
||||||
|
// Sticky drag
|
||||||
if (Time.unscaledTime - dragTimeStart < 0.05f) return;
|
if (Time.unscaledTime - dragTimeStart < 0.05f) return;
|
||||||
|
|
||||||
interactable = true;
|
interactable = true;
|
||||||
base.OnDrag(eventData);
|
base.OnDrag(eventData);
|
||||||
|
|
||||||
|
// Snap to nearest keyframe (on another timeline)
|
||||||
int targetTick = Workspace.FindClosestKeyFrameAtTick(keyframe.atTick.Value, Mathf.CeilToInt(Workspace.StageWindowSize * 0.01f), actorID);
|
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)
|
if (Input.GetKey(KeyCode.LeftShift) && Workspace.Instance.DoesPawnKeyframeExistAtTick(Workspace.stageID, actorID, targetTick) == false)
|
||||||
{ value = (float)targetTick; }
|
{ value = (float)targetTick; }
|
||||||
|
|
||||||
// Prevent frames from being moved to tick 1
|
// Prevent other frames from being moved to the first keyframe
|
||||||
if (value == 1)
|
if (value == Constants.minTick)
|
||||||
{ value = 2; }
|
{ value = Constants.minTick + 1; }
|
||||||
|
|
||||||
//AnimationController.Instance.stageTick = keyframe.atTick.Value;
|
|
||||||
Workspace.actorID = actorID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEndDrag(PointerEventData eventData)
|
public void OnEndDrag(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
if (keyframe.atTick == 1)
|
if (keyframe.atTick == Constants.minTick)
|
||||||
{ value = 1; return; }
|
{ value = Constants.minTick; return; }
|
||||||
|
|
||||||
|
foreach (Selectable otherSlider in Selectable.allSelectablesArray)
|
||||||
|
{
|
||||||
|
if (otherSlider is KeyframeSlider)
|
||||||
|
{ Debug.Log("unlinked keyframes"); (otherSlider as KeyframeSlider).linkedSlider = null; }
|
||||||
|
}
|
||||||
|
|
||||||
interactable = false;
|
interactable = false;
|
||||||
Workspace.Instance.RecordEvent("Keyframe move");
|
Workspace.Instance.RecordEvent("Keyframe move");
|
||||||
|
@ -154,25 +182,60 @@ namespace RimWorldAnimationStudio
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
|
// Update outdated values
|
||||||
|
if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
|
||||||
|
{ linkedSlider = null; }
|
||||||
|
|
||||||
|
else if (AnimationController.Instance.stretchKeyframesToggle.isOn && linkedSlider != null && linkedSlider.IsPivotKeyframe(keyframe) == false)
|
||||||
|
{
|
||||||
|
//int minTick = linkedSlider.pivotKeyframe.atTick.Value + GetIndexAmongstSelectedKeyframes();
|
||||||
|
//value = Mathf.Clamp(Mathf.CeilToInt(linkedSlider.keyframe.atTick.Value + linkedOffset * linkedSlider.ScaledOffsetFromPivot()), minTick, Workspace.StageWindowSize);
|
||||||
|
value = Mathf.CeilToInt(linkedSlider.keyframe.atTick.Value + linkedOffset * linkedSlider.ScaledOffsetFromPivot());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (AnimationController.Instance.stretchKeyframesToggle.isOn == false && linkedSlider != null)
|
||||||
|
{ value = Mathf.Clamp(linkedSlider.keyframe.atTick.Value + linkedOffset, Constants.minTick + 1, Workspace.StageWindowSize); }
|
||||||
|
|
||||||
|
else if (keyframe.atTick.Value != value)
|
||||||
|
{ value = keyframe.atTick.Value; }
|
||||||
|
|
||||||
|
// Update key color
|
||||||
if (keyframe.atTick.HasValue && Workspace.keyframeID.Contains(keyframeID) && AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
if (keyframe.atTick.HasValue && Workspace.keyframeID.Contains(keyframeID) && AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
||||||
{ handleImage.color = Constants.ColorPurple; }
|
{ handleImage.color = Constants.ColorPurple; }
|
||||||
|
|
||||||
else if (Workspace.keyframeID.Contains(keyframeID))
|
else if (Workspace.keyframeID.Contains(keyframeID))
|
||||||
{ handleImage.color = Constants.ColorCyan; }
|
{ handleImage.color = Constants.ColorCyan; }
|
||||||
|
|
||||||
else if (keyframe.atTick.HasValue && AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
else if (AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
||||||
{ handleImage.color = Constants.ColorPink; }
|
{ handleImage.color = Constants.ColorPink; }
|
||||||
|
|
||||||
else
|
else
|
||||||
{ handleImage.color = Constants.ColorGrey; }
|
{ handleImage.color = Constants.ColorGrey; }
|
||||||
|
|
||||||
|
// Show sound symbol
|
||||||
string soundDef = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID)?.soundEffect;
|
string soundDef = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID)?.soundEffect;
|
||||||
|
soundIcon.SetActive(soundDef != null && soundDef != "" && soundDef != "None");
|
||||||
|
}
|
||||||
|
|
||||||
if (soundDef != null && soundDef != "" && soundDef != "None")
|
public float ScaledOffsetFromPivot()
|
||||||
{ soundIcon.SetActive(true); }
|
{
|
||||||
|
//if (IsPivotKeyframe(keyframe)) return 1f;
|
||||||
|
if (dragTickStart == pivotKeyframe.atTick.Value) return 0f;
|
||||||
|
|
||||||
else
|
return (float)(keyframe.atTick.Value - pivotKeyframe.atTick.Value) / (dragTickStart - pivotKeyframe.atTick.Value);
|
||||||
{ soundIcon.SetActive(false); }
|
}
|
||||||
|
|
||||||
|
public bool IsPivotKeyframe(Keyframe otherKeyframe)
|
||||||
|
{
|
||||||
|
return pivotKeyframe == otherKeyframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetIndexAmongstSelectedKeyframes()
|
||||||
|
{
|
||||||
|
List<PawnKeyframe> selectedKeyframes = Workspace.Instance.GetPawnKeyframes(Workspace.keyframeID).OrderBy(x => x.atTick)?.ToList();
|
||||||
|
if (selectedKeyframes.NullOrEmpty() || selectedKeyframes.Contains(keyframe) == false) return -1;
|
||||||
|
|
||||||
|
return selectedKeyframes.IndexOf(keyframe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace RimWorldAnimationStudio
|
||||||
|
|
||||||
if (Workspace.stageID != transform.GetSiblingIndex())
|
if (Workspace.stageID != transform.GetSiblingIndex())
|
||||||
{
|
{
|
||||||
AnimationController.Instance.stageTick = 1;
|
AnimationController.Instance.stageTick = Constants.minTick;
|
||||||
Workspace.Instance.RecordEvent("Stage selected");
|
Workspace.Instance.RecordEvent("Stage selected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace RimWorldAnimationStudio
|
||||||
{
|
{
|
||||||
[Header("Animation settings")]
|
[Header("Animation settings")]
|
||||||
public bool isAnimating = false;
|
public bool isAnimating = false;
|
||||||
public int stageTick = 1;
|
public int stageTick = Constants.minTick;
|
||||||
|
|
||||||
[Header("Object references")]
|
[Header("Object references")]
|
||||||
public Slider stageTimelineSlider;
|
public Slider stageTimelineSlider;
|
||||||
|
@ -25,7 +25,7 @@ namespace RimWorldAnimationStudio
|
||||||
public ActorCard actorCard;
|
public ActorCard actorCard;
|
||||||
public Transform animationTimelines;
|
public Transform animationTimelines;
|
||||||
public Transform actorBodies;
|
public Transform actorBodies;
|
||||||
public Toggle stretchkeyframesToggle;
|
public Toggle stretchKeyframesToggle;
|
||||||
public InputField playBackSpeedField;
|
public InputField playBackSpeedField;
|
||||||
public Button playToggleButton;
|
public Button playToggleButton;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace RimWorldAnimationStudio
|
||||||
public GameObject animationTimelinePrefab;
|
public GameObject animationTimelinePrefab;
|
||||||
|
|
||||||
// Private timing variables
|
// Private timing variables
|
||||||
private int lastStageTick = 1;
|
private int lastStageTick = Constants.minTick;
|
||||||
private float timeSinceLastUpdate = 0;
|
private float timeSinceLastUpdate = 0;
|
||||||
private int cycleIndex = 0;
|
private int cycleIndex = 0;
|
||||||
private bool isDirty = true;
|
private bool isDirty = true;
|
||||||
|
@ -57,7 +57,7 @@ namespace RimWorldAnimationStudio
|
||||||
{ Initialize(); }
|
{ Initialize(); }
|
||||||
|
|
||||||
// Update tick if animating
|
// Update tick if animating
|
||||||
stageTick = Mathf.Clamp(stageTick, 1, Workspace.StageWindowSize);
|
stageTick = Mathf.Clamp(stageTick, Constants.minTick, Workspace.StageWindowSize);
|
||||||
|
|
||||||
if (isAnimating)
|
if (isAnimating)
|
||||||
{
|
{
|
||||||
|
@ -72,12 +72,12 @@ namespace RimWorldAnimationStudio
|
||||||
if (stageTick > Workspace.StageWindowSize)
|
if (stageTick > Workspace.StageWindowSize)
|
||||||
{
|
{
|
||||||
if (stageLoopDropdown.value == 1)
|
if (stageLoopDropdown.value == 1)
|
||||||
{ stageTick = 1; }
|
{ stageTick = Constants.minTick; }
|
||||||
|
|
||||||
else if (stageLoopDropdown.value >= 2)
|
else if (stageLoopDropdown.value >= 2)
|
||||||
{
|
{
|
||||||
++cycleIndex;
|
++cycleIndex;
|
||||||
stageTick = 1;
|
stageTick = Constants.minTick;
|
||||||
|
|
||||||
if ((stageLoopDropdown.value == 2 && cycleIndex >= int.Parse(cyclesNormalField.text)) ||
|
if ((stageLoopDropdown.value == 2 && cycleIndex >= int.Parse(cyclesNormalField.text)) ||
|
||||||
(stageLoopDropdown.value == 3 && cycleIndex >= int.Parse(cyclesFastField.text)))
|
(stageLoopDropdown.value == 3 && cycleIndex >= int.Parse(cyclesFastField.text)))
|
||||||
|
@ -148,7 +148,7 @@ namespace RimWorldAnimationStudio
|
||||||
bool requiresGenitals = actor.requiredGenitals.Any(x => x == "Penis") || Workspace.animationDef.actors[actorID].isFucking;
|
bool requiresGenitals = actor.requiredGenitals.Any(x => x == "Penis") || Workspace.animationDef.actors[actorID].isFucking;
|
||||||
|
|
||||||
float clipPercent = (float)(stageTick % clip.duration) / clip.duration;
|
float clipPercent = (float)(stageTick % clip.duration) / clip.duration;
|
||||||
if (stageTick == clip.duration) clipPercent = 1f;
|
if (stageTick > Constants.minTick && stageTick == clip.duration) clipPercent = 1f;
|
||||||
|
|
||||||
if (Workspace.animationDef.animationStages[Workspace.stageID].isLooping == false)
|
if (Workspace.animationDef.animationStages[Workspace.stageID].isLooping == false)
|
||||||
{ clipPercent = (float)stageTick / clip.duration; }
|
{ clipPercent = (float)stageTick / clip.duration; }
|
||||||
|
@ -401,7 +401,7 @@ namespace RimWorldAnimationStudio
|
||||||
if (tickToPasteAt < 1) continue;
|
if (tickToPasteAt < 1) continue;
|
||||||
if (tickToPasteAt > Workspace.StageWindowSize)
|
if (tickToPasteAt > Workspace.StageWindowSize)
|
||||||
{
|
{
|
||||||
if (stretchkeyframesToggle.isOn)
|
if (stretchKeyframesToggle.isOn)
|
||||||
{ ResizeStageWindowSize(tickToPasteAt); }
|
{ ResizeStageWindowSize(tickToPasteAt); }
|
||||||
|
|
||||||
else continue;
|
else continue;
|
||||||
|
@ -487,7 +487,7 @@ namespace RimWorldAnimationStudio
|
||||||
|
|
||||||
if (keyframe == null || clip == null) return;
|
if (keyframe == null || clip == null) return;
|
||||||
|
|
||||||
if (keyframe.atTick == 1 && force == false)
|
if (keyframe.atTick == Constants.minTick && force == false)
|
||||||
{ Debug.LogWarning("Cannot delete key frame - the first key frame of an animation clip cannot be deleted"); return; }
|
{ Debug.LogWarning("Cannot delete key frame - the first key frame of an animation clip cannot be deleted"); return; }
|
||||||
|
|
||||||
if (clip.keyframes.Count <= 2 && force == false)
|
if (clip.keyframes.Count <= 2 && force == false)
|
||||||
|
@ -527,7 +527,7 @@ namespace RimWorldAnimationStudio
|
||||||
if (Workspace.animationDef == null) return;
|
if (Workspace.animationDef == null) return;
|
||||||
|
|
||||||
int.TryParse(animationClipTimeField.text, out int newStageTick);
|
int.TryParse(animationClipTimeField.text, out int newStageTick);
|
||||||
stageTick = Mathf.Clamp(newStageTick, 1, Workspace.StageWindowSize);
|
stageTick = Mathf.Clamp(newStageTick, Constants.minTick, Workspace.StageWindowSize);
|
||||||
stageTimelineSlider.value = stageTick;
|
stageTimelineSlider.value = stageTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,8 +540,11 @@ namespace RimWorldAnimationStudio
|
||||||
|
|
||||||
Debug.Log("Resizing animation clip length to " + newStageWindowSize.ToString() + " ticks.");
|
Debug.Log("Resizing animation clip length to " + newStageWindowSize.ToString() + " ticks.");
|
||||||
|
|
||||||
if (stretchkeyframesToggle.isOn)
|
if (stretchKeyframesToggle.isOn)
|
||||||
{ StretchKeyframes(newStageWindowSize); }
|
{
|
||||||
|
List<PawnKeyframe> keyframes = Workspace.animationDef.animationStages[Workspace.stageID].animationClips.SelectMany(x => x.keyframes)?.ToList();
|
||||||
|
StretchKeyframes(keyframes, Workspace.StageWindowSize, newStageWindowSize);
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -566,7 +569,7 @@ namespace RimWorldAnimationStudio
|
||||||
ResizeStageWindowSize(newStageWindowSize);
|
ResizeStageWindowSize(newStageWindowSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StretchKeyframes(int newStageWindowSize)
|
/*public void StretchKeyframes(int newStageWindowSize)
|
||||||
{
|
{
|
||||||
float scale = (float)newStageWindowSize / Workspace.StageWindowSize;
|
float scale = (float)newStageWindowSize / Workspace.StageWindowSize;
|
||||||
|
|
||||||
|
@ -580,6 +583,39 @@ namespace RimWorldAnimationStudio
|
||||||
|
|
||||||
clip.BuildSimpleCurves();
|
clip.BuildSimpleCurves();
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public void StretchKeyframes(List<PawnKeyframe> keyframesToStretch, int v1, int v2)
|
||||||
|
{
|
||||||
|
int v0 = keyframesToStretch.Min(x => x.atTick.Value);
|
||||||
|
|
||||||
|
if (v1 == v0)
|
||||||
|
{ OffsetKeyframes(keyframesToStretch, v1, v2); return; }
|
||||||
|
|
||||||
|
float scaleFactor = (float)(v2 - v0) / (v1 - v0);
|
||||||
|
|
||||||
|
foreach (PawnKeyframe keyframe in keyframesToStretch)
|
||||||
|
{
|
||||||
|
keyframe.atTick = Mathf.RoundToInt(scaleFactor * (keyframe.atTick.Value - v0) + v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(PawnAnimationClip clip in Workspace.animationDef.animationStages[Workspace.stageID].animationClips)
|
||||||
|
{ clip.BuildSimpleCurves(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OffsetKeyframes(List<PawnKeyframe> keyframesToOffset, int v1, int v2)
|
||||||
|
{
|
||||||
|
float offset = v2 - v1;
|
||||||
|
|
||||||
|
foreach (PawnKeyframe keyframe in keyframesToOffset)
|
||||||
|
{
|
||||||
|
keyframe.atTick = Mathf.RoundToInt(keyframe.atTick.Value + offset);
|
||||||
|
Debug.Log(keyframe.atTick);
|
||||||
|
Workspace.Instance.GetAnimationClipThatOwnsKeyframe(keyframe.keyframeID, out int clipID).BuildSimpleCurves();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (PawnAnimationClip clip in Workspace.animationDef.animationStages[Workspace.stageID].animationClips)
|
||||||
|
{ clip.BuildSimpleCurves(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResizeStageWindowSize(int newStageWindowSize)
|
public void ResizeStageWindowSize(int newStageWindowSize)
|
||||||
|
|
|
@ -341,19 +341,19 @@ namespace RimWorldAnimationStudio
|
||||||
public void ToPreviousTick()
|
public void ToPreviousTick()
|
||||||
{
|
{
|
||||||
if (Workspace.animationDef == null) return;
|
if (Workspace.animationDef == null) return;
|
||||||
AnimationController.Instance.stageTick = Mathf.Clamp(AnimationController.Instance.stageTick - 1, 1, Workspace.StageWindowSize);
|
AnimationController.Instance.stageTick = Mathf.Clamp(AnimationController.Instance.stageTick - 1, Constants.minTick, Workspace.StageWindowSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToNextTick()
|
public void ToNextTick()
|
||||||
{
|
{
|
||||||
if (Workspace.animationDef == null) return;
|
if (Workspace.animationDef == null) return;
|
||||||
AnimationController.Instance.stageTick = Mathf.Clamp(AnimationController.Instance.stageTick + 1, 1, Workspace.StageWindowSize);
|
AnimationController.Instance.stageTick = Mathf.Clamp(AnimationController.Instance.stageTick + 1, Constants.minTick, Workspace.StageWindowSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToFirstTick()
|
public void ToFirstTick()
|
||||||
{
|
{
|
||||||
if (Workspace.animationDef == null) return;
|
if (Workspace.animationDef == null) return;
|
||||||
AnimationController.Instance.stageTick = 1;
|
AnimationController.Instance.stageTick = Constants.minTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToLastTick()
|
public void ToLastTick()
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace RimWorldAnimationStudio
|
||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
public static int defaultAnimationClipLength = 600;
|
public static int defaultAnimationClipLength = 600;
|
||||||
|
public static int minTick = 1;
|
||||||
public static int minAnimationClipLength = 2;
|
public static int minAnimationClipLength = 2;
|
||||||
public static int maxAnimationClipLength = 9999;
|
public static int maxAnimationClipLength = 9999;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@ namespace RimWorldAnimationStudio
|
||||||
if (animationDef.animationStages[stageID].stageWindowSize < 0)
|
if (animationDef.animationStages[stageID].stageWindowSize < 0)
|
||||||
{ animationDef.animationStages[stageID].stageWindowSize = animationDef.animationStages[stageID].animationClips.Select(x => x.duration).Max(); }
|
{ animationDef.animationStages[stageID].stageWindowSize = animationDef.animationStages[stageID].animationClips.Select(x => x.duration).Max(); }
|
||||||
|
|
||||||
|
Debug.Log(animationDef.animationStages[stageID].stageWindowSize);
|
||||||
|
|
||||||
|
|
||||||
return animationDef.animationStages[stageID].stageWindowSize;
|
return animationDef.animationStages[stageID].stageWindowSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue