Improved adding and removal of anim events

This commit is contained in:
AbstractConcept 2022-09-17 19:06:33 -05:00
parent f0d46df3d6
commit 8523abf957
276 changed files with 1401 additions and 5422 deletions

View file

@ -33,5 +33,26 @@ namespace RimWorldAnimationStudio
public bool ShouldSerializecontrolGenitalAngle() { return controlGenitalAngle != null; }
public bool ShouldSerializeisFucking() { return isFucking != null; }
public bool ShouldSerializeisFucked() { return isFucked != null; }
public bool MakeNew()
{
if (Workspace.animationDef == null)
{ Debug.LogWarning("Cannot make new actor - there is no AnimationDef"); return false; }
Workspace.animationDef.actors.Add(this);
foreach (AnimationStage stage in Workspace.animationDef.animationStages)
{
PawnAnimationClip clip = new PawnAnimationClip();
if (clip.MakeNew())
{
stage.animationClips.Add(clip);
stage.Initialize();
}
}
return true;
}
}
}

View file

@ -30,7 +30,6 @@ namespace RimWorldAnimationStudio
BodyFacing.Clear();
HeadBob.Clear();
GenitalAngle.Clear();
SoundEffects.Clear();
int duration = 0;
@ -60,9 +59,6 @@ namespace RimWorldAnimationStudio
if (keyframe.genitalAngle.HasValue)
{ GenitalAngle.Add((float)keyframe.atTick / (float)duration, keyframe.genitalAngle.Value, true); }
if (keyframe.soundEffect != null)
{ SoundEffects.Add((int)keyframe.atTick, keyframe.soundEffect); }
if (i + 1 < keyframes.Count)
{ keyframes[i].tickDuration = keyframes[i + 1].atTick.Value - keyframes[i].atTick.Value; }
}
@ -78,10 +74,7 @@ namespace RimWorldAnimationStudio
HeadBob.Add((float)keyframePosition / (float)duration, keyframe.headBob, true);
if (keyframe.genitalAngle.HasValue)
GenitalAngle.Add((float)keyframePosition / (float)duration, keyframe.genitalAngle.Value, true);
if (keyframe.soundEffect != null)
{ SoundEffects.Add(keyframePosition, keyframe.soundEffect); }
{ GenitalAngle.Add((float)keyframePosition / (float)duration, keyframe.genitalAngle.Value, true); }
if (keyframe.tickDuration != 1 && keyframe.quiver.HasValue)
{
@ -96,5 +89,19 @@ namespace RimWorldAnimationStudio
keyframes[keyframes.Count - 1].tickDuration = 1;
}
public bool MakeNew()
{
PawnKeyframe keyframeA = new PawnKeyframe();
keyframeA.tickDuration = 60;
keyframes.Add(keyframeA);
PawnKeyframe keyframeB = new PawnKeyframe();
keyframes.Add(keyframeB);
BuildSimpleCurves();
return true;
}
}
}

View file

@ -1,16 +1,17 @@
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using UnityEngine;
namespace RimWorldAnimationStudio
{
public class AnimationStage
{
public string stageName = "default";
public string stageName = "NewStage";
public int stageIndex = 0;
public int playTimeTicks = 0;
public int playTimeTicksQuick = -1;
public bool isLooping = true;
public bool isLooping = false;
[XmlArray("animationClips"), XmlArrayItem("li")]
public List<PawnAnimationClip> animationClips = new List<PawnAnimationClip>();
@ -26,5 +27,25 @@ namespace RimWorldAnimationStudio
{ playTimeTicks = clip.duration; }
}
}
public bool MakeNew()
{
if (Workspace.animationDef == null)
{ Debug.LogWarning("Cannot make new animation stage - there is no AnimationDef"); return false; }
foreach(Actor actor in Workspace.animationDef.actors)
{
PawnAnimationClip clip = new PawnAnimationClip();
if (clip.MakeNew())
{ animationClips.Add(clip); }
}
Initialize();
Workspace.animationDef.animationStages.Add(this);
return true;
}
}
}

View file

@ -9,6 +9,7 @@ namespace RimWorldAnimationStudio
public class ActorBody : MonoBehaviour, IPointerClickHandler, IDragHandler
{
public int actorID;
public string bodyType = "Male";
public SpriteRenderer bodyRenderer;
public SpriteRenderer headRenderer;
@ -22,8 +23,51 @@ namespace RimWorldAnimationStudio
{
if (eventData.pointerCurrentRaycast.gameObject.GetComponent<ActorBody>() == null)
{ return; }
foreach (ActorBody actorBody in AnimationController.Instance.actorBodies)
Activate();
}
public void OnDrag(PointerEventData eventData)
{
Activate();
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
if (Workspace.Instance.GetCurrentPawnKeyframe() == null)
{ Debug.LogWarning("Cannot alter actor - no keyframe data available"); return; }
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
{
keyframe.bodyOffsetX = mousePosition.x;
keyframe.bodyOffsetZ = mousePosition.y;
}
else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
{
float angle = Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
keyframe.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;
keyframe.bodyFacing = facing;
}
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
clip.BuildSimpleCurves();
}
public void Activate()
{
Workspace.actorID = actorID;
foreach (ActorBody actorBody in AnimationController.Instance.GetComponentsInChildren<ActorBody>())
{
if (actorBody == this)
{ continue; }
@ -34,40 +78,6 @@ namespace RimWorldAnimationStudio
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();
}
}
}

View file

@ -16,17 +16,13 @@ namespace RimWorldAnimationStudio
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);
Activate();
}
public void OnDrag(PointerEventData eventData)
{
Activate();
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
PawnKeyframe keyframe = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[parent.actorID].keyframes.FirstOrDefault(x => x.keyframeID == Workspace.keyframeID);
@ -63,5 +59,18 @@ namespace RimWorldAnimationStudio
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(parent.actorID);
clip.BuildSimpleCurves();
}
public void Activate()
{
Workspace.actorID = parent.actorID;
foreach (ActorBody actorBody in AnimationController.Instance.GetComponentsInChildren<ActorBody>())
{
actorBody.bodyRenderer.color = new Color(1f, 1f, 1f);
actorBody.headRenderer.color = new Color(1f, 1f, 1f);
}
bodyPartRenderer.color = new Color(0f, 1f, 0f);
}
}
}

View file

@ -13,22 +13,11 @@ namespace RimWorldAnimationStudio
public InputField bodyOffsetZField;
public Toggle initiatorToggle;
private Actor actor;
public string bodyType
{
get
{
string _bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
if (_bodyType == "") return "Male";
return _bodyType;
}
}
public void Initialize(Actor actor)
public void Initialize()
{
this.actor = actor;
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
string bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
bodyType = bodyType == null || bodyType == "" ? "Male" : bodyType;
initiatorToggle.isOn = actor.initiator;
bodyOffsetXField.text = actor.bodyTypeOffset.GetOffset(bodyType).x.ToString();
@ -37,18 +26,23 @@ namespace RimWorldAnimationStudio
public void UpdateAnimationDef()
{
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
string bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
bodyType = bodyType == null || bodyType == "" ? "Male" : bodyType;
Debug.Log(bodyType);
AnimationController.Instance.transform.GetChild(Workspace.actorID).GetComponent<ActorBody>().bodyType = bodyType;
float.TryParse(bodyOffsetXField.text, out float x);
float.TryParse(bodyOffsetZField.text, out float z);
actor.bodyTypeOffset.SetOffset(bodyType, new Vector2(x, z));
actor.initiator = initiatorToggle.isOn;
if (actor.isFucking == null)
{ }
actor.initiator = initiatorToggle.isOn;
}
public void OpenSelectBodyPartsDialog()
{
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
var dialog = Resources.FindObjectsOfTypeAll(typeof(SelectBodyPartsDialog)) as SelectBodyPartsDialog[];
if (dialog != null)
@ -57,6 +51,7 @@ namespace RimWorldAnimationStudio
public void OpenSelectDefNamesDialog()
{
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
var dialog = Resources.FindObjectsOfTypeAll(typeof(SelectDefNamesDialog)) as SelectDefNamesDialog[];
if (dialog != null)
@ -65,6 +60,7 @@ namespace RimWorldAnimationStudio
public void OpenSelectBodyDefTypesDialog()
{
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
var dialog = Resources.FindObjectsOfTypeAll(typeof(SelectBodyDefTypesDialog)) as SelectBodyDefTypesDialog[];
if (dialog != null)

View file

@ -20,8 +20,11 @@ namespace RimWorldAnimationStudio
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;
if (Workspace.actorID >= AnimationController.Instance.transform.childCount)
{ return; }
ActorBody actorBody = AnimationController.Instance.transform.GetChild(Workspace.actorID).GetComponent<ActorBody>();
string bodyType = actorBody.bodyType;
PawnAnimationClip clip = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[Workspace.actorID];
float clipPercent = (float)(AnimationController.Instance.stageTick % clip.duration) / clip.duration;

View file

@ -17,6 +17,8 @@ namespace RimWorldAnimationStudio
{
this.actorID = actorID;
Reset();
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
if (clip == null || clip.keyframes.NullOrEmpty())
@ -35,22 +37,22 @@ namespace RimWorldAnimationStudio
}
}
public void AddKeyFrame(int atTick)
public void Reset()
{
foreach(KeyframeSlider keyframeSlider in GetComponentsInChildren<KeyframeSlider>())
{ Destroy(keyframeSlider.gameObject); }
}
public bool CanAddKeyFrameAtTick(int atTick)
public void AddPawnKeyFrame(int keyframeID)
{
foreach (Transform child in transform)
{
KeyframeSlider keyframeSlider = child.GetComponent<KeyframeSlider>();
KeyframeSlider keyframeSlider = Instantiate(keyframeSliderPrefab, transform);
keyframeSlider.Initialize(this, actorID, keyframeID);
}
if (keyframeSlider != null && Workspace.Instance.GetPawnKeyframe(keyframeSlider.actorID, keyframeSlider.keyframeID).atTick == atTick)
{ return false; }
}
return true;
public void RemovePawnKeyFrame(int keyframeID)
{
KeyframeSlider keyframeSlider = GetComponentsInChildren<KeyframeSlider>().FirstOrDefault(x => x.keyframeID == keyframeID);
Destroy(keyframeSlider?.gameObject);
}
}
}

View file

@ -12,9 +12,6 @@ namespace RimWorldAnimationStudio
public class KeyframeSlider : Slider, IPointerClickHandler, IBeginDragHandler, IEndDragHandler
{
public AnimationTimeline timeline;
//public AnimationClip clip;
//public Keyframe keyframe;
public Transform ghostSliders;
public Slider ghostSliderPrefab;
public int maxGhosts = 4;
@ -22,18 +19,22 @@ namespace RimWorldAnimationStudio
public int actorID;
public int keyframeID;
private PawnAnimationClip clip;
private PawnKeyframe keyframe;
public void Initialize(AnimationTimeline timeline, int actorID, int keyframeID)
{
this.timeline = timeline;
//this.clip = clip;
//this.keyframe = keyframe;
this.clip = Workspace.Instance.GetPawnAnimationClip(actorID);
this.keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
this.actorID = actorID;
this.keyframeID = keyframeID;
PawnKeyframe keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
Debug.Log(keyframe.atTick);
value = (float)keyframe.atTick / Workspace.animationClipWindowSize;
maxValue = Workspace.animationClipWindowSize;
value = keyframe.atTick.Value;
OnValueChanged();
onValueChanged.AddListener(delegate (float value) { OnValueChanged(); });
@ -41,12 +42,7 @@ namespace RimWorldAnimationStudio
public void OnValueChanged()
{
PawnKeyframe keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
int newTick = Mathf.RoundToInt(value * Workspace.animationClipWindowSize);
keyframe.atTick = newTick;
keyframe.atTick = (int)value;
UpdateGhostFrames();
@ -58,9 +54,6 @@ namespace RimWorldAnimationStudio
// Ghost sliders are non-interactable slider handle
public void UpdateGhostFrames()
{
PawnKeyframe keyframe = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID);
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
if (maxGhosts == 0)
{ return; }
@ -79,7 +72,7 @@ namespace RimWorldAnimationStudio
Slider ghostSlider = ghostSliderObject.GetComponent<Slider>();
Debug.Log(ghostSlider);
ghostSlider.value = (float)((i + 1) * clip.duration + keyframe.atTick) / Workspace.animationClipWindowSize;
ghostSlider.value = (int)((i + 1) * clip.duration + keyframe.atTick);
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);
@ -92,8 +85,6 @@ namespace RimWorldAnimationStudio
public int GetGhostFramesRequired()
{
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(actorID);
if (Workspace.animationDef.animationStages[Workspace.stageID].isLooping == false)
{ return 0; }
@ -105,31 +96,48 @@ namespace RimWorldAnimationStudio
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;
Activate();
}
public void OnBeginDrag(PointerEventData eventData)
{
Activate();
if (keyframe.atTick == 1)
{ return; }
interactable = true;
}
public override void OnDrag(PointerEventData eventData)
{
base.OnDrag(eventData);
Activate();
}
public void OnEndDrag(PointerEventData eventData)
{
interactable = false;
}
public void Activate()
{
AnimationController.Instance.stageTick = keyframe.atTick.Value;
Workspace.keyframeID = keyframeID;
foreach (AnimationTimeline _timeline in AnimationController.Instance.animationTimelines.GetComponentsInChildren<AnimationTimeline>())
{
foreach (KeyframeSlider keyframeSlider in _timeline.GetComponentsInChildren<KeyframeSlider>())
{
if (keyframeSlider.keyframe.atTick.Value == keyframe.atTick.Value)
{ keyframeSlider.transform.FindDeepChild("Handle").GetComponent<Image>().color = new Color(0f, 1f, 0f); }
else
{ keyframeSlider.transform.FindDeepChild("Handle").GetComponent<Image>().color = new Color(1f, 1f, 1f); }
}
}
}
}
}

View file

@ -2,23 +2,20 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class StageCard : MonoBehaviour
public class StageCard : MonoBehaviour, IPointerClickHandler
{
private Text stageName;
private InputField stageNameField;
private Image banner;
private Toggle toggle;
public void OnNameChange()
{
}
public void OnSelectStage()
{
if (GetComponent<Toggle>().isOn && Workspace.stageID != transform.GetSiblingIndex())
{ Workspace.stageID = transform.GetSiblingIndex(); }
stageName.text = stageNameField.text;
stageNameField.gameObject.SetActive(false);
}
public void OnMoveStage(int delta)
@ -32,30 +29,39 @@ namespace RimWorldAnimationStudio
}
}
public void Start()
public void Initialize(string stageName)
{
banner = transform.Find("Banner").GetComponent<Image>();
toggle = GetComponent<Toggle>();
toggle.group = StageCardManager.Instance.GetComponent<ToggleGroup>();
this.stageName = transform.Find("StageName").GetComponent<Text>();
this.stageNameField = transform.Find("StageNameField").GetComponent<InputField>();
this.banner = transform.Find("Banner").GetComponent<Image>();
this.stageName.text = stageName;
}
public void Update()
{
if (Workspace.stageID == transform.GetSiblingIndex())
{
banner.gameObject.SetActive(true);
if (toggle.isOn == false)
{ toggle.isOn = true; }
}
{ banner.gameObject.SetActive(true); }
else
{
banner.gameObject.SetActive(false);
if (toggle.isOn)
{ toggle.isOn = false; }
stageNameField.gameObject.SetActive(false);
}
}
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.clickCount >= 2)
{
stageNameField.text = stageName.text;
stageNameField.gameObject.SetActive(true);
}
Workspace.stageID = transform.GetSiblingIndex();
AnimationController.Instance.ResetAnimationTimeline();
AnimationController.Instance.InitializeAnimationTimeline();
}
}
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5d9672c420dae5b4095d933223c39cd5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -12,35 +12,28 @@ namespace RimWorldAnimationStudio
{
public class AnimationController : Singleton<AnimationController>
{
[Header("Animation settings")]
public bool isAnimating = false;
public bool isLooping = true;
public int stageTick = 0;
public bool autoAdvanceToNextStage = false;
public int stageTick = 1;
[Header("Object references")]
public Slider stageTimelineSlider;
public GameObject actorBodyPrefab;
public List<ActorBody> actorBodies = new List<ActorBody>();
public Text stageTickText;
public Text stageLengthText;
public Transform actorCards;
public GameObject actorCardPrefab;
public Dropdown stageLoopDropdown;
public InputField stageIDField;
public Transform animationTimelines;
public AnimationTimeline animationTimelinePrefab;
private float currentTime = 0;
private int cycleIndex = 0;
public InputField cyclesNormalField;
public InputField cyclesFastField;
public Text stageTickText;
public Text stageLengthText;
public ActorCard actorCard;
public Transform animationTimelines;
[Header("Prefabs")]
public ActorBody actorBodyPrefab;
public AnimationTimeline animationTimelinePrefab;
// Private timing variables
private float timeSinceLastUpdate = 0;
private int cycleIndex = 0;
public void Update()
{
// No animation, exit
@ -50,61 +43,65 @@ namespace RimWorldAnimationStudio
if (Workspace.animationDef != null && Workspace.isDirty)
{ Initialize(); return; }
// Not animating, update preview
if (isAnimating == false) { UpdateAnimation(); return; }
// Update tick if animating
if (isAnimating)
{
timeSinceLastUpdate += Time.deltaTime;
// Animating, update stage tick before updating preview
currentTime += Time.deltaTime;
if (timeSinceLastUpdate < 1f / 60f)
{ return; }
if (currentTime < 1f/60f)
{ return; }
timeSinceLastUpdate -= 1f / 60f;
stageTick += 1;
currentTime -= 1f/60f;
stageTick += 1;
if (stageTick > Workspace.animationClipWindowSize)
{
if (stageLoopDropdown.value == 1)
{ stageTick = 1; }
else if (stageLoopDropdown.value == 2 && Workspace.stageID < Workspace.animationDef.animationStages.Count - 1)
if (stageTick > Workspace.animationClipWindowSize)
{
++cycleIndex;
stageTick = 1;
if (stageLoopDropdown.value == 1)
{ stageTick = 1; }
if (cycleIndex > int.Parse(cyclesNormalField.text))
else if (stageLoopDropdown.value == 2 && Workspace.stageID < Workspace.animationDef.animationStages.Count - 1)
{
++Workspace.stageID;
stageIDField.text = Workspace.stageID.ToString();
cycleIndex = 0;
}
}
++cycleIndex;
stageTick = 1;
else
{ stageTick = Workspace.animationClipWindowSize; }
if (cycleIndex > int.Parse(cyclesNormalField.text))
{
++Workspace.stageID;
cycleIndex = 0;
}
}
else
{ stageTick = Workspace.animationClipWindowSize; }
}
}
// Update stage timeline
stageTimelineSlider.maxValue = Workspace.animationClipWindowSize;
stageTimelineSlider.value = stageTick;
stageTickText.text = stageTick.ToString();
stageLengthText.text = Workspace.animationClipWindowSize.ToString();
// Update animation
UpdateAnimation();
}
public void UpdateAnimation()
{
if (stageTickText != null)
{ stageTickText.text = stageTick.ToString(); }
if (stageLengthText != null)
{ stageLengthText.text = Workspace.animationClipWindowSize.ToString(); }
List<ActorBody> actorBodies = GetComponentsInChildren<ActorBody>().ToList();
for (int actorID = 0; actorID < actorBodies.Count; actorID++)
{
ActorBody actorBody = actorBodies[actorID];
string bodyType = actorCards.transform.GetChild(actorID).GetComponent<ActorCard>().bodyType;
PawnAnimationClip clip = Workspace.animationDef?.animationStages[Workspace.stageID]?.animationClips[actorID];
if (clip == null)
{ continue; }
PawnAnimationClip clip = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID];
float clipPercent = (float)(stageTick % clip.duration) / clip.duration;
ActorBody actorBody = actorBodies[actorID];
string bodyType = actorBody.bodyType;
Vector3 deltaPos = new Vector3(clip.BodyOffsetX.Evaluate(clipPercent), 0, clip.BodyOffsetZ.Evaluate(clipPercent));
deltaPos += Workspace.animationDef.actors[actorID].bodyTypeOffset.GetOffset(bodyType);
@ -140,75 +137,64 @@ namespace RimWorldAnimationStudio
}
}
public void UpdateStageID()
{
if (Workspace.animationDef == null)
{
stageIDField.text = "0";
return;
}
int.TryParse(stageIDField.text, out int i);
Workspace.stageID = Mathf.Clamp(i, 0, Workspace.animationDef.animationStages.Count - 1);
stageTick = 0;
stageIDField.text = Workspace.stageID.ToString();
}
public void Initialize()
{
Debug.Log("Initializing animation preview");
Reset();
Workspace.animationClipWindowSize = Workspace.animationDef.animationStages[Workspace.stageID].animationClips.Select(x => x.duration).Max();
stageTimelineSlider.maxValue = Workspace.animationClipWindowSize;
InitializeAnimationTimeline();
StageCardManager.Instance.Initialize();
Workspace.isDirty = false;
}
public void InitializeAnimationTimeline()
{
Workspace.animationClipWindowSize = Workspace.animationDef.animationStages[Workspace.stageID].animationClips.Select(x => x.duration).Max();
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]);
ActorBody actorBody = Instantiate(actorBodyPrefab, transform);
actorBody.Initialize(actorID);
AnimationTimeline animationTimeline = Instantiate(animationTimelinePrefab, animationTimelines);
animationTimeline.Initialize(actorID);
}
StageCardManager.Instance.Initialize();
Workspace.isDirty = false;
UpdateAnimation();
stageTimelineSlider.maxValue = Workspace.animationClipWindowSize;
stageTimelineSlider.value = 1;
stageTick = 1;
}
public void Reset()
{
Workspace.stageID = 0;
stageTick = 0;
ResetAnimationTimeline();
StageCardManager.Instance.Reset();
}
public void ResetAnimationTimeline()
{
isAnimating = false;
timeSinceLastUpdate = 0;
cycleIndex = 0;
foreach (ActorBody actorBody in actorBodies)
foreach (ActorBody actorBody in GetComponentsInChildren<ActorBody>())
{ Destroy(actorBody.gameObject); }
foreach (Transform actorCard in actorCards)
{ Destroy(actorCard.gameObject); }
foreach (Transform animationTimeline in animationTimelines)
{ Destroy(animationTimeline.gameObject); }
actorBodies.Clear();
}
public bool AddAnimationStage()
{
return true;
AnimationStage stage = new AnimationStage();
return stage.MakeNew();
}
public bool CloneAnimationStage()
@ -248,17 +234,20 @@ namespace RimWorldAnimationStudio
return true;
}
public bool AddActor()
public void AddActor()
{
return true;
Actor actor = new Actor();
if (actor.MakeNew())
{ Initialize(); }
}
public bool RemoveActor()
public void RemoveActor()
{
if (Workspace.animationDef.actors.Count == 1)
{
Debug.LogWarning("Cannot delete actor - the animation must contain at least one actor.");
return false;
return;
}
foreach (AnimationStage stage in Workspace.animationDef.animationStages)
@ -267,21 +256,66 @@ namespace RimWorldAnimationStudio
Workspace.animationDef.actors.RemoveAt(Workspace.actorID);
Workspace.actorID = Workspace.actorID >= Workspace.animationDef.actors.Count ? Workspace.actorID = Workspace.animationDef.actors.Count - 1 : Workspace.actorID;
return true;
Initialize();
}
public void AddPawnKeyframe()
{
PawnAnimationClip clip = Workspace.Instance.GetCurrentPawnAnimationClip();
List<PawnKeyframe> keyframes = clip?.keyframes;
if (clip == null || keyframes == null)
{ Debug.LogWarning("Cannot add pawn keyframe - the AnimationDef is invalid"); return; }
if (keyframes.FirstOrDefault(x => x.atTick == stageTick) != null)
{ Debug.LogWarning("Cannot add pawn keyframe - a keyframe already exists at this tick"); return; }
float clipPercent = (float)(stageTick % clip.duration) / clip.duration;
PawnKeyframe keyframe = new PawnKeyframe();
keyframe.bodyAngle = clip.BodyAngle.Evaluate(clipPercent);
keyframe.headAngle = clip.HeadAngle.Evaluate(clipPercent);
keyframe.headBob = clip.HeadBob.Evaluate(clipPercent);
keyframe.bodyOffsetX = clip.BodyOffsetX.Evaluate(clipPercent);
keyframe.bodyOffsetZ = clip.BodyOffsetZ.Evaluate(clipPercent);
keyframe.headFacing = clip.HeadFacing.Evaluate(clipPercent);
keyframe.bodyFacing = clip.BodyFacing.Evaluate(clipPercent);
keyframe.genitalAngle = clip.GenitalAngle.Evaluate(clipPercent);
keyframe.atTick = stageTick;
PawnKeyframe nextKeyframe = keyframes.FirstOrDefault(x => x.atTick > stageTick);
if (nextKeyframe != null)
{ keyframes.Insert(keyframes.IndexOf(nextKeyframe), keyframe); }
else
{ keyframes.Add(keyframe); }
clip.BuildSimpleCurves();
animationTimelines.GetChild(Workspace.actorID).GetComponent<AnimationTimeline>().AddPawnKeyFrame(keyframe.keyframeID);
}
public void RemovePawnKeyframe()
{
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe(false);
if (keyframe != null)
{
animationTimelines.GetChild(Workspace.actorID).GetComponent<AnimationTimeline>().RemovePawnKeyFrame(keyframe.keyframeID);
PawnAnimationClip clip = Workspace.Instance.GetCurrentPawnAnimationClip();
clip.keyframes.Remove(keyframe);
clip.BuildSimpleCurves();
}
}
public void ToggleAnimation()
{
isAnimating = !isAnimating;
}
public void ToggleAnimationLoop()
{
isLooping = !isLooping;
}
public void UpdateFromStageTimelineSlider()
{
if (Workspace.animationDef == null)

View file

@ -49,9 +49,6 @@ namespace RimWorldAnimationStudio
curZoom += Input.GetAxis("Mouse ScrollWheel") * scrollSpeed * 0.1f;
curZoom = Mathf.Clamp(curZoom, maxZoom, minZoom);
x = transform.position.x + Input.GetAxis("Horizontal") * scrollSpeed * Time.deltaTime;
y = transform.position.y + Input.GetAxis("Vertical") * scrollSpeed * Time.deltaTime;
Vector3 cameraPosition = Vector3.Lerp(transform.position, new Vector3(x, y, -10), 0.2f);
transform.position = cameraPosition;
cam.orthographicSize = Mathf.Abs(curZoom);

View file

@ -12,9 +12,13 @@ namespace RimWorldAnimationStudio
public void Initialize()
{
foreach(AnimationStage stage in Workspace.animationDef.animationStages)
{
MakeStageCard(stage.stageName);
}
{ MakeStageCard(stage.stageName); }
}
public void Reset()
{
foreach(StageCard stageCard in GetComponentsInChildren<StageCard>())
{ Destroy(stageCard.gameObject); }
}
public StageCard MakeStageCard(string stageName = null)
@ -22,14 +26,15 @@ namespace RimWorldAnimationStudio
StageCard stageCard = Instantiate(stageCardPrefab, transform);
if (stageName != null)
{ stageCard.transform.Find("StageNameField").GetComponent<InputField>().text = stageName; }
{ stageCard.Initialize(stageName); }
return stageCard;
}
public void OnNewStage()
{
MakeStageCard();
if (AnimationController.Instance.AddAnimationStage())
{ MakeStageCard("NewStage"); }
}
public void OnCloneStage()

