private void UpdateRotationData(int beatmapEventDataValue, ref RotationData rotationData, float startRotationOffset, float direction) { if (beatmapEventDataValue == 0) { rotationData.enabled = false; for (int i = 0; i < rotationData.transforms.Length; i++) { rotationData.transforms[i].localRotation = rotationData.startRotations[i]; if (_toggleGameObjects) { rotationData.transforms[i].gameObject.SetActive(false); } } return; } if (beatmapEventDataValue > 0) { rotationData.enabled = true; for (int i = 0; i < rotationData.transforms.Length; i++) { if (_toggleGameObjects) { rotationData.transforms[i].gameObject.SetActive(true); } rotationData.transforms[i].localRotation = rotationData.startRotations[i]; rotationData.transforms[i].Rotate(rotationData.rotationVector[i], startRotationOffset, Space.Self); } rotationData.rotationSpeed = beatmapEventDataValue * 20f * direction; } }
/// <summary> Applies a Givens plane rotation</summary> private void applyPlaneRotation(RotationData RD) { double temp = RD.cs * RD.dx + RD.sn * RD.dy; RD.dy = (-RD.sn) * RD.dx + RD.cs * RD.dy; RD.dx = temp; }
internal static Quaternion?GetLocalRotation(dynamic dynData, float time) { Quaternion?localRotation = null; IEnumerable <float> localRotRaw = ((List <object>)Trees.at(dynData, LOCALROTATION))?.Select(Convert.ToSingle); if (localRotRaw != null) { localRotation = Quaternion.Euler(localRotRaw.ElementAt(0), localRotRaw.ElementAt(1), localRotRaw.ElementAt(2)); } List <RotationData> localRotationData = Trees.at(dynData, "varLocalRotation"); if (localRotationData != null) { RotationData truncatedRotation = localRotationData .Where(n => n.time < time) .Where(n => n.time + n.duration > time) .LastOrDefault(); if (truncatedRotation != null) { return(Quaternion.Lerp(truncatedRotation.startRotation, truncatedRotation.endRotation, Easings.Interpolate((time - truncatedRotation.time) / truncatedRotation.duration, truncatedRotation.easing))); } } return(localRotation); }
internal static Quaternion?GetWorldRotation(dynamic dynData, float time) { Quaternion?worldRotation = null; dynamic rotation = Trees.at(dynData, ROTATION); if (rotation != null) { if (rotation is List <object> list) { IEnumerable <float> _rot = (list)?.Select(Convert.ToSingle); worldRotation = Quaternion.Euler(_rot.ElementAt(0), _rot.ElementAt(1), _rot.ElementAt(2)); } else { worldRotation = Quaternion.Euler(0, (float)rotation, 0); } } List <RotationData> rotationData = Trees.at(dynData, "varRotation"); if (rotationData != null) { RotationData truncatedRotation = rotationData .Where(n => n.time < time) .Where(n => n.time + n.duration > time) .LastOrDefault(); if (truncatedRotation != null) { return(Quaternion.Lerp(truncatedRotation.startRotation, truncatedRotation.endRotation, Easings.Interpolate((time - truncatedRotation.time) / truncatedRotation.duration, truncatedRotation.easing))); } } return(worldRotation); }
public void ExecuteBehaviour(object[] args) { //Rotation data RotationData a = new RotationData(args); //Move a.TransformReference.Rotate(a.Axis, a.Speed); }
public static void LerpToRotation(Projectile projectile, RotationData rotData) { if (!float.IsNaN(rotData.rotationAdjustment)) { projectile.rotation = projectile.rotation.AngleTowards(projectile.velocity.ToRotation() - rotData.rotationAdjustment, rotData.rotationAmount); } }
public RotationControl(MainForm owner, RotationData rotationData, int localRotIndex) { InitializeComponent(); _owner = owner; _rotationData = rotationData; _currentRotation = _currentRotation + localRotIndex; UpdateValues(); }
public SplitBoundsBranch(string name, SplittedRegion splittedRegion, Vector3 pos, RotationData data, GroupBranch group) : base (name, pos, data, group) { BaseTree staticBranch = new BaseTree("Static", new Vector3(), this, NodeConfig.StaticAndPropogate); TracksLeaf = new BaseTree("Tracks", new Vector3(), staticBranch, NodeConfig.StaticAndPropogate); BlocksLeaf = new BaseTree("Blocks", new Vector3(), staticBranch, NodeConfig.StaticAndPropogate); OthersLeaf = new BaseTree("Others", new Vector3(), this, NodeConfig.Dynamic); SplittedRegion = splittedRegion; Group = group; group.AddSplitBoundsBranch(this); Name = name; }
private GroupBranch(Vector3 pos, Data groupData, RotationData rotationData, LevelTree level) : base(groupData.Group.Id, pos, rotationData, level) { Level = level; GroupData = groupData; ParticlesLeaf = new BaseTree("Particles", new Vector3(), this, NodeConfig.Dynamic); DoodadsLeaf = new BaseTree("Doodads", new Vector3(), this, NodeConfig.Dynamic); level.AddGroupBranch(this); foreach (SplitTrack track in Tracks) { track.OnAttachedToGroupBranch(this); } }
public override void PostAI(Projectile projectile) { Player player = Main.player[projectile.owner]; if (!SummonRotationAdjustments.ContainsKey(projectile.type)) { return; } RotationData data = SummonRotationAdjustments[projectile.type]; projectile.rotation = _savedRotation; LerpToRotation(projectile, data); if (data.spriteDirectionOverride != 0) { projectile.spriteDirection = data.spriteDirectionOverride; } if (projectile.type == ModContent.ProjectileType <CinderBlossom>()) { float rotationOffsetBySpeed = MathHelper.ToRadians(1.5f) + player.velocity.X / player.maxRunSpeed / 5f * player.direction; rotationOffsetBySpeed *= player.direction; projectile.rotation = _savedRotation + rotationOffsetBySpeed; } if (projectile.type == ModContent.ProjectileType <CalamariMinion>()) { projectile.rotation = _savedRotation; NPC target = player.HasMinionAttackTargetNPC ? Main.npc[player.MinionAttackTargetNPC] : Main.npc.FirstOrDefault(n => n.CanBeChasedBy(projectile)); if (target == null) { return; } Vector2 npcPos = target.position + target.Size * new Vector2(0.5f, 0f); Vector2 wantedRotation = npcPos - projectile.Center; wantedRotation.Normalize(); wantedRotation *= 12f; projectile.rotation = projectile.rotation.AngleTowards(wantedRotation.ToRotation() - MathHelper.PiOver2, 0.2f); } }
internal void Init(Transform[] _transformL, Transform[] _transformR, bool _toggleGameObjects, Vector3[] _rotationVectorsL, Vector3[] _rotationVectorsR, SongEventType _eventL, SongEventType _eventR, bool _useRandomValues) { //this._transformL = _transformL; //this._transformR = _transformR; this._toggleGameObjects = _toggleGameObjects; this._rotationVectorsL = _rotationVectorsL; this._rotationVectorsR = _rotationVectorsR; this._eventL = _eventL; this._eventR = _eventR; this._useRandomValues = _useRandomValues; Quaternion[] rotL = new Quaternion[_transformL.Length]; Quaternion[] rotR = new Quaternion[_transformR.Length]; for (int i = 0; i < _transformL.Length; i++) { rotL[i] = _transformL[i].rotation; } for (int i = 0; i < _transformR.Length; i++) { rotR[i] = _transformR[i].rotation; } _rotationDataL = new RotationData { enabled = false, rotationSpeed = 0f, startRotations = rotL, transforms = _transformL, rotationVector = _rotationVectorsL }; _rotationDataR = new RotationData { enabled = false, rotationSpeed = 0f, startRotations = rotR, transforms = _transformR, rotationVector = _rotationVectorsR }; enabled = false; if (_toggleGameObjects) { for (int i = 0; i < _rotationVectorsL.Length; i++) { _rotationDataL.transforms[i].gameObject.SetActive(false); } for (int i = 0; i < _rotationVectorsR.Length; i++) { _rotationDataR.transforms[i].gameObject.SetActive(false); } } }
public static Matrix4x4 RotationEulerInverse(Vector3 rotation) { RotationData rot = new RotationData(rotation); //!xelpmoc yllaer s'tI return(new Matrix4x4( m11: rot.cosXYZ.Z *rot.cosXYZ.Y, m21: rot.sinXYZ.Z *rot.cosXYZ.Y, m31: -rot.sinXYZ.Y, m12: -rot.cosXsinZ + rot.cosXYZ.Z * rot.sinXsinY, m22: rot.cosXYZ.Z *rot.cosXYZ.X + rot.sinXYZ.Z *rot.sinXsinY, m32: rot.cosXYZ.Y * rot.sinXYZ.X, m13: rot.cosXYZ.Z * rot.cosXsinY + rot.sinXsinZ, m23: -rot.cosXYZ.Z * rot.sinXYZ.X + rot.sinXYZ.Z * rot.cosXsinY, m33: rot.cosXYZ.Y * rot.cosXYZ.X, m14: 0, m24: 0, m34: 0, m41: 0, m42: 0, m43: 0, m44: 1)); }
public static Matrix4x4 RotationEuler(Vector3 rotation) { RotationData rot = new RotationData(rotation); //It's really complex! return(new Matrix4x4( m11: rot.cosXYZ.Y *rot.cosXYZ.Z, m21: rot.sinXsinY *rot.cosXYZ.Z - rot.cosXsinZ, m31: rot.cosXsinY * rot.cosXYZ.Z + rot.sinXsinZ, m12: rot.cosXYZ.Y * rot.sinXYZ.Z, m22: rot.cosXYZ.X * rot.cosXYZ.Z + rot.sinXsinY * rot.sinXYZ.Z, m32: -rot.sinXYZ.X * rot.cosXYZ.Z, m13: -rot.sinXYZ.Y, m23: rot.sinXYZ.X * rot.cosXYZ.Y, m33: rot.cosXYZ.X * rot.cosXYZ.Y, m14: 0, m24: 0, m34: 0, m41: 0, m42: 0, m43: 0, m44: 1)); }
/// <summary> Constructs a Givens rotation, to be used by applyPlaneRotation</summary> private void generatePlaneRotation(RotationData RD) { if (RD.dy == 0.0) { RD.cs = 1.0; RD.sn = 0.0; } else if (Math.Abs(RD.dy) > Math.Abs(RD.dx)) { double temp = RD.dx / RD.dy; RD.sn = 1.0 / Math.Sqrt(1.0 + temp * temp); RD.cs = temp * RD.sn; } else { double temp = RD.dy / RD.dx; RD.cs = 1.0 / Math.Sqrt(1.0 + temp * temp); RD.sn = temp * RD.cs; } }
public static LightPairRotationEffectController Create(LightPairRotationEventEffect baseEffect) { BeatmapEventType eventToggleRandomize = Helper.GetValue <BeatmapEventType>(baseEffect, "_switchOverrideRandomValuesEvent"); BeatmapEventType eventL = Helper.GetValue <BeatmapEventType>(baseEffect, "_eventL"); BeatmapEventType eventR = Helper.GetValue <BeatmapEventType>(baseEffect, "_eventR"); bool useZOffset = Helper.GetValue <bool>(baseEffect, "_useZPositionForAngleOffset"); float zOffsetScale = Helper.GetValue <float>(baseEffect, "_zPositionAngleOffsetScale"); Vector3 rotationVector = Helper.GetValue <Vector3>(baseEffect, "_rotationVector"); object baseRotationDataL = Helper.GetValue <object>(baseEffect, "_rotationDataL"); object baseRotationDataR = Helper.GetValue <object>(baseEffect, "_rotationDataR"); Transform transformL = Helper.GetValue <Transform>(baseRotationDataL, "transform"); Quaternion startRotationL = Helper.GetValue <Quaternion>(baseRotationDataL, "startRotation"); float startRotationAngleL = Helper.GetValue <float>(baseRotationDataL, "startRotationAngle"); Transform transformR = Helper.GetValue <Transform>(baseRotationDataR, "transform"); Quaternion startRotationR = Helper.GetValue <Quaternion>(baseRotationDataR, "startRotation"); float startRotationAngleR = Helper.GetValue <float>(baseRotationDataR, "startRotationAngle"); RotationData rotationDataL = new RotationData(transformL, startRotationL, startRotationAngleL); RotationData rotationDataR = new RotationData(transformR, startRotationR, startRotationAngleR); LightPairRotationEffectController controller = new GameObject("TwitchFXLightPairRotationEffectController").AddComponent <LightPairRotationEffectController>(); controller.eventToggleRandomize = eventToggleRandomize; controller.eventL = eventL; controller.eventR = eventR; controller.transform = baseEffect.transform; controller.useZOffset = useZOffset; controller.zOffsetScale = zOffsetScale; controller.rotationVector = rotationVector; controller.rotationL = rotationDataL; controller.rotationR = rotationDataR; return(controller); }
private static void AddRotationDataToClip(IReadOnlyList <RotationData> rotationData, string boneName, AnimationClip clip) { int frameCount = rotationData.Count; Keyframe[] rotX = new Keyframe[frameCount]; Keyframe[] rotY = new Keyframe[frameCount]; Keyframe[] rotZ = new Keyframe[frameCount]; Keyframe[] rotW = new Keyframe[frameCount]; for (int i = 0; i < frameCount; i++) { RotationData data = rotationData[i]; rotX[i] = new Keyframe(data.Time, data.X); rotY[i] = new Keyframe(data.Time, data.Y); rotZ[i] = new Keyframe(data.Time, data.Z); rotW[i] = new Keyframe(data.Time, data.W); } clip.SetCurve(boneName, typeof(Transform), "localRotation.x", new AnimationCurve(rotX)); clip.SetCurve(boneName, typeof(Transform), "localRotation.y", new AnimationCurve(rotY)); clip.SetCurve(boneName, typeof(Transform), "localRotation.z", new AnimationCurve(rotZ)); clip.SetCurve(boneName, typeof(Transform), "localRotation.w", new AnimationCurve(rotW)); }
public PlayerData() { rotation = new RotationData(); position = new Vector3Data(); }
void Instantiate(int count) { var planetOwnership = new List <int> { 1, 1, 2, 2 }; for (var i = 0; i < count; ++i) { var sphereRadius = UnityEngine.Random.Range(5.0f, 20.0f); var safe = false; float3 pos; int attempts = 0; do { if (++attempts >= 500) { Debug.Log("Couldn't find a good planet placement. Settling for the planets we already have"); return; } var randomValue = (Vector3)UnityEngine.Random.insideUnitSphere; randomValue.y = 0; pos = (randomValue * radius) + new Vector3(transform.position.x, transform.position.z); var collisions = Physics.OverlapSphere(pos, sphereRadius); if (!collisions.Any()) { safe = true; } } while (!safe); var randomRotation = UnityEngine.Random.insideUnitSphere; var go = GameObject.Instantiate(_planetPrefab, pos, quaternion.identity); var planetEntity = go.GetComponent <GameObjectEntity>().Entity; var meshGo = go.GetComponentsInChildren <Transform>().First(c => c.gameObject != go).gameObject; var collider = go.GetComponent <SphereCollider>(); var meshEntity = meshGo.GetComponent <GameObjectEntity>().Entity; collider.radius = sphereRadius; meshGo.transform.localScale = new Vector3(sphereRadius * 2.0f, sphereRadius * 2.0f, sphereRadius * 2.0f); var planetData = new PlanetData { TeamOwnership = 0, Radius = sphereRadius, Position = pos }; var rotationData = new RotationData { RotationSpeed = randomRotation }; if (planetOwnership.Any()) { planetData.TeamOwnership = planetOwnership.First(); planetOwnership.Remove(planetData.TeamOwnership); } else { planetData.Occupants = UnityEngine.Random.Range(1, 100); } entities[planetEntity] = go; SetColor(planetEntity, planetData.TeamOwnership); _entityManager.AddComponentData(planetEntity, planetData); _entityManager.AddComponentData(meshEntity, rotationData); } }
public void OnEvent(BeatmapEventData eventData) { if (eventData.type == eventToggleRandomize) { randomizeValues = !randomizeValues; } int currentFrame = Time.frameCount; if ( (eventData.type == eventL || eventData.type == eventR || eventData.type == eventToggleRandomize) && currentFrame != lastValueGenerationFrame ) { if (randomizeValues) { startRotationGenerated = Random.Range(0f, 180f); directionGenerated = Random.value > 0.5f ? 1f : -1f; } else { startRotationGenerated = eventData.type == eventL ? currentFrame : -currentFrame; if (useZOffset) { startRotationGenerated += transform.position.z * zOffsetScale; } directionGenerated = eventData.type == eventL ? 1f : -1f; } lastValueGenerationFrame = currentFrame; } if (eventData.type == eventL || eventData.type == eventR) { CustomBeatmapEventData customEventData = eventData as CustomBeatmapEventData; float direction = customEventData?.direction ?? directionGenerated; float speed = customEventData?.rotationSpeed ?? eventData.value; bool lockPosition = customEventData?.rotationLockPosition ?? false; float?startPosition = customEventData?.rotationStartPosition; if (eventData.type != eventL) { direction = -direction; } RotationData rotation = eventData.type == eventL ? rotationL : rotationR; if (startPosition.HasValue) { rotation.rotationAngle = (eventData.type == eventL ? startPosition.Value : -startPosition.Value) + rotation.startRotationAngle; rotation.transform.localRotation = rotation.startRotation * Quaternion.Euler(rotationVector * rotation.rotationAngle); } if (eventData.value == 0) { rotation.enabled = false; if (!lockPosition && !startPosition.HasValue) { rotation.transform.localRotation = rotation.startRotation * Quaternion.Euler(rotationVector * rotation.startRotationAngle); } } else if (eventData.value > 0) { rotation.enabled = true; rotation.rotationSpeed = speed * direction * 20f; if (!lockPosition && !startPosition.HasValue) { rotation.rotationAngle = (eventData.type == eventL ? startRotationGenerated : -startRotationGenerated) + rotation.startRotationAngle; rotation.transform.localRotation = rotation.startRotation * Quaternion.Euler(rotationVector * rotation.rotationAngle); } } } else if (eventData.type == eventToggleRandomize) { rotationL.rotationAngle = startRotationGenerated + rotationL.startRotationAngle; rotationL.rotationSpeed = Mathf.Abs(rotationL.rotationSpeed); rotationR.rotationAngle = -startRotationGenerated + rotationR.startRotationAngle; rotationR.rotationSpeed = -Mathf.Abs(rotationL.rotationSpeed); } enabled = rotationL.enabled || rotationR.enabled; }
/// <summary> /// Helper method to read all animations from a Puppet file and return a list of them /// </summary> /// <param name="sectionReader">BinaryReader instance containing the Animation section data</param> /// <param name="version">Version of the Puppet file</param> /// <returns>List of animations from the Puppet file</returns> public static List <Animation> ReadAllAnimations(BinaryReader sectionReader, Version version) { List <Animation> Animations = new List <Animation>(); while (sectionReader.BaseStream.Position < sectionReader.BaseStream.Length) { Animation animation = new Animation(); animation.BoneID = sectionReader.ReadByte(); // Once the root bone is reached (ID 255) stop reading animations if (animation.BoneID == 255) { break; } // Bone ID 254 have two additional bytes after the ID (FE 00) to skip over if (animation.BoneID == 254) { animation.SubID = sectionReader.ReadByte(); animation.SubSubID = sectionReader.ReadByte(); } uint positionDataCount = sectionReader.ReadUInt32(); animation.PositionData = new PositionData[positionDataCount]; for (int i = 0; i < positionDataCount; i++) { PositionData positionData = new PositionData { Time = sectionReader.ReadSingle(), X = sectionReader.ReadSingle(), Y = sectionReader.ReadSingle(), Z = sectionReader.ReadSingle(), }; animation.PositionData[i] = positionData; } uint rotationDataCount = sectionReader.ReadUInt32(); animation.RotationData = new RotationData[rotationDataCount]; if (version.Minor == 0) { // TODO: Check if this is an unknown value or just padding animation.Unknown1 = sectionReader.ReadUInt32(); } for (int i = 0; i < rotationDataCount; i++) { RotationData rotationData; if (version.Minor >= 2) { rotationData = new RotationData { Time = sectionReader.ReadSingle(), X = sectionReader.ReadSingle(), Y = sectionReader.ReadSingle(), Z = sectionReader.ReadSingle(), W = sectionReader.ReadSingle() }; } else { rotationData = new RotationData { X = sectionReader.ReadSingle(), Y = sectionReader.ReadSingle(), Z = sectionReader.ReadSingle(), W = sectionReader.ReadSingle(), Time = sectionReader.ReadSingle() }; } animation.RotationData[i] = rotationData; } if (version.Minor >= 2) { uint scalingDataCount = sectionReader.ReadUInt32(); animation.ScalingData = new ScalingData[scalingDataCount]; for (int i = 0; i < scalingDataCount; i++) { ScalingData scalingData = new ScalingData { Time = sectionReader.ReadSingle(), X = sectionReader.ReadSingle(), Y = sectionReader.ReadSingle(), Z = sectionReader.ReadSingle() }; animation.ScalingData[i] = scalingData; } } if (version.Minor >= 3) { uint animationFlagCount = sectionReader.ReadUInt32(); animation.AnimationFlags = new AnimationFlag[animationFlagCount]; for (int i = 0; i < animationFlagCount; i++) { AnimationFlag animationFlag = new AnimationFlag { Time = sectionReader.ReadSingle(), Value = sectionReader.ReadSingle() }; animation.AnimationFlags[i] = animationFlag; } } Animations.Add(animation); } return(Animations); }
public static GroupBranch CreateAndAttachTo(LevelTree level, Data groupData, RotationData rotationData) { return new GroupBranch(new Vector3(), groupData, rotationData, level); }
protected internal override void SolveI(IMatrix A, IVector b, IVector x) { IVector[] tempv = Factory.createVectors(b, 3); IVector w = tempv[0], temp = tempv[1], r = tempv[2]; double[] s = new double[restart + 1], cs = new double[restart + 1], sn = new double[restart + 1]; double[,] H = new double[restart + 1, restart]; for (int i = 0; i < restart + 1; i++) { // { // H[i] = new double[restart]; // } temp = Blas.Default.MultAdd(-1.0, A, x, b, temp); } r = M.Apply(A, temp, r); double normr = Blas.Default.Norm(r, NORMS.NORM2); temp = M.Apply(A, b, temp); IVector[] v = Factory.createVectors(b, restart + 1); for (iter.Reset(); !iter.Converged(r, x); iter.MoveNext()) { v[0] = Blas.Default.ScaleCopy(1.0 / normr, r, v[0]); SupportClass.ArraySupport.Fill(s, 0.0); s[0] = normr; for (int i = 0; i < restart; i++, iter.MoveNext()) { temp = Blas.Default.Mult(A, v[i], temp); w = M.Apply(A, temp, w); for (int k = 0; k <= i; k++) { H[k, i] = Blas.Default.Dot(w, v[k]); w = Blas.Default.Add(-H[k, i], v[k], w); } H[i + 1, i] = Blas.Default.Norm(w, NORMS.NORM2); v[i + 1] = Blas.Default.ScaleCopy(1.0 / H[i + 1, i], w, v[i + 1]); for (int k = 0; k < i; k++) { RotationData RD = new RotationData(this, H[k, i], H[k + 1, i], cs[k], sn[k]); applyPlaneRotation(RD); H[k, i] = RD.dx; H[k + 1, i] = RD.dy; cs[k] = RD.cs; sn[k] = RD.sn; } RotationData RD2 = new RotationData(this, H[i, i], H[i + 1, i], cs[i], sn[i]); generatePlaneRotation(RD2); H[i, i] = RD2.dx; H[i + 1, i] = RD2.dy; cs[i] = RD2.cs; sn[i] = RD2.sn; applyPlaneRotation(RD2); H[i, i] = RD2.dx; H[i + 1, i] = RD2.dy; cs[i] = RD2.cs; sn[i] = RD2.sn; RD2.dx = s[i]; RD2.dy = s[i + 1]; applyPlaneRotation(RD2); s[i] = RD2.dx; s[i + 1] = RD2.dy; cs[i] = RD2.cs; sn[i] = RD2.sn; if (iter.Converged(Math.Abs(s[i + 1]), x)) { update(x, i, s, v, H); return; } } update(x, restart - 1, s, v, H); temp = Blas.Default.MultAdd(-1.0, A, x, b, temp); r = M.Apply(A, temp, r); normr = Blas.Default.Norm(r, NORMS.NORM2); } }
public static SplitBoundsBranch CreateAndAttachTo(int count, SplittedRegion splittedRegion, GroupBranch groupBranch, RotationData rotationData) { string name = "split_" + count; return new SplitBoundsBranch(name, splittedRegion, new Vector3(), rotationData, groupBranch); }
protected RotateableBranch(string name, Vector3 pos, RotationData data, BaseTree parent) : base(name, pos, parent, NodeConfig.Dynamic) { Data = data; }
public RotationAnimator(RotationData rotationData, Transform transform) { RotationData = rotationData; Transform = transform; }