Posts: 21
Threads: 2
Joined: Dec 2016
Hello, I have a car following the spline with an spline controller. I see I can animate (ease) the movement with a curve, but right now it follows the animation curve as long as Time Scale longs.
What I pretend to do is to decelerate the car each time I reach a control point and accelerate at the beginning of each one. The problem is that my cp arent separated by the same distance (and I cant made them do it because of the circuit), so the time to reach the next cp varies and I cant synchronice the animation with the cp.
Are there an easy way to synchronice the curve with distance instead of with time? Or other way to do that?
Thank you
Posts: 690
Threads: 71
Joined: Jan 2015
What about setting animation time by length of segment? You can access the segment either in the OnControlPointReached event or in your custom controller and it has a Length property.
I'd go the custom controller route (it's more flexible) and check the distance to the last and the next CP frequently. Then you can apply speed changes at will.
Posts: 21
Threads: 2
Joined: Dec 2016
(01-30-2017, 05:46 PM)Jake Wrote: What about setting animation time by length of segment? You can access the segment either in the OnControlPointReached event or in your custom controller and it has a Length property.
I'd go the custom controller route (it's more flexible) and check the distance to the last and the next CP frequently. Then you can apply speed changes at will.
Its a good idea but I'm having some problems to try to accomplish that. I'm trying to create a custom controller based on SplineController, and access to the segment length and animation time from there (as you said). The problem is I am looking at the SplineController and CurvyController and cant handle how it works properly. I get access to Speed, Length, TF value and other data but I dont know how to access to the current segment (F and length) or the animation time.
Can you point me out how to access this values with a small code snipet please? (I know the theory from your advice, just not sure how to get the data necessary) I'm trying to understand both CurvyController and SplineController but there are many things beyond my comprehension.
Thank you again
Posts: 690
Threads: 71
Joined: Jan 2015
Ok, some more details. Unfortunately I don't have Unity at hand now, but we give it a try:
Create a custom controller, override UserAfterInit() and bind a method to the OnControlPointReached event. In this method, you'll get access to the spline segment (e.ControlPoint). The segment's length is simply e.ControlPoint.Length.
Feed the controller's TimeScale property with the duration you want the animation to take and Speed with the distance you want to move in a single animation shot (be sure to use Distance in the controller settings).
That should do the trick.
Posts: 21
Threads: 2
Joined: Dec 2016
(02-01-2017, 08:01 PM)Jake Wrote: Ok, some more details. Unfortunately I don't have Unity at hand now, but we give it a try:
Create a custom controller, override UserAfterInit() and bind a method to the OnControlPointReached event. In this method, you'll get access to the spline segment (e.ControlPoint). The segment's length is simply e.ControlPoint.Length.
Feed the controller's TimeScale property with the duration you want the animation to take and Speed with the distance you want to move in a single animation shot (be sure to use Distance in the controller settings).
That should do the trick.
Hello Jake, I almost get it but still a little problem.
I did all you said, and it works except the event OnControlPointReached only get call if animation in the controller is disabled.
This is the simple controller I did:
Code: public class SplineMotorController : SplineController
{
[Section("Motor")]
public float MaxSpeed = 30;
protected override void UserAfterInit()
{
base.UserAfterInit ();
}
public void CPReached (CurvySplineMoveEventArgs e)
{
//Debug.Log(e.ControlPoint.Length);
Speed = e.ControlPoint.Length;
}
}
And this is how I have configured the controller. Not sure if I have some setup wrong, but the "Animate" setting make the event stop working, and if I enable it works again modifying the speed according to the length of the segment (as intended).
Posts: 21
Threads: 2
Joined: Dec 2016
(02-03-2017, 07:47 PM)yandrako Wrote: (02-01-2017, 08:01 PM)Jake Wrote: Ok, some more details. Unfortunately I don't have Unity at hand now, but we give it a try:
Create a custom controller, override UserAfterInit() and bind a method to the OnControlPointReached event. In this method, you'll get access to the spline segment (e.ControlPoint). The segment's length is simply e.ControlPoint.Length.
Feed the controller's TimeScale property with the duration you want the animation to take and Speed with the distance you want to move in a single animation shot (be sure to use Distance in the controller settings).
That should do the trick.
Hello Jake, I almost get it but still a little problem.
I did all you said, and it works except the event OnControlPointReached only get call if animation in the controller is disabled.
This is the simple controller I did:
Code: public class SplineMotorController : SplineController
{
[Section("Motor")]
public float MaxSpeed = 30;
protected override void UserAfterInit()
{
base.UserAfterInit ();
}
public void CPReached (CurvySplineMoveEventArgs e)
{
//Debug.Log(e.ControlPoint.Length);
Speed = e.ControlPoint.Length;
}
}
And this is how I have configured the controller. Not sure if I have some setup wrong, but the "Animate" setting make the event stop working, and if I enable it works again modifying the speed according to the length of the segment (as intended).
Any hints on this? I think it should some small detail that I am missing.
Thanks
Posts: 690
Threads: 71
Joined: Jan 2015
Sorry, my fault. I forgot that Animate doesn't raise events. The problem is that the Animate feature doesn't move along the spline, but instead warps based on a curve.
So back to your original problem, I'd like to focus on my original idea, a custom controller that alters movement speed (no Animate, just regular movement) by distance from/to adjacent CPs.
Something like this inside your custom controller:
Code: public AnimationCurve SpeedTween; // a curve describing either change of speed or absolute speed, depending on the way you want to work
public float TweenStartDistance=1; // distance in world units TOWARDS a CP to begin tweening =>Evaluate(0) of the above curve
public float TweenEndDistance=2; // distance after a CP to end tweening => Evaluate(1) of above curve
protected override void Advance(ref float tf, ref int direction, MoveModeEnum mode, float absSpeed, CurvyClamping clamping)
{
// Either advance before speed change or afterwards. Here we do it before
base.Advance (ref tf, ref direction, mode, absSpeed, clamping);
// Steps:
// Convert TF to current segment and distance within it
// Check, if it's in the "influence range" around the CP
// If yes, alter speed
float localF;
var seg = Spline.TFToSegment(tf,out localF);
float localDist=seg.LocalFToDistance(localF);
if (localDist<TweenEndDistance || localDist)
{ // acceleration phase
// map localDist to 0..1 inside the curve
Speed+=SpeedTween(mappedValue);
} else if (seg.Length-localDist<TweenStartDistance)
{ // brake phase
// map localDist to 0..1 inside the curve
Speed+=SpeedTween(mappedValue);
}
}
Sure it needs a bit more polishing (ensure you set speed back to original value if outside influence range, handle segments shorter than influence range etc...), but this may work well.
Perhaps use two animationcurves (or even better, checkout DTEase class of DevTools, it contains the regular, well-known easing methods).
Cheers
Jake
Posts: 21
Threads: 2
Joined: Dec 2016
(02-23-2017, 06:20 PM)Jake Wrote: Sorry, my fault. I forgot that Animate doesn't raise events. The problem is that the Animate feature doesn't move along the spline, but instead warps based on a curve.
So back to your original problem, I'd like to focus on my original idea, a custom controller that alters movement speed (no Animate, just regular movement) by distance from/to adjacent CPs.
Something like this inside your custom controller:
Code: public AnimationCurve SpeedTween; // a curve describing either change of speed or absolute speed, depending on the way you want to work
public float TweenStartDistance=1; // distance in world units TOWARDS a CP to begin tweening =>Evaluate(0) of the above curve
public float TweenEndDistance=2; // distance after a CP to end tweening => Evaluate(1) of above curve
protected override void Advance(ref float tf, ref int direction, MoveModeEnum mode, float absSpeed, CurvyClamping clamping)
{
// Either advance before speed change or afterwards. Here we do it before
base.Advance (ref tf, ref direction, mode, absSpeed, clamping);
// Steps:
// Convert TF to current segment and distance within it
// Check, if it's in the "influence range" around the CP
// If yes, alter speed
float localF;
var seg = Spline.TFToSegment(tf,out localF);
float localDist=seg.LocalFToDistance(localF);
if (localDist<TweenEndDistance || localDist)
{ // acceleration phase
// map localDist to 0..1 inside the curve
Speed+=SpeedTween(mappedValue);
} else if (seg.Length-localDist<TweenStartDistance)
{ // brake phase
// map localDist to 0..1 inside the curve
Speed+=SpeedTween(mappedValue);
}
}
Sure it needs a bit more polishing (ensure you set speed back to original value if outside influence range, handle segments shorter than influence range etc...), but this may work well.
Perhaps use two animationcurves (or even better, checkout DTEase class of DevTools, it contains the regular, well-known easing methods).
Cheers
Jake
Using that code as a base I managed to accomplish the effect desired.
Thank you so much for all your help
Andrés
|