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
2
Question by $$anonymous$$ · Feb 18, 2013 at 09:54 PM · c#spritecoroutineswitch

8 Directional sprite in 3d world, how to retrieve angle?

I'm trying to do an 8 directional sprite in a 3d world like Doom. I managed to get it almost wworking, but my script is not very precise as ti try to retrieve absolute angles, and if the player move too fast sometime it skips part of the code, this is my actual script:

UPDATED With Professor Snake solution and Zeh suggestions:

 using UnityEngine;
 using System.Collections;
 
 public class LookDirection : MonoBehaviour {
 
     Transform player;
     public float angle;
     Vector3 direction;
     
     public Renderer spriteObj;
     
     public Material[] mat;
     
     void Awake () {player = GameObject.FindWithTag("Player").transform;}
     
     void Update () {
 
         direction = player.transform.position - transform.position;
         angle = Mathf.Atan2(direction.x,direction.z) * Mathf.Rad2Deg;
         ChangeDirection ();
 
     }
  
     void ChangeDirection () {
         if (angle < 0) angle += 360; // Just in case
         spriteObj.renderer.sharedMaterial = mat[(int)Mathf.Round(angle / 360f * mat.Length) % mat.Length];
     }
 }

Consider that the public Material variables are just for testing now to see if it changes properly.

So as you see in the coroutine I just send the angle as string with the first 2 digits only on the overload method of the function ChangeDirection. And the switch check when the angle reach a certain angle, but is not that precise and sometime as I saied before it skips the angle strings.

Any suggestion on a better approach to get a precise angle reference?

Screenshot of what I'm doing: Screenshot

cd_sprite.jpg (187.2 kB)
Comment
Add comment · Show 15
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 Professor Snake · Feb 18, 2013 at 10:11 PM 1
Share

Just a question, perhaps it is a misunderstanding on my end. You said that you are sending only the first two digits of the angle? Wouldn't that make an angle such as 145 appear as 14? Because if so, then it might be the source of your problem.

avatar image $$anonymous$$ · Feb 18, 2013 at 10:29 PM 0
Share

Whops, I feel dumb now, yeah you are right, but still the problem persist as with 3 digits now skips the 2 digits one. I guess I'm totally using the worst approach to this, but I'm out of ideas on that. I tried also parsing the angle float to a string, but couldn't get anything working.

avatar image Benproductions1 · Feb 18, 2013 at 10:56 PM 1
Share

Just as a tip, never write 1 liners with more than 1, short function call It's good practice to allways use {} :)

avatar image Professor Snake · Feb 19, 2013 at 12:18 AM 1
Share

I wonder why you are parsing it to a String. You could simply just use the floats themselves. I also think i know what your issue is. If the gameobject changes rotation too fast, the rotation variable may jump values from one frame to another. So, ins$$anonymous$$d of a simple case x, have a case (angle < y&& angle > x). (Which would only be viable if you are using the floats)

avatar image Professor Snake · Feb 19, 2013 at 12:31 AM 1
Share

Then try using a lot of "if" statements with the comparison method i proposed above. It might not look pretty but hey, whatever works.

Show more comments

2 Replies

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

Answer by Professor Snake · Feb 19, 2013 at 01:23 AM

Then what about a short yet clever algorithm? You could store the the different textures for the objects in an array, and then in every frame, you could use:

 spriteObj.renderer.sharedMaterial=array[(((int)angle+180)/45)];

Untested, but it should work, assuming the angles go from 0 to 360.

(if angle<45, int.Parse(((int)angle+180)/45) should equal 0, if it's between 45 and 90, int.Parse(angle/45) will equal 1 etc etc)

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
avatar image
1

Answer by zeh · Feb 19, 2013 at 10:45 PM

You're testing for the right angles but not for the ranges the player can be in. At the very least, you'd need a numerical comparison of ranges. So you should never try that kind of comparison as strings.

But similarly to what ProfessorSnake said, because this is a sequence (of angle ranges) that maps to another sequence (of materials), you should just need an array of your angles and then calculate accordingly.

 // Initialize the list of materials somewhere else
 Material[] materials = new Material[8] {F, FR, R, BR, B, BL, L, FL};

 // When you need to set the material depending on the angle
 if (angle < 0) angle += 360; // Just in case
 spriteObj.renderer.sharedMaterial = materials[Math.round(angle / 360f * array.Length) % array.Length];

The above code assumes 0" is front, and that rotation goes clockwise. If not, you'll have to adjust the order of the array accordingly.

Also, are you sure you need StartCoroutine and yield? Your code can be vastly simplified by removing that.

Comment
Add comment · Show 5 · 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 Professor Snake · Feb 19, 2013 at 11:04 PM 0
Share

If you take a closer look at the comments section of the question, you will see that the string method is not used anymore. The answer was a converted comment that only makes complete sense when read in context with the rest of the comments. Although i do agree about StartCoroutine and yield.

avatar image $$anonymous$$ · Feb 20, 2013 at 11:43 AM 0
Share

I've updated the question with Professor Snake solution. I'm using a coroutine for this as I have to know the angle always and I though would be less performance demanding to use a coroutine ins$$anonymous$$d of putting it on Update as I will need many of those sprites in a scene. The yield is there to prevent a crashing of Unity, I think it goes in loop and just freeze. So what would you suggest to use for getting the angle without a Coroutine?

Also posted a screenshot of what I'm doing, obiviously the Cyberdemon is there just for test.

avatar image zeh · Feb 20, 2013 at 02:26 PM 1
Share

Just update the angle once on Update(). That function will get called once per frame, so that's what you want to do to change the material. Your whole code can be simplified to a couple of lines without additional functions.

If you will need many of those sprites in a scene and you want to avoid calling the material changing code too many times (which is a good idea), you can cache the array index of the material you used last (the number inside array[] on Professor Snake's code) and only re-apply the material if the index changes. That'd be the best, nay, correct solution performance-wise.

I'm not sure why you have the infinite while() loop there. But you shouldn't need it in your code, since Update() is continuously called. Same with the StartCoroutine() and yield: in reality, there are very very few reasons why you need either of those in any realistic code.

avatar image $$anonymous$$ · Feb 20, 2013 at 04:28 PM 0
Share

Updated the code with your suggestion, so far without caching the index on over 50 sprites the fps are really stable, even better than before, so thank you zeh.

avatar image zeh · Feb 20, 2013 at 05:45 PM 0
Share

That's great to hear, thanks for the follow-up!

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

11 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

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

WaitForSeconds Not Working 4 Answers

Returning an IEnumerator as an int? 1 Answer

Getting dynamic indicies from multiple dropdown menus 0 Answers


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