Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 /
  • Help Room /
avatar image
0
Question by Yog555 · Sep 20, 2017 at 06:23 PM · functionsrecursion

If I call a function from within itself, will it return to its original place when the recursive call is finished?

I have a turn based game system where after calling the NextTurn function, the current unit is deactivated and the next unit in the initiative order is made active. If there are no more units in the turn order list, StartTurn is called and a new round begun.

I've added a timed buff system, and the current spell effects on a unit should tick at the start of the units action, in case damage over time effects etc kill it before it has a chance to act. However this leaves my current function broken when killed by a spell effect and then referenced by the remaining part of the function where it should be taking its action.

I want to include a sanity check to make sure the unit is still active, and if not advance to the next unit in the turn order but I'm not sure where it should go. If I tick spell effects, then test if the active unit is null and then call NextTurn again if so, is this like calling a break on my current iteration through the function, or will it return to the exact same spot after executing and the problem is still there? I thought about encapsulating all the unit selection part in a while selectedUnit != null loop, but not quite sure how to structure this with the else condition that calls StartTurn at the end of the initiative list, since if there's no other valid unit in the turn order that loop will continue forever? Any idea how i should structure this? Thank you!

edit: I'm also removing the unit from the initiative liston its Death() function but it might be more sensible to just not remove it there, allow that index to be null and rebuild it at the top of the turn? Since if it's triggering death off a spell effect and removing itself from the list this seems like it might screw with the indices

     public void StartTurn(){
         //reset the target highlights
         foreach (GameObject tile in map.tileArray)
             tile.GetComponent<SpriteRenderer> ().color = Color.white;
         
         //reset initiative order and advance round counter
         currentInitIndex = 0;
         roundCounter += 1;
 
         //reset hero's ability to cast
         playerHero.hasCast = false;
         playerHero.GetComponent<SpriteRenderer> ().color = Color.white;
 
         map.GetComponent<CombatLog> ().NewMessage ("ROUND " + roundCounter +" BEGINS");
         map.selectedUnit = map.initiativeOrder [currentInitIndex];
         map.selectedUnit.GetComponent<Unit> ().isActive = true;
 
         foreach (TimedBuff buff in map.selectedUnit.GetComponent<Unit>().currentBuffs.ToArray()) {
             buff.Tick (1);
         }
 
         if (map.selectedUnit.GetComponent<Enemy> ()) {
             map.selectedUnit.GetComponent<Enemy> ().TakeTurn ();
         }
     }
 
     public void NextTurn(){
         //reset the target highlights
         foreach (GameObject tile in map.tileArray)
             tile.GetComponent<SpriteRenderer> ().color = Color.white;
 
         //null path and reset movement points
         map.selectedUnit.GetComponent<Unit> ().currentPath = null;
         map.selectedUnit.GetComponent<Unit> ().remainingMovement = map.selectedUnit.GetComponent<Unit> ().moveSpeed;
 
         //remove any expired buffs from the current unit before advancing turn, this is separate from the tick logic which should apply at start of turn
 
         foreach (TimedBuff buff in map.selectedUnit.GetComponent<Unit>().currentBuffs.ToArray()) {
     
             if (buff.IsFinished) {
                 map.selectedUnit.GetComponent<Unit> ().currentBuffs.Remove (buff);
             }
         }
             
 
         //advance the next unit in the initiative order array as the active unit and deactive the previous unit
         if (currentInitIndex < map.initiativeOrder.Count-1) {
             map.selectedUnit.GetComponent<Unit> ().isActive = false;
             currentInitIndex += 1;
             map.selectedUnit = map.initiativeOrder [currentInitIndex];
             map.selectedUnit.GetComponent<Unit> ().isActive = true;
 
             //advance all times buffs by one tick, we want to advance after selecting the new unit but before it acts, in case it is killed by a spell effect
             foreach (TimedBuff buff in map.selectedUnit.GetComponent<Unit>().currentBuffs.ToArray()) {
                 //all buffs currently decrement by one tick per turn
                 buff.Tick (1);
 
             }
             //TODO sanity check in case a fatal debuff has killed the unit before taking its turn
 
             
             //if the next unit to act is an enemy, take its turn
             if (map.selectedUnit.GetComponent<Enemy> ()) {
                 map.selectedUnit.GetComponent<Enemy> ().TakeTurn ();
             }
 
         } else {
             //we have reached the end of the initiative order list, begin a new combat round
             map.selectedUnit.GetComponent<Unit>().isActive = false;
             map.selectedUnit = null;
             StartTurn();
         }
 
     }

Comment
Add comment
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

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by TheSOULDev · Sep 20, 2017 at 08:33 PM

Tl;dr - yes, recusions work perfectly fine in C#, without recursions the language would obviously be Turing incomplete and then it would never come into use, let alone be a language for Unity.

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
0

Answer by Yog555 · Sep 21, 2017 at 02:35 AM

Thanks TheSOULDev (tried to submit this as a comment on your reply but it doesnt seem to work)

I thought that was the case so I guess just recurring the function before doing the action doesn't quite work since it will eventually return and either execute a double action or act on a null object.. could I encapsulate it like this example below? I'd also have to null-check the lines at the top of NextTurn and StartTurn since I can no longer guarantee a valid unit exists at that point to be acted on but this check seems like it should work - at the point it is recurring NextTurn if needed, there is no further code to execute in the root function call.

The if statement checking the next index in preparation to recur it might need to be tweaked - if I'm calling List.Remove on that object as part of its death, do all the indices after it in the list get decremented by one? If so I should be checking the same index.. but then when I recur the function it's going to then increment the counter and shoot past a valid index. In that case should I just destroy the object but not remove it from the list, iterate through the indices recursively as normal and then remove all nulls from the list as part of my start turn cleanup procedure?

       //*select units and tick through buffs*
     
                    if(map.selectedUnit != null){
         
                         //if the next unit to act is an enemy, take its turn (otherwise done, wait for player input)
                         if (map.selectedUnit.GetComponent<Enemy> ()) {
                              map.selectedUnit.GetComponent<Enemy> ().TakeTurn ();
                           }
                 } else{
         
                 //selected unit is null, so it has died from a spell effect before acting
                 //check if there is another unit in the turn order list, if so recur NextTurn otherwise call the next round
                 
         
                    if(currentInitIndex+1 < map.initiativeOrder.Count-1){
                     NextTurn();
                    }else{
                     StartTurn();
                     }
         
                 }
 
Comment
Add comment · Show 1 · 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 Arocide · Sep 22, 2017 at 03:46 AM 0
Share

You need to think of how the scripts run as a stack (and that's actually what it's referred to you may want to research the 'stack' a little bit to become more familiar with how things in C# is interpreted, just don't go too far down the rabbit hole yet cause the stack is a very complex thing, but a general overview would help you). Essentially with a stack you can only ever take the top most object in the case of .NET/$$anonymous$$ONO this means execution of previous functions are paused until the topmost function has been returned, in a general sense. So Calling a function will place it at the top of the stack (of the thread, which adds more complexity to the topic so don't worry about threads just yet) and the previous function is paused until this new function has returned, so on and so forth.

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

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

Related Questions

Get all combinations of a list of lists of arrays... 2 Answers

Random.Range throws StackOverFlow exception in recursion 1 Answer

How do I get all of my code in start function 1 Answer

When player enters area. Object that script is attached to walks toward the entering object(player). 1 Answer

Calling a function in a prefab from a function of another GameObject in C#,Calling a function in a prefab from a function in another GameObject in C# 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