Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Cherno · Aug 24, 2013 at 05:19 PM · rpgisometricturning

Isometric tile-based RPG: Restricting turns to 45 degrees?

I'm creating an isometric RPG-style game, and the world is tile-based (so one character per tile, etc.). Think Jagged Alliance 2, X-Com or whatever.

As common with these games, characters can only look in one of 8 viewing directions (fwd, back, left, right, and the diagionals).

When I click my mouse button somewhere on the terrain around the character, he should turn towards it smoothly (not instantly) but only until he reaches a rotation that is the nearest 45 degree angle (for 8 possible rotations) for the point I clicked at.

I have trouble working with Quaternions so I took the cumbersome approach: Have 8 seperate colliding planes around the character in an octagonal fashion, and then cast a ray out from the chracter towards the point I clicked. Depending on the plane that was hit by the ray, the Vector3 coordinates of the final point that the character should rotate towards (one of the eight tiles around him) are assigned.

The system only works kind of, though. When first ordered to turn, the Vector3 isn't updated, only if I click again, and the same hold true after reaching a new waypoint. (-> "Look rotation viewing vector is zero" error)

The question is, how can I make the turning mechanic more simple?

 var MouseCoords : Vector3;
 var LookTarget : Vector3;
 var TurnSpeed : float = 3.0;
 var IsTurning : boolean;
 
 function Update()
 {
      if (Physics.Raycast (ray, hit, Mathf.Infinity, TerrainMask))
      {
           MouseCoords = Vector3( Mathf.RoundToInt(hit.point.x),  Mathf.RoundToInt(hit.point.y),  Mathf.RoundToInt(hit.point.z));
      }
 
 
      if(Input.GetButtonDown("Fire1"))
      {
           CheckRotation();
           TurnTowards(LookTarget);
      }
 }
 
 function CheckRotation()
 {
     var RotationTargetX : float = transform.position.x;
     var RotationTargetZ : float = transform.position.z;
     
     var LocalOffset : Vector3 = transform.position + transform.up * 0.5;
     var TurnTarget : Vector3 = Vector3(MouseCoords.x, transform.position.y, MouseCoords.z);
     var hit : RaycastHit;
     
     if(Physics.Raycast (transform.position, TurnTarget - transform.position, hit, Mathf.Infinity, RotationMask))
     {
         if (hit.collider.gameObject.CompareTag("RotationMeshN"))
         {
             RotationTargetZ += 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshNE"))
         {
             RotationTargetX += 1.0;
             RotationTargetZ += 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshE"))
         {
             RotationTargetX += 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshSE"))
         {
             RotationTargetX += 1.0;
             RotationTargetZ -= 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshS"))
         {
             RotationTargetZ -= 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshSW"))
         {
             RotationTargetX -= 1.0;
             RotationTargetZ -= 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshW"))
         {
             RotationTargetX -= 1.0;
         }
         if (hit.collider.gameObject.CompareTag("RotationMeshNW"))
         {
             RotationTargetX -= 1.0;
             RotationTargetZ += 1.0;
         }
     }
 
     LookTarget = Vector3(RotationTargetX, transform.position.y, RotationTargetZ);
     TurnTowards(LookTarget);
 }
 
 function TurnTowards(LookAtTarget : Vector3)
 {
      if(IsTurning == false)
      {
           var dir : Vector3 = (LookAtTarget - transform.position).normalized;
       var NewRotation = Quaternion.LookRotation(dir);    
  
       for (u = 0.0; u <= 1.0; u += (TurnSpeed * Time.deltaTime)) 
       {
            IsTurning = true;
            //transform.LookAt(LookAtTarget); // for instant turns
             
            if(LookAtTarget != transform.position)
            {
                     transform.rotation = Quaternion.Slerp( transform.rotation, Quaternion.LookRotation(LookAtTarget - transform.position), TurnSpeed);
               } 
             yield;
       }
         
       IsTurning = false;
      }
 }
 
Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image getyour411 · Aug 25, 2013 at 01:34 AM 0
Share

See if this helps

http://forum.unity3d.com/threads/53407-Euler-Quaternions-Radians-Degrees-huh

I think Eulers match your design and you should not have to worry about the complications of pitch/yawl in this simplified turning scenario.

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by robertbu · Aug 25, 2013 at 04:52 AM

I had a hard time sorting out your code, so I'm going to give you some example code instead:

 #pragma strict 
 
 var speed = 90.0;
 private var qTo : Quaternion;
 
 function Update() {
      if(Input.GetButtonDown("Fire1")) {
           NewTurn();
      }
      transform.rotation = Quaternion.RotateTowards(transform.rotation, qTo, speed * Time.deltaTime);
 }
  
 function NewTurn () {
     var hit : RaycastHit;
     var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 
     if(Physics.Raycast (ray, hit)) {
         var aimingDirection = hit.point - transform.position;
         var angle = -Mathf.Atan2(aimingDirection.z, aimingDirection.x) * Mathf.Rad2Deg + 90.0;
         angle = Mathf.Round(angle / 45.0f) * 45.0f;
         qTo = Quaternion.AngleAxis(angle, Vector3.up);
     }
 }

If you want a more eased movement to the turn, replace Quaternion.RotateTowards() with Quaternion.Slerp() and adjust the speed way down.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Cherno · Aug 26, 2013 at 12:31 AM 0
Share

No, this doesn't work :( I tried playing around with the values but the operations are hard to grasp for me as well :(

avatar image robertbu · Aug 26, 2013 at 01:08 AM 0
Share

Before you write-off the code above, do the following:

  • Create a new scene

  • Add a plane and resize to something large

  • Add a Cube sitting on the plane

  • Add the above script to the cube

  • Adjust the camera for a more downward view

  • Run and click on the plane

I tested this code before I posted it, so it should work in the above configuration. I don't know if or how your configuration differs from this one. But start by verifying the code works in this simple case.

The way this code works is on line 19, we use Atan2 to get the angle between the 'character' and the point hit on the plane. Line 20, rounds that angle to the nearest 45 degrees. Line 21 then rotates the character to that angle.

avatar image Cherno · Aug 26, 2013 at 01:42 AM 0
Share

Thank you, it works, I made a c&p error.

I tried modifiying it so the actual transformation doesn't happen in the Update phase, I fear that this causes unneccessary CPU overhead when basically all characters rotate every frame (even ifthe angle is zero)? However, I didn't manage to get it to turn smoothly with either slerp or rotatetowards, all it ever does is turn instantly (the basic boolean/t += time.deltaTime system works in my old turning script)

     #pragma strict
      
     var speed = 90.0;
     private var qTo : Quaternion;
     var IsTurning : boolean;
      
     function Update() {
     if(Input.GetButtonDown("Fire1")) {
     NewTurn();
     }
     
     }
      
 function NewTurn () 
 {
     if(IsTurning == false)
     {
         var hit : RaycastHit;
         var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
          
         if(Physics.Raycast (ray, hit)) 
         {
             var ai$$anonymous$$gDirection = hit.point - transform.position;
             var angle = -$$anonymous$$athf.Atan2(ai$$anonymous$$gDirection.z, ai$$anonymous$$gDirection.x) * $$anonymous$$athf.Rad2Deg + 90.0;
             angle = $$anonymous$$athf.Round(angle / 45.0f) * 45.0f;
             qTo = Quaternion.AngleAxis(angle, Vector3.up);
             var t : float;
             for (t = 0.0; t <= 1.0; t +=  Time.deltaTime) 
             {
                 IsTurning = true;
                 transform.rotation = Quaternion.Lerp(transform.rotation, qTo, speed);
                 yield;
             }
             IsTurning = false;
         }
     }
 }
avatar image Cherno · Aug 31, 2013 at 04:27 PM 0
Share

Got it working finally, thanks again. Your method works flawlessly° I put in another way of doing it below in a seperate answer.

avatar image
0

Answer by Cherno · Aug 31, 2013 at 04:26 PM

I finally managed to get it to work, seems like I made another mistake and for some reason typed in "Lerp" instead of "Slerp" ^_^

Here is the working code that has everything but the initial mouseclick and function call in a seperate function outside Update():

     var speed = 90.0;
     private var qTo : Quaternion;
     var IsTurning : boolean;
     var t : float;
      
 function Update() 
 {
     if(Input.GetButtonDown("Fire1")) 
     {
         NewTurn();
     }
 
 }
      
 function NewTurn () 
 {
     if(IsTurning == false)
     {
         var hit : RaycastHit;
         var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
          
         if(Physics.Raycast (ray, hit)) 
         {
             var aimingDirection = hit.point - transform.position;
             var angle = -Mathf.Atan2(aimingDirection.z, aimingDirection.x) * Mathf.Rad2Deg + 90.0;
             angle = Mathf.Round(angle / 45.0f) * 45.0f;
             qTo = Quaternion.AngleAxis(angle, Vector3.up);
             print(qTo);
             for (t = 0.0; t <= 1.0; t += Time.deltaTime * speed) 
             {
                 IsTurning = true;
                 transform.rotation = Quaternion.Slerp(transform.rotation, qTo, t);
                 yield;
             }
             IsTurning = false;
         }
     }
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

16 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Tile-Based 2D Isometric RPG. Building a map? 3 Answers

3D Isometric Grid Based System, a feast of questions; 1 Answer

2d Isometric game? 1 Answer

Isometric 2.5D RPG: Advice 7 Answers

Isometric movement in Unity3D... 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges