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
7
Question by Persona · Oct 22, 2010 at 02:11 AM · turn-based

Turn Based Battle System

I've been trying to set up a battle system using Unity but I've hit a bit of a snag: Player Turn script

static var Playerturn: boolean = true;

function Awake(){

Select();

}

function Select(){ print("Make your move!!"); yield WaitForSeconds(2); Battle_Menu.choice = true; print("Battle Phase Begins!!"); yield WaitForSeconds(2); //BattlePhase(); }

static function BattlePhase(){ //RPGPlayer.OnAttack(); RPGEnemy.OnDamage(); yield WaitForSeconds(2); print("Battle Phase Ends!!"); TurnEnd(); }

static function TurnEnd(){ print("Turn end!"); if(Playerturn == true){ Playerturn = false; Enemy_Turn.Select(); } if(Playerturn == false){ Playerturn = true; } }

function GameOver(){ //Play audio oneshot //Destroy player //WaitforSeconds(); //Load level GameOver }

function Victory(){ //Play audio oneshot //Destroy enemy //WaitforSeconds(); //Load level Victory }

Menu Script:

static var choice: boolean = false;

function OnGUI () { if (choice == true){ // Make a background box GUI.Box (Rect (10,10,100,90), "Battle Menu");

 // Make the first button. If it is pressed, Application.Loadlevel (1) will be executed
 if (GUI.Button (Rect (20,40,80,20), "Attack")) {
     //Application.LoadLevel (1);
     RPGPlayer.OnAttack();
     print("The Player Attacks!!");
     Run();
     choice = false;
     }

 // Make the second button.
 if (GUI.Button (Rect (20,70,80,20), "Defend")) {
     //Application.LoadLevel (2);
     RPGPlayer.OnDefense();
     print("The Player blocked!!");
     Run();
     choice = false;
     }
 }
 if (choice == false){
 return;

 }

}

function Run(){ Player_Turn.BattlePhase();

}

Basically, I tried to run it to where the player turns begins and displays an attack or defend button using OnGUI and it sends makes the Player Turn function Battle phase run. However, the code stops progressing once the player chooses attack or defend and it stays put.

Does anyone have a solution?

Edit: Thanks to all the gave an answer. This will greatly benefit the Unity community!

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

6 Replies

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

Answer by Statement · Dec 06, 2010 at 11:51 PM

This is a sort of rewrite entirely.

Mainly because I got confused reading the original code, I am not accustomed to JS but the bounty made me want to have a stab at it.

The heart of it is the Start function, which allows each player ("human" and "enemy") to take turns. There is no actual damage implementation, and no real "players" at all, just a string representation. You'd want to plug in your actual objects in the code. This is probably more of a scaffolding. If you set battle = false, the current round ends (a round is a turn each).

var action : String; var player : String; var battle = true; var displayGui = false;

function Start () { while (battle) { yield PlayerChoice(); yield BattlePhase(); yield TurnEnd();

     yield EnemyChoice();
     yield BattlePhase();
     yield TurnEnd();
 }

}

function PlayerChoice() { print("human makes a decision"); player = "human"; displayGui = true;

 while (displayGui)
     yield;        

}

function BattlePhase() { print("battle rages on"); yield new WaitForSeconds(1); print(player + " " + action); yield new WaitForSeconds(1); }

function EnemyChoice() { print("enemy makes a decision"); yield new WaitForSeconds(1); player = "enemy"; action = "attacks"; }

function TurnEnd() { print("turn ends"); yield new WaitForSeconds(1); }

function OnGUI() { if (!displayGui) return;

 GUI.Box (Rect (10,10,100,90), "Battle Menu");

 if (GUI.Button (Rect (20,40,80,20), "Attack"))
 {
     action = "attacks";
     displayGui = false;
 } 

 if (GUI.Button (Rect (20,70,80,20), "Defend"))
 {
     action = "defends";
     displayGui = false;
 }

}

Comment
Add comment · Show 2 · 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 Persona · Dec 09, 2010 at 07:58 PM 1
Share

Nice answer. This one is done in Javascript so I can understand it better. It's easily understandable too, so I can grasp it mostly.

avatar image aviose · Apr 17, 2012 at 03:53 PM 2
Share

I have been looking for the answer to how to make a turn based system in Unity for a couple weeks... This topic was VERY useful to me, and helped me with some school work drastically.

avatar image
11

Answer by Peter G · Dec 07, 2010 at 12:28 AM

I would use a more state based driven code with events to set up your turn based system, now you seem to be trying to do that, but you are waiting an arbitrary length (2 seconds) before you move onto the next screen. Here's an example of how to have one turn trigger the next. It has 2 built-in events. Each one fires when its respective turn ends. It's written in C# because js has a strange if existent ways of doing events and I don't like how it writes Coroutines (C# is more explicit in the latter).

What you still have to add is the instruction for finding an object, and responding to the events. I haven't fully tested this code either. It might be missing a yield or 2.

So here it is full of comments.

using UnityEngine; using System.Collections;

public delegate void TurnEnded(TurnInfo tI);

public class StateManager : MonoBehaviour {

 public event TurnEnded enemyTurnEnded;
 public event TurnEnded playerTurnEnded;


 // Use this for initialization
 void Start () {
     StartCoroutine(UpdateState());
     //Immediately start our loop
 }

 // Update is called once per frame
 IEnumerator UpdateState () {
     for(;;) {
     //This is short hand for infinity loop.  Same as while(true).   

         yield return StartCoroutine(PlayerTurn());
         //Start our player loop, and wait for it to finish
         //Before we continue.

         yield return StartCoroutine(EnemyTurn());
         //Do enemy loop, finish, restart loop

     }
 }

 IEnumerator PlayerTurn() {

     Transform target = null;
     //This could be placed in a higher scope for memory purposes.

     bool objectSelected = false;
     //have we selected an object.

     TurnInfo tI = new TurnInfo();
     //create a new turn info tracker.

     yield return StartCoroutine(SelectObject(target));
     //Wait until we find a target before continuing.

     if(target != null) 
         yield return StartCoroutine(Attack(target));
     //Wait until we find a target before continuing.


     Debug.Log("Attacked");

     if(playerTurnEnded != null) 
         playerTurnEnded(tI);

 }

 IEnumerator EnemyTurn() {

     Transform target = null;
     //This could be placed in a higher scope for memory purposes.

     bool objectSelected = false;
     //have we selected an object.

     TurnInfo tI = new TurnInfo();
     //create a new turn info tracker.

     yield return StartCoroutine(SelectObject(target));
     //Wait until we find a target before continuing.

     if(target != null) 
         yield return StartCoroutine(Attack(target));
     //Wait until we find a target before continuing.


     Debug.Log("Attacked1");

     if(enemyTurnEnded != null) 
         playerTurnEnded(tI);

 }

 IEnumerator SelectObject (Transform target) {
     bool objectSelected = false;

     while (!objectSelected) {
         target = SomeMethodForFindingATarget();
         if(target != null) {
             objectSelected = true;
             Debug.Log("object selected");
         }

         yield return null;
     }
 }

 Transform SomeMethodForFindingATarget() {
         return null;
                     //return a transform
 }

 IEnumerator Attack (Transform target) {
     bool attacked = false;

     while(!attacked) {

         //Attack the targeted object.
         target.SendMessage("Attacked", SendMessageOptions.DontRequireReceiver);

         //the last value should always be true.
         //If the attack was successful and the turn will end.
         attacked = true;

         yield return null;
     }   

 }






}

public struct TurnInfo { //custom Turn info struct.
//Feel free add or remove any fields.

 private float m_DamageDone;
 private string m_MoveUsed;
 private float m_HealthLeft;             
 private bool m_TurnOver;

 public float DamageDone
 {
     get {
         return m_DamageDone;
     }

     set {
         m_DamageDone = value;
     }
 }
 //How much damage did we do.

 public string MoveUsed
 {
     get {
         return m_MoveUsed;
     }

     set {
         m_MoveUsed = value;
     }
 }
 //What move did we use.

 public float HealthLeft
 {
     get {
         return m_HealthLeft;
     }

     set {
         m_HealthLeft = value;
     }
 }
 //How much health do we have left.

 public bool TurnOver
 {
     get {
         return m_TurnOver;
         //read only
     }
 }
 //Should the turn end?

 //Constructor.
 public TurnInfo(float damage, string moveUsed, float healthLeft, bool turnOver) {   
     m_DamageDone = damage;
     m_MoveUsed = moveUsed;
     m_HealthLeft = healthLeft;
     m_TurnOver = turnOver;
 }

}

I revised my code to be more state driven. Should work generally better now. You can find the old version in the edited page if you need it though.

C# Events

Delegates

Properties

Comment
Add comment · Show 7 · 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 Proclyon · Dec 08, 2010 at 01:54 PM 1
Share

well done on answer, and quite rare seeing for(;;) being used aswell, first time I have seen it outside of my own code or a tutorial

avatar image diabloroxx · Dec 09, 2010 at 08:08 PM 1
Share

Could you please tell why you created the UpdateState ins$$anonymous$$d of using the regular Update?

avatar image Peter G · Dec 09, 2010 at 09:16 PM 1
Share

It has to do with the fact that TBS games are essentially event driven. Update() is called every frame, and while Update in itself is an event, it is difficult to create an event based system from that without using excessive conditional statements. So, UpdateState works by creating what is basically event driven. UpdateState first calls the PlayerTurn() method, then waits until that finishes (@ the end of the player's turn) then calls the EnemyTurn() method. After that it restarts. In order to do that in Update() you would have to have have several bools that switch as the turn (cont.)

avatar image Peter G · Dec 09, 2010 at 09:18 PM 1
Share

(cont.) progresses. The other nice thing this set up does is it fires events when each turn ends. You could do that in Update(), but I do think it is worth mentioning that you can have other objects listen for these events to do other implementation.

avatar image GrinningPariah · Nov 19, 2013 at 05:28 AM 0
Share

I know I'm gravedigging the hell out of this, I hope you can still answer a quick question:

The only part of this sample code that confuses me is the statement at the end of the turns:

 if(playerTurnEnded != null) 
     playerTurnEnded(tI);

and

 if(enemyTurnEnded != null) 
     playerTurnEnded(tI);

$$anonymous$$aybe I just don't understand events in C#, but what does calling these accomplish? The events dont seem to be used anywhere but those 4 lines.

Also, why does the event take the TurnInfo as an argument? Where do you specify what it does with that?

Show more comments
avatar image
4

Answer by Proclyon · Dec 07, 2010 at 02:07 PM

Well here's some advice , not really much of an answer.

I really can not figure out why there is no state controller being used for a turn based system. Turn based is all about states. When is who doing what.

Make a control flow for your game.

Somewhat like magic the gathering: (Somewhat similar , this is not exactly the same)

[Draw]

[Upkeep]

[Pre-Attack Main Phase] (spells and creatures lands > etc)

[Attack Phase] --> Declare attackkers, defenders instant spells etc Interaction with enemy

[Post-Attack Main Phase] (more spells creatures lands etc)

[Discard/CleanUp]

Use an enum a bunch of bools any container to keep track of what object is in what state.

If you have a master controller where there is per player per turn instead of all players in one turn (the 2 most common turn based systems) you need to focus on keeping track of pausing when interacting between two objects, without the master controller you need to force control the order in which the events can take place on it self instead rather than also work on global control flow.

Static functions are great sure, untill you acces it when you shouldn't be accessing it. Anybody can call end turn at any time? That takes a lot of accuracy in the control flow, not to mention

Playing sounds and performing attacks should only be called and automatically be called when the player is performing an action called "Attacking" or otherwise named. My point being that when you have a state called "Attack Phase" you can slide permission for the static attack function call to be set to true, for THIS object even would be an even better specification, as globally accessible functions do not differentiate between anything unless caught. Hence my conclusion to use Player as an object and modify it when a master controller decides it gets to do anything at all, all actions the player can perform should be methods inside the player, all public, all encapsulated except the user input requests marked as public , the rest is not accesible and just does the real work. (Public private , if you just went WTF , you can mimic it here if you want )

If you want to skip keeping track of states, and ignore the permissions set to who can call what when in a turn based game, I will simply tell you , test , test , test again, pray it works.

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
3

Answer by · Oct 22, 2010 at 02:29 AM

TurnEnd() will always leave Playerturn as 'true', which will no doubt cause problems along the way.

static function TurnEnd(){
   print("Turn end!");
   if(Playerturn == true){    // Playerturn is initially true, so this is true
      Playerturn = false;     // Playerturn is now false
      Enemy_Turn.Select();
   }
   if(Playerturn == false){   // Playerturn was just made false
      Playerturn = true;      // Playerturn is set back to true
   }
}

You could rewrite it like this:

static function TurnEnd(){
   print("Turn end!");
   if(Playerturn == true){           // if it was the playerturn before TurnEnd()
      Enemy_Turn.Select();           // run Enemy_Turn.Select()
   }
      Playerturn = !Playerturn;      // Playerturn boolean is flipped
}

It might not solve all your problems, but it'll be a start. Let me know how it goes!

Comment
Add comment · Show 3 · 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 Persona · Oct 22, 2010 at 03:19 AM 1
Share

No visible changes. The problem is most likely before that part of the code initializes. Still, it'll save me many problems in the future since I set myself in an endless loop like that.

avatar image Persona · Oct 25, 2010 at 06:08 PM 1
Share

Anymore suggestions?

avatar image · Oct 25, 2010 at 09:16 PM 1
Share

I totally forgot to investigate over the weekend, apologies! I'll have another think today, but hopefully someone else will be able to spot the problem.

avatar image
1

Answer by bjarnefisker · Dec 06, 2010 at 10:39 PM

I'm pretty sure that you can't use yield in a static function. Try to comment out the yield command in the BattlePhase function and i think your good to go.

static function BattlePhase(){
//RPGPlayer.OnAttack();
RPGEnemy.OnDamage();
//yield WaitForSeconds(2);
print("Battle Phase Ends!!");
TurnEnd();
}

Also i agree with Marowi that you might want to look through your if statements and when you are setting the Playerturn. But fixing this bug would make it a lot easier to debug :)

Let me know how it works.

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
  • 1
  • 2
  • ›

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

7 People are following this question.

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

Related Questions

how well does unity work for turn-based game time-type? 3 Answers

How to colour individual labels with UnityScript? 2 Answers

Creating an Interactable Grid for Tactics Game (C#) 1 Answer

Best practice for a turn-based game 1 Answer

Where can I find Memory Game Demo package? 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