mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Keyframe stretching plus appendage manipulation
This commit is contained in:
parent
18c0473f39
commit
1af7f41d63
427 changed files with 7003 additions and 1147 deletions
|
@ -9,16 +9,31 @@ namespace RimWorldAnimationStudio
|
|||
public class ActorBody : MonoBehaviour, IPointerClickHandler, IDragHandler
|
||||
{
|
||||
public int actorID;
|
||||
public string bodyType = "Male";
|
||||
public string bodyType = "Male";
|
||||
public bool isSelected = false;
|
||||
|
||||
public SpriteRenderer bodyRenderer;
|
||||
public SpriteRenderer headRenderer;
|
||||
public SpriteRenderer appendageRenderer;
|
||||
|
||||
public bool actorBodyPartSelected { get { return GetComponentsInChildren<ActorBodyPart>().Any(x => x.isSelected); } }
|
||||
|
||||
public void Initialize(int actorID)
|
||||
{
|
||||
this.actorID = actorID;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (Workspace.actorID == actorID && Workspace.selectedBodyPart == null)
|
||||
{ bodyRenderer.color = Constants.ColorGreen; }
|
||||
|
||||
else
|
||||
{ bodyRenderer.color = Constants.ColorWhite; }
|
||||
|
||||
appendageRenderer.gameObject.SetActive(Workspace.animationDef.actors[actorID].requiredGenitals.Any(x => x == "Penis" || x == "Any appendage"));
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.pointerCurrentRaycast.gameObject.GetComponent<ActorBody>() == null)
|
||||
|
@ -31,9 +46,9 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
Activate();
|
||||
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe(true);
|
||||
|
||||
if (Workspace.Instance.GetCurrentPawnKeyframe() == null)
|
||||
if (keyframe == null)
|
||||
{ Debug.LogWarning("Cannot alter actor - no keyframe data available"); return; }
|
||||
|
||||
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
@ -66,18 +81,28 @@ namespace RimWorldAnimationStudio
|
|||
public void Activate()
|
||||
{
|
||||
Workspace.actorID = actorID;
|
||||
Workspace.selectedBodyPart = null;
|
||||
|
||||
foreach (ActorBody actorBody in AnimationController.Instance.actorBodies.GetComponentsInChildren<ActorBody>())
|
||||
/*foreach (ActorBody actorBody in AnimationController.Instance.actorBodies.GetComponentsInChildren<ActorBody>())
|
||||
{
|
||||
if (actorBody == this)
|
||||
{ continue; }
|
||||
|
||||
actorBody.bodyRenderer.color = Constants.ColorWhite;
|
||||
actorBody.headRenderer.color = Constants.ColorWhite;
|
||||
actorBody.appendageRenderer.color = Constants.ColorWhite;
|
||||
|
||||
actorBody.isSelected = false;
|
||||
}
|
||||
|
||||
bodyRenderer.color = Constants.ColorGreen;
|
||||
headRenderer.color = Constants.ColorGreen;
|
||||
appendageRenderer.color = Constants.ColorGreen;
|
||||
|
||||
foreach (ActorBodyPart actorBodyPartSelected in GetComponentsInChildren<ActorBodyPart>())
|
||||
{ actorBodyPartSelected.isSelected = false; }
|
||||
|
||||
isSelected = true;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,17 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
public SpriteRenderer bodyPartRenderer;
|
||||
public ActorBody parent;
|
||||
public bool isHead = false;
|
||||
public bool isSelected = false;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if ((Workspace.actorID == parent.actorID && Workspace.selectedBodyPart == null) || Workspace.selectedBodyPart == this)
|
||||
{ bodyPartRenderer.color = Constants.ColorGreen; }
|
||||
|
||||
else
|
||||
{ bodyPartRenderer.color = Constants.ColorWhite; }
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
|
@ -23,38 +34,48 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
Activate();
|
||||
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe(true);
|
||||
|
||||
if (Workspace.Instance.GetCurrentPawnKeyframe() == null)
|
||||
if (keyframe == null)
|
||||
{ Debug.LogWarning("Cannot alter actor - no keyframe data available"); return; }
|
||||
|
||||
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
||||
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
|
||||
if (isHead)
|
||||
{
|
||||
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));
|
||||
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
|
||||
{
|
||||
Vector3 headOffset = new Vector3(0f, 0.34f, 0f);
|
||||
headOffset = Quaternion.Euler(0, 0, keyframe.bodyAngle) * headOffset;
|
||||
|
||||
keyframe.headBob = distance;
|
||||
float distance = Vector2.Dot(parent.transform.up, (Vector2)(mousePosition - parent.transform.position - headOffset));
|
||||
|
||||
keyframe.headBob = distance;
|
||||
}
|
||||
|
||||
else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
keyframe.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;
|
||||
|
||||
keyframe.headFacing = facing;
|
||||
}
|
||||
}
|
||||
|
||||
else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
|
||||
else
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
keyframe.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;
|
||||
|
||||
keyframe.headFacing = facing;
|
||||
if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
|
||||
{
|
||||
float angle = Vector2.SignedAngle(Vector2.up, (Vector2)mousePosition - (Vector2)transform.position);
|
||||
keyframe.genitalAngle = angle;
|
||||
}
|
||||
}
|
||||
|
||||
PawnAnimationClip clip = Workspace.Instance.GetPawnAnimationClip(parent.actorID);
|
||||
|
@ -64,14 +85,23 @@ namespace RimWorldAnimationStudio
|
|||
public void Activate()
|
||||
{
|
||||
Workspace.actorID = parent.actorID;
|
||||
Workspace.selectedBodyPart = this;
|
||||
|
||||
/*foreach (ActorBodyPart actorBodyPart in AnimationController.Instance.actorBodies.GetComponentsInChildren<ActorBodyPart>())
|
||||
{
|
||||
actorBodyPart.isSelected = false;
|
||||
}
|
||||
|
||||
foreach (ActorBody actorBody in AnimationController.Instance.actorBodies.GetComponentsInChildren<ActorBody>())
|
||||
{
|
||||
actorBody.bodyRenderer.color = Constants.ColorWhite;
|
||||
actorBody.headRenderer.color = Constants.ColorWhite;
|
||||
actorBody.appendageRenderer.color = Constants.ColorWhite;
|
||||
}
|
||||
|
||||
bodyPartRenderer.color = Constants.ColorGreen;
|
||||
|
||||
isSelected = true;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,14 @@ namespace RimWorldAnimationStudio
|
|||
public InputField positionXField;
|
||||
public InputField positionZField;
|
||||
public InputField rotationField;
|
||||
public InputField headBobField;
|
||||
public InputField headRotationField;
|
||||
public InputField appendageRotationField;
|
||||
|
||||
private int lastTick = -1;
|
||||
private bool isDirty = false;
|
||||
|
||||
// Move to anim controller
|
||||
public void Update()
|
||||
{
|
||||
if ((Workspace.animationDef == null || AnimationController.Instance.stageTick == lastTick) && isDirty == false)
|
||||
|
@ -41,15 +45,17 @@ namespace RimWorldAnimationStudio
|
|||
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);
|
||||
|
||||
float headBob = clip.HeadBob.Evaluate(clipPercent);
|
||||
Vector3 bodyPos = new Vector3(deltaPos.x, deltaPos.z, 0);
|
||||
Vector3 headPos = new Vector3(headBob.x, headBob.z, 0);
|
||||
|
||||
float appendageRotation = clip.GenitalAngle.Evaluate(clipPercent);
|
||||
|
||||
positionXField.text = bodyPos.x.ToString("0.000");
|
||||
positionZField.text = bodyPos.y.ToString("0.000");
|
||||
rotationField.text = bodyAngle.ToString("0.000");
|
||||
headBobField.text = headBob.ToString("0.000");
|
||||
headRotationField.text = headAngle.ToString("0.000");
|
||||
appendageRotationField.text = appendageRotation.ToString("0.000");
|
||||
|
||||
lastTick = AnimationController.Instance.stageTick;
|
||||
isDirty = false;
|
||||
|
@ -57,12 +63,19 @@ namespace RimWorldAnimationStudio
|
|||
|
||||
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);
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe(true);
|
||||
|
||||
keyframe.bodyOffsetX = float.Parse(positionXField.text);
|
||||
keyframe.bodyOffsetZ = float.Parse(positionZField.text);
|
||||
keyframe.bodyAngle = float.Parse(rotationField.text);
|
||||
keyframe.headBob = float.Parse(headBobField.text);
|
||||
keyframe.headAngle = float.Parse(headRotationField.text);
|
||||
keyframe.genitalAngle = float.Parse(appendageRotationField.text);
|
||||
|
||||
Workspace.Instance.GetPawnAnimationClip(Workspace.actorID).BuildSimpleCurves();
|
||||
isDirty = true;
|
||||
|
||||
Workspace.Instance.MakeDirty();
|
||||
}
|
||||
}
|
||||
}
|
28
Assets/Scripts/GUI/AddSoundDefButton.cs
Normal file
28
Assets/Scripts/GUI/AddSoundDefButton.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class AddSoundDefButton : MonoBehaviour
|
||||
{
|
||||
private Text text;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
text = GetComponentInChildren<Text>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
|
||||
|
||||
if (keyframe != null)
|
||||
{ text.text = keyframe.soundEffect == null || keyframe.soundEffect == "" ? "None" : keyframe.soundEffect; }
|
||||
|
||||
else
|
||||
{ text.text = "None"; }
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/GUI/AddSoundDefButton.cs.meta
Normal file
11
Assets/Scripts/GUI/AddSoundDefButton.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 329a2ecc35813f94fa879c7f434c8fb7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
88
Assets/Scripts/GUI/DialogBoxes/SelectSoundDefDialog.cs
Normal file
88
Assets/Scripts/GUI/DialogBoxes/SelectSoundDefDialog.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class SelectSoundDefDialog : DialogBox
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void AddSoundDef(InputField field)
|
||||
{
|
||||
if (field?.text == null || field.text == "")
|
||||
{ return; }
|
||||
|
||||
if (Workspace.soundDefs.Contains(field.text))
|
||||
{ field.text = ""; return; }
|
||||
|
||||
Workspace.soundDefs.Add(field.text);
|
||||
|
||||
Initialize(true);
|
||||
}
|
||||
|
||||
public void Initialize(bool addedNewTag = false)
|
||||
{
|
||||
if (Workspace.animationDef == null) return;
|
||||
|
||||
foreach (AnimationStage stage in Workspace.animationDef.animationStages)
|
||||
{
|
||||
foreach (PawnAnimationClip clip in stage.animationClips)
|
||||
{
|
||||
foreach (string soundDef in clip.keyframes.Select(x => x.soundEffect))
|
||||
{
|
||||
if (Workspace.soundDefs.Contains(soundDef) == false && soundDef != "")
|
||||
{ Workspace.soundDefs.Add(soundDef); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Transform contentWindow = transform.FindDeepChild("Content");
|
||||
Reset();
|
||||
|
||||
for (int i = 0; i < Workspace.soundDefs.Count; i++)
|
||||
{
|
||||
string soundDef = Workspace.soundDefs[i];
|
||||
|
||||
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
|
||||
_optionToggle.Find("Text").GetComponent<Text>().text = soundDef;
|
||||
|
||||
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
|
||||
toggleComp.isOn = Workspace.animationDef.sexTypes.Contains(soundDef);
|
||||
toggleComp.onValueChanged.AddListener(delegate {
|
||||
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
|
||||
|
||||
if (keyframe != null)
|
||||
{ keyframe.soundEffect = soundDef; }
|
||||
|
||||
Workspace.Instance.MakeDirty();
|
||||
});
|
||||
|
||||
toggleComp.group = contentWindow.GetComponent<ToggleGroup>();
|
||||
|
||||
if (addedNewTag && i == Workspace.soundDefs.Count - 1)
|
||||
{ toggleComp.isOn = true; }
|
||||
}
|
||||
|
||||
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
|
||||
_optionField.Find("Placeholder").GetComponent<Text>().text = "Enter new sound def...";
|
||||
|
||||
InputField fieldComp = _optionField.GetComponent<InputField>();
|
||||
fieldComp.onEndEdit.AddListener(delegate { AddSoundDef(fieldComp); });
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Transform contentWindow = transform.FindDeepChild("Content");
|
||||
RemoveCloneObjectsFromParent(contentWindow);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/GUI/DialogBoxes/SelectSoundDefDialog.cs.meta
Normal file
11
Assets/Scripts/GUI/DialogBoxes/SelectSoundDefDialog.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7cc6afc7ba6ae0f42b3a2df6e73c5b16
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -14,6 +14,8 @@ namespace RimWorldAnimationStudio
|
|||
public AnimationTimeline timeline;
|
||||
public Transform ghostSliders;
|
||||
public Slider ghostSliderPrefab;
|
||||
public Image handleImage;
|
||||
public GameObject soundIcon;
|
||||
public int maxGhosts = 4;
|
||||
|
||||
public int actorID;
|
||||
|
@ -131,17 +133,25 @@ namespace RimWorldAnimationStudio
|
|||
{
|
||||
base.Update();
|
||||
|
||||
if (Workspace.keyframeID == keyframeID && AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
||||
{ transform.FindDeepChild("Handle").GetComponent<Image>().color = Constants.ColorPurple; }
|
||||
if (keyframe.atTick.HasValue && Workspace.keyframeID == keyframeID && AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
||||
{ handleImage.color = Constants.ColorPurple; }
|
||||
|
||||
else if (Workspace.keyframeID == keyframeID)
|
||||
{ transform.FindDeepChild("Handle").GetComponent<Image>().color = Constants.ColorCyan; }
|
||||
{ handleImage.color = Constants.ColorCyan; }
|
||||
|
||||
else if (AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
||||
{ transform.FindDeepChild("Handle").GetComponent<Image>().color = Constants.ColorPink; }
|
||||
else if (keyframe.atTick.HasValue && AnimationController.Instance.stageTick == keyframe.atTick.Value)
|
||||
{ handleImage.color = Constants.ColorPink; }
|
||||
|
||||
else
|
||||
{ transform.FindDeepChild("Handle").GetComponent<Image>().color = Constants.ColorWhite; }
|
||||
{ handleImage.color = Constants.ColorWhite; }
|
||||
|
||||
string soundDef = Workspace.Instance.GetPawnKeyframe(actorID, keyframeID).soundEffect;
|
||||
|
||||
if (soundDef != null && soundDef != "" && soundDef != "None")
|
||||
{ soundIcon.SetActive(true); }
|
||||
|
||||
else
|
||||
{ soundIcon.SetActive(false); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
Assets/Scripts/GUI/QuiverToggle.cs
Normal file
24
Assets/Scripts/GUI/QuiverToggle.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class QuiverToggle : MonoBehaviour
|
||||
{
|
||||
public void Update()
|
||||
{
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
|
||||
GetComponent<Toggle>().isOn = keyframe != null && keyframe.quiver.HasValue && keyframe.quiver.Value;
|
||||
}
|
||||
|
||||
public void OnValueChanged()
|
||||
{
|
||||
PawnKeyframe keyframe = Workspace.Instance.GetCurrentPawnKeyframe();
|
||||
|
||||
if (keyframe != null)
|
||||
{ keyframe.quiver = GetComponent<Toggle>().isOn; }
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/GUI/QuiverToggle.cs.meta
Normal file
11
Assets/Scripts/GUI/QuiverToggle.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1aaf656fd4e788245accc65162730545
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue