- Home /
How do I solve a jerk in movement?
So I'm making a SHMUP/Bullet Hell style game and am having a problem with my boss. His overall script mostly works but one of his attacks is bugged and I'm unsure how to fix it. As an opening attack he rushes towards the player and then slowly move back to his starting position while sending bursts of bullets. The problem is that when he starts moving back home there is a sudden jerk forward. I have already had play tests where the player should have died but didn't because of this. So far it's been consistent enough that I can already abuse it, plus it looks kind of bad.
So overall how would I go about fixing this to be smoother?
IEnumerator ChargeAI() {
yield return new WaitForSeconds(lungeWaitTime);
//TODO: play audio and flex animation
float startTime = Time.time;
//charge towards player
Vector3 start = transform.position;
Vector3 end = HeroController2.Instance.transform.position;
while (Time.time - startTime < lungeTime)
{
anim.SetBool("Charge", true);
transform.position = Vector3.Lerp(start, end, (Time.time - startTime) / lungeTime);
anim.SetBool("Charge", false);
yield return null;
}
yield return new WaitForSeconds(landingPause);
yield return new WaitForSeconds(lungeWaitTime);
if (fireBurst != null)
{
StopCoroutine(fireBurst);
}
fireBurst = doFireBurst();
StartCoroutine(fireBurst);
//startTime = 0;
while (Time.time - startTime < returnTime)
{
anim.SetBool("Walk", true);
transform.position = Vector3.Lerp(end, start, (Time.time - startTime) / returnTime);
anim.SetBool("Walk", false);
yield return null;
}
yield return null;
$$anonymous$$aybe the current coroutine is not finished while you already start the next one? check the interval of ChargeAI calls in comparison to the overall time of the whole coroutine.
just a tip: you're calling Charge and Walk animations SetBool true and false during a single frame, is that correct? If so consider using SetTrigger
The overall Coroutine works pretty much as intended. During testing when the ti$$anonymous$$gs were off or when other things were running, he never managed to get back to start before continuing with his attacks. I feel like the problem is in the speed at which he returns but I don't know how to even him out.
I'll look into fixing the animations later, as it stands it looks "mostly" alright lol. Thanks for the tip though.
are you sure? You use Starttime as the lerp value for the fallback, which is set right at the beginning of the coroutine. If it is, it resets the result of the fallback lerp to 0 again which is the front position.
Ive seen that calculating inside a Lerp function can cause troubles so maybe put the calculation in a variable and use that? Also, maybe you can use Vector3.SmoothDamp ins$$anonymous$$d of lerp and see if that makes a difference?
Is there a frame dip because of the burst of shots that the boss releases maybe?
Alright, I've done some further testing and I believe its because of how bad my laptop is that I'm building this on. Even so the further the guy charges the more the jump in distance. I've tested moving the calculation outside of the lerp and making it a variable and it helped slightly but not greatly. Is there a way to apply Time.deltaTime to this and make it work?
Answer by Mordetherelicor · Nov 29, 2016 at 04:55 PM
Alright I finally ended up fixing this (with a bit of help). Had to move the lerp calculations outside of the actual Lerp, and restate the start time. Works fine now.
IEnumerator ChargeAI() {
yield return new WaitForSeconds(lungeWaitTime);
//TODO: play audio and flex animation
float startTime = Time.time;
//charge towards player
Vector3 start = transform.position;
Vector3 end = HeroController2.Instance.transform.position;
while (Time.time - startTime < lungeTime)
{
lungeTimePercent = (Time.time - startTime) / lungeTime;
anim.SetBool("Charge", true);
transform.position = Vector3.Lerp(start, end, lungeTimePercent);
anim.SetBool("Charge", false);
yield return null;
}
yield return new WaitForSeconds(landingPause);
yield return new WaitForSeconds(lungeWaitTime);
if (fireBurst != null)
{
StopCoroutine(fireBurst);
}
fireBurst = doFireBurst();
StartCoroutine(fireBurst);
startTime = Time.time;
while (Time.time - startTime < returnTime)
{
float returnTimePercent = (Time.time - startTime) / returnTime; //this line here is what fixed it.
anim.SetBool("Walk", true);
transform.position = Vector3.Lerp(end, returnPosition.transform.position, returnTimePercent);
anim.SetBool("Walk", false);
yield return null;
}
yield return null;
}
Answer by SarfaraazAlladin · Nov 28, 2016 at 11:24 PM
Responding to your comment about making Time.deltaTime work:
You definitely can. Time.deltaTime returns the time in seconds between the current frame and the last frame.
In order to make a timer, you would simply make a float that starts at 0, then add Time.delaTime to it each frame.
float timer = 0;
while(timer < x)
{
timer += Time.deltaTime;
yield return null;
}
in this example, x would be the amount of time that the code will stay in the while loop.
To create an effective lerp though, try you could try something like this:
float t = 0;
float speed = 0.5f;
while(t<1)
{
transform.position = Vector3.Lerp(end, start, t);
t += Time.deltaTime * speed;
yield return null;
}
In this example, the speed variable gives you half of the time between the previous frame and the current one, effectivly extending your lerp from 1 second to 2. (If I'm not mistaken)