8
Assets/Scripts/Math.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8ac88bae1e709d142bde52c3a5f17a9b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0288c6c177cf10045b08f5d2b9ad52c4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,35 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class Tag : MonoBehaviour
{
public string tagName = "New Tag";
public Text tagText;
public GameObject tagPrefab;
public void Initialize(string tagName)
{
this.tagName = tagName;
tagText.text = tagName;
}
public void AddTag()
{
GameObject newTag = Instantiate(tagPrefab, transform.parent);
newTag.GetComponent<Tag>().Initialize(tagText.text);
tagText.text = tagName;
transform.SetAsLastSibling();
}
public void DeleteTag()
{
//SendMessageUpwards("DeleteTag", this);
Destroy(gameObject);
}
}
}

View file

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

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ecaf47cada431924c86ace2e8056da7e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c7b8488a225a00944963946ebfa7a654
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -28,12 +28,22 @@ namespace RimWorldAnimationStudio
public static ActorManipulationMode actorManipulationMode = ActorManipulationMode.Pan;
public static int animationClipWindowSize = 600;
public PawnKeyframe GetCurrentPawnKeyframe(bool makeNewIfNull = true)
{
int stageTick = AnimationController.Instance.stageTick;
PawnKeyframe keyframe = animationDef?.animationStages[stageID]?.animationClips[actorID]?.keyframes.FirstOrDefault(x => x.atTick == stageTick);
//public int? GetCurrentKeyframe()
//{
// return animationDef?.animationStages[stageID]?.animationClips[actorID]?.keyframes.FirstOrDefault(x => x.keyframeID == keyframeID)?.keyframeID;
//}
if (keyframe != null || makeNewIfNull == false)
{ return keyframe; }
AnimationController.Instance.AddPawnKeyframe();
return animationDef?.animationStages[stageID]?.animationClips[actorID]?.keyframes.FirstOrDefault(x => x.atTick == stageTick);
}
public PawnAnimationClip GetCurrentPawnAnimationClip()
{
return animationDef.animationStages[stageID].animationClips[actorID];
}
public PawnAnimationClip GetPawnAnimationClip(int actorID)
{