Hello, I’m trying to create an effect that’s like the camera shake caused by impulse, but one that is persistent until told to stop.
Most guns have a slow enough rate of fire that I can tie this directly to the gun firing, but for the case of very high rate of fire weapons (e.g. a Vulcan gun) this isn’t quite practical. Aside from the unknown performance/garbage creation implications of calling so many events in rapid succession, the effect the player sees is a jittering rather than a smooth camera shake. It seems as if every frame it starts a new shake, which puts the camera at a new rotation.
I’ve been trying to figure out a way to have an impulse effect that runs until it gets told to turn off, but I haven’t been able to figure out a method for this. It needs to be an impulse effect because it needs be in physical space. The player can move the camera away, or near this gun as it’s going off.
As an aside, I’m really enjoying Cinemachine overall. It’s been an extremely powerful tool in enhancing the camera code that I tend to write.
TL;DR: I want to add a smooth and constant camera shake, that I can turn on/off, to a gun that fires at very high rates of fire.
To get rid of the jerk when a new event starts or stops, create smooth attack and decay on the signal envelope. Then they will overlap and blend nicely.
I tried that, but it doesn’t seem to work that way, unless maybe I set it up incorrectly. Stacking so many events in such a short period of time just resulted in it snapping to a new view constantly because the start position of every new event is going to be somewhere else. It doesn’t create a smooth shake that feels persistent, just a very violent one. I wasn’t able to get it to blend in a way that felt smooth.
Maybe we need to look at the setting more closely.
What about having an impulse with just a really really really long sustain time? Lerp the listener’s gain in and out according to whether or not you want to shake.
The listener is listening to shake events other than just this one, so I can’t do it on the listener. However that does make me wonder if I could instead have the super long impulse event as you said, but lerp the amplitude of the source itself up and down. Is that something that it would react to, or are those values only used when the impulse event is generated?
Even if there is no good immediate option for this, I do think it makes sense for there to be some way to natively generate a constant camera shake around some source. Another example for this would be a tank moving along the ground. When the camera gets near it, it should shake. However that also needs to be able to be turned on/off as the tank isn’t always moving.
This isn’t the first time I’ve run into this issue. In a previous project I wanted to add camera shake when the camera was near a spaceship engine. However I can’t just use an ultra-long impulse because the engines could turn on/off.
You can’t put it on the emitter, because changes will only affect the next impulse event, not ones already emitted.
So we’re back to a series of overlapping events. No worries about GC, because impulse events are recycled. Can you send me the signal asset you’re using? I’d like to give it a try.
It’s just using the “Handheld_normal_extreme” at the moment but with very low amplitude values (0.015) on the emitter so that it’s not too jarring when the next call comes in to a random position. It’s not ideal, and feels only appropriate for something like this ultra high rate of fire gun, but it’s usable for the time being.
I think you need to improve the overlap of your events. These settings work nicely for me:
And the emitter script:
using UnityEngine;
using Cinemachine;
public class ContinuousImpulse : MonoBehaviour
{
public bool Active;
[CinemachineImpulseDefinitionProperty]
public CinemachineImpulseDefinition ImpulseDefinition = new CinemachineImpulseDefinition();
float LastEventTime = 0;
void Update()
{
var now = Time.time;
float eventLength = ImpulseDefinition.m_TimeEnvelope.m_AttackTime + ImpulseDefinition.m_TimeEnvelope.m_SustainTime;
if (Active && now - LastEventTime > eventLength)
{
ImpulseDefinition.CreateEvent(transform.position, Vector3.down);
LastEventTime = now;
}
}
}
Attack and decay should be the same time, with inverse linear curves, to get a good blend.
Durations should be scaled to approximately match the periodicity of the signal. Rapid-fire guns can have shorter times, but should use an appropriately high-frequency signal, e.g. 6D Shake or a custom-built one.
I had a feeling I might have been misusing the attack/decay functions. I’ll give it a shot and report my findings next time I’m working that section of the code. Thank you!
Hello, just wanted to follow up by saying that using settings the way you described have worked out well and produced the smooth and continuous shake I was looking for. It’s still less than ideal because it’s a not an intuitive solution, but this is definitely workable. Thanks again!