New member here. Sorry my first post is a question but I’ve been looking thru posts searching the site and wiki and answerunity with no luck.
I’m hard at work on a 2d side scrolling game.
I have a bobbing script on my spaceship which moves the ship up and down ever so slightly to give it a nice hovering effect when it is stationary.
My problem is when I use the LookAt script to follow my ship from left to right. I target my ship and when I play it works well except now the whole scene is bobbing up and down.
How do I have only my ship bob up and down but still have my camera follow the ship?
Is there a way to have the Lookat script ignore the bobbing script without disabling its properties?
If I understand the problem correctly, what you want is for the camera to follow the point where the ship would be if the ‘bobbing’ effect were not applied.
The first thing that comes to mind is to represent the ship using a composite game object. The parent object would respond to user input and would not have the ‘bobbing’ effect applied to it (this is the object that the camera would follow). You would then create a child object that ‘bobs’ relative to the parent object.
If the bobbing is a visual effect only and doesn’t affect game play (collision detection, etc.) in any way, this is probably the way I would go.
The approach that I was suggesting will probably require splitting up your current player functionality into one or more scripts. Specifically, everything but the bobbing will need to be associated with the parent game object, and the bobbing (and only the bobbing) will need to be associated with the child game object. The camera will then follow the parent (player) object, while the child object (which will be a visual effect only) will bob up and down.
Perhaps someone else can suggest an easier solution, but this is the most straightforward solution I can think of at the moment.
Thanks very much. It worked! I would have given up earlier if not for your more thorough workaround.
The only thing I would add is that for the Child, I left in the Bobbing script as well as the Capsule (Mesh Filter) , Mesh Renderer and Box Collider. And took these same components out of the Parent object, otherwise I saw two images kind of ghosting each other because of two Meshes in the game view.
What is rendered is from the Child and all of the movement is from the Parent, as you surmised.
Cheers!
P.S. Could you help with one other thing. I’ve been trying to figure out how to fix the scene in place relative to the Camera so that only the Ship moves and the camera follows it. I’ve attached a screen shot of how I would like my scene to start out.
But when I press play it follows the ship up to the borders of my scene and you can see beyond the border to empty space. I need to fix the scene in place. I’m sure its probably something really obvious but I can’t think figure it out at the moment.
I’m not quite clear from your description on how you want the camera to behave. Do you want the ship to move about the screen while the scene stays static? Or do you want the ship to always appear to be in the middle of the screen (aside from the bobbing effect) while the scene scrolls around it? Or do you want the ship to stay in the middle of the screen except for when it’s near the ‘edges’ of the scene (to prevent being able to see past the edge of the scene)?
If you could describe the behavior you’re after in more detail, that would help. Perhaps you could also post the code that you’re currently using to position and orient the camera.
Yes, like a typical 2D side-scroll game such as Zombieville. The Player would walk all the way Left or Right of the screen but the camera stays within the scene and not go beyond it. My script shows alot of space behind the borders. I guess because my ship is always centered in the middle of the screen.
One other thing, since my object is a ship it would move up briefly up to my top border so the bottom border would briefly leave the camera view and see just a sky background and when I move down to the ground it should just meet the ground and the camera should not move beyond it, just like on the left and right sides.
Sorry for the long reply. Thanks again.
Code is below but not written by me, found these on the forums and work quite well together.
//What is our forward direction? Our spaceship moves in the positive x,y direction.
var forwardDirection : Vector3 = Vector3 (0.0, 0.0, 0.0);
// Below we create two helper classes, MovementSettings and SpecialEffects
// Although the helper classes are not necessary, it makes for nice clean code and usage.
class MovementSettings {
// What is the maximum speed of this movement?
var maxSpeed : float;
// What's the acceleration in the positive and negative directions associated with this movement?
var positiveAcceleration : float;
var negativeAcceleration : float;
// How much drag should we apply when there isn't input for this movement?
var dragWhileCoasting : float;
// How much drag should we apply to slow down the movement for speeds above maxSpeed?
var dragWhileBeyondMaxSpeed : float;
// When neither of the above drag factors are in play, how much drag should there normally be? (Usually very small.)
var dragWhileAcceleratingNormally : float;
// This function determines which drag variable to use and returns one.
function ComputeDrag (input : float, velocity : Vector3) {
//Is the input not zero (the 0.01 allows for some error since we're working with floats and they aren't completely precise)
if (Mathf.Abs (input) > 0.01) {
// Are we greater or less than our max speed? Then return the appropriate drag.
if (velocity.magnitude > maxSpeed)
return dragWhileBeyondMaxSpeed;
else
return dragWhileAcceleratingNormally;
} else
//If the input is zero, use dragWhileCoasting
return dragWhileCoasting;
}
}
class SpecialEffects {
// There are four possible special effects that can be assigned.
var positiveThrustEffect : GameObject;
var negativeThrustEffect : GameObject;
var positiveTurnEffect : GameObject;
var negativeTurnEffect : GameObject;
// How loud should collision sounds be? This is used in the OnCollisionEnter () function.
var collisionVolume = 0.01;
}
// We create two instances using our MovementSettings helper class.
// One will be for translational (position) movement, the other for rotational.
var positionalMovement : MovementSettings;
var rotationalMovement : MovementSettings;
// We create an instance using our SpecialEffects helper class.
var specialEffects : SpecialEffects;
// Can the user control the spaceship currently? This will be toggled by another script that also toggles what the camera should track.
var canControl = true;
//FixedUpdate () is advantageous over Update () for working with rigidbody physics.
function FixedUpdate () {
// Retrieve input. Note the use of GetAxisRaw (), which in this case helps responsiveness of the controls.
// GetAxisRaw () bypasses Unity's builtin control smoothing.
thrust = Input.GetAxisRaw ("Vertical");
turn = Input.GetAxisRaw ("Horizontal");
if (!canControl) {
thrust = 0.0;
turn = 0.0;
}
//Use the MovementSettings class to determine which drag constant should be used for the positional movement.
//Remember the MovementSettings class is a helper class we defined ourselves. See the top of this script.
rigidbody.drag = positionalMovement.ComputeDrag (thrust, rigidbody.velocity);
//Then determine which drag constant should be used for the angular movement.
rigidbody.angularDrag = rotationalMovement.ComputeDrag (turn, rigidbody.angularVelocity);
//Determines which direction the positional and rotational motion is occurring, and then modifies thrust/turn with the given accelerations.
//If you are not familiar with the ?: conditional, it is basically shorthand for an "if..else" statement pair. See [url]http://www.javascriptkit.com/jsref/conditionals.shtml[/url]
thrust *= (thrust > 0.0) ? positionalMovement.positiveAcceleration : positionalMovement.negativeAcceleration;
turn *= (turn > 0.0) ? rotationalMovement.positiveAcceleration : rotationalMovement.negativeAcceleration;
// Add torque and force to the rigidbody. Torque will rotate the body and force will move it.
// Always modify your forces by Time.deltaTime in FixedUpdate (), so if you ever need to change your Time.fixedTime setting,
// your setup won't break.
rigidbody.AddRelativeTorque (Vector3 (0.0, 0.0, -1.0) * turn * Time.deltaTime, ForceMode.VelocityChange);
rigidbody.AddRelativeForce (forwardDirection * thrust * Time.deltaTime, ForceMode.VelocityChange);
}
// This function allows us to SendMessage to an object to set whether or not the player can control it
function SetControllable (controllable : boolean) {
canControl = controllable;
}
// The Update () function only serves to provide special effects in this case.
function Update () {
//Collecting appropriate input.
thrust = Input.GetAxisRaw ("Vertical");
turn = Input.GetAxisRaw ("Horizontal");
if (!canControl) {
thrust = 0.0;
turn = 0.0;
}
// If the thrust effect slots aren't null in the inspector, send a message.
// The message will be received by the component SpecialEffectHandler
// If the boolean statement is true, (e.g. (thrust > 0.01)) then the special effects will be enabled.
if (specialEffects.positiveThrustEffect)
specialEffects.positiveThrustEffect.SendMessage ("SetSpecialEffectActive", (thrust > 0.01));
if (specialEffects.negativeThrustEffect)
specialEffects.negativeThrustEffect.SendMessage ("SetSpecialEffectActive", (thrust < -0.01));
if (specialEffects.positiveTurnEffect)
specialEffects.positiveTurnEffect.SendMessage ("SetSpecialEffectActive", (turn > 0.01));
if (specialEffects.negativeTurnEffect)
specialEffects.negativeTurnEffect.SendMessage ("SetSpecialEffectActive", (turn < -0.01));
}
/*
// The OnCollisionEnter () function only serves to provide special effects in this case.
function OnCollisionEnter (collision : Collision) {
// Get the component "CollisionSoundEffect" of the object we collided with.
// The platforms in this tutorial have a CollisionSoundEffect component.
var collisionSoundEffect : CollisionSoundEffect = collision.gameObject.GetComponent (CollisionSoundEffect);
// If collisionSoundEffect isn't null, get the audio clip, set the volume, and play.
if (collisionSoundEffect) {
audio.clip = collisionSoundEffect.audioClip;
// By multiplying by collision.relativeVelocity.sqrMagnitude, the sound will be louder for faster impacts.
audio.volume = collisionSoundEffect.volumeModifier * collision.relativeVelocity.sqrMagnitude * specialEffects.collisionVolume;
audio.Play ();
}
}
*/
// The Reset () function is called by Unity when you first add a script, and when you choose Reset on the
// gear popup menu for the script.
function Reset () {
// Set some nice default values for our MovementSettings.
// Of course, it is always best to tweak these for your specific game.
positionalMovement.maxSpeed = 3.0;
positionalMovement.dragWhileCoasting = 3.0;
positionalMovement.dragWhileBeyondMaxSpeed = 4.0;
positionalMovement.dragWhileAcceleratingNormally = 0.01;
positionalMovement.positiveAcceleration = 50.0;
// By default, we don't have reverse thrusters.
positionalMovement.negativeAcceleration = 0.0;
rotationalMovement.maxSpeed = 2.0;
rotationalMovement.dragWhileCoasting = 32.0;
rotationalMovement.dragWhileBeyondMaxSpeed = 16.0;
rotationalMovement.dragWhileAcceleratingNormally = 0.1;
// For rotation, acceleration is usually the same in both directions.
// It could make for interesting unique gameplay if it were significantly
// different, however!
rotationalMovement.positiveAcceleration = 50.0;
rotationalMovement.negativeAcceleration = 50.0;
}
// In order for this script to work, the object its applied to must have a Rigidbody and AudioSource component.
// This tells Unity to always have the components when this script is attached.
@script RequireComponent (Rigidbody, AudioSource)
#pragma strict
// The speed of the keyboard controls. A higher value will
// cause the object to move more rapidly.
var keyboardSpeed = 20.0;
// FixedUpdate is a built-in unity function that is called every fixed framerate frame.
// According to the docs, FixedUpdate should be used instead of Update when dealing with a
// Rigidbody.
// See [url]http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.FixedUpdate.html[/url]
// for more information.
function FixedUpdate () {
// This is where we move the object.
// Get input from the keyboard, with automatic smoothing (GetAxis instead of GetAxisRaw).
// We always want the movement to be framerate independent, so we multiply by Time.deltaTime.
var keyboardX = Input.GetAxis("Horizontal") * keyboardSpeed * Time.deltaTime;
var keyboardY = Input.GetAxis("Vertical") * keyboardSpeed * Time.deltaTime;
// Calculate the new position based on the above input.
// If you want to limit the movement, you can use Mathf.Clamp
// to limit the allowed range of newPos.x or newPos.y.
var newPos = rigidbody.position + Vector3(keyboardX, keyboardY, 0.0);
// Move the object.
rigidbody.MovePosition(newPos);
}
// Require a Rigidbody component to be attached to the same GameObject.
@script RequireComponent(Rigidbody)
/*
This camera smoothes out rotation around the y-axis and height.
Horizontal Distance to the target is always fixed.
There are many different ways to smooth the rotation but doing it this way gives you a lot of control over how the camera behaves.
For every of those smoothed values we calculate the wanted value and the current value.
Then we smooth it using the Lerp function.
Then we apply the smoothed values to the transform's position.
*/
// The target we are following
var target : Transform;
// The distance in the x-z plane to the target
var distance = 10.0;
// the height we want the camera to be above the target
var height = 0.0;
// How much we
var heightDamping = 2.0;
var rotationDamping = 3.0;
// Place the script in the Camera-Control group in the component menu
@script AddComponentMenu("Camera-Control/Smooth Follow")
function LateUpdate () {
// Early out if we don't have a target
if (!target)
return;
// Calculate the current rotation angles
wantedRotationAngle = target.eulerAngles.y;
wantedHeight = target.position.y + height;
currentRotationAngle = transform.eulerAngles.y;
currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position.y = currentHeight;
// Always look at the target
transform.LookAt (target);
}
I’d probably have to play around with the project myself to be sure of getting this right, but here are some suggestions, added to your current code (I don’t code in JS, so I can’t guarantee the syntax will be exactly right):
/*
This camera smoothes out rotation around the y-axis and height.
Horizontal Distance to the target is always fixed.
There are many different ways to smooth the rotation but doing it
this way gives you a lot of control over how the camera behaves.
For every of those smoothed values we calculate the wanted value and the current value.
Then we smooth it using the Lerp function.
Then we apply the smoothed values to the transform's position.
*/
// The target we are following
var target : Transform;
// The distance in the x-z plane to the target
var distance = 10.0;
// the height we want the camera to be above the target
var height = 0.0;
// How much we
var heightDamping = 2.0;
var rotationDamping = 3.0;
// Add four new variables specifying the bounds of the scene in the XZ plane:
var left = 0.0;
var right = 0.0;
var top = 0.0;
var bottom = 0.0;
// Add one new variable specifying how close to an edge of the scene (in the XZ
// plane) the camera should be allowed to get:
var sceneEdgeBuffer = 0.0;
// Place the script in the Camera-Control group in the component menu
@script AddComponentMenu("Camera-Control/Smooth Follow")
function LateUpdate () {
// Early out if we don't have a target
if (!target)
return;
// We're going to make a copy of the target position and work with that
// instead of working with the target directly; this will allow us to
// clamp the position to the 'allowed area':
var targetPosition = target.position;
// Clamp:
targetPosition.x = Mathf.Clamp(
targetPosition.x, left + sceneEdgeBuffer, right - sceneEdgeBuffer);
targetPosition.y = Mathf.Clamp(
targetPosition.y, bottom + sceneEdgeBuffer, top - sceneEdgeBuffer);
// Calculate the current rotation angles
wantedRotationAngle = target.eulerAngles.y;
wantedHeight = targetPosition.y + height;
currentRotationAngle = transform.eulerAngles.y;
currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle (
currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = targetPosition;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position.y = currentHeight;
// Always look at the target
transform.LookAt (targetPosition);
}
The script is working but when I am move the ship vertically 45 degrees and as it reaches the mid-point of the screen it hits a sort of imaginary bump for half a second, goes horizontal and then continues on its original trajectory.
Is there a way to smooth this bump away script-wise? Its not such a terrible thing but since the rest of the movement is so smooth, this bit is that much more noticeable.
Hm, I don’t know. What you’re describing isn’t a behavior that would be inherent to the ‘camera clamping’ method I described earlier, so I would imagine it’s being caused by something else in your code. (The ‘camera clamping’ should not affect the movement of the player ship at all, so it shouldn’t be causing a ‘bump’ of the type you describe.)