• Advertisement

C# Looking for help with rotating sprites

Recommended Posts

I am trying to rotate my car sprite just slightly to the left or right depending on input up to a small maximum. When I use this code, the rotation doesn't stop at the maximum i give it. When i try to reset the rotation back to its original state when not pressing any input, the car also jitters between a z axis rotation of 0 and 2.5. I don't understand why the rotation doesn't stop at the given maximums, nor do I understand why its jittering. Can anybody provide me some insight?

        float movementHorizontal = 0f;
        float movementVertical = 0f;

        if (Input.GetKey(KeyCode.A) && Input.GetKey(KeyCode.D))
        {
        }
        else if (Input.GetKey(KeyCode.A))
        {
            movementHorizontal = -1;

            if (transform.rotation.z < 10f)
            {
                transform.Rotate(zAxis, 2.5f);
            }            
        }
        else if (Input.GetKey(KeyCode.D))
        {
            movementHorizontal = 1;

            if (transform.rotation.z > -10f)
            {
                transform.Rotate(zAxis, -2.5f);
            }
            
        }
        else
        {
            if(transform.rotation.z > 0)
            {
                transform.Rotate(zAxis, -2.5f);
                //transform.rotation.Set(0, 0, 0, 0);
            }
            else if (transform.rotation.z < 0)
            {
                transform.Rotate(zAxis, 2.5f);
                //transform.rotation.Set(0, 0, 0, 0);
            }
            
        }

Share this post


Link to post
Share on other sites
Advertisement

Floating point numbers have a finite precision. In your last else branch you check for less than 0 and greater than 0, and doing nothing if equal to zero. However, the probability that the value is exactly 0 after some computation like rotation is very low; it is much more likely that values like 0.0000000123 will result. This is often the reason for stability problems like you observe.

One approach to overcome that problem is to weaken the comparison by considering a small tolerance value, i.e. check not for equal to 0 but very close to 0, like so:

if(transform.rotation.z > 0.01)
...
else if(transform.rotation.z < -0.01)
...
else
...

Finding an appropriate tolerance is a problem though, because it depends on the circumstances. In your case we're speaking of an orientation angle in degrees (presumably), so 0.01 is probably already a small enough value.

Another thing is that restricting values (to a maximum in your case) is sometimes better be done on the result, i.e. after the computation. This is a way to avoid overshooting.

Share this post


Link to post
Share on other sites

