Skip to content

Instantly share code, notes, and snippets.

@simon56modder
Last active August 28, 2021 10:07
Show Gist options
  • Save simon56modder/eea8c648639a73711195a7bd28fb3b1c to your computer and use it in GitHub Desktop.
Save simon56modder/eea8c648639a73711195a7bd28fb3b1c to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICities;
using ColossalFramework;
using UnityEngine;
using ProceduralObjects;
using ProceduralObjects.Classes;
using ProceduralObjects.UI;
using ProceduralObjects.Tools;
namespace BackAndForthModule
{
public class BackAndForthPOMod : LoadingExtensionBase, IUserMod
{
public string Name { get { return "Back-and-Forth Module"; } }
public string Description { get { return "Back-and-forth behaviour module for Procedural Objects"; } }
private POModuleType moduleType;
public override void OnCreated(ILoading loading)
{
base.OnCreated(loading);
if (moduleType == null)
{
moduleType = new POModuleType()
{
Name = Name,
Author = "Simon Royer",
TypeID = "BackAndForthModule",
ModuleType = typeof(BackAndForthModule),
maxModulesOnMap = 1000
};
}
if (!ProceduralObjectsMod.ModuleTypes.Contains(moduleType))
ProceduralObjectsMod.ModuleTypes.Add(moduleType);
}
public override void OnReleased()
{
base.OnReleased();
if (moduleType == null)
return;
if (ProceduralObjectsMod.ModuleTypes.Contains(moduleType))
ProceduralObjectsMod.ModuleTypes.Remove(moduleType);
}
}
public class BackAndForthModule : POModule
{
public Vector3 absPointA = Vector3.zero, absPointB = Vector3.zero, relPointA, relPointB;
public byte speedCurve;
public bool groupFollows;
public float animDurationAB = 3f, animDurationBA = 3f, restingTimePointA = 1f, restingTimePointB = 1f;
private float totalTime, Timer;
public readonly Vector3 modifyingMarker = new Vector3(2000f, -95.267894f, 2000f);
private GUIUtils.FloatInputField animABfield, animBAfield, restAfield, restBfield;
public override void OnModuleCreated(ProceduralObjectsLogic logic)
{
base.OnModuleCreated(logic);
window = new Rect(0, 0, 325, 250);
animABfield = new GUIUtils.FloatInputField(animDurationAB);
animBAfield = new GUIUtils.FloatInputField(animDurationBA);
restAfield = new GUIUtils.FloatInputField(restingTimePointA);
restBfield = new GUIUtils.FloatInputField(restingTimePointB);
if ((absPointA == Vector3.zero && absPointB == Vector3.zero) && (relPointA != Vector3.zero && relPointB != Vector3.zero))
{
absPointA = parentObject.m_position - relPointA;
absPointB = parentObject.m_position + relPointB;
}
else if ((absPointA != Vector3.zero && absPointB != Vector3.zero) && (relPointA == Vector3.zero && relPointB == Vector3.zero))
calculateRelativePos();
}
public override void GetData(Dictionary<string, string> data, bool forSaveGame)
{
if (forSaveGame)
{
data.Add("pointA", absPointA.ToStringUnrounded());
data.Add("pointB", absPointB.ToStringUnrounded());
}
else
{
data.Add("relPointA", relPointA.ToStringUnrounded());
data.Add("relPointB", relPointB.ToStringUnrounded());
}
data.Add("speedCurve", speedCurve.ToString());
data.Add("groupFollows", groupFollows.ToString());
data.Add("timer", Timer.ToString());
data.Add("animDurationAB", animDurationAB.ToString());
data.Add("animDurationBA", animDurationBA.ToString());
data.Add("restingTimePointA", restingTimePointA.ToString());
data.Add("restingTimePointB", restingTimePointB.ToString());
}
public override void LoadData(Dictionary<string, string> data, bool fromSaveGame)
{
if (fromSaveGame)
{
if (data.ContainsKey("pointA"))
absPointA = VertexUtils.ParseVector3(data["pointA"]);
if (data.ContainsKey("pointB"))
absPointB = VertexUtils.ParseVector3(data["pointB"]);
}
else
{
if (data.ContainsKey("relPointA"))
relPointA = VertexUtils.ParseVector3(data["relPointA"]);
if (data.ContainsKey("relPointB"))
relPointB = VertexUtils.ParseVector3(data["relPointB"]);
}
if (data.ContainsKey("speedCurve"))
speedCurve = byte.Parse(data["speedCurve"]);
if (data.ContainsKey("groupFollows"))
groupFollows = bool.Parse(data["groupFollows"]);
if (data.ContainsKey("timer"))
Timer = float.Parse(data["timer"]);
if (data.ContainsKey("animDurationAB"))
animDurationAB = float.Parse(data["animDurationAB"]);
if (data.ContainsKey("animDurationBA"))
animDurationBA = float.Parse(data["animDurationBA"]);
if (data.ContainsKey("restingTimePointA"))
restingTimePointA = float.Parse(data["restingTimePointA"]);
if (data.ContainsKey("restingTimePointB"))
restingTimePointB = float.Parse(data["restingTimePointB"]);
}
public override void UpdateModule(ProceduralObjectsLogic logic, bool simulationPaused, bool layerVisible)
{
if (absPointA == Vector3.zero && absPointB == Vector3.zero)
return;
if (logic.IsSettingPosition())
{
if (notBeingModified())
{
absPointA = parentObject.m_position - relPointA;
absPointB = parentObject.m_position + relPointB;
}
return;
}
if (simulationPaused || !layerVisible)
return;
if (absPointA == modifyingMarker || absPointB == modifyingMarker)
return;
totalTime = restingTimePointA + animDurationAB + restingTimePointB + animDurationBA;
float t = 0f;
if (Timer >= (totalTime - animDurationBA))
t = (totalTime - Timer) / animDurationBA;
else if (Timer >= restingTimePointA + animDurationAB)
t = 1f;
else if (Timer < restingTimePointA)
t = 0f;
else // animDurationAB
t = (Timer - restingTimePointA) / animDurationAB;
Vector3 newPos = Vector3.Lerp(absPointA, absPointB, GetTimeForCurve(t));
MoveChildrenObj(newPos);
parentObject.m_position = newPos;
if (notBeingModified())
calculateRelativePos();
Timer += Time.deltaTime;
if (Timer > totalTime)
Timer = Timer - totalTime;
}
public override void DrawCustomizationWindow(int id)
{
base.DrawCustomizationWindow(id);
GUI.Label(new Rect(5, 50, 200, 22), "Points :");
if (GUI.Button(new Rect(5, 72, 155, 28), (absPointA == Vector3.zero || absPointA == modifyingMarker) ? "UNSET / Click to set" : "Point A / Click to set"))
{
bool wasModified = (absPointA == modifyingMarker);
absPointA = parentObject.m_position;
if (absPointB != modifyingMarker && !wasModified)
absPointB = modifyingMarker;
calculateRelativePos();
}
if (GUI.Button(new Rect(165, 72, 155, 28), (absPointB == Vector3.zero || absPointB == modifyingMarker) ? "UNSET / Click to set" : "Point B / Click to set"))
{
bool wasModified = (absPointB == modifyingMarker);
absPointB = parentObject.m_position;
if (absPointA != modifyingMarker && !wasModified)
absPointA = modifyingMarker;
calculateRelativePos();
}
GUI.Label(new Rect(5, 105, 90, 20), "Speed curve :");
speedCurve = (byte)GUI.Toolbar(new Rect(100, 102, 220, 26), speedCurve, new string[] { "Straight", "Smooth", "Logistic" });
if (!(absPointA == Vector3.zero || absPointA == modifyingMarker))
{
if (GUI.Button(new Rect(4, 129, 127, 22), ""))
{
if (notBeingModified())
{
Vector3 newPos = absPointA;
// MoveChildrenObj(newPos);
parentObject.m_position = newPos;
calculateRelativePos();
Timer = 0f;
}
}
}
GUI.Label(new Rect(5, 130, 120, 20), "Rest at A (s)");
GUI.Label(new Rect(5, 150, 120, 20), "From A to B (s)");
if (!(absPointB == Vector3.zero || absPointB == modifyingMarker))
{
if (GUI.Button(new Rect(4, 169, 127, 22), ""))
{
if (notBeingModified())
{
Vector3 newPos = absPointB;
// MoveChildrenObj(newPos);
parentObject.m_position = newPos;
calculateRelativePos();
Timer = restingTimePointA + animDurationAB;
}
}
}
GUI.Label(new Rect(5, 170, 120, 20), "Rest at B (s)");
GUI.Label(new Rect(5, 190, 120, 20), "From B to A (s)");
restingTimePointA = restAfield.DrawField(new Rect(135, 130, 180, 20), restingTimePointA, false).returnValue;
animDurationAB = animABfield.DrawField(new Rect(135, 150, 180, 20), animDurationAB, false).returnValue;
restingTimePointB = restBfield.DrawField(new Rect(135, 170, 180, 20), restingTimePointB, false).returnValue;
animDurationBA = animBAfield.DrawField(new Rect(135, 190, 180, 20), animDurationBA, false).returnValue;
if (GUI.Button(new Rect(5, 220, 315, 23), "Children in group follow motion : " + (groupFollows ? "ON" : "OFF")))
groupFollows = !groupFollows;
}
public override POModule Clone()
{
var m = (BackAndForthModule)this.MemberwiseClone();
if (m.relPointA != Vector3.zero && m.relPointB != Vector3.zero)
{
m.absPointA = Vector3.zero;
m.absPointB = Vector3.zero;
}
return m;
}
private float GetTimeForCurve(float t)
{
if (speedCurve == 0)
return t;
if (speedCurve == 1)
return (1.063f / (1 + Mathf.Exp(-7f * t + 3.4f))) - 0.035f;
if (speedCurve == 2)
return (1.0135f / (1 + Mathf.Exp(-10f * t + 5))) - 0.0067f;
return 0;
}
private void MoveChildrenObj(Vector3 newPos)
{
if (!groupFollows || !parentObject.isRootOfGroup)
return;
if (parentObject.group == null)
return;
var diffPos = newPos - parentObject.m_position;
foreach (var child in parentObject.group.objects.Where(p => p != parentObject))
child.m_position += diffPos;
}
private bool notBeingModified()
{
return (absPointA != modifyingMarker && absPointB != modifyingMarker);
}
private void calculateRelativePos()
{
if (absPointA != modifyingMarker)
relPointA = parentObject.m_position - absPointA;
if (absPointB != modifyingMarker)
relPointB = absPointB - parentObject.m_position;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment