Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Mixing 2 Scripts

Discussion in 'Scripting' started by khrysller, May 17, 2020.

  1. khrysller

    khrysller

    Joined:
    Mar 14, 2019
    Posts:
    125
    Hi : ) I am new to Unity and I am having a hard time trying to mix 2 scripts together. I would like to have my main script which is MovementInput.cs with the Dash() and Jump() function from the Character.cs script.

    MovementInput.cs
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. //This script requires you to have setup your animator with 3 parameters, "InputMagnitude", "InputX", "InputZ"
    7. //With a blend tree to control the inputmagnitude and allow blending between animations.
    8. [RequireComponent(typeof(CharacterController))]
    9. public class MovementInput : MonoBehaviour {
    10.  
    11.     public float Velocity;
    12.     [Space]
    13.  
    14.     public float InputX;
    15.     public float InputZ;
    16.     public Vector3 desiredMoveDirection;
    17.     public bool blockRotationPlayer;
    18.     public float desiredRotationSpeed = 0.1f;
    19.     public Animator anim;
    20.     public float Speed;
    21.     public float allowPlayerRotation = 0.1f;
    22.     public Camera cam;
    23.     public CharacterController controller;
    24.     public bool isGrounded;
    25.  
    26.     [Header("Animation Smoothing")]
    27.     [Range(0, 1f)]
    28.     public float HorizontalAnimSmoothTime = 0.2f;
    29.     [Range(0, 1f)]
    30.     public float VerticalAnimTime = 0.2f;
    31.     [Range(0,1f)]
    32.     public float StartAnimTime = 0.3f;
    33.     [Range(0, 1f)]
    34.     public float StopAnimTime = 0.15f;
    35.  
    36.     public float verticalVel;
    37.     private Vector3 moveVector;
    38.  
    39.     // Use this for initialization
    40.     void Start () {
    41.         anim = this.GetComponent<Animator> ();
    42.         cam = Camera.main;
    43.         controller = this.GetComponent<CharacterController> ();
    44.     }
    45.  
    46.     // Update is called once per frame
    47.     void Update () {
    48.         InputMagnitude ();
    49.  
    50.         isGrounded = controller.isGrounded;
    51.         if (isGrounded)
    52.         {
    53.             verticalVel -= 0;
    54.         }
    55.         else
    56.         {
    57.             verticalVel -= 1;
    58.         }
    59.         moveVector = new Vector3(0, verticalVel * .2f * Time.deltaTime, 0);
    60.         controller.Move(moveVector);
    61.  
    62.  
    63.     }
    64.  
    65.     void PlayerMoveAndRotation() {
    66.         InputX = Input.GetAxis ("Horizontal");
    67.         InputZ = Input.GetAxis ("Vertical");
    68.  
    69.         var camera = Camera.main;
    70.         var forward = cam.transform.forward;
    71.         var right = cam.transform.right;
    72.  
    73.         forward.y = 0f;
    74.         right.y = 0f;
    75.  
    76.         forward.Normalize ();
    77.         right.Normalize ();
    78.  
    79.         desiredMoveDirection = forward * InputZ + right * InputX;
    80.  
    81.         if (blockRotationPlayer == false) {
    82.             transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (desiredMoveDirection), desiredRotationSpeed);
    83.             controller.Move(desiredMoveDirection * Time.deltaTime * Velocity);
    84.         }
    85.     }
    86.  
    87.     public void LookAt(Vector3 pos)
    88.     {
    89.         transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(pos), desiredRotationSpeed);
    90.     }
    91.  
    92.     public void RotateToCamera(Transform t)
    93.     {
    94.  
    95.         var camera = Camera.main;
    96.         var forward = cam.transform.forward;
    97.         var right = cam.transform.right;
    98.  
    99.         desiredMoveDirection = forward;
    100.  
    101.         t.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(desiredMoveDirection), desiredRotationSpeed);
    102.     }
    103.  
    104.     void InputMagnitude() {
    105.         //Calculate Input Vectors
    106.         InputX = Input.GetAxis ("Horizontal");
    107.         InputZ = Input.GetAxis ("Vertical");
    108.  
    109.         //anim.SetFloat ("InputZ", InputZ, VerticalAnimTime, Time.deltaTime * 2f);
    110.         //anim.SetFloat ("InputX", InputX, HorizontalAnimSmoothTime, Time.deltaTime * 2f);
    111.  
    112.         //Calculate the Input Magnitude
    113.         Speed = new Vector2(InputX, InputZ).sqrMagnitude;
    114.  
    115.         //Physically move player
    116.  
    117.         if (Speed > allowPlayerRotation) {
    118.             anim.SetFloat ("Blend", Speed, StartAnimTime, Time.deltaTime);
    119.             PlayerMoveAndRotation ();
    120.         } else if (Speed < allowPlayerRotation) {
    121.             anim.SetFloat ("Blend", Speed, StopAnimTime, Time.deltaTime);
    122.         }
    123.     }
    124. }
    125.  
    Character.cs
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Character : MonoBehaviour
    6. {
    7.     public float Speed = 5f;
    8.     public float JumpHeight = 2f;
    9.     public float Gravity = -9.81f;
    10.     public float GroundDistance = 0.2f;
    11.     public float DashDistance = 5f;
    12.     public LayerMask Ground;
    13.     public Vector3 Drag;
    14.  
    15.     private CharacterController _controller;
    16.     private Vector3 _velocity;
    17.     private bool _isGrounded = true;
    18.     private Transform _groundChecker;
    19.  
    20.  
    21.     void Start()
    22.     {
    23.         _controller = GetComponent<CharacterController>();
    24.         _groundChecker = transform.GetChild(0);
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         _isGrounded = Physics.CheckSphere(_groundChecker.position, GroundDistance, Ground, QueryTriggerInteraction.Ignore);
    30.         if (_isGrounded && _velocity.y < 0)
    31.             _velocity.y = 0f;
    32.  
    33.         Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    34.         _controller.Move(move * Time.deltaTime * Speed);
    35.         if (move != Vector3.zero)
    36.             transform.forward = move;
    37.  
    38.         _velocity.y += Gravity * Time.deltaTime;
    39.  
    40.         _velocity.x /= 1 + Drag.x * Time.deltaTime;
    41.         _velocity.y /= 1 + Drag.y * Time.deltaTime;
    42.         _velocity.z /= 1 + Drag.z * Time.deltaTime;
    43.  
    44.         _controller.Move(_velocity * Time.deltaTime);
    45.     }
    46.  
    47.     public void Dash()
    48.     {
    49.         _velocity += Vector3.Scale(transform.forward, DashDistance * new Vector3((Mathf.Log(1f / (Time.deltaTime * Drag.x + 1)) / -Time.deltaTime), 0, (Mathf.Log(1f / (Time.deltaTime * Drag.z + 1)) / -Time.deltaTime)));
    50.     }
    51.  
    52.     public void Jump()
    53.     {
    54.         _velocity.y += Mathf.Sqrt(JumpHeight * -2f * Gravity);
    55.     }
    56. }
    Thanks for any help on this.
     
  2. TheCakeIsReal

    TheCakeIsReal

    Joined:
    Feb 10, 2018
    Posts:
    7
    Hi khrysller,

    Easy solution : Inheritance
    I don't know if it makes sense to do it in your project, but you can make MovementInput a child class of Character. You will have to declare Start and Update as virtual functions in Character, override them in MovementInput and call the base version as well.

    Alternative solution : Delegation
    If for one reason or another you cannot use inheritance, you can try this solution. It is less elegant, but it will certainly work. It requires to attach a Character script to the game object having your MovementInput script (which I do in the start method, but you can do it manually in the editor).

    Code (CSharp):
    1. class MovementInput : MonoBehaviour
    2. {
    3.     private Character character;
    4.  
    5.     void Start() {
    6.         character = AddComponent<Character>();
    7.     }
    8.  
    9.     public void Jump()
    10.     {
    11.         character.Jump();
    12.     }
    13.  
    14.     public void Dash()
    15.     {
    16.         character.Dash();
    17.     }
    18. }
    Hope it helps you !
     
  3. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I'd argue against inheritance in this scenario regardless. Inheritance should be reserved for "is a" relationships between objects that contain common functions & attributes. Anything else is setting yourself up for loads of spaghetti code.

    I.E: A "Car" is a "Vehicle", and a "Boat" is a "Vehicle" as well. Both "Car" and "Boat" have an "engine" attribute and a "Drive" method, which can be defined in the "Vehicle" parent class, because these are common functions among all types of "Vehicles".

    In this case, a "MovementInput" is not a "Character", because these two things are completely unrelated to each other.
    However, a "Character" has a "MovementInput", which is what your second solution describes, and makes much more sense. This would actually be far more elegant solution.

    It's the same as delegating physics tasks to Rigidbody components, or audio tasks to AudioSource components.
    A custom MonoBehaviour script has a Rigidbody and has an AudioSource, but it is not a Rigidbody and is not an AudioSource.
     
    Last edited: May 17, 2020
    TeagansDad and jasonatkaruna like this.
  4. jasonatkaruna

    jasonatkaruna

    Joined:
    Feb 26, 2019
    Posts:
    64
    Agree with Vryken here. Only thing I'll add, is that Unity's component system has a tool for component dependencies,
    [RequireComponent]
    . This tells the Unity Editor to add the required component to any GameObject with the attributed component. For example, if you change the
    Character
    component to require the
    MovementInput
    component:
    Code (CSharp):
    1. [RequireComponent(typeof(MovementInput))]
    2. public class Character : MonoBehaviour
    3. {
    4. // ...
    5. }
    then anywhere you put a
    Character
    component, there will be a
    MovementInput
    component. I prefer this to adding the
    MovementInput
    component in
    Start()
    because the dependency is known before runtime.

    Keep in mind that the
    RequireComponentAttribute
    only looks at the GameObject the attributed component is on. It's not a good tool for dependencies on singletons. If you want to reference a singleton, you can make it a public field and drag-n-drop the
    MovementInput
    reference in the inspector.
     
    Last edited: May 18, 2020
  5. khrysller

    khrysller

    Joined:
    Mar 14, 2019
    Posts:
    125
    Thank you all for all the information but I really want to have only one script. I am still trying to do this. Thanks