Manual timeline, cycle and actor tweaking

This commit is contained in:
AbstractConcept 2022-09-16 17:50:15 -05:00
parent dfa564759b
commit 1dd7781179
165 changed files with 4040 additions and 166 deletions

View File

@ -66,6 +66,7 @@
<Compile Include="Assets\Scripts\ActorBody.cs" />
<Compile Include="Assets\Scripts\ActorCard.cs" />
<Compile Include="Assets\Scripts\AnimationComponents\Actor.cs" />
<Compile Include="Assets\Scripts\AnimationComponents\ActorBodyPart.cs" />
<Compile Include="Assets\Scripts\AnimationComponents\AlienRaceOffset.cs" />
<Compile Include="Assets\Scripts\AnimationComponents\AnimationClips\AnimationClip.cs" />
<Compile Include="Assets\Scripts\AnimationComponents\AnimationClips\PawnAnimationClip.cs" />
@ -89,8 +90,10 @@
<Compile Include="Assets\Scripts\DialogBoxes\SelectDefNamesDialog.cs" />
<Compile Include="Assets\Scripts\DialogBoxes\SelectInteractionDefsDialog.cs" />
<Compile Include="Assets\Scripts\DialogBoxes\SelectSexTypesDialog.cs" />
<Compile Include="Assets\Scripts\Enums.cs" />
<Compile Include="Assets\Scripts\Extensions\IListExtensions.cs" />
<Compile Include="Assets\Scripts\Extensions\TransformExtensions.cs" />
<Compile Include="Assets\Scripts\GUI\ActorKeyframeCard.cs" />
<Compile Include="Assets\Scripts\GUI\AnimationTimeline.cs" />
<Compile Include="Assets\Scripts\GUI\KeyframeSlider.cs" />
<Compile Include="Assets\Scripts\GenMath.cs" />

View File

@ -10,6 +10,8 @@ GameObject:
m_Component:
- component: {fileID: 7929422519883802245}
- component: {fileID: 7929422519883802244}
- component: {fileID: 3275330537164762353}
- component: {fileID: 7621569460770085946}
m_Layer: 0
m_Name: ActorHead
m_TagString: Untagged
@ -70,17 +72,57 @@ SpriteRenderer:
m_SortingLayerID: -2115984483
m_SortingLayer: 22
m_SortingOrder: 1
m_Sprite: {fileID: 0}
m_Sprite: {fileID: 21300000, guid: 0b37cc6354dc6a94cb2d2de2529baa4e, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_Size: {x: 1.28, y: 1.28}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!114 &3275330537164762353
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7929422519883802246}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b23e33f312d52c642b86f5f2138f4030, type: 3}
m_Name:
m_EditorClassIdentifier:
bodyPartRenderer: {fileID: 7929422519883802244}
parent: {fileID: -4411442180840688308}
--- !u!61 &7621569460770085946
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7929422519883802246}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: 0}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0.5, y: 0.5}
oldSize: {x: 1.28, y: 1.28}
newSize: {x: 1.28, y: 1.28}
adaptiveTilingThreshold: 0.5
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 0.5, y: 0.5}
m_EdgeRadius: 0
--- !u!1 &7929422520673851210
GameObject:
m_ObjectHideFlags: 0
@ -92,6 +134,7 @@ GameObject:
- component: {fileID: 7929422520673851209}
- component: {fileID: 7929422520673851208}
- component: {fileID: -4411442180840688308}
- component: {fileID: -7575978412006062152}
m_Layer: 0
m_Name: ActorBody
m_TagString: Untagged
@ -153,15 +196,15 @@ SpriteRenderer:
m_SortingLayerID: -2115984483
m_SortingLayer: 22
m_SortingOrder: 0
m_Sprite: {fileID: 0}
m_Sprite: {fileID: 21300000, guid: e6887bc2f64df4d4b91bd2d0ad0ffd98, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_Size: {x: 1.5058824, y: 1.5058824}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!114 &-4411442180840688308
@ -176,5 +219,32 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 511a9ed9093e7fc458dec8d3c657f9a5, type: 3}
m_Name:
m_EditorClassIdentifier:
actorID: 0
bodyRenderer: {fileID: 7929422520673851208}
headRenderer: {fileID: 7929422519883802244}
--- !u!61 &-7575978412006062152
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7929422520673851210}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: -0.2}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0.5, y: 0.5}
oldSize: {x: 1.5058824, y: 1.5058824}
newSize: {x: 1.5058824, y: 1.5058824}
adaptiveTilingThreshold: 0.5
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 0.75, y: 1}
m_EdgeRadius: 0

View File

@ -107,7 +107,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 0.5}
m_AnchorMax: {x: 1, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 20}
m_SizeDelta: {x: -10, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &7758949423219383195
MonoBehaviour:
@ -147,7 +147,7 @@ MonoBehaviour:
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_Interactable: 0
m_TargetGraphic: {fileID: 0}
m_FillRect: {fileID: 0}
m_HandleRect: {fileID: 4629009613275671144}
@ -164,6 +164,8 @@ MonoBehaviour:
ghostSliderPrefab: {fileID: 3581489635090573721, guid: 890d76c226858de4fa96adfe7cc85383,
type: 3}
maxGhosts: 0
actorID: 0
keyframeID: 0
--- !u!1 &8359461402257861397
GameObject:
m_ObjectHideFlags: 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f2673788e9e92e147b38af939d2fb7fe
guid: 51ffbfed19686f041975a6e1757db741
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
@ -45,7 +45,7 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 20
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1

File diff suppressed because it is too large Load Diff

View File

@ -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();
}
}
}

View 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();
}
}
}

View File

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

View File

@ -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);

View File

@ -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()

View File

@ -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;
}
}
}

View File

@ -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
View File

@ -0,0 +1,7 @@
public enum ActorManipulationMode
{
Pan,
Rotate,
Face,
}

View File

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

View 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;
}
}
}

View File

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

View File

@ -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;
}
}
}

View File

@ -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)
{

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.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

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