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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Moving on a grid in first person. Forward, Backward, Strafing, and rotating

Discussion in 'Scripting' started by The_Adventurer, Sep 8, 2015.

  1. The_Adventurer

    The_Adventurer

    Joined:
    Mar 10, 2015
    Posts:
    12
    Hey all, I've suddenly found myself thrust back into unity development and have hit a bit of a road block on the basics.

    I have a first person camera that I'm going to have moving around in a ridged grid. Where you can move one block forward, backward, strafe left and right. But you can also pivot in place in 90 degree intervals to change your heading. I figured out the directional stuff (sort of), but I'm having serious trouble with rotating.

    here's my Javascript movement code so far....

    Code (JavaScript):
    1. private var speed = 10.0;
    2. private var pos : Vector3;
    3. private var tr : Transform;
    4. private var rot : Quaternion;
    5. public var rotSpeed = 140.0;
    6.  
    7.  
    8. function Start () {
    9.     pos = transform.position;
    10.     tr = transform;
    11.     rot = transform.rotation;
    12. }
    13.  
    14. function Update () {
    15.  
    16.  
    17.     if (Input.GetKeyDown(KeyCode.E) && tr.position == pos) {
    18.         pos += Vector3(5,0,0); //right
    19.     }
    20.     else if (Input.GetKeyDown(KeyCode.Q) && tr.position == pos) {
    21.         pos += Vector3(-5,0,0); //left
    22.     }
    23.     else if (Input.GetKeyDown(KeyCode.W) && tr.position == pos) {
    24.         pos += Vector3(0,0,5); //forward  
    25.     }
    26.     else if (Input.GetKeyDown(KeyCode.S) && tr.position == pos) {
    27.         pos += Vector3(0,0,-5); //backward
    28.     }
    29.     else if (Input.GetKeyDown(KeyCode.D) && tr.position == pos) {
    30.         rot = Quaternion.Euler (0,90,0); // rotate right
    31.     }
    32.     else if (Input.GetKeyDown(KeyCode.A) && tr.position == pos) {
    33.         rot = Quaternion.Euler (0,-90,0); // rotate left
    34.     }
    35.  
    36.     transform.rotation = Quaternion.RotateTowards (transform.rotation, rot, Time.deltaTime * rotSpeed);
    37.     transform.position = Vector3.MoveTowards(transform.position, pos, Time.deltaTime * speed);
    38. }
    I'm getting the snappy grid based movement I want, but rotating just isn't working. Instead of turning 90 degrees left or right in increments its just setting the rotation angle to 90 or -90 degrees. Clearly I should be adding or subtracting to some value, but I can't for the life of me figure out how to find it, or set it properly (damn you Quaternions!).

    This is of course leading to a bigger problem very soon, as rotating doesn't change the directional movement orientation based on the direction my camera is looking. W still moves on the Z axis etc... Will I need to code a bunch of if/then checks to reorient at every angle?

    Thanks for any help or suggestions you might have for me.
     
  2. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    I have instant turn method as:
    Code (CSharp):
    1.  
    2.     public void Turn( bool left )
    3.     {
    4.         if ( !left )
    5.             transform.Rotate( 0, 90, 0, Space.Self );
    6.         else
    7.             transform.Rotate( 0, -90, 0, Space.Self );
    8.     }
    9.  
    and moving needs to have its direction translated from local to world with:
    Code (CSharp):
    1.  
    2. Vector3 worldDirection = transform.TransformDirection( direction );
    3.  
    direction would propably be equal to 'pos' in your code.

    Hopes this will help you right direction ;)
     
  3. The_Adventurer

    The_Adventurer

    Joined:
    Mar 10, 2015
    Posts:
    12
    I guess I'm unclear on some things, plugging in your rotate commands work for proper 360 rotation, but its instantanious when I'm looking for a smooth transition over deltatime. (like how transform.position= Vector3.MoveTowards(transform.position, pos, Time.deltaTime* speed); does it for stepping in directions)

    worldDirection looks really useful, but I have no idea where to enter it into my code so its relevant. Could you clarify?
     
  4. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    Try something like this:
    Code (CSharp):
    1.  
    2. var dir;
    3. ///some lines between
    4.    if (Input.GetKeyDown(KeyCode.E) ) {
    5.         dir= -Vector3.left; //right
    6. ///and below
    7. //edit 'Damn mobile'
    8. Insert the line with worldPosition here
    9.  
    10.  
    11. transform.position = Vector3.MoveTowards(transform.position, worldDirection *5 , Time.deltaTime * speed);
    12.  
    I'm throwing these from the top of my head as I'm not at my dev computer.
    Rotation probably needs similar local to world conversion.
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,201
    Rotations can be multiplied to add them together. So if you do:

    Code (CSharp):
    1. transform.rotation = transform.rotation * Quaternion.Euler(0, 90, 0);
    That would rotate your character 90 degrees to the right of it's current rotation.

    which means that you'll want to replace:

    Code (javascript):
    1. rot = Quaternion.Euler(0,90,0);// rotate right
    with this:

    Code (javascript):
    1. rot = rot * Quaternion.Euler(0,90,0);// rotate right
    and you should be good.
     
  6. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    Thx Baste for that.
    Did you get it to work The_Adventurer?
    Here's mine a bit modified playerMove script ( I have separate script for input etc.. )
    It's in Csharp but I'm sure you can manage to modify it to unityScript.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class PlayerMovementMod : MonoBehaviour
    6. {
    7.  
    8.     public float gridSize;
    9.  
    10.     public float moveSpeed = 15;
    11.     public float rotationSpeed = 300f;
    12.  
    13.     public Vector3 position;
    14.     public Quaternion rotation;
    15.  
    16.     public void Turn( bool left )
    17.     {
    18.         if ( isAnimating() )
    19.             return;
    20.         if ( !left )
    21.             rotation = rotation * Quaternion.Euler( 0, 90, 0 );
    22.         else
    23.             rotation = rotation * Quaternion.Euler( 0, -90, 0 );
    24.     }
    25.  
    26.     private void Move( Vector3 dir )
    27.     {
    28.         //Translates direction from local to world
    29.         Vector3 worldDirection = transform.TransformDirection( dir );
    30.  
    31.         if ( isFreeTile( worldDirection ) )
    32.         {
    33.             position = worldDirection * gridSize + transform.position;
    34.         }
    35.     }
    36.  
    37.  
    38.     private bool isFreeTile( Vector3 worldDirection )
    39.     {
    40.    
    41.         RaycastHit hit;
    42.  
    43.         //Debug.DrawLine( transform.position, transform.position + worldDirection * gridSize, Color.red, 1f );
    44.  
    45.         if ( Physics.Raycast( transform.position, worldDirection, out hit, gridSize ) )
    46.         {
    47.             Debug.Log( "Bump " + hit.transform.name );
    48.             return false;
    49.         }
    50.         else
    51.             return true;
    52.     }
    53.  
    54.     void Start()
    55.     {
    56.         position = transform.position;
    57.         rotation = transform.rotation;
    58.     }
    59.  
    60.     void Update()
    61.     {
    62.    
    63.         transform.rotation = Quaternion.RotateTowards( transform.rotation, rotation, Time.deltaTime * rotationSpeed );
    64.         transform.position = Vector3.MoveTowards( transform.position, position, Time.deltaTime * moveSpeed );
    65.     }
    66.  
    67.     private bool isAnimating()
    68.     {
    69.         if ( transform.position != position )
    70.             return true;
    71.         if ( ( rotation.eulerAngles - transform.rotation.eulerAngles ).sqrMagnitude > 0.1f )
    72.             return true;
    73.         else
    74.             transform.rotation = rotation;
    75.         return false;
    76.     }
    77. }
    78.  
     
  7. The_Adventurer

    The_Adventurer

    Joined:
    Mar 10, 2015
    Posts:
    12
    I'm getting closer, but the worldDirection stuff is still hanging me up. I'm getting wonky rotation effects when I turn it on (I now rotate in place properly if I have it off, but my movement direction is locked) and my controls lock up.

    Current code looks like....

    Code (JavaScript):
    1. #pragma strict
    2.  
    3. private var speed = 10.0;
    4. private var pos : Vector3;
    5. private var tr : Transform;
    6. private var rot : Quaternion;
    7. private var tiltAngle = 90.0;
    8. private var rotSpeed = 140.0;
    9. public var worldDirection : Vector3;
    10.  
    11. function Start () {
    12.     pos = transform.position;
    13.     tr = transform;
    14.     rot = transform.rotation;
    15. }
    16.  
    17. function Update () {
    18.    
    19.     if (Input.GetKeyDown(KeyCode.E) && tr.position == pos) {
    20.         pos += Vector3(5,0,0); //right
    21.     }
    22.     else if (Input.GetKeyDown(KeyCode.Q) && tr.position == pos) {
    23.         pos += Vector3(-5,0,0); //left
    24.     }
    25.     else if (Input.GetKeyDown(KeyCode.W) && tr.position == pos) {
    26.         pos += Vector3(0,0,5); //forward  
    27.     }
    28.     else if (Input.GetKeyDown(KeyCode.S) && tr.position == pos) {
    29.         pos += Vector3(0,0,-5); //backward
    30.     }
    31.     else if (Input.GetKeyDown(KeyCode.D) && tr.position == pos) {
    32.         //z += Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;  
    33.         rot = rot * Quaternion.Euler (0,90,0);
    34.     }
    35.     else if (Input.GetKeyDown(KeyCode.A) && tr.position == pos) {
    36.         //z -= Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;  
    37.         rot = rot * Quaternion.Euler (0,-90,0);
    38.     }
    39.  
    40.     transform.rotation = Quaternion.RotateTowards (transform.rotation, rot, Time.deltaTime * rotSpeed);
    41.     worldDirection = transform.TransformDirection(pos);
    42.     transform.position = Vector3.MoveTowards(transform.position, worldDirection, Time.deltaTime * speed);
    43. }
    I feel like this is getting close to working, I'm just missing something.
     
  8. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    Change the last line to
    Code (CSharp):
    1.     transform.position = Vector3.MoveTowards(transform.position, worldDirection + tr.position, Time.deltaTime * speed);
    2.  
    And in update
    Code (CSharp):
    1.   If(!isAnimating)
    2. {
    3. if (Input.GetKeyDown(KeyCode.E) ) {
    4.         pos += Vector3(5,0,0); //right
    5.     }
    6.     else if (Input.GetKeyDown(KeyCode.Q) ) {
    7.         pos += Vector3(-5,0,0); //left
    8.     }
    9.     else if (Input.GetKeyDown(KeyCode.W) ) {
    10.         pos += Vector3(0,0,5); //forward
    11.     }
    12.     else if (Input.GetKeyDown(KeyCode.S)) {
    13.         pos += Vector3(0,0,-5); //backward
    14.     }
    15.     else if (Input.GetKeyDown(KeyCode.D)) {
    16.         //z += Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;
    17.         rot = rot * Quaternion.Euler (0,90,0);
    18.     }
    19.     else if (Input.GetKeyDown(KeyCode.A) ) {
    20.         //z -= Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;
    21.         rot = rot * Quaternion.Euler (0,-90,0);
    22.     }
    23. }
    Otherwise you will be able to move while rotating and you'll be soon off the grid.
     
  9. The_Adventurer

    The_Adventurer

    Joined:
    Mar 10, 2015
    Posts:
    12
    Still doesn't work. Leaving my last execution lines as...

    Code (JavaScript):
    1.  
    2. transform.rotation = Quaternion.RotateTowards (transform.rotation, rot, Time.deltaTime * rotSpeed);
    3.     worldDirection = transform.TransformDirection(pos);
    4.     transform.position = Vector3.MoveTowards(transform.position, worldDirection + tr.position, Time.deltaTime * speed);
    just causes my player object to just fly off forever when I run the game with no keyboard response.
     
  10. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    I think it because 'pos' dont get updated at all now.
    change:
    Code (CSharp):
    1.  
    2. worldDirection = transform.TransformDirection(pos);
    3. transform.position = Vector3.MoveTowards(transform.position, worldDirection + tr.position, Time.deltaTime * speed);
    4.  
    to:
    Code (CSharp):
    1.  
    2. [U]pos[/U] = transform.TransformDirection(pos);+ tr.[URL='http://unity3d.com/support/documentation/ScriptReference/30_search.html?q=position'][U]position[/U][/URL];
    3. transform.position = Vector3.MoveTowards(transform.position, [U][COLOR=#0066cc]pos[/COLOR][/U], Time.deltaTime * speed);
    4.  
    My code is working, so yours cant be far away either.
     
  11. The_Adventurer

    The_Adventurer

    Joined:
    Mar 10, 2015
    Posts:
    12
    Could you post your complete code? Even with that change I'm still flying off forever with no input. I think worldDirection/pos is getting updated continually with new values, which is why I'm flying off. I don't know why.
     
  12. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    I'm giving you a treat with two files. These are certified to work.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public enum MoveDirections
    5. {
    6.     None,
    7.     Forward,
    8.     Right,
    9.     Back,
    10.     Left
    11. }
    12.  
    13. public class PlayerMovement : MonoBehaviour {
    14.  
    15.     public float gridSize = 5f;
    16.  
    17.     public float animationSpeed = 15f;
    18.  
    19.     public Vector3 position;
    20.     public Quaternion rotation;
    21.  
    22.     public void Move( MoveDirections dir )
    23.     {
    24.         if ( isAnimating() )
    25.             return;
    26.  
    27.         Vector3 moveDirection = Vector3.zero;
    28.  
    29.         switch ( dir )
    30.         {
    31.             case MoveDirections.Forward:
    32.                 {
    33.                     moveDirection = Vector3.forward;
    34.                     break;
    35.                 }
    36.             case MoveDirections.Right:
    37.                 {
    38.                     moveDirection = -Vector3.left;
    39.                     break;
    40.                 }
    41.             case MoveDirections.Back:
    42.                 {
    43.                     moveDirection = -Vector3.forward;
    44.                     break;
    45.                 }
    46.             case MoveDirections.Left:
    47.                 {
    48.                     moveDirection = Vector3.left;
    49.                     break;
    50.                 }
    51.             default:
    52.                 {
    53.                     Debug.LogWarning( "Unknown direction" );
    54.                     break;
    55.                 }
    56.         }
    57.         Move( moveDirection );
    58.     }
    59.  
    60.     private bool isAnimating()
    61.     {
    62.         if ( transform.position != position )
    63.             return true;
    64.         if ( ( rotation.eulerAngles - transform.rotation.eulerAngles ).sqrMagnitude > 0.1f )
    65.             return true;
    66.         else
    67.             transform.rotation = rotation;
    68.         return false;
    69.     }
    70.  
    71.     public void Turn( bool left )
    72.     {
    73.         if ( isAnimating() )
    74.             return;
    75.         if ( !left )
    76.             rotation = rotation * Quaternion.Euler( 0, 90, 0 );
    77.         else
    78.             rotation = rotation * Quaternion.Euler( 0, -90, 0 );
    79.     }
    80.  
    81.     private void Move( Vector3 dir )
    82.     {
    83.         //Translates direction from local to world
    84.         Vector3 worldDirection = transform.TransformDirection( dir );
    85.  
    86.        
    87.         if ( isFreeTile( worldDirection ) )
    88.         {
    89.             position = worldDirection * gridSize + transform.position;
    90.         }
    91.     }
    92.  
    93.  
    94.     private bool isFreeTile( Vector3 worldDirection )
    95.     {
    96.  
    97.         RaycastHit hit;
    98.  
    99.         //Debug.DrawLine( transform.position, transform.position + worldDirection * gridSize, Color.red, 1f );
    100.  
    101.         if ( Physics.Raycast( transform.position, worldDirection, out hit, gridSize ) )
    102.         {
    103.             Debug.Log( "Bump " + hit.transform.name );
    104.             return false;
    105.         }
    106.         else
    107.             return true;
    108.     }
    109.  
    110.  
    111.     // Use this for initialization
    112.     void Start () {
    113.         position = transform.position;
    114.         rotation = transform.rotation;
    115.     }
    116.  
    117.     // Update is called once per frame
    118.     void Update()
    119.     {
    120.         transform.rotation = Quaternion.RotateTowards( transform.rotation, rotation, Time.deltaTime * 300f );
    121.         transform.position = Vector3.MoveTowards( transform.position, position, Time.deltaTime * animationSpeed );
    122.     }
    123. }
    124.  

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerInputMod : MonoBehaviour
    5. {
    6.  
    7.     PlayerMovement playerMovement;
    8.  
    9.     // Use this for initialization
    10.     void Start()
    11.     {
    12.         playerMovement = GetComponent<PlayerMovement>();
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.  
    19.         if ( Input.GetKeyDown( KeyCode.W ) )
    20.             playerMovement.Move( MoveDirections.Forward );
    21.         if ( Input.GetKeyDown( KeyCode.S ) )
    22.             playerMovement.Move( MoveDirections.Back );
    23.         if ( Input.GetKeyDown( KeyCode.A ) )
    24.             playerMovement.Move( MoveDirections.Left );
    25.         if ( Input.GetKeyDown( KeyCode.D ) )
    26.             playerMovement.Move( MoveDirections.Right );
    27.  
    28.         if ( Input.GetKeyDown( KeyCode.Q ) )
    29.             playerMovement.Turn( true );
    30.         if ( Input.GetKeyDown( KeyCode.E ) )
    31.             playerMovement.Turn( false );
    32.     }
    33.  
    34.     public void MoveForward()
    35.     {
    36.         playerMovement.Move( MoveDirections.Forward );
    37.     }
    38.     public void MoveBack()
    39.     {
    40.         playerMovement.Move( MoveDirections.Back );
    41.     }
    42.     public void MoveLeft()
    43.     {
    44.         playerMovement.Move( MoveDirections.Left );
    45.     }
    46.     public void MoveRight()
    47.     {
    48.         playerMovement.Move( MoveDirections.Right );
    49.     }
    50.     public void TurnRight()
    51.     {
    52.         playerMovement.Turn( false );
    53.     }
    54.     public void TurnLeft()
    55.     {
    56.         playerMovement.Turn( true );
    57.     }
    58. }
    59.  
     
    RogueSalamander likes this.
  13. The_Adventurer

    The_Adventurer

    Joined:
    Mar 10, 2015
    Posts:
    12
    Well, that certainly works exactly how I want it too. I really appreciate the work you've done to help me out. Now I need to go over it with a fine tooth comb to figure out what its doing different. Also figure out C# vs Javascript.

    Again, thanks a lot.
     
  14. Hoonius

    Hoonius

    Joined:
    Jul 18, 2013
    Posts:
    8
    No problemo. I needed the practice myself and I really was just doing that for my own project. I suggest go ahead and learn/switch to c# while your at it.