- Home /
2d Platformer Tutorial moving the camera via script and disabling player controls when entering a trigger
Hi guys,
First post... new to unity but liking it a lot so far. Anyhow, I'm currently messing around with the 2d Platformer Tutorial and I got stuck trying to work with triggers. What I want to do:
---> When the player enters a trigger have script destroy a specific game object and then have the camera focus in on another object elsewhere in the gameworld, while stopping the movement of the player. Then after about 5 seconds I want the camera to go back to the player and resume gameplay where it was left off. Kind of like "when you step on a switch in a game the camera will do a small cutscene and focus in on the door that the switch opened. Then the camera will return to the player and gameplay will resume." The camera has a couple of scripts attached to it: "Camera Scrolling" and "Camera Focus." I created a trigger object with the following code... I'm totally stuck trying to get this to work... I keep getting errors during runtime when trying to reference the script. I tried copying some of the ideas from camera focus to write this. I probably am going about it all wrong but thats why I'm hoping someone can help me see the light :) Anyhow here is my code so far:
pragma strict
ar buttonTop : GameObject;
var targets : Transform[];
private var player1 : GameObject;
private var cameraSwitch : CameraScrolling;
function OnTriggerEnter(col : Collider) {
cameraSwitch = GetComponent(CameraScrolling);
player1 = GameObject.FindWithTag("Player");
if (col.gameObject.tag == "Player") {
Destroy (buttonTop);
cameraSwitch.SetTarget(targets[1], true);
} }
Here is the "Camera Focus" script:
// It works by sending SetControllable messages to turn the different characters on and off.
// It also changes who the CameraScrolling scripts looks at.
// An internal reference to the attached CameraScrolling script
private var cameraScrolling : CameraScrolling;
// Who is the player controlling private var selected = 0;
// List of objects to control var targets : Transform[];
// What to display on the buttons in the window var targetButtonNames : String[];
// On start up, we send the SetControllable () message to turn the different players on and off. function Awake () {
// Get the reference to our CameraScrolling script attached to this camera;
cameraScrolling = GetComponent (CameraScrolling);
// Set the scrolling camera's target to be our character at the start.
cameraScrolling.SetTarget (targets[0], true);
// tell all targets (except the first one) to switch off.
for (var i=0; i < targets.Length; i++)
targets[i].gameObject.SendMessage ("SetControllable", (i == 0), SendMessageOptions.DontRequireReceiver);
}
// Ensure there is a CameraScrolling script attached to the same GameObject, as this script // relies on it. @script RequireComponent (CameraScrolling)
And finally here is the "Camera Scrolling" script:
// The object in our scene that our camera is currently tracking.
private var target : Transform; // How far back should the camera be from the target? var distance = 15.0; // How strict should the camera follow the target? Lower values make the camera more lazy. var springiness = 4.0;
// Keep handy reference sto our level's attributes. We set up these references in the Awake () function. // This also is very slightly more performant, but it's mostly just convenient. private var levelAttributes : LevelAttributes; private var levelBounds : Rect;
private var targetLock = false;
// This is for setting interpolation on our target, but making sure we don't permanently // alter the target's interpolation setting. This is used in the SetTarget () function. private var savedInterpolationSetting = RigidbodyInterpolation.None;
function Awake () { // Set up our convenience references. levelAttributes = LevelAttributes.GetInstance (); levelBounds = levelAttributes.bounds; }
function SetTarget (newTarget : Transform, snap : boolean) { // If there was a target, reset its interpolation value if it had a rigidbody. if (target) { // Reset the old target's interpolation back to the saved value. targetRigidbody = target.GetComponent (Rigidbody); if (targetRigidbody) targetRigidbody.interpolation = savedInterpolationSetting; }
// Set our current target to be the value passed to SetTarget ()
target = newTarget;
// Now, save the new target's interpolation setting and set it to interpolate for now.
// This will make our camera move more smoothly. Only do this if we didn't set the
// target to null (nothing).
if (target) {
targetRigidbody = target.GetComponent (Rigidbody);
if (targetRigidbody) {
savedInterpolationSetting = targetRigidbody.interpolation;
targetRigidbody.interpolation = RigidbodyInterpolation.Interpolate;
}
}
// If we should snap the camera to the target, do so now.
// Otherwise, the camera's position will change in the LateUpdate () function.
if (snap) {
transform.position = GetGoalPosition ();
}
}
// Provide another version of SetTarget that doesn't require the snap variable to set. // This is for convenience and cleanliness. By default, we will not snap to the target. function SetTarget (newTarget : Transform) { SetTarget (newTarget, false); }
// This is a simple accessor function, sometimes called a "getter". It is a publically callable // function that returns a private variable. Notice how target defined at the top of the script // is marked "private"? We can not access it from other scripts directly. Therefore, we just // have a function that returns it. Sneaky! function GetTarget () { return target; }
// You almost always want camera motion to go inside of LateUpdate (), so that the camera follows // the target after it has moved. Otherwise, the camera may lag one frame behind. function LateUpdate () { // Where should our camera be looking right now? var goalPosition = GetGoalPosition ();
// Interpolate between the current camera position and the goal position.
// See the documentation on Vector3.Lerp () for more information.
transform.position = Vector3.Lerp (transform.position, goalPosition, Time.deltaTime * springiness);
}
// Based on the camera attributes and the target's special camera attributes, find out where the // camera should move to. function GetGoalPosition () { // If there is no target, don't move the camera. So return the camera's current position as the goal position. if (!target) return transform.position;
// Our camera script can take attributes from the target. If there are no attributes attached, we have
// the following defaults.
// How high in world space should the camera look above the target?
var heightOffset = 0.0;
// How much should we zoom the camera based on this target?
var distanceModifier = 1.0;
// By default, we won't account for any target velocity in our calculations;
var velocityLookAhead = 0.0;
var maxLookAhead = Vector2 (0.0, 0.0);
// Look for CameraTargetAttributes in our target.
var cameraTargetAttributes = target.GetComponent (CameraTargetAttributes);
// If our target has special attributes, use these instead of our above defaults.
if (cameraTargetAttributes) {
heightOffset = cameraTargetAttributes.heightOffset;
distanceModifier = cameraTargetAttributes.distanceModifier;
velocityLookAhead = cameraTargetAttributes.velocityLookAhead;
maxLookAhead = cameraTargetAttributes.maxLookAhead;
}
// First do a rough goalPosition that simply follows the target at a certain relative height and distance.
var goalPosition = target.position + Vector3 (0, heightOffset, -distance * distanceModifier);
// Next, we refine our goalPosition by taking into account our target's current velocity.
// This will make the camera slightly look ahead to wherever the character is going.
// First assume there is no velocity.
// This is so if the camera's target is not a Rigidbody, it won't do any look-ahead calculations because everything will be zero.
var targetVelocity = Vector3.zero;
// If we find a Rigidbody on the target, that means we can access a velocity!
var targetRigidbody = target.GetComponent (Rigidbody);
if (targetRigidbody)
targetVelocity = targetRigidbody.velocity;
// If we find a PlatformerController on the target, we can access a velocity from that!
targetPlatformerController = target.GetComponent (PlatformerController);
if (targetPlatformerController)
targetVelocity = targetPlatformerController.GetVelocity ();
// If you've had a physics class, you may recall an equation similar to: position = velocity * time;
// Here we estimate what the target's position will be in velocityLookAhead seconds.
var lookAhead = targetVelocity * velocityLookAhead;
// We clamp the lookAhead vector to some sane values so that the target doesn't go offscreen.
// This calculation could be more advanced (lengthy), taking into account the target's viewport position,
// but this works pretty well in practice.
lookAhead.x = Mathf.Clamp (lookAhead.x, -maxLookAhead.x, maxLookAhead.x);
lookAhead.y = Mathf.Clamp (lookAhead.y, -maxLookAhead.y, maxLookAhead.y);
// We never want to take z velocity into account as this is 2D. Just make sure it's zero.
lookAhead.z = 0.0;
// Now add in our lookAhead calculation. Our camera following is now a bit better!
goalPosition += lookAhead;
// To put the icing on the cake, we will make so the positions beyond the level boundaries
// are never seen. This gives your level a great contained feeling, with a definite beginning
// and ending.
var clampOffset = Vector3.zero;
// Temporarily set the camera to the goal position so we can test positions for clamping.
// But first, save the previous position.
var cameraPositionSave = transform.position;
transform.position = goalPosition;
// Get the target position in viewport space. Viewport space is relative to the camera.
// The bottom left is (0,0) and the upper right is (1,1)
// @TODO Viewport space changing in Unity 2.0?
var targetViewportPosition = camera.WorldToViewportPoint (target.position);
// First clamp to the right and top. After this we will clamp to the bottom and left, so it will override this
// clamping if it needs to. This only occurs if your level is really small so that the camera sees more than
// the entire level at once.
// What is the world position of the very upper right corner of the camera?
var upperRightCameraInWorld = camera.ViewportToWorldPoint (Vector3 (1.0, 1.0, targetViewportPosition.z));
// Find out how far outside the world the camera is right now.
clampOffset.x = Mathf.Min (levelBounds.xMax - upperRightCameraInWorld.x, 0.0);
clampOffset.y = Mathf.Min ((levelBounds.yMax - upperRightCameraInWorld.y), 0.0);
// Now we apply our clamping to our goalPosition. Now our camera won't go past the right and top boundaries of the level!
goalPosition += clampOffset;
// Now we do basically the same thing, except clamp to the lower left of the level. This will override any previous clamping
// if the level is really small. That way you'll for sure never see past the lower-left of the level, but if the camera is
// zoomed out too far for the level size, you will see past the right or top of the level.
transform.position = goalPosition;
var lowerLeftCameraInWorld = camera.ViewportToWorldPoint (Vector3 (0.0, 0.0, targetViewportPosition.z));
// Find out how far outside the world the camera is right now.
clampOffset.x = Mathf.Max ((levelBounds.xMin - lowerLeftCameraInWorld.x), 0.0);
clampOffset.y = Mathf.Max ((levelBounds.yMin - lowerLeftCameraInWorld.y), 0.0);
// Now we apply our clamping to our goalPosition once again. Now our camera won't go past the left and bottom boundaries of the level!
goalPosition += clampOffset;
// Now that we're done calling functions on the camera, we can set the position back to the saved position;
transform.position = cameraPositionSave;
// Send back our spiffily calculated goalPosition back to the caller!
return goalPosition;
}
Wha, nice sripting. Dude its 2d, all you need is a trigger and a manager, Player lands on trigger bam! gui pops up open door to next level, yes or No- Yes, bang activates a cutscene, character goes into door, door closes onto next level. What else, what is this Zelda or something.
haha im just messing around with the 2d tutorial... trying things out. using all the assets from the tutorial though... but I guess you could assume that what I'm trying to do is very Zelda-esque. If anyone has suggestions I'd appreciate it
Answer by StephenS · Apr 06, 2012 at 06:28 AM
Ok, so anyone trying to do this: I got it working... just set up a second camera and when entering the trigger set the main camera to inactive, disable the player's controls and set the 2nd camera to active. Make sure the focal point of camera 2 is on the desired object. Also i started a coroutine here because there's a lot of events I want to happen but this is the basic idea :)
Your answer
Follow this Question
Related Questions
on collision stop transform.translate 1 Answer
Proper mouse aim of bullets with rigidbody2d and side scrolling? 0 Answers
Switching Camera on Collision won't work 0 Answers
Alternating Two Settings with One OnTriggerEnter Collider 1 Answer
Move camera on the z axis forward and backward with coroutine 0 Answers