Wow, thanks to you both! I looked closer and my rotation was indeed not quite 0. The Mathf.Approximately was unknown to me. Thanks for pointing it out, I will give it a try. If it doesn't work out, I will try a manual check. Thanks again, fellas!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By Felis Nigripes
      I'm doing a test quest.
      The player gets a quest from an NPC to bring him fish.

      Once the player picks up the fish, the original NPC gets replaced by a new one with a new conversation trigger. The NPC tells the Player "Well done" and should give 200xp.

      The script tells the xp counter to go up by making a reference to the gameobject that holds the text component
       
      But it throws this error:
       

       
      I'm aware that the error may hide in plain sight. I just have to sort this out, since I'm writing the AI at the same time, and the time it takes to resolve everyone of these errors is tremendous.
      Plus, I think I'll learn something. I've been having trouble with some basic functionalities recently. There might be something wrong with my understanding on how programming works.
       
      Glad if someone could help (:
       
       
       
      Edit: I'm fully aware that the update function requires an input. I call the function in the editor when the dialogue ends, it still doesn't work.
       
    • By Vu Chi Thien
      Hi fellow game devs,
      With the help of  @CombatWombat in my previous post about clutch modeling, I now have a solid direction for the modeling the clutch. The way I'm doing it is having 2 clutch states: locked and unlocked. EngineRPM and torque will be calculated separately in each state. My problem right now is the logic and code for specifying locking and unlocking.
      The condition for locking is when (engineSpeed - drivetrainSpeed) in previous update cross zero (different sign) with the current update (to determine if engineSpeed = drivetrainSpeed or not in-between updates) and engineTorque <= clutchTorque.
      The condition for unlocking is when engineTorque > clutchTorque.
      The diagram looks roughly like this (taken from matlab website with the similar implementation):

       
      However, the 2 conditions are triggers for switching states, not for determine the current state to be in, so in the end my clutch state just jumped around. I don't have a lot of experience in doing state machine, so can some one give me rough code of how to implement this? Below is my rough code:
      speedError = engineSpeed - drivetrainSpeed; if ((Math.Sign(speedError) != Math.Sign(deltaW) && currentTotalEngineTorque <= clutchReactTorque)) { clutchLocked = true; } else clutchLocked = false; deltaW = speedError; //end of update I think the main struggle is the cross zero. Because cross zero is the "trigger condition" to check if the clutch should lock when it is slipping, not the condition for continuous locking, while the code I have above is the "continuous condition" saying "this condition is true then it is locked/unlocked". Another word, if the clutch is slipping, the condition above would decide if it's locked or not, but once it is locked, the cross zero condition is not true anymore (since speedError and deltaW have same sign as engineSpeed == drivetrainSpeed when clutch is locked). I'm sorry that I cannot explain this better as English is not my first language.
    • By nxrighthere

      BenchmarkNet is a console application for testing the reliable UDP networking solutions.
      Features:
      Asynchronous simulation of a large number of clients Stable under high loads Simple and flexible simulation setup Detailed session information Supported networking libraries:
      ENet (C# Wrapper) UNet LiteNetLib Lidgren MiniUDP Hazel Photon Neutrino DarkRift More information and source code on GitHub.
      You can find the latest benchmark results on the wiki page.
    • By Timothy Sharp
      I need help on a script. I am recreating a scene from A Hat In Time where Hat Girl goes into Queen Vanessa's manor. She has to collect keys and avoid Queen Vanessa. How would I script the door where you can open it and peek through it without actually going out the door? Any help is appreciated. Thanks!

      EDIT: Not peeking throught the keyhole, just poke your head out the door
    • By 3dmodelerguy
      So I am building a survival / roguelike? (not sure of the "real" definition of that but the game has perma-death, randomly / procedurally generated worlds, etc.) and I am starting to prototype item decay. Let me example how the turn based system is currently simulated as that is probably important for this discussion.
      The way the turn based simulation works is there is a singleton GameActionManager object that keeps track of the action units that have pasted since the being of the game. 1 action unit = 1 second in the game and generally this is progressed from the the player performing an action. When the player does anything that has an action unit cost associated with it, it calls a method on the GameActionManager to increase the current action units. The other things the GameActionManager exposes are methods to register / unregister "event listeners" (currently using delegates). When the GameActionManager increases the action units, it notifies all of these listeners so the can perform the right action (like a burning tile decreasing the health of the structure that is burning, an enemy can move toward or attack something, etc.).
      I am also only simulating a small portion of the world at a given time since well, the world eventually will be huge and well computers can only do so much. My current goal for the simulated area is 120 x 80 tiles (with is a total of 9600 tiles). So as the player moves, game entities (enemies, structures, items, etc.) come in and out of the simulation area (and register / unregister with the GameActionManager). With this size in mind, none of the things that currently attach listeners to the GameActionManager has the chance of getting big enough to have me think that I really need to think about an alternative solution for when it becomes an issue because I don't see it becoming an issue any time soon (at least at the current stage of development). Items however is a different story.
      The game is going to have a ton of different items and 1 or more items can be on any tile. If each tile averaged 2.5 items (which I will grant you seem ridiculous but I always think crazy extremes when it comes to this kind of thing), that would be close for 25000 items that would possible have to manage decay. So instead of having each item attach a "listener", since the action for managing decay is going to be exactly the same thing for each item (just a method call), I figured having 1 listener that knows about all the items would be better.
      The general approach that I am taking for this first prototype is to have a singleton manager class (lets call it ItemDecayManager). Any time a item that has decay come into the simulated area, it would register itself with the manager and when it leaves the simulated area, it would unregister itself (which would just add and remove itself from a private List the manager is maintaining). Any time the action units are increased, the ItemDecayManager's listener on the would fire and just loop through the List of registered item and just perform the required function call.
      I have done some crude benchmarking and it currently can handle 100000 items at which point it starts to have a little effect on the FPS (but still around 80) even when moving about 15 times per second (and each move causes an action unit increase). Also bear in mind these numbers of from running the game in the Unity editor which has a bit of extra overhead that running the real game build not not have.
      While I am going to run with this solution for now I want to throw out this idea and get any kind of feedback i can because I imagine when more is happen as the action units increase (and even imagining the process for managing decay become more even just slight more complex than the current simple calculation), this solution might not hold up and I would like to have so ideas ready for the situations. I also think of anything that is going to be simulation, this is going to be the first things to have issues  from the shear number of items that could be in the simulation area.
      Thanks in advance for any and all comments.
       
  • Advertisement