Search Unity

Issue with Queue / Dequeue

Discussion in 'Scripting' started by RetroVertigo2019, Dec 30, 2021.

  1. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    Hey everyone
    Sorry for what I am sure is a basic question/issue but I am having a strange issue with my queue follow script.

    Here is my code:
    Code (CSharp):
    1.  
    2.             if (playerNum == globalControllerScript.PlayerNumber.one)
    3.             {
    4.                 if (inputMovement.x != 0 || inputMovement.y != 0)
    5.                 {
    6.                     if (globalController.followQueue.Count < followQueueCountMax)
    7.                     {
    8.                         Vector3 pos = transform.position;
    9.                         globalController.followQueue.Enqueue(pos);
    10.                         globalController.movementAnimQueue.Enqueue(currentAnimState);
    11.                         globalController.secondMovementAnimQueue.Enqueue(currentAnimState);
    12.                     }
    13.                 }
    14.             }
    15.        
    16.             //handle AI follow for movement
    17.             if (playerNum == globalControllerScript.PlayerNumber.two)
    18.             {
    19.                 if (globalController.followQueue.Count >= followQueueCountMax)
    20.                 {
    21.                     Vector3 aiInput = globalController.followQueue.Dequeue();
    22.                     transform.position = new Vector3(aiInput.x, aiInput.y, aiInput.z);
    23.                     animAIQueue = globalController.movementAnimQueue.Dequeue();
    24.                     ChangeAnimationState(animAIQueue);
    25.  
    26.                     if (globalController.secondFollowQueue.Count < followQueueCountMax)
    27.                     {
    28.                         Vector3 aiOtherInput = transform.position;
    29.                         globalController.secondFollowQueue.Enqueue(aiOtherInput);
    30.                     }
    31.                 }
    32.             }
    33.  
    My issue is that, when I initially load the game, it works fine. The AI player objects follow player one exactly, but when I run some other code/get in a battle, and then come back to this code for my players to move around and follow me, all the characters are in player one's exact spot, and don't follow behind anymore. I checked with a debug log and it appears that the queue is getting loaded with a ton of the same positions, like 8 in a row or so, before a new position updates.
    I looked around on this, and the only thing I can see is if there is an issue with multi threading / non thread safe queues, but that seems to be more of a network issue, and this is just for player objects to follow player one.
    Anyway, I hope I described my issue well enough, and I appreciate any input/assistance on this.

    Thanks
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Are you using threads or is this just random speculation? By default every scripting action in Unity is single-threaded, and by requirement EVERY interaction with the Unity API must be from the main thread or you will have very explicit errors from Unity complaining about it.

    Sounds like something didn't get reset. Start debugging to see if the codepaths taken upon reload are different.

    Regardless of what it turns out to be, you must find a way to get the information you need in order to reason about what the problem is.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is

    To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494
     
  3. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    Thanks for the reply / info.

    That is speculation on my part, so thanks for the info on Unity API.

    To clarify, as I didn't in my original post.

    I currently see no evidence that I have this script being run more than once, based on my objects in game, variables, and using debug log breaks to check.

    I did further debug.log and break, and I found something that might be the issue, and it isn't with the queue. It looks like my time.deltaTime is changing from .02 before a battle, to .001 after a battle. This is effecting the movement of my player object, in that it is taking longer to move across the X/Z axis and thus, I believe, loading in multiple of the same Vector3 location when the d-pad is pressed.
    So, I am not sure why this change is occurring in my game. I know my frame rate goes from 130-150 to 100 FPS before and after the battle respectively, but would that have such an impact on my deltaTime?
    Also, I do use a "slow down" mechanic for the battle, which changes the Time scale to 0 and then ramps back up to 1. I tried changing my code from deltaTime, to unscaleDeltaTime, but still, the unscaledDeltaTime also goes from .02 to .001.
    I might be down the wrong path here, but this is the only change I can see in my code from before to after the battle within my movement code.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Is it fully making it back up to 1? Print out time scale, find out.

    I question it because of this:

    If that's just one frame, eh, okay, super-low-load frame might complete at 1000fps, but if it is about the same as before and now is much faster, then ... something is funny.
     
  5. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    Delta time is your frame rate. Reduce delta time you have lower frame rate. Overload delta time you have lower* frame rates. If your delta time is below 0.1 you will have trouble detected inputs like mouse or key press. Check profiler where the load is precise frame, switch to hierarchy view when found navigate the high percentage, If you get lucky it’s just an editor thing. Else you get a decent clue of what to fix.
     
  6. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    Here is a post battle timeScale print with the unscaledDeltaTime also:

     
  7. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    Yah that is weird. Unless that’s what the value says it is in the project settings time. Your fps also doesn’t indicate you are under load.

    nice 3D retro theme btw. I made a duke nukem 3D like this once, I gave him the gravity glove from half life 3.
     
  8. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    I checked my profiler and before I go into a battle, I have over 120 FPS, no issues,





    and then after I go through a battle, my profiler is showing a Huge spike and my FPS tanks to 20 FPS when walking around. It is showing that the fixedUpdate in my mainPlayerController script is the cause, but I am not sure why this would cause an issue AFTER a battle.





    When my players go into a battle, it instantiates a few objects, and once the battle is over those objects are destroyed. The scene then has fewer objects in the scene than before, so I don't think that is the issue.
    It seems to me that it might be something linked to how many times FixedUpdate is being called, but what is the different in this from Before a battle, to After? That is what I am struggling with.
     
  9. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    When it’s happening look at remaining objects in hierarchy deactivate one by one to find the culprit
     
  10. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    So, I have looked into the profiler further, and I see and know what piece of code is having the issue, but my problem is this. The code works fine initially, and then after going into a battle, and coming back out, the same piece of code will cause a spike in my CPU and slows everything down.
    I can't figure out why this is happening. I have no new objects created after the battle (in fact, there are less objects than before).

    Here is the profiler before a battle:



    Here it is after a battle with the FixedUpdate taking 63.9%



    Anyone have any ideas on what else I could check in my game that would cause the fixedUpdate to spike so much? I have a state based system, so initial walking around is in the movement state, then the object goes into a battle, and once it is back out the object goes back into Movement state.

    I just don't understand how it would work with little to no impact on CPU initially, and then after going into a few different states, and the game instantiating enemy objects, and then those (Enemy) objects being destroyed, and the player object going back into the movement state, would it then spike my CPU.

    Here is the full code:

    Code (CSharp):
    1. void PlayerMovementFU()
    2.     {
    3.         if (playerControl == globalControllerScript.PlayerControl.player) //player controlled
    4.         {
    5.             //check for limitation / prevention from GCO based on camera bounds
    6.             if (CheckForPlayerMovementLimit)
    7.             {
    8.                 if ((inputMovement.x != 0 || inputMovement.y != 0))
    9.                 {
    10.                     Vector3 newPos = new Vector3(inputMovement.x, 0, inputMovement.y) * speed * Time.unscaledDeltaTime;
    11.                     newPos += this.gameObject.transform.position;
    12.                     if (globalControllerObj.GetComponent<globalControllerScript>().LimitPlayerMovementForCamera(newPos, this.gameObject))
    13.                         CantMove = true;
    14.                     else
    15.                         CantMove = false;
    16.                 }
    17.             }
    18.  
    19.             if (!CantMove)
    20.             {
    21.                 Vector3 movement = new Vector3(inputMovement.x, 0, inputMovement.y) * speed * Time.unscaledDeltaTime;
    22.                 //transform.Translate(movement);
    23.                 if (movement != Vector3.zero)
    24.                     cController.Move(movement);
    25.                 if(!onElevator)
    26.                 {
    27.                     if ((inputMovement.x != 0 || inputMovement.y != 0) && OnSlope())
    28.                         cController.Move(Vector3.down * cController.height / 2 * slopeForce * Time.unscaledDeltaTime);
    29.  
    30.                     if (cController.isGrounded == false)
    31.                         cController.Move(Vector3.down * cController.height / 2 * slopeForce * Time.unscaledDeltaTime);
    32.                 }
    33.             }
    34.  
    35.             //handle enqueue for AI
    36.             if (playerNum == globalControllerScript.PlayerNumber.one)
    37.             {
    38.                 if (inputMovement.x != 0 || inputMovement.y != 0)
    39.                 {
    40.                    // Debug.Log("TimeScale: " + Time.timeScale.ToString());
    41.                    // Debug.Log("DeltaTime: " + Time.unscaledDeltaTime.ToString());
    42.                     if (globalController.followQueue.Count < followQueueCountMax)
    43.                     {
    44.                         Vector3 pos = transform.position;
    45.                         globalController.followQueue.Enqueue(pos);
    46.                         globalController.movementAnimQueue.Enqueue(currentAnimState);
    47.                         globalController.secondMovementAnimQueue.Enqueue(currentAnimState);
    48.                        // Debug.Log("Position Enqueue: " + pos.ToString());
    49.                     }
    50.                 }
    51.             }
    52.  
    53.         }
    54.         else //AI control - handle queue follow
    55.         {
    56.             //handle AI follow for movement
    57.             if (playerNum == globalControllerScript.PlayerNumber.two)
    58.             {
    59.                 if (globalController.followQueue.Count >= followQueueCountMax)
    60.                 {
    61.                     Vector3 aiInput = globalController.followQueue.Dequeue();
    62.                     transform.position = new Vector3(aiInput.x, aiInput.y, aiInput.z);
    63.  
    64.                     animAIQueue = globalController.movementAnimQueue.Dequeue();
    65.                     ChangeAnimationState(animAIQueue);
    66.  
    67.                     if (globalController.secondFollowQueue.Count < followQueueCountMax)
    68.                     {
    69.                         Vector3 aiOtherInput = transform.position;
    70.                         globalController.secondFollowQueue.Enqueue(aiOtherInput);
    71.                     }
    72.                 }
    73.                 else
    74.                 {
    75.                     if (animAIQueue == PLAYER_FRONT_WALK || animAIQueue == PLAYER_FRONT_RUN)
    76.                         ChangeAnimationState(PLAYER_FRONT_IDLE);
    77.                     else if (animAIQueue == PLAYER_BACK_WALK || animAIQueue == PLAYER_BACK_RUN)
    78.                         ChangeAnimationState(PLAYER_BACK_IDLE);
    79.                     else if (animAIQueue == PLAYER_LEFT_WALK || animAIQueue == PLAYER_LEFT_RUN)
    80.                         ChangeAnimationState(PLAYER_LEFT_IDLE);
    81.                     else if (animAIQueue == PLAYER_RIGHT_WALK || animAIQueue == PLAYER_RIGHT_RUN)
    82.                         ChangeAnimationState(PLAYER_RIGHT_IDLE);
    83.                 }
    84.             }
    85.             else if (playerNum == globalControllerScript.PlayerNumber.three)
    86.             {
    87.                 if (globalController.players[1].GetComponent<mainPlayerController>().playerControl == globalControllerScript.PlayerControl.AI)
    88.                 {
    89.                     if (globalController.secondFollowQueue.Count >= followQueueCountMax)
    90.                     {
    91.                         Vector3 aiInput = globalController.secondFollowQueue.Dequeue();
    92.                         transform.position = new Vector3(aiInput.x, aiInput.y, aiInput.z);
    93.  
    94.                         secondAnimAIQueue = globalController.secondMovementAnimQueue.Dequeue();
    95.                         ChangeAnimationState(secondAnimAIQueue);
    96.                     }
    97.                     else
    98.                     {
    99.                         if (secondAnimAIQueue == PLAYER_FRONT_WALK || secondAnimAIQueue == PLAYER_FRONT_RUN)
    100.                             ChangeAnimationState(PLAYER_FRONT_IDLE);
    101.                         else if (secondAnimAIQueue == PLAYER_BACK_WALK || secondAnimAIQueue == PLAYER_BACK_RUN)
    102.                             ChangeAnimationState(PLAYER_BACK_IDLE);
    103.                         else if (secondAnimAIQueue == PLAYER_LEFT_WALK || secondAnimAIQueue == PLAYER_LEFT_RUN)
    104.                             ChangeAnimationState(PLAYER_LEFT_IDLE);
    105.                         else if (secondAnimAIQueue == PLAYER_RIGHT_WALK || secondAnimAIQueue == PLAYER_RIGHT_RUN)
    106.                             ChangeAnimationState(PLAYER_RIGHT_IDLE);
    107.                     }
    108.                 }
    109.                 else //player two is player controlled so have player three just follow player one
    110.                 {
    111.                     if (globalController.followQueue.Count >= followQueueCountMax)
    112.                     {
    113.                         Vector3 aiInput = globalController.followQueue.Dequeue();
    114.                         transform.position = new Vector3(aiInput.x, aiInput.y, aiInput.z);
    115.  
    116.                         animAIQueue = globalController.movementAnimQueue.Dequeue();
    117.                         ChangeAnimationState(animAIQueue);
    118.  
    119.                         if (globalController.secondFollowQueue.Count < followQueueCountMax)
    120.                         {
    121.                             Vector3 aiOtherInput = transform.position;
    122.                             globalController.secondFollowQueue.Enqueue(aiOtherInput);
    123.                         }
    124.                     }
    125.                     else
    126.                     {
    127.                         if (animAIQueue == PLAYER_FRONT_WALK || animAIQueue == PLAYER_FRONT_RUN)
    128.                             ChangeAnimationState(PLAYER_FRONT_IDLE);
    129.                         else if (animAIQueue == PLAYER_BACK_WALK || animAIQueue == PLAYER_BACK_RUN)
    130.                             ChangeAnimationState(PLAYER_BACK_IDLE);
    131.                         else if (animAIQueue == PLAYER_LEFT_WALK || animAIQueue == PLAYER_LEFT_RUN)
    132.                             ChangeAnimationState(PLAYER_LEFT_IDLE);
    133.                         else if (animAIQueue == PLAYER_RIGHT_WALK || animAIQueue == PLAYER_RIGHT_RUN)
    134.                             ChangeAnimationState(PLAYER_RIGHT_IDLE);
    135.                     }
    136.                 }
    137.             }
    138.         }
    139.     }
     

    Attached Files:

  11. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    bump, any input? I am still seeing this issue with other things. I can have code working before I go into a battle, and then once I leave a battle I am seeing things like the Update and FixedUpdate not running at the same time.
    I am assuming it is due to the fixed update running so often that it is slowing down to calculating everything within a frame, but I am not sure why this is happening. like I said, there are no additional objects being created and there are no duplicate player objects running the code either, so why would it increase so much?
     
  12. RetroVertigo2019

    RetroVertigo2019

    Joined:
    Dec 29, 2020
    Posts:
    30
    OK, I might have it figured out. In case anyone else runs into something like this. I used a Bracey's tutorial for slow down effect and they left out an important part for their code. Earlier I checked my timeScale value and it goes back to 1 for the slow motion effect, but the part I didn't see was that Time.fixedDeltaTime was changed on the initial start of the slow motion and they (Brackey's / Myself) failed to reset Time.fixedDeltaTime back to it's original setting.
    In summary, my slow motion code set timeScale to 0 and fixedDeltaTime to Time.timeScale * .02; Once the slow motion is completed and timeScale is set back to 1, I also needed to set fixedDeltaTime back to Time.timeScale * .02f. which fixes my problem and deltaTime no longer stays at .001.
     
    Kurt-Dekker likes this.