The Art of Screenshake in Unity2D


Due to the fact that our Big Bad Bearded Boss is a huge Vlambeer fan, my first task was to watch the presentation of Vlambeers Jan Willem Nijman Gamefeel. JW showed 30 little tricks to make your action game more fun. This post is about how to implement some of this tricks in Unity for our upcoming game Shooting Stars.

Screenshake

Let's start with the screenshake effect. The main approach is to shake the camera randomly in special moments of the game. For example on a bullet impact or an explosion. My first attempt to get this done was using iTweens ShakePosition(). The effect itself was really cool, BUT there was a problem with multiple screenshakes at the same time using ShakePosition(), so I started to implement my own solution:

private Vector3 cameraStartPosition;
private float shakeAmountX;
private float shakeAmountY;
private float time;
bool reset=true;

public void Init () {
    cameraStartPosition=Camera.main.gameObject.transform.position;
    InvokeRepeating("CameraShake", 0, .01f);
}

public void ScreenShake(float amountX, float amountY, float _time){
    if(amountX>shakeAmountX){
        shakeAmountX = amountX;
    }

    if(amountY>shakeAmountY){
        shakeAmountY = amountY;
    }
    if(_time>time){
        time=_time;
    }
    reset=false;    
}

public void ScreenShake(float amount, float _time){
    if(amount>shakeAmountX && amount>shakeAmountY){
        shakeAmountX = amount;
        shakeAmountY = amount;
    }
    if(_time>time){
        time=_time;
    }
    reset=false;
}

void CameraShake(){
    if(shakeAmountX>0 && shakeAmountY>0 && time>0) {
        time-=.01f;
        float quakeAmtX = UnityEngine.Random.value*Mathf.Sin( shakeAmountX)*2 - shakeAmountX;
        float quakeAmtY = UnityEngine.Random.value*Mathf.Sin(shakeAmountY)*2 - shakeAmountY;
        Vector3 pp = cameraStartPosition;
        pp.y+= quakeAmtY; // can also add to x and/or z
        pp.x+= quakeAmtX;
        Camera.main.transform.position = pp;
    }else if(!reset){
        Camera.main.transform.position=cameraStartPosition;
        reset=true;
    }
}

Kickback on Shoot

Another thing I wanted to implement is a little kickback whenever our main character is shooting lazers, bullets or whatever. Due to the fact that our game is a vertical shootemup this was quite easy to implement. Whenever our main character is shooting I manipulate his y position by a small random amount:

targetPosition.y=targetPosition.y-UnityEngine.Random.Range (0.1f, 0.3f);

Permanence

I also thought about implementing some permanence. So I decided to make our “lazer shells” permanent. First of all I created a flight path for our shells by using iTweens MoveTo(). Not really satisfied with the result I added some rotation to the shells by using RotateBy(). After the movement of our shells is over the GameObjects will stay whereever they moved to. The problem is, that after some minutes of constantly shooting, you have a lot of shells lying around. This is not a problem for the PC or Mac version, but will be a problem for mobile devices due to limited amount of available Memory. So for performance reasons I have to destroy the shells (or move them back to a pool) after some time.

float height=UnityEngine.Random.Range (0.2f, 0.7f);
iTween.MoveTo(gameObject, iTween.Hash("path",new Vector3[]{
    new Vector3(transform.position.x+0.4f,transform.position.y+height,0), 
new Vector3(transform.position.x+height+0.2f,transform.position.y-0.4f,0)}, "time",1,"easetype",iTween.EaseType.linear));
iTween.RotateBy(gameObject, iTween.Hash(
    "name", "ShellRotation", "looptype",iTween.LoopType.none, "z", Random.Range(-6f, 6f), "time",  0.9f));
Destroy (gameObject, 10f);

What's next?

Because of problems with permanence, missing image effects, etc. we consider switching from the free version to Unity Pro. Come back soon, if you want to know which way we will go.

Comment

Alexander Haider

Even though Alex may be the quiet one but his godlike development skills will render you speechless for quite a while. Some people say: Wherever there's a problem there's an Alex to fix it.