Search Unity

Rigidbody going down river

Discussion in 'Scripting' started by danield, Sep 30, 2014.

  1. danield

    danield

    Joined:
    Sep 30, 2014
    Posts:
    40
    I am working on simulating an object in flowing water that changes direction occasionally and allows side to side movement based on input.
    So far, the script I have achieves the look but has a drawback. I want other objects to affect its movement (rocks, trees, ramps, etc) and that is proving difficult. Some changes to velocity are ignored on the next FixedUpdate() call. The reason I didn't use addForce is I want to cap it's speed but not affect gravity which I read "Drag" does.

    Any ideas for this or ideas for capping speed from addForce?

    Code (CSharp):
    1.     void FixedUpdate () {
    2.         RaycastHit water;
    3.         bool inWater = Physics.Raycast(gameObject.transform.position + Vector3.up, Vector3.down, out water, 1.4f);
    4.         if(inWater && motionEnabled) {
    5.             _flow = water.transform.forward;
    6.             waterMove(water.transform);
    7.             waterRotate(water.transform);
    8.             Debug.Log(gameObject.rigidbody.velocity.magnitude);
    9.         }
    10.     }
    11.  
    12.     /* Simulation Method
    13.      * (Pros) Top speed easy to set, predictable
    14.      * (Cons) Velocity changes harder to enforce
    15.     */
    16.  
    17.     void waterMove(Transform waterFlow) {
    18.         // move character in water by setting velocity and simulating acceleration
    19.         Vector3 sideMotion = (waterFlow.right * localInputs.sideInput * Time.fixedDeltaTime);
    20.         gameObject.rigidbody.velocity = sideMotion + calcVel(waterFlow.forward);
    21.     }
    22.  
    23.     Vector3 calcVel(Vector3 target) {
    24.         Vector3 output = Vector3.SmoothDamp(gameObject.rigidbody.velocity, target * speed, ref velocity, accel);
    25.         Vector3 dirVel = Vector3.Project(output, target);
    26.         output[1] = dirVel[1];
    27.         return output;
    28.     }
     
  2. danield

    danield

    Joined:
    Sep 30, 2014
    Posts:
    40
    After a bit of digging, I found a good solution.
    Code (CSharp):
    1. void waterForce(Transform waterFlow) {
    2.         // Default movement
    3.         Vector3 sideMotion = waterFlow.right * localInputs.sideInput(side);
    4.         Vector3 maxSpeed = waterFlow.forward * speed;
    5.         Vector3 forceSpeed = (Mathf.Sign(waterFlow.forward.y) >= 0f) ? maxSpeed - gameObject.rigidbody.velocity : maxSpeed.normalized * 5f;
    6.         float forceDir = Vector3.Dot(waterFlow.forward, gameObject.rigidbody.velocity.normalized);
    7.         if(forceDir >= 0 || gameObject.rigidbody.velocity == Vector3.zero) {
    8.             gameObject.rigidbody.AddForce(sideMotion + Vector3.ClampMagnitude(forceSpeed, speed + 5f), ForceMode.Acceleration);
    9.         } else {
    10.             // Player is bounced back
    11.             gameObject.rigidbody.AddForce(sideMotion + waterFlow.forward * (gameObject.rigidbody.velocity.magnitude + 2.5f), ForceMode.Acceleration);
    12.         }
    13.     }
    To simulate buoyancy, I added a configurable joint to a second rigidbody (the visible object) that only has a spring force in the y direction. While this looks nice it has one major flaw that is most evident when I give the anchor a force upwards.
    The anchor(mass 1.2) pulls the rigidbody(mass 0.5, useGravity = false, no drag), then the rigidbody pulls the anchor, and so on. Is there a way or formula that can move both anchor and rigidbody as one? Or, is there an alternate suggestion for simulating buoyancy.