Camer Shake Effect when big scary monster comes charging

Started by
6 comments, last by Paul C Skertich 9 years, 9 months ago

I want to make a camera shake effect when a scary monster comes chasing after you or at least for a cinematic effect then the player can do whatever.


if (isKeyPressed(0x56))  //-- If V key is pressed.
		{
			static float shakeAmount = cameraYaw;
			static float maxShake = cameraYaw + 1.0f * (XM_PI / 4.0);
			static float rndJerkiness = ((rand() % 2) - 4);

			shakeAmount += cameraYaw + rndJerkiness; // ((rand() % 2) + cameraYaw - 2); // +(XM_PI / 4.0f);

			if (shakeAmount > 1.0f  * maxShake) {
				shakeAmount -= rndJerkiness;
			}
			if(shakeAmount < -1.0f * maxShake) {
				shakeAmount += rndJerkiness;
			}
			cameraYaw *= shakeAmount;
			std::ofstream out("Logs/Camera.log", std::ios_base::app);
			out << cameraYaw << ":" << cameraPitch << std::endl;
			out.close();
			//shakeAmount = 0.0f;

		}

As of now it's just tied to the V key for testing purposes. The camera yaw is tied to the updateCamera function which is tied into the pitch, roll and yaw function of the xnamath.h header file.

I'm getting close the camera shakes alright - sometimes it gets out of control and the screen turns black inside the level editor. Possibly something happened and it went past the sky box which is literally impossible because the skybox is scaled for infinity. I'm not sure what's causing that anyways. The random jerkiness is to make it appear jerkier and spazmatic. I was trying to make it random from - 2 to 2. It's outputted for now so I know what's going on inside the log file. The cameraYaw is initialized as 0.0.

I was just wondering if there was something I can do better inside the code?

Game Engine's WIP Videos - http://www.youtube.com/sicgames88
SIC Games @ GitHub - https://github.com/SICGames?tab=repositories
Simple D2D1 Font Wrapper for D3D11 - https://github.com/SICGames/D2DFontX
Advertisement

The entire routine is confusing me. When I read "shake effect" I think of an offset added temporarily to the current orientation. Instead, the routine uses a multiplication, and it does so in a permanent manner. This seems we the wrong attempt.

Some issues in detail:

1.) Accordingly to this page, if you're using the standard C++ rand() routine, then rndJerkiness = ((rand() % 2) - 4) gives you values from the set { -4, -3 }. If you want the set { -2, -1, 0, +1, +2 } then you need to use ((rand() % 5) - 2) instead. Notice that the rndJerkiness is still whole-numbered. That may be okay because you want "jerkiness", but it does not suit the goal very well (see solution suggestion below).

2.) You're initializing shakeAmount = cameraYaw, and cameraYaw is (concluded from the name) an absolute angle. Then you compute the shakeAmount by adding cameraYaw again, and you add rndJerkiness. So the shakeAmount depends on the original view direction.

3.) The 2 conditions to restrict shakeAmount (at least I assume them to be intended to do so), will not work correctly due to issue 1.

4.) You multiply cameraYaw with shakeAmount. If cameraYaw is zero, i.e. the camera looks forward, then the multiply has no effect. If the cameraYaw is e.g. 90 degree then shakeAmount has a much greater impact compared to when the cameraYaw is e.g. only 45 degree. So, instead of just shaking the view, you rotate it dependent on the current view direction.

IMHO, a more suitable implementation would be:

* Store the "unshaked" cameraYaw in a camera local variable, e.g. cameraYawLook.

* Compute shakeAmount as a variation of an angle. Because you're probably dealing with radian, use a range like for example [ -15°/2pi , +15°/2pi ].

* Add shakeAmount to the current cameraYawLook and set this as current cameraYaw (from where to compute the view transformation).

Hi there.

I'm using this in my plane class for a hovering craft

//we can add a wobble to the plane if we are not dead

D3DXVECTOR3 offsetwobble;

//WobbleRadius = 300;

float oldwobble = randomAngle;

WobbleRadius *=0.09;

//diminish radius each frame

randomAngle =(180 - RandInRange(-30, 30));

//pick new angle RandInRange(0, 1)

float d = mTimer->getDeltaTime();

randomAngle = mylerp2(oldwobble, randomAngle, d);

offsetwobble = D3DXVECTOR3(sin(randomAngle) * WobbleRadius , cos(randomAngle) * WobbleRadius, cos(randomAngle) * WobbleRadius);

World._41 = ComponentMotion->m_vPos.x + offsetwobble.x;

World._42 = ComponentMotion->m_vPos.y + offsetwobble.y;

World._43 = ComponentMotion->m_vPos.z + offsetwobble.z;

if(WobbleRadius <= 110)

WobbleRadius = 300;

a simple screenshake that uses Haegarr's random interval (-2 though 2), and changes position, not rotation (a la Ankhd's method)...

 
setcam( player_x+dice(5)-2, player_y+dice(5)-2, player_z+dice(5)-2 );
 

this is the type of approach i usually use

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

the same idea in a rotation:

 
setcam (player_x, player_y, player_z, player_xr+dice(21)*0.01f-0.1f, player_yr+dice(21)*0.01f-0.1f );
 

this aims the camera in the player's direction, with a "jitter" of -0.1 to 0.1 radians in x and y rotations.

in general, i've found that it doesn't require much jitter to get the desired effect. just move the camera a foot or two, or just a couple of degrees.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Only reason why I chose the rotation not position is because the rotation avoids collision detection with walls - so if the player is pinned against the wall and the camera shake happens - then there could be issues, right? In some games I was able to go pass the physics collider of a wall or something with enough running and jumping at the wall (doesn't do it a lot though). The rotation keeps the player at the same position giving a bit jitter.

Game Engine's WIP Videos - http://www.youtube.com/sicgames88
SIC Games @ GitHub - https://github.com/SICGames?tab=repositories
Simple D2D1 Font Wrapper for D3D11 - https://github.com/SICGames/D2DFontX


so if the player is pinned against the wall and the camera shake happens - then there could be issues, right?

yes, that could lead to clipping issues and graphic artifacts (IE camera behind wall for a moment). but it would seem to me that a wall would get backface culled when the camera popped behind it for a moment, so it would probably still look ok.

either type of jitter (position or rotation) ought to work ok, with only minor differences in camera behavior (how it shakes).

excessive and cumulative jitter is what caused your initial problems.


In some games I was able to go pass the physics collider of a wall or something with enough running and jumping at the wall

their stepped movement interval is too large, or they're not using stepped movement at all, or their collision detection range is out of sync with their movement step size.

when jittering, you only move the camera, not the player. in fact, i often implement it not as a continuous realtime effect during gameplay, but as a quick canned animation, draw about half a second's worth of frames with jitter, then continue. works great for things like taking hits with your shields down. an example of continuous would be the gravcar "float" in Combat Racer, a simple:

 
current_y = base_y + sin(turn_counter)
 

before you draw each frame. it makes the gravcars float up and down over time.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Yes, the execessive jitter was the main issue because I looked at the log file and I saw the if statements were never being reached because the cameraShakeAmount was constantly accumulating to the current camera Yaw and testing to see if if was greater than the maxium shake amount was never being reached. So I came up with this new code which helps out a lot more than previous and I don't have to multiply the results to the camera yaw - just assign it.


void CameraShake() {
		static float shakeAmount = 0.0f;
		float oldCameraYaw = cameraYaw;

		static float maxShake = 1.0f * cameraYaw + (1.0f * XM_PI / 2 * 0.2f);
		static float rndJerkiness = ((rand() % 5) - 2);

		shakeAmount += 0.5f; // +rndJerkiness; // ((rand() % 2) + cameraYaw - 2); // +(XM_PI / 4.0f);

		if (shakeAmount > 1.0f * maxShake) {
			shakeAmount *= -0.5f; // * rndJerkiness;
		}
		if (shakeAmount < -1.0f * maxShake) {
			shakeAmount *= 0.5f;// *rndJerkiness;
		}
		oldCameraYaw = shakeAmount;
		cameraYaw = oldCameraYaw;
		updateCameraLens();


	}

I know I can use XM_PIDIV2 for the max shake equation but I'll get to that later. What's good is that it doesn't shake out of countrol leaving the player facing the other direction. If the player got to ecape he sure doesn't want to face a wall or obstacle each time the ground shakes. The camera shake may be used as a post process effect which I'll get into later because I don't think I want the camera to shake all the time - only when there's a major event happen to signify the importance of why the ground is shaking. Like tomb stones rising from the ground or something or the ground breaking in half causing the camera shake effect to happen. Or when the house explodes at the ending or something like that.

I may even create a joint for the camera to the player so if the ground shakes the camera will be linked to the player already as the player moves up and down - creating the effect of camera shake in first player mode.

I love the fact when I come on here my creative juices begin flowing because of the help with great people on this forum.

Game Engine's WIP Videos - http://www.youtube.com/sicgames88
SIC Games @ GitHub - https://github.com/SICGames?tab=repositories
Simple D2D1 Font Wrapper for D3D11 - https://github.com/SICGames/D2DFontX

This topic is closed to new replies.

Advertisement