Search Unity

FPF - how to make a first person fish?

Discussion in 'Scripting' started by dome, Mar 29, 2010.

  1. dome

    dome

    Joined:
    Mar 17, 2010
    Posts:
    15
    hi all,

    I'm starting with my first project using Unity. What I'm trying to accomplish is to move around a underwater scene from a fish point of view. In the end I expect to move forward and backward using up/down arrow and the direction I swim would be controlled with the mouse. The fish should also detect collisions.

    I've start from looking this forum for posts regarding swim / fly / spaceship / car controllers, and I've tried to apply some of the scripts and concepts explained and finished with a box carries my camera up and down.

    At the moment I feel a bit lost, I would really appreciate some help regarding:
    - what objects should be on scene
    - how to combine the keyboard + mouse (goes all in the same script?)

    Thanks,
    am
    :)

    EDIT: I will fill up with some more details of my current setup, maybe it helps to realize my noobish state ;)

    > cube { Box Collider + Rigidbody(use gravity set to off, prevent rotation on), FPFcontroller script }
    >> Main Camera { Mouse Look script }

    FPFcontroller
    Code (csharp):
    1.  
    2.  
    3. var swimSpeed = 10;
    4.  
    5. // Adds a force upwards in the global coordinate system
    6. function FixedUpdate () {
    7.     if (Input.GetKeyDown (KeyCode.UpArrow)) {
    8.         rigidbody.AddForce (transform.forward * swimSpeed);
    9.     }
    10.    
    11.     if (Input.GetKeyDown (KeyCode.DownArrow)) {
    12.         rigidbody.AddForce (transform.forward * -swimSpeed);
    13.     }
    14.     /*
    15.     if (Input.GetKeyDown (KeyCode.RightArrow)) {
    16.         rigidbody.AddForce (Vector3.right * 10);
    17.     }
    18.    
    19.     if (Input.GetKeyDown (KeyCode.LeftArrow)) {
    20.         rigidbody.AddForce (Vector3.right * -10);
    21.     }
    22.     */
    23. }
    24.  
    That's all, with this I can move in a straight line and crash into the terrain without flipping the camera (prevent rotation check helps to avoid this).
    I don't know how could I combine the mouse move to the physics forces to make the fish turn, and when I open the MouseMove script I get a little scared with the Quaternion.AngleAxis kinda stuff :D
     
  2. dome

    dome

    Joined:
    Mar 17, 2010
    Posts:
    15
    :)

    after some play I've been able to combine the mouse with the keys, in a way that keys addForces and mouse transforms the rotation of the object. So when a new force is applied and if you are "looking" to a different direction the object will move towards that direction. Here is the script:

    Code (csharp):
    1.  
    2. var swimSpeed = 10;
    3. var turnSensitivity = 10;
    4.  
    5. private var rotationX : float = 0;
    6. private var rotationY : float = 0;
    7. private var originalRotation : Quaternion;
    8.  
    9. function Start ()
    10. {
    11.     originalRotation = transform.localRotation;
    12. }
    13.  
    14. // Adds a force upwards in the global coordinate system
    15. function FixedUpdate () {
    16.     if (Input.GetKeyDown (KeyCode.UpArrow)) {
    17.         rigidbody.AddForce (transform.forward * swimSpeed);
    18.     }
    19.    
    20.     if (Input.GetKeyDown (KeyCode.DownArrow)) {
    21.         rigidbody.AddForce (transform.forward * -swimSpeed);
    22.     }
    23.    
    24.     // Read the mouse input axis
    25.     rotationX += Input.GetAxis("Mouse X") * turnSensitivity;
    26.     rotationY += Input.GetAxis("Mouse Y") * turnSensitivity;
    27.            
    28.     xQuaternion = Quaternion.AngleAxis (rotationX, Vector3.up);
    29.     yQuaternion = Quaternion.AngleAxis (rotationY, Vector3.left);
    30.            
    31.     transform.localRotation = originalRotation * xQuaternion * yQuaternion;
    32. }
    this script is attached to a cube with the camera as child. the cube have a box collider and it's a rigidbody.

    when addForce I start moving in the direction where the cube is pointed at, then if I change the rotation using the mouse the direction should also change... but this doesn't happen while I don't addForce once again... this makes sense, I just don't know how to solve it.

    :roll:
     
  3. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You need a sideways drag force on the object. This is proportional to the object's velocity in its local sideways direction. This is neatly calculated with the dot product of the velocity and transform.right:-
    Code (csharp):
    1. var fwdForce: float;
    2. var sideDrag: float;
    3. var turnTorque: float;
    4.  
    5. function FixedUpdate () {
    6.     rigidbody.AddForce(transform.forward * fwdForce * Input.GetAxis("Vertical"));
    7.     rigidbody.AddTorque(transform.up * turnTorque * Input.GetAxis("Horizontal"));
    8.     rigidbody.AddForce(-transform.right * Vector3.Dot(rigidbody.velocity, transform.right) * sideDrag);
    9. }
     
  4. dome

    dome

    Joined:
    Mar 17, 2010
    Posts:
    15
    hi andeeee!

    thanks for the help. Once I tried the code it was not turning at all. Then realized I had the "freezed rotation" checked... so after uncheck the code work fine.
    But the problem I've now is when colliding against the terrain the camera starts spinning without control.
    Any ideas how could I avoid this?

    Thanks,
    am
     
  5. hybrent

    hybrent

    Joined:
    Feb 26, 2010
    Posts:
    80
    Not the expert here, but does your camera have a collider on it? Sounds like the camera may be being affected by something.
     
  6. dome

    dome

    Joined:
    Mar 17, 2010
    Posts:
    15
    hi hybrent,

    it does, I'm using the collider so the camera don't goes through the terrain while "swimming" but when it collides against it starts rotating. Before I was using the prevent rotation, but this would let the script act upon the camera...

    so how to lock the rotation after a collision using script?
     
  7. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    How are you controlling the camera? Can you post the script you are using for it?
     
  8. dome

    dome

    Joined:
    Mar 17, 2010
    Posts:
    15
    sorry the delay here...
    back to the player control, I just start it over to try to find a simpler way to control the fish since i'm too short with time.

    For now I forgot the keyboard input, so I have for the player the following setup:
    - rigidbody
    - box collider
    - FPF(script)
    - MouseLook(script from FPS prefab)
    > camera as child

    what happens is I apply a constant force on Z axis so the player moves constantly forward, plus there is another force that "fix" the gravity, so player mantain the same depth. At the same time the mouseLook gives rotation to the the player so you can move in any direction. Because you can collide agains objects there is a lock in z rotation. Here is the script

    Code (csharp):
    1. var swimSpeed = 10;
    2. var floatingForce = 10;
    3.  
    4. // Adds a force upwards in the global coordinate system
    5. function FixedUpdate () {
    6.     transform.localRotation.z = 0;
    7.    
    8.     rigidbody.AddForce (transform.forward * swimSpeed);
    9.     rigidbody.AddForce (transform.up * floatingForce);
    10. }
    11.  
    It's a really rude solution, but at least I arrived kinda a safe harbor.
    What I'm looking for a for a more soft movement when you move the mouse, I think I should get rid of the mouseLook script and try to read the mouse inside my script. I've tried this before but without good results.
    Any ideas at this point would be welcome!

    Thank you.

    EDIT: I guess it's really bad practice to tweak the transform properties of a object controlled by physics, but if not how could I prevent it from rotating z :?:
     
  9. Mcadieux

    Mcadieux

    Joined:
    Nov 13, 2009
    Posts:
    55
    To prevent the random spinning, turn up the angular drag of your fish. In real life, the drag in water is high, you probably still have it set to 0. If you took a fish out of water and droped it on the ground it would "roll down a hill".
     
  10. dome

    dome

    Joined:
    Mar 17, 2010
    Posts:
    15
    hi Mcadieux,

    the rotation was not a problem anymore. the last solution I wrote in the previous post I could control the rotation, anyway I've added angular drag... to be honest I can't find any difference in the behavior.

    right now I've moved to a different setup, trying to get the head rotation smoother. Again it looks really hackish and not that I like how its done but it starts looking like what I was looking for :roll:

    i've a "fish" with the camera and a cameraTarget nested and a FPF script and SmoothLookAt(cameraTarget). The cameraTarget is ahead of the camera and I tell it to move in x/y according to the mouse position. Because there is a SmoothLookAt applied to the fish this will make it follow the target giving rotation to the fish... not sure if I explain my self... here are the scripts:

    Code (csharp):
    1.  
    2.  
    3. var swimSpeed = 10;
    4. var floatingForce = 10;
    5.  
    6. var mainCamera : GameObject;
    7. var cameraTarget : GameObject;
    8. var gui : GameObject;
    9.  
    10. var sensitivityX : float = 0.05;
    11. var sensitivityY : float = 0.05;
    12.  
    13. var yMinLimit = -20;
    14. var yMaxLimit = 20;
    15.  
    16. var rangeX : float = 3;
    17. var rangeY : float = 3;
    18.    
    19. private var positionX : float = 0;
    20. private var positionY : float = 0;
    21. private var positionZ : float = 0;
    22.  
    23. private var intro : boolean = true;
    24. private var end : boolean = false;
    25.  
    26. function Start () {
    27.    
    28.     Debug.Log(gui.GetComponent(GUI_intro).textTime);
    29.    
    30.     positionZ = cameraTarget.transform.localPosition.z;
    31.    
    32.     yield WaitForSeconds(20);
    33.     Debug.Log("intro end");
    34.     intro = false;
    35.     //yield WaitForSeconds(10);
    36.     //Debug.Log("end");
    37.     //GetComponent(SmoothLookAt).enabled = false;
    38.     //end = true;
    39. }  
    40.  
    41. function FixedUpdate () {
    42.     if (intro)
    43.         rigidbody.AddForce (transform.up * -8);
    44.     else if (!end)
    45.         // constant force forward
    46.         rigidbody.AddForce (transform.forward * swimSpeed);
    47.     else {
    48.         // Debug.Log("end");
    49.         rigidbody.AddForce (transform.up * 20);
    50.     }
    51. }
    52.  
    53. function Update () {
    54.     if (intro) {
    55.        
    56.     }
    57.     else if (!end) {
    58.         Debug.Log("mouse enabled");
    59.         positionX += Input.GetAxis("Mouse X") * sensitivityX;
    60.         positionY += Input.GetAxis("Mouse Y") * sensitivityY;
    61.        
    62.         if (positionX > rangeX)
    63.         positionX = rangeX;
    64.         else if (positionX < -rangeX)
    65.         positionX = -rangeX;
    66.        
    67.         if (positionY > rangeY)
    68.         positionY = rangeY;
    69.         else if (positionY < -rangeY)
    70.         positionY = -rangeY;
    71.        
    72.         rotationX = transform.eulerAngles.x;
    73.         // get negative rotation insted of full ex:(350 == -10)
    74.         if (rotationX > 180)
    75.         rotationX -= 360;
    76.    
    77.         if (rotationX > 30)
    78.         positionY = 0.01;
    79.         else if (rotationX < -10)
    80.         positionY = -0.01;
    81.    
    82.         cameraTarget.transform.localPosition = Vector3(positionX, positionY, positionZ);
    83.     }
    84.     else {
    85.         //mainCamera.transform.rotation = -90;
    86.         transform.eulerAngles = Vector3(-90, 0, 0);
    87.     }
    88. }
    89.  
    Code (csharp):
    1. var target : Transform;
    2. var damping = 6.0;
    3. var smooth = true;
    4.  
    5. @script AddComponentMenu("Camera-Control/Smooth Look At")
    6.  
    7. function LateUpdate () {
    8.     if (target) {
    9.         if (smooth)
    10.         {
    11.             // Look at and dampen the rotation
    12.             var rotation = Quaternion.LookRotation(target.position - transform.position);
    13.            
    14.             transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * damping);
    15.         }
    16.         else
    17.         {
    18.             // Just lookat
    19.             transform.LookAt(target);
    20.         }
    21.     }
    22. }
    23.  
    24. function Start () {
    25.     // Make the rigid body not change rotation
    26.     if (rigidbody)
    27.         rigidbody.freezeRotation = true;
    28. }
    I'm pretty sure I'm complicating the situation, maybe someone could enlighten me :wink: