- Home /
How to copy camera rotation, plus custom setup for parallax scrolling?
Hi,
I'm a new user and I really enjoy discovering Unity3D. I'm more an artist than a programmer, so I have some difficulties to "translate" my thoughts into code.
Would you help me with javascript scripting?
I would like the camera 2 to copy the camera 1 rotation. It should work for case B also.
I would like to try a setup where the camera 2 rotates on the left when the camera 1 moves to the right. I want to use it for a sidescroller. The more Camera 1 goes to the right, the more Camera 2 rotates to the left. If Camera 1 goest to the left, Camera 2 rotates to the right.
The best would be to have a variable that allows me to make the rotation faster/slower per axis.
- I would like to mix 1) and 2) : see image below.
Here is what I have so far, but it doesn't work the way that is described in the images above :
var rot_speed : Vector3; var myTransform : Transform;
function Update () { var target_rot = myTransform.eulerAngles; for (i=0;i<3;i++){ target_rot[i] = target_rot[i]*rot_speed[i]; transform.eulerAngles = target_rot; }
Can you help me on that?
Answer by skovacs1 · Sep 29, 2010 at 07:43 PM
Your script seems to be on the right track. You should describe what your script is not doing when you post a script so that it is clearer what problem to solve.
What you describe is rather simple. Your code seems to be a bit confused about what eulerAngles are and you've left out some rather important details about your implementation.
In order to mirror the rotation about the right axis, you would apply this to your first camera
//this is the other camera. var other : Transform;
function Update() { if(other) other.eulerAngles.x = transform.eulerAngles.x; }
eulerAngles.x is your rotation about the right (x) axis and will make your camera look up or down. All you need to mirror the rotation is to set the rotation of your mimic camera to be the same as your lead camera.
To mirror all rotation, you would simply need:
other.eulerAngles = transform.eulerAngles;
You've left out the part where you are translating one of your cameras. I don't really know how you mean to move your camera so it's challenging to assume a given movement system.
Wherever you move your camera, you would need to do something like:
var rotateScale : float = -15.0; //rotate left 15 degrees per unit moved right
var movementAmount : float = something; //Where you get your movement from
camera1.position.x += movementAmount;
camera2.eulerAngles.y += movementAmount * rotateScale;
Here's a script to attach to your main camera that will move based on input axes;
Master.js
var other : Transform; //the slave var moveSpeedX : float = 2.0; //units to move per unit of input var rotateSpeedX : float = 5.0; //degrees per unit of input var rotateSpeedY : float = -15.0; //degrees per unit of input
function Update() { //Get input var v : float = Input.GetAxis("Vertical") time.deltaTime rotateSpeedX; var h : float = Input.GetAxis("Horizontal") * time.deltaTime;
//Move this
transform.position.x += h * moveSpeedX;
transform.eulerAngles.x += v;
//Move the slave
if(other) {
other.eulerAngles.y += h * rotateSpeedY;
other.eulerAngles.x += v;
}
}
EDIT 10/04/10
From the slave perspective
Master.js
var moveSpeedX : float = 1.0; //units to move per unit of input var h : float = 0.0; //The horizontal input
function Update () { h = Input.GetAxis("Horizontal") Time.deltaTime;
transform.position.x += h moveSpeedX; }
Slave.js
var master : Master; var moveSpeedX : float = 1.0; //units to move per unit of input
function LateUpdate () { if(master) { var script : Master = master.GetComponent(Master); if(script && script.h) transform.position.x += script.h * moveSpeedX; } }
Copying rotation is the same as copying position above, but replacing transform.position with transform.eulerAngles.
Considering things from the slave perspective is really spreading your code out. I assume this may be because you want the script to just work with a prefab and require little-to-no setup. You can achieve this from the master perspective by having the slaves add themselves to their master, changing the first scripting to something like:
Master.js
var slaves : Transform[] = new Array(); //the slaves var moveSpeedX : float = 2.0; //units to move per unit of input var rotateSpeedX : float = 5.0; //degrees per unit of input var rotateSpeedY : float = -15.0; //degrees per unit of input
function Update() { //Get input var v : float = Input.GetAxis("Vertical") time.deltaTime; var h : float = Input.GetAxis("Horizontal") time.deltaTime;
//Move this
transform.position.x += h * moveSpeedX;
transform.eulerAngles.x += v * rotateSpeedX;
//Move the slaves
for(var slave : Transform in slaves) {
//If you wanted to use slave-specific values
//var script : Slave = slave.GetComponent(Slave);
//if(script) {
// slave.eulerAngles.y += h * script.rotateSpeedY;
// slave.eulerAngles.x += v * script.rotateSpeedX;
//}
slave.eulerAngles.y += h * rotateSpeedY;
slave.eulerAngles.x += v * rotateSpeedX;
}
}
Slave.js
var master : Transform;
function Start() { //add yourself as a slave var script : Master = master.GetComponent(Master); if(script) script.slaves.push(transform);
}
EDIT 10/07/10
If you cannot get your deltas directly or use input or some such (as in the case where using physics), you will have to calculate them manually.
Master.js
var slaves : Transform[] = new Array(); //the slaves private var oldPosition : Vector3; //the position we had last frame private var oldRotation : Quaternion; //the rotation we had last frame
function Start() { oldPosition = transform.position; oldRotation = transform.rotation; }
function Update() { //We may have been moved. Get deltas var deltaPosition : Vector3 = transform.position - oldPosition; var deltaRotation : Vector3 = Quaternion.FromToRotation(oldRotation, transform.rotation).eulerAngles; oldPosition = transform.position; oldRotation = transform.rotation;
//Move the slaves
for(var slave : Transform in slaves) {
var script : Slave = slave.GetComponent(Slave);
if(script) {
slave.eulerAngles.y += deltaPosition.x * script.rotateSpeedY;
slave.eulerAngles.x += deltaRotation.x * script.rotateSpeedX;
}
}
}
Slave.js
var master : Transform; var rotateSpeedX : float = 1.0; //degrees per unit of input var rotateSpeedY : float = -5.0; //degrees per unit of input
function Start() { //add yourself as a slave var script : Master = master.GetComponent(Master); if(script) script.slaves.push(transform);
}
Note that from the master's perspective, we only calculate their delta's once per frame, whereas from the slave perspective, every slave would have to re-calculate.
Hi skovacs, thank your for your answer and explanations.
It helped me understand the way I can handle my issue and break your script in several parts. I'm trying to give a more detailed explanation of the problem I'm trying to solve in the answer below. If you could take a look, that would help me a lot. Thank you.
Unless you are actually posting the answer to your question, you should either edit your question if the edits don't change its general meaning or post one or more separate questions. Also, as it says in the FAQ, you should break your problem into discrete sub-questions.
Thank you again for taking the time, as a beginner I appreciate that. I will study your answer carefully. I wanted to have my script on my slave so that I can have different movespeedX and other variables per slave. That's required for what I'm trying to achieve (simulate parallax scrolling and more).
I will also be more careful with the way I write my questions. I'm not familiar with the way that UnityAnswers works yet (so true that my message was not an answer at all...).
Now, it's time to study your explanations!
No problem. Like I put in the code comment, if you have a rotateSpeedX and/or rotateSpeedY in the Slave script and use the commented out code, you would use the slave values for each slave. You can always vote to delete your answer and edit your quesitons, but your should generally keep the meaning the same. When in doubt, check the criteria in the FAQ
I see. How would you modify the script in order to get the master's movement without input? - let's say that the master is a falling rigid body/sphere) - or, the master is a camera (or any other object) whose parent is the main character (moved by input) If I could write my script without using input variables, that would be great. Would you please give me some hints? (I will edit my questions as soon as I can)
Answer by cray · Oct 02, 2010 at 04:22 PM
I have decided to break my setup into 2 distinct scripts :
Setup 1 : Camera 2 movement Camera 2 copies Camera 1 movements on X axis. moveSpeedX variable is used to control the scrolling speed.
Camera 1 movements script Simplified for testing purposes
var moveSpeedX : float = 1.0; //units to move per unit of input
function Update () {
var h : float = Input.GetAxis("Horizontal") * Time.deltaTime;
//Move this
transform.position.x += h * moveSpeedX;
}
Camera 2 copy Camera 1 movements script
var master_obj : Transform; // Camera 1 var moveSpeedX : float = 1.0; //degrees per unit of input var moveSpeedY : float = 1.0; //degrees per unit of input var moveSpeedZ : float = 1.0; //degrees per unit of input
function Start () { // Here I want to save initial Camera 2 position : InitPosX, InitPosY, InitPosZ
}
function Update () {
if (master_obj){
//Move this
transform.position.x = master_obj.position.x * moveSpeedX + InitPosX;
transform.position.y = master_obj.position.y * moveSpeedY + InitPosY;
transform.position.z = master_obj.position.z * moveSpeedZ + InitPosZ;
}
}
Problem
I don't know how to save the initial transform.position in a Start() function and use it in Update() function. Or maybe something like transform.Globalposition.x = master_obj.Localposition.x * moveSpeedX exists in some way, and would do the trick?
More explanations
With the help of the first answer I got, here is the setup I actually have :
On layer 1, Camera 1 is parented to the main character. On layer 2, Camera 2 is put in front of a background (image, or 3D scene in that case). Camera 2 copies Camera 1 orientation.
The main character is moving with the following script (simplified for testing)
Camera 1 is parented to the main character.
Camera 2 is the "slave" of Camera 1.
Being able to save the Camera 2 initial position would help me to change its position at startup and get something like the following image :
Setup 2 : Camera 2 orientation Simplified for testing purposes
Camera 2 copies Camera 1 orientation on its local axis. See images above.
var master_obj : Transform; //the master Camera 1 var rotateSpeedX : float = 1.0; //degrees per unit of input
function Start () { // Here I want to save initial Camera 2 orientation : InitOrX, InitOrY, InitOrZ
} function Update() {
if (master_obj){ transform.eulerAngles.x = InitOrX + master_obj.eulerAngles.x * rotateSpeedX; }
}
Problem
I don't know how to save the initial transform.eulerAngles in a Start() function and use it in Update() function. Or maybe something like transform.Globalorientation.x = master_obj.Localorientation.x * moveSpeedX exists in some way, and would do the trick?
I don't know how to get the expected result. I am a bit confused about the way I can get it. I don't want my camera 2 to copy Camera 1 position but more like "ADD" it to its current position. I don't want my camera 2 to copy Camera 1 orientation but more like "ADD" it to its current orientation.
After that, I will try to implement the Camera 1 translation on x / Camera 2 rotation on Y axis.
I've tried to describe my question precisely.
Thank you again for your help.