Manual timeline, cycle and actor tweaking
This commit is contained in:
parent
dfa564759b
commit
1dd7781179
Binary file not shown.
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
public enum ActorManipulationMode
|
||||
{
|
||||
Pan,
|
||||
Rotate,
|
||||
Face,
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee120e06e7d8c1f45ad58fc6baab0d47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
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.
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.
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.
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