mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Manual timeline, cycle and actor tweaking
This commit is contained in:
parent
dfa564759b
commit
1dd7781179
165 changed files with 4040 additions and 166 deletions
|
@ -1,12 +1,73 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class ActorBody : MonoBehaviour
|
||||
public class ActorBody : MonoBehaviour, IPointerClickHandler, IDragHandler
|
||||
{
|
||||
public int actorID;
|
||||
|
||||
public SpriteRenderer bodyRenderer;
|
||||
public SpriteRenderer headRenderer;
|
||||
|
||||
public void Initialize(int actorID)
|
||||
{
|
||||
this.actorID = actorID;
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.pointerCurrentRaycast.gameObject.GetComponent<ActorBody>() == null)
|
||||
{ return; }
|
||||
|
||||
foreach (ActorBody actorBody in AnimationController.Instance.actorBodies)
|
||||
{
|
||||
if (actorBody == this)
|
||||
{ continue; }
|
||||
|
||||
actorBody.bodyRenderer.color = new Color(1f, 1f, 1f);
|
||||
actorBody.headRenderer.color = new Color(1f, 1f, 1f);
|
||||
}
|
||||
|
||||
bodyRenderer.color = new Color(0f, 1f, 0f);
|
||||
headRenderer.color = new Color(0f, 1f, 0f);
|
||||
|
||||
Workspace.actorID = actorID;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
||||
|
||||
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
|
||||
{
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyOffsetX = mousePosition.x;
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyOffsetZ = mousePosition.y;
|
||||
}
|
||||
|
||||
else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyAngle = angle;
|
||||
}
|
||||
|
||||
else if (Workspace.actorManipulationMode == ActorManipulationMode.Face)
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.up, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
int facing = -Mathf.RoundToInt(angle / 90f );
|
||||
facing = facing < 0 ? facing + 4 : facing;
|
||||
|
||||
Debug.Log(facing.ToString());
|
||||
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyFacing = facing;
|
||||
}
|
||||
|
||||
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
|
||||
clip.BuildSimpleCurves();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
67
Assets/Scripts/AnimationComponents/ActorBodyPart.cs
Normal file
67
Assets/Scripts/AnimationComponents/ActorBodyPart.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class ActorBodyPart : MonoBehaviour, IDragHandler, IPointerClickHandler
|
||||
{
|
||||
public SpriteRenderer bodyPartRenderer;
|
||||
public ActorBody parent;
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.pointerCurrentRaycast.gameObject.GetComponent<ActorBodyPart>() == null)
|
||||
{ return; }
|
||||
|
||||
foreach (ActorBody actorBody in AnimationController.Instance.actorBodies)
|
||||
{
|
||||
actorBody.bodyRenderer.color = new Color(1f, 1f, 1f);
|
||||
actorBody.headRenderer.color = new Color(1f, 1f, 1f);
|
||||
}
|
||||
|
||||
bodyPartRenderer.color = new Color(0f, 1f, 0f);
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
PawnKeyframe keyframe = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[parent.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID);
|
||||
|
||||
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
|
||||
{
|
||||
float distance = ((Vector2)mousePosition - (Vector2)transform.position).y;
|
||||
Vector3 headOffset = new Vector3(0f, 0.34f, 0f);
|
||||
headOffset = Quaternion.Euler(0, 0, keyframe.bodyAngle) * headOffset;
|
||||
|
||||
distance = Vector2.Dot(parent.transform.up, (Vector2)(mousePosition - parent.transform.position - headOffset));
|
||||
|
||||
Debug.Log(headOffset.ToString());
|
||||
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[parent.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).headBob = distance;
|
||||
}
|
||||
|
||||
else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[parent.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).headAngle = angle;
|
||||
}
|
||||
|
||||
else if (Workspace.actorManipulationMode == ActorManipulationMode.Face)
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.up, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
int facing = -Mathf.RoundToInt(angle / 90f);
|
||||
facing = facing < 0 ? facing + 4 : facing;
|
||||
|
||||
Debug.Log(facing.ToString());
|
||||
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[parent.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).headFacing = facing;
|
||||
}
|
||||
|
||||
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(parent.actorID);
|
||||
clip.BuildSimpleCurves();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/AnimationComponents/ActorBodyPart.cs.meta
Normal file
11
Assets/Scripts/AnimationComponents/ActorBodyPart.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b23e33f312d52c642b86f5f2138f4030
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -49,8 +49,6 @@ namespace RimWorldAnimationStudio
|
|||
if (keyframe.HasValidKeyframeID() == false)
|
||||
{ keyframe.GenerateKeyframeID(); }
|
||||
|
||||
Debug.Log(keyframe.atTick.Value);
|
||||
|
||||
BodyAngle.Add((float)keyframe.atTick / (float)duration, keyframe.bodyAngle, true);
|
||||
HeadAngle.Add((float)keyframe.atTick / (float)duration, keyframe.headAngle, true);
|
||||
BodyOffsetX.Add((float)keyframe.atTick / (float)duration, keyframe.bodyOffsetX, true);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
|
@ -25,8 +26,15 @@ namespace RimWorldAnimationStudio
|
|||
|
||||
public void GenerateKeyframeID()
|
||||
{
|
||||
keyframeID = Random.Range(100000, 1000000);
|
||||
Debug.Log("Generated ID: " + keyframeID);
|
||||
int _keyframeID = Random.Range(100000, 1000000);
|
||||
|
||||
if (Workspace.animationDef.animationStages.Any(x => x.animationClips.Any(y => y.keyframes.Any(z => z.keyframeID == _keyframeID))))
|
||||
{
|
||||
GenerateKeyframeID();
|
||||
return;
|
||||
}
|
||||
|
||||
keyframeID = _keyframeID;
|
||||
}
|
||||
|
||||
public bool HasValidKeyframeID()
|
||||
|
|
|
@ -36,6 +36,10 @@ namespace RimWorldAnimationStudio
|
|||
public AnimationTimeline animationTimelinePrefab;
|
||||
|
||||
private float currentTime = 0;
|
||||
private int cycleIndex = 0;
|
||||
|
||||
public InputField cyclesNormalField;
|
||||
public InputField cyclesFastField;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
@ -58,25 +62,29 @@ namespace RimWorldAnimationStudio
|
|||
currentTime -= 1f/60f;
|
||||
stageTick += 1;
|
||||
|
||||
int stageLenght = Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicks;
|
||||
|
||||
if (stageTick > stageLenght)
|
||||
if (stageTick > Workspace.animationClipWindowSize)
|
||||
{
|
||||
if (stageLoopDropdown.value == 1)
|
||||
{ stageTick = 1; }
|
||||
|
||||
else if (stageLoopDropdown.value == 2 && Workspace.stageID < Workspace.animationDef.animationStages.Count - 1)
|
||||
{
|
||||
stageTick = 1;
|
||||
Workspace.stageID++;
|
||||
stageIDField.text = Workspace.stageID.ToString();
|
||||
{
|
||||
++cycleIndex;
|
||||
stageTick = 1;
|
||||
|
||||
if (cycleIndex > int.Parse(cyclesNormalField.text))
|
||||
{
|
||||
++Workspace.stageID;
|
||||
stageIDField.text = Workspace.stageID.ToString();
|
||||
cycleIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{ stageTick = stageLenght; }
|
||||
{ stageTick = Workspace.animationClipWindowSize; }
|
||||
}
|
||||
|
||||
stageTimelineSlider.maxValue = stageLenght;
|
||||
stageTimelineSlider.maxValue = Workspace.animationClipWindowSize;
|
||||
stageTimelineSlider.value = stageTick;
|
||||
|
||||
UpdateAnimation();
|
||||
|
@ -87,12 +95,12 @@ namespace RimWorldAnimationStudio
|
|||
if (stageTickText != null)
|
||||
{ stageTickText.text = stageTick.ToString(); }
|
||||
if (stageLengthText != null)
|
||||
{ stageLengthText.text = Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicks.ToString(); }
|
||||
{ stageLengthText.text = Workspace.animationClipWindowSize.ToString(); }
|
||||
|
||||
for (int actorID = 0; actorID < actorBodies.Count; actorID++)
|
||||
{
|
||||
ActorBody actorBody = actorBodies[actorID];
|
||||
string bodyType = actorCards.transform.GetChild(actorID).GetComponent<ActorCard>().bodyType; //bodyTypeDropdowns[actorID].options[bodyTypeDropdowns[actorID].value].text;
|
||||
string bodyType = actorCards.transform.GetChild(actorID).GetComponent<ActorCard>().bodyType;
|
||||
|
||||
PawnAnimationClip clip = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID];
|
||||
float clipPercent = (float)(stageTick % clip.duration) / clip.duration;
|
||||
|
@ -128,7 +136,7 @@ namespace RimWorldAnimationStudio
|
|||
|
||||
actorBody.bodyRenderer.sortingLayerName = clip.layer;
|
||||
actorBody.headRenderer.sortingLayerName = clip.layer;
|
||||
actorBody.headRenderer.sortingOrder = headFacing == 2 ? 1 : -1;
|
||||
actorBody.headRenderer.sortingOrder = headFacing == 0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,10 +162,17 @@ namespace RimWorldAnimationStudio
|
|||
|
||||
Reset();
|
||||
|
||||
Workspace.animationClipWindowSize = Workspace.animationDef.animationStages[Workspace.stageID].animationClips.Select(x => x.duration).Max();
|
||||
stageTimelineSlider.maxValue = Workspace.animationClipWindowSize;
|
||||
|
||||
cyclesNormalField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicks / Workspace.animationClipWindowSize), 1).ToString();
|
||||
cyclesFastField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicksQuick / Workspace.animationClipWindowSize), 1).ToString();
|
||||
|
||||
for (int actorID = 0; actorID < Workspace.animationDef.actors.Count; actorID++)
|
||||
{
|
||||
GameObject actorBodyObject = Instantiate(actorBodyPrefab, transform);
|
||||
actorBodies.Add(actorBodyObject.GetComponent<ActorBody>());
|
||||
actorBodyObject.GetComponent<ActorBody>().Initialize(actorID);
|
||||
|
||||
GameObject actorCardObject = Instantiate(actorCardPrefab, actorCards);
|
||||
actorCardObject.GetComponent<ActorCard>().Initialize(Workspace.animationDef.actors[actorID]);
|
||||
|
@ -204,10 +219,13 @@ namespace RimWorldAnimationStudio
|
|||
if (Workspace.animationDef == null)
|
||||
{ return; }
|
||||
|
||||
int stageLenght = Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicks;
|
||||
|
||||
if (stageLenght != (int)stageTimelineSlider.value)
|
||||
if (stageTick != (int)stageTimelineSlider.value)
|
||||
{ stageTick = (int)stageTimelineSlider.value; }
|
||||
}
|
||||
|
||||
public void ToggleActorManipulationMode(int mode)
|
||||
{
|
||||
Workspace.actorManipulationMode = (ActorManipulationMode)mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,8 +48,8 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
Debug.Log("Loaded AnimationDef: " + animationDef.defName);
|
||||
|
||||
animationDef.Initialize();
|
||||
Workspace.animationDef = animationDef;
|
||||
animationDef.Initialize();
|
||||
Workspace.isDirty = true;
|
||||
|
||||
var animationDefCards = Resources.FindObjectsOfTypeAll(typeof(AnimationDefCard)) as AnimationDefCard[];
|
||||
|
@ -78,8 +78,19 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
Debug.Log("Saving AnimationDef: " + Workspace.animationDef.defName);
|
||||
|
||||
AnimationDef animationDef = Workspace.animationDef;
|
||||
|
||||
foreach (AnimationStage stage in animationDef.animationStages)
|
||||
{
|
||||
foreach (PawnAnimationClip clip in stage.animationClips)
|
||||
{
|
||||
clip.keyframes = clip.keyframes.OrderBy(x => x.atTick).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Defs defs = new Defs();
|
||||
defs.animationDefs.Add(Workspace.animationDef);
|
||||
defs.animationDefs.Add(animationDef);
|
||||
|
||||
XmlUtility.WriteXML(defs, path);
|
||||
}
|
||||
|
|
7
Assets/Scripts/Enums.cs
Normal file
7
Assets/Scripts/Enums.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
public enum ActorManipulationMode
|
||||
{
|
||||
Pan,
|
||||
Rotate,
|
||||
Face,
|
||||
}
|
||||
|
11
Assets/Scripts/Enums.cs.meta
Normal file
11
Assets/Scripts/Enums.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee120e06e7d8c1f45ad58fc6baab0d47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
65
Assets/Scripts/GUI/ActorKeyframeCard.cs
Normal file
65
Assets/Scripts/GUI/ActorKeyframeCard.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class ActorKeyframeCard : MonoBehaviour
|
||||
{
|
||||
public InputField positionXField;
|
||||
public InputField positionZField;
|
||||
public InputField rotationField;
|
||||
|
||||
private int lastTick = -1;
|
||||
private bool isDirty = false;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if ((Workspace.animationDef == null || AnimationController.Instance.stageTick == lastTick) && isDirty == false)
|
||||
{ return; }
|
||||
|
||||
ActorBody actorBody = AnimationController.Instance.actorBodies[Workspace.actorID];
|
||||
string bodyType = AnimationController.Instance.actorCards.transform.GetChild(Workspace.actorID).GetComponent<ActorCard>().bodyType;
|
||||
|
||||
PawnAnimationClip clip = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[Workspace.actorID];
|
||||
float clipPercent = (float)(AnimationController.Instance.stageTick % clip.duration) / clip.duration;
|
||||
|
||||
Vector3 deltaPos = new Vector3(clip.BodyOffsetX.Evaluate(clipPercent), 0, clip.BodyOffsetZ.Evaluate(clipPercent));
|
||||
deltaPos += Workspace.animationDef.actors[Workspace.actorID].bodyTypeOffset.GetOffset(bodyType);
|
||||
|
||||
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;
|
||||
|
||||
int bodyFacing = (int)clip.BodyFacing.Evaluate(clipPercent);
|
||||
Vector3 headBob = new Vector3(0, 0, clip.HeadBob.Evaluate(clipPercent)) + PawnUtility.BaseHeadOffsetAt(bodyType, bodyFacing);
|
||||
|
||||
Vector3 bodyPos = new Vector3(deltaPos.x, deltaPos.z, 0);
|
||||
Vector3 headPos = new Vector3(headBob.x, headBob.z, 0);
|
||||
|
||||
positionXField.text = bodyPos.x.ToString("0.000");
|
||||
positionZField.text = bodyPos.y.ToString("0.000");
|
||||
rotationField.text = bodyAngle.ToString("0.000");
|
||||
|
||||
lastTick = AnimationController.Instance.stageTick;
|
||||
isDirty = false;
|
||||
}
|
||||
|
||||
public void OnValueChanged()
|
||||
{
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[Workspace.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyOffsetX = float.Parse(positionXField.text);
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[Workspace.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyOffsetZ = float.Parse(positionZField.text);
|
||||
Workspace.animationDef.animationStages[Workspace.stageID].animationClips[Workspace.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID).bodyAngle = float.Parse(rotationField.text);
|
||||
|
||||
Workspace.Instance.GetPawnAnimationClip(Workspace.actorID).BuildSimpleCurves();
|
||||
isDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/GUI/ActorKeyframeCard.cs.meta
Normal file
11
Assets/Scripts/GUI/ActorKeyframeCard.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 58ad3d066d9103541806d07bc98823d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -4,11 +4,12 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class KeyframeSlider : Slider
|
||||
public class KeyframeSlider : Slider, IPointerClickHandler, IBeginDragHandler, IEndDragHandler
|
||||
{
|
||||
public AnimationTimeline timeline;
|
||||
//public AnimationClip clip;
|
||||
|
@ -31,9 +32,8 @@ namespace RimWorldAnimationStudio
|
|||
this.keyframeID = keyframeID;
|
||||
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
|
||||
Debug.Log(keyframe);
|
||||
|
||||
value = (float)keyframe.atTick / Workspace.Instance.GetCurrentStageLength();
|
||||
Debug.Log(keyframe.atTick);
|
||||
value = (float)keyframe.atTick / Workspace.animationClipWindowSize;
|
||||
OnValueChanged();
|
||||
|
||||
onValueChanged.AddListener(delegate (float value) { OnValueChanged(); });
|
||||
|
@ -44,32 +44,15 @@ namespace RimWorldAnimationStudio
|
|||
PawnKeyframe keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
|
||||
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
|
||||
|
||||
int stageLength = Workspace.Instance.GetCurrentStageLength();
|
||||
int newTick = Mathf.RoundToInt(value * stageLength);
|
||||
|
||||
/*if (timeline.CanAddKeyFrameAtTick(newTick) == false)
|
||||
{
|
||||
int delta = keyframe.atTick > newTick ? 1 : -1;
|
||||
|
||||
while (timeline.CanAddKeyFrameAtTick(newTick) == false)
|
||||
{
|
||||
newTick += delta;
|
||||
|
||||
if (newTick == 1 || newTick == stageLength) { break; }
|
||||
}
|
||||
|
||||
if (timeline.CanAddKeyFrameAtTick(newTick) == false)
|
||||
{ value = (float)keyframe.atTick / stageLength; return; }
|
||||
}*/
|
||||
int newTick = Mathf.RoundToInt(value * Workspace.animationClipWindowSize);
|
||||
|
||||
keyframe.atTick = newTick;
|
||||
|
||||
Debug.Log("Value changed: " + newTick);
|
||||
//value = (float)keyframe.atTick / stageLength;
|
||||
|
||||
UpdateGhostFrames();
|
||||
|
||||
clip.BuildSimpleCurves();
|
||||
|
||||
AnimationController.Instance.stageTick = keyframe.atTick.Value;
|
||||
}
|
||||
|
||||
// Ghost sliders are non-interactable slider handle
|
||||
|
@ -81,12 +64,11 @@ namespace RimWorldAnimationStudio
|
|||
if (maxGhosts == 0)
|
||||
{ return; }
|
||||
|
||||
int stageLength = Workspace.Instance.GetCurrentStageLength();
|
||||
int nGhosts = GetGhostFramesRequired();
|
||||
|
||||
for (int i = 0; i < Mathf.Max(nGhosts, ghostSliders.childCount); i++)
|
||||
{
|
||||
if ((i - 1) * clip.duration + keyframe.atTick <= stageLength)
|
||||
if ((i - 1) * clip.duration + keyframe.atTick <= Workspace.animationClipWindowSize)
|
||||
{
|
||||
if (ghostSliders.childCount <= i)
|
||||
{ Instantiate(ghostSliderPrefab, ghostSliders); }
|
||||
|
@ -97,7 +79,7 @@ namespace RimWorldAnimationStudio
|
|||
|
||||
Slider ghostSlider = ghostSliderObject.GetComponent<Slider>();
|
||||
Debug.Log(ghostSlider);
|
||||
ghostSlider.value = (float)((i + 1) * clip.duration + keyframe.atTick) / stageLength;
|
||||
ghostSlider.value = (float)((i + 1) * clip.duration + keyframe.atTick) / Workspace.animationClipWindowSize;
|
||||
|
||||
float mult = 1f - Mathf.Pow((float)i / maxGhosts, 2);
|
||||
ghostSlider.transform.FindDeepChild("Handle").GetComponent<Image>().color = new Color(0, 0.5f, 0.5f, 0.5f * mult);
|
||||
|
@ -118,7 +100,36 @@ namespace RimWorldAnimationStudio
|
|||
if (clip.duration <= 1)
|
||||
{ return 0; }
|
||||
|
||||
return Math.Min(Mathf.CeilToInt((float)Workspace.Instance.GetCurrentStageLength() / clip.duration), maxGhosts);
|
||||
return Math.Min(Mathf.CeilToInt((float)Workspace.animationClipWindowSize / clip.duration), maxGhosts);
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
|
||||
|
||||
foreach (KeyframeSlider keyframeSlider in timeline.transform.GetComponentsInChildren<KeyframeSlider>())
|
||||
{
|
||||
if (keyframeSlider == this)
|
||||
{ continue; }
|
||||
|
||||
keyframeSlider.transform.FindDeepChild("Handle").GetComponent<Image>().color = new Color(1f, 1f, 1f);
|
||||
}
|
||||
|
||||
transform.FindDeepChild("Handle").GetComponent<Image>().color = new Color(0f, 1f, 0f);
|
||||
|
||||
AnimationController.Instance.stageTick = keyframe.atTick.Value;
|
||||
|
||||
Workspace.keyframeID = keyframeID;
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
interactable = true;
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
interactable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
public static AnimationDef animationDef;
|
||||
public static int stageID = 0;
|
||||
public static int actorID = 0;
|
||||
public static int keyframeID = 0;
|
||||
public static bool isDirty = false;
|
||||
|
||||
public static List<string> defNames = new List<string>() { "Human" };
|
||||
|
@ -23,13 +25,15 @@ namespace RimWorldAnimationStudio
|
|||
private static int maxHistoryDepth = 100;
|
||||
private static int historyIndex = 0;
|
||||
|
||||
public int GetCurrentStageLength()
|
||||
{
|
||||
if (stageID < 0 || stageID >= animationDef.animationStages.Count)
|
||||
{ return 0; }
|
||||
public static ActorManipulationMode actorManipulationMode = ActorManipulationMode.Pan;
|
||||
public static int animationClipWindowSize = 600;
|
||||
|
||||
return animationDef.animationStages[stageID].playTimeTicks;
|
||||
}
|
||||
|
||||
|
||||
//public int? GetCurrentKeyframe()
|
||||
//{
|
||||
// return animationDef?.animationStages[stageID]?.animationClips[actorID]?.keyframes.FirstOrDefault(x => x.keyframeID == keyframeID)?.keyframeID;
|
||||
//}
|
||||
|
||||
public PawnAnimationClip GetPawnAnimationClip(int actorID)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue