# Tic-Tac-Toe Tutorial (aka Noughts and Crosses) Q&A

Discussion in 'Community Learning & Teaching' started by Adam-Buckner, Apr 22, 2016.

Joined:
Jun 27, 2007
Posts:
5,670
2. ### GazEcc

Joined:
Jun 3, 2014
Posts:
6
hey, i think I found a bug? if i put an x in all 4 corners and o in all 4 edges (or vice versa, the final x makes the game a draw? I'm gonna do the last bit of the tutorial tomorrow, (the pick a player part) but just wondering about that.

Joined:
Jun 27, 2007
Posts:
5,670
Interesting. I'll test that today and see what happens.

Joined:
Jun 27, 2007
Posts:
5,670
Looking at my final project, it works as expected:

Now, I'm having a hard time (without redoing the project) checking to see if there's an issue at your step... but first:

I'd check the code in EndTurn to make sure that all the test are correct. Tho' that should trigger 4 separate lines of code and 4 possible wins (1 row, 1 column, 2 diagonals). You'd have to have 4 lines wrong to make that not a win.

The other thing to check is to make sure that the center grid space is correctly assigned and in the correct order...

Can you win with a diagonal, row or column that goes thru the center before the last turn?

Can you have a win with any last place turn? EG: From this setup, starting with X, placing the last X should create another 9th turn win.

5. ### GazEcc

Joined:
Jun 3, 2014
Posts:
6
It only really seems to happen as

xox
oxo
xox
(invertable)

and only when the last square is the middle square.

Ive included a few wins through the middle square at various stages which all seem to be on the money.

- Gaz

6. ### GazEcc

Joined:
Jun 3, 2014
Posts:
6
And just trying there to get the last square winning and yeah it seems square 9 is always a draw, does that mean the draw condition >=9 is the fault?

Joined:
Jun 27, 2007
Posts:
5,670
What value do you start your move count with? And when and where do you increment it. You may inadvertently be one move ahead... Or something similar.

Have you jumped ahead at any point?

There is one point where the entire EndTurn gets moved from if's to an if/else block.

...

Where are you in the tutorial?

8. ### GazEcc

Joined:
Jun 3, 2014
Posts:
6
Hey there Adam, I haven't moved on any further than the second last section. here's my code

(Please Ignore the comments as I put them there just to show myself why I've done x y or z in that area and they show my complete n00bness )
Code (csharp):
1.
2. using UnityEngine;
3. using UnityEngine.UI;
4. using System.Collections;
5.
6. [System.Serializable]
7. //creatingaclassissomethingtolookinto
8. //itseemsthatyoucanthenassignittoanobjectorwhateverandpullitinasyouneed?invoidsandstuff.
10. public class Player
11. {
12.  public Image panel;
13.  public Text text;
14. }
15.
16. [System.Serializable]
17. public class PlayerColor
18. {
19.  public Color panelColor;
20.  public Color textColor;
21. }
22.
23. public class GameController : MonoBehaviour {
24.  //The[]meanscreateanarraythatispopulatedinthe editor
25.  public Text[] buttonList;
26.  //JusttheGameOvertextpaneland text
27.  public GameObject gameOverPanel;
28.  public Text gameOverText;
29.  //Torestartthe game
30.  public GameObject restartButton;
31.  //Playerisacustomclasswecallhere...
32.  public Player playerX;
33.  public Player playerO;
34.  //PlayerColourisalsoapublicclasswecallherethatwecreatedandpopulatedintheeditor.
35.  public PlayerColor activePlayerColor;
36.  public PlayerColor inactivePlayerColor;
37.  private string playerSide;
38.  //movecounterstored here
39.  private int moveCount;
40.
41.  void Awake ()
42.  {
43.  SetGameControllerReferenceOnButtons();
44.  playerSide = "X";
45.  //stopsthegameoverwindowonfirst move
46.  gameOverPanel.SetActive(false);
48.  moveCount = 0;
49.  //turnsoffthereset button
50.  restartButton.SetActive(false);
51.  //setouractiveandinactiveplayercolours.
52.  SetPlayerColors(playerX, playerO);
53.  }
54.
55.  void SetGameControllerReferenceOnButtons ()
56.  {
57.  for (int i = 0; i < buttonList.Length; i++)
58.  {
59.  buttonList .GetComponentInParent<GridSpace>().SetGameControllerReference(this);
60.  }
61.  }
62.
63.  public string GetPlayerSide ()
64.  {
65.  return playerSide;
66.  }
67.
68.  public void EndTurn ()
69.  {
71.  moveCount ++;
73.  if (moveCount >= 9)
74.  {
75.  GameOver ("draw");
76.  }
77.  //checkstoseeiftheHorizontallinesare complete
78.  else if (buttonList [0].text == playerSide && buttonList [1].text == playerSide && buttonList [2].text == playerSide)
79.  {
80.  GameOver (playerSide);
81.  }
82.  else if (buttonList [3].text == playerSide && buttonList [4].text == playerSide && buttonList [5].text == playerSide)
83.  {
84.  GameOver (playerSide);
85.  }
86.  else if (buttonList [6].text == playerSide && buttonList [7].text == playerSide && buttonList [8].text == playerSide)
87.  {
88.  GameOver (playerSide);
89.  }
90.  //checkstoseeiftheverticallinesare complete
91.  else if (buttonList [0].text == playerSide && buttonList [3].text == playerSide && buttonList [6].text == playerSide)
92.  {
93.  GameOver (playerSide);
94.  }
95.  else if (buttonList [1].text == playerSide && buttonList [4].text == playerSide && buttonList [7].text == playerSide)
96.  {
97.  GameOver (playerSide);
98.  }
99.  else if (buttonList [2].text == playerSide && buttonList [5].text == playerSide && buttonList [8].text == playerSide)
100.  {
101.  GameOver (playerSide);
102.  }
103.  //checkstoseeifthediagonallinesare complete
104.  else if (buttonList [0].text == playerSide && buttonList [4].text == playerSide && buttonList [8].text == playerSide)
105.  {
106.  GameOver (playerSide);
107.  }
108.  else if (buttonList [2].text == playerSide && buttonList [4].text == playerSide && buttonList [6].text == playerSide)
109.  {
110.  GameOver (playerSide);
111.  }
112.  else ChangeSides ();
113.  }
114.
115.  void ChangeSides ()
116.  {
117.  playerSide = (playerSide == "X") ? "O" : "X";
118.  if (playerSide == "X")
119.  {
120.  SetPlayerColors(playerX, playerO);
121.  }
122.  else
123.  {
124.  SetPlayerColors(playerO, playerX);
125.  }
126.  }
127.
128.  void SetPlayerColors (Player newPlayer,Player oldPlayer)
129.  {
130.  newPlayer.panel.color = activePlayerColor.panelColor;
131.  newPlayer.text.color = activePlayerColor.textColor;
132.  oldPlayer.panel.color = inactivePlayerColor.panelColor;
133.  oldPlayer.text.color = inactivePlayerColor.textColor;
134.  }
135.
136.  void GameOver(string winningPlayer)
137.  {
138.  if (winningPlayer == "draw")
139.  {
141.  }
142.  else
143.  {
144.  SetGameOverText(winningPlayer + "Wins!");
145.  }
146.  SetBoardInteractable (false);
147.  restartButton.SetActive(true);
148.  }
149.
150.  void SetGameOverText(string value)
151.  {
152.  gameOverPanel.SetActive(true);
153.  gameOverText.text = value;
154.  }
155.  public void RestartGame()
156.  {
157.  playerSide = "X";
158.  moveCount = 0;
159.  gameOverPanel.SetActive(false);
160.  restartButton.SetActive(false);
161.  SetPlayerColors(playerX, playerO);
162.  for (int i = 0; i < buttonList.Length; i++)
163.  {
164.  buttonList .text = "";
165.  }
166.  SetBoardInteractable(true);
167.  }
168.
169.  void SetBoardInteractable (bool toggle)
170.  {
171.  for (int i = 0; i < buttonList.Length; i++)
172.  {
173.  buttonList .GetComponentInParent<Button>().interactable = toggle;
174.  }
175.  }
176. }
177.

Edited to fix code tags... Tried to add some new lines to make it more readable... Moderator

Last edited by a moderator: Apr 10, 2017

Joined:
Jun 27, 2007
Posts:
5,670
FWIW our code tags take square brackets: [ ]

I would have added them, but your code has lost its formatting.

It looks like you have the move count test first, not last. As code is executed top top bottom in a function, it reaches the move count test before the win test, so if it's turn 9, you will always get a draw.

Joined:
Jun 27, 2007
Posts:
5,670
I see that you have some questions in your comments. If you still have questions, feel free to ask them.

11. ### GazEcc

Joined:
Jun 3, 2014
Posts:
6

And well, I'm still confused as to WHY I'm doing a lot of these things, I find it a little hard to understand WHY I use things like void, but I know void update is everytime the game refreshes or something similar, in a previous project I used fixed update which was like a regular pulse. But yeah.. what is void?

12. ### GazEcc

Joined:
Jun 3, 2014
Posts:
6
And Sorry about the <> I used to do HTML, guess I just fell into an old habit

13. ### Socrates

Joined:
Mar 29, 2011
Posts:
751
The "void" is saying "this function returns nothing at all." For a "void" you can use "return;" or not have a return at all. For other types of returns, you set up the proper return value.

For example:
Code (csharp):
1. void SomeFunction() {} // Returns nothing.
2.
3. int SomeOtherFunction()
4. {
5.     return 5;
6. } // Returns an int.
7.
8. bool SomeTrueFunction()
9. {
10.     return true;
11. }  // Always return true.
12.
The Update() function is called every single frame, every time Unity draws the screen. There is some official documentation here. The FixedUpdate() is probably what you mention using before and is explained here.

This short tutorial may help make it more clear.

Edited to make more sense than my first post.

Joined:
Jun 27, 2007
Posts:
5,670
What @Socrates said...

void is a return type for a function. In C#, all functions must have a return type. In many cases, functions simply "Do Something" but are not necessarily processing data and returning a result. These are void.

Code (csharp):
1. void SetBoardInteractable (bool toggle)
2. {
3.    for (int i = 0; i < buttonList.Length; i++)
4.    {
5.       buttonList .GetComponentInParent<Button>().interactable = toggle;
6.    }
7. }
In the above example, the function toggles all of the buttons in buttonList, but returns no value, so the return type is void.

Code (csharp):
1. int AddTwo (int a, int b)
2. {
3.    return a + b;
4. }
In the above example, the function processes data and returns a value, so the return type must be int.

TYPE is the type of thing this is, in that "Is this a GameObject? Is this a Camera? Is this a float?" The type is the name of the class. If you write your own class, eg: public class GameController, the type is GameController. Don't forget that ultimately, even tho' Components are "built-in", these Components - like Cameras and Rigidbodies - are defined somewhere and they are usually classes, just like the classes you write in your scripts. They are identified by type.

Now, C# can get a little pedantic with type.

Code (csharp):
1. int myNewInt = AddTwo (4, 5);
2.
3. int AddTwo (int a, int b)
4. {
5.    int calculatedValue = a + b;
6.    return calculatedValue;
7. }
We define int 3 times! 5 is you count the parameters! Shouldn't the compiler know this should be a fussing int??

Or...

Code (csharp):
1. GameObject clone = Instantiate (prefab) as GameObject;
Well, yes the compiler can figure it out but in many cases C# is pedantic by design so you are required to be absolutely clear about what you are writing. Other languages like JavaScript (or even UnityScript) are more forgiving and can try to figure out what type things are by implication.

There are some situations now, in C#, where you can let the compiler figure out type.

Code (csharp):
1. var clone = Instantiate (prefab) as GameObject;
The var her means "This is a variable of the type being returned by the right hand side of the statement" - in this case GameObject.

In general, it's safest to make sure you write these out by hand so there is no confusion.

As a side note, functions that do not return a value still do return when the function is done. Control of the game is returned to wherever it came from. If you think of the flow of logic in a game - the logic is flowing in a big loop reading all of the code on all of the relevant and active scripts and then Unity renders a frame and then the loop goes all over again.

Code (csharp):
1. public Text displayText;
2.
3. void Update ()
4. {
5.    // Some code goes here - checking for input and doing things.
6.    SetDisplay (Time.time);
7.    // More code goes here - checking for input and doing things.
8. }
9.
10. void SetDisplay (float time)
11. {
12.    displayText.text = time.ToString();
13. }

If you have a function like Update() and in Update, you call a function like SetDisplay. They are both functions that return void. Unity's main game loop (which we don't have control of) calls Update. The control of the game is now in Update doing things. During the execution of Update, the function SetDisplay is called. The control of the game - or the code being executed - is now in SetDisplay. Unity has executed "some code" in Update, but has not yet called "more code". The control moved to SetDisplay first. Unity executes all the code in SetDisplay and then SetDisplay returns void - but it does return. It just returns empty, nothing, void - and control of the game returns back to where it came from - in this case back to Update right after the line calling SetDisplay. Unity now executes "more code" in Update. When Update is done, the function Update then returns void and control of the game is handed back to the main Unity game loop, which will go on and look for any more Update functions on any other Components and then continue on with all the other things it does.

So - the flow of logic is handed off to different functions and then handed back to where it left off all in a linear fashion, like a mouse threading through a maze.

For more reading, this is the order of events that Unity calls:
http://docs.unity3d.com/Manual/ExecutionOrder.html

Unity will call all of these events on all relevant and enabled scripts on active GameObjects and then move on the next set of events, in a big loop, until the game's application is closed.

As a lst side note, in advanced coding, you can have what is called "multiple threads" all executing code simultaneously. This goes beyond the definition above "all code is executed in one long linear sequence" but you have to choose to do that and it's an advanced topic. Know that it exists, but ignore it for now.

Socrates likes this.
15. ### EASY Studios

Joined:
Jan 1, 2016
Posts:
1
In tutorial#8 (Ending in a draw),
if(moveCount >= 9)
should be
else if(moveCount >= 9)
Because if a player wins in the 9th move, without that else it will display "It's a Draw!".

Joined:
Jun 27, 2007
Posts:
5,670
At what stage of the tutorial are you? "Else If" is the final state. If you follow the tutorial and do the save and test steps, this should work as expected. If you're testing in the middle of a step, then you might have problems. Be aware that code executes from top to bottom and the order of the code is important. If you have that line above the win checks, you'll have problems.

If you feel there is a different error, then please point out the exact step you are in when it fails, as our tests of this tutorial don't find this issue.

17. ### Rockyeahh

Joined:
May 19, 2016
Posts:
17
Hey there I'm at the end of part 5 but I keep getting an error telling me on the gamecontroller script.
The type arguments for method 'Component.GetComponentInParent<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I also get an error on the grid space script that says 'GameController' does not contain a definition for 'GetplayerSide' and no extension method 'GetplayerSide' accepting a first argument of type 'GameController' could be found (are you missing a using directive or an assembly reference?)

I've attached pictures of both scripts. I'm thinking I've just missed something small.

File size:
64.6 KB
Views:
919
File size:
59 KB
Views:
954
18. ### Rockyeahh

Joined:
May 19, 2016
Posts:
17

I fixed the Component.GetComponentInParent problem, I had missed out <GridSpace>

but I'm still lost on the GameController problem.

19. ### Rockyeahh

Joined:
May 19, 2016
Posts:
17

Haha I just forgot to use a capital P. I'm an idiot but at least it's fixed now.

20. ### TiredOwl

Joined:
Feb 2, 2016
Posts:
4
Hi,
I'm having a problem where a ninth move win comes up as a draw. I'm at the end of part 8, "Ending in a draw". Here is my code:

Code (CSharp):
1. using UnityEngine.UI;
2. using UnityEngine;
3. using System.Collections;
4.
5. public class GameController : MonoBehaviour {
6.
7.     public Text[] buttonList;
8.     public GameObject gameOverPanel;
9.     public Text gameOverText;
10.
11.     private string playerSide;
12.     private int moveCount;
13.
14.     void Awake ()
15.     {
16.         SetGameControllerReferenceOnButtons ();
17.         playerSide = "X";
18.         gameOverPanel.SetActive (false);
19.         moveCount = 0;
20.     }
21.
22.     void SetGameControllerReferenceOnButtons ()
23.     {
24.         for (int i = 0; i < buttonList.Length; i++)
25.         {
26.             buttonList [i].GetComponentInParent<GridSpace> ().SetGameControllerReference(this);
27.         }
28.     }
29.
30.     public string GetPlayerSide ()
31.     {
32.         return playerSide;
33.     }
34.
35.     public void EndTurn ()
36.     {
37.         moveCount++;
38.         if (buttonList [0].text == playerSide && buttonList [1].text == playerSide && buttonList [2].text == playerSide)
39.         {
40.             GameOver ();
41.         }
42.         if (buttonList [3].text == playerSide && buttonList [4].text == playerSide && buttonList [5].text == playerSide)
43.         {
44.             GameOver ();
45.         }
46.         if (buttonList [6].text == playerSide && buttonList [7].text == playerSide && buttonList [8].text == playerSide)
47.         {
48.             GameOver ();
49.         }
50.         if (buttonList [0].text == playerSide && buttonList [3].text == playerSide && buttonList [6].text == playerSide)
51.         {
52.             GameOver ();
53.         }
54.         if (buttonList [1].text == playerSide && buttonList [4].text == playerSide && buttonList [7].text == playerSide)
55.         {
56.             GameOver ();
57.         }
58.         if (buttonList [2].text == playerSide && buttonList [5].text == playerSide && buttonList [8].text == playerSide)
59.         {
60.             GameOver ();
61.         }
62.         if (buttonList [0].text == playerSide && buttonList [4].text == playerSide && buttonList [8].text == playerSide)
63.         {
64.             GameOver ();
65.         }
66.         if (buttonList [2].text == playerSide && buttonList [4].text == playerSide && buttonList [6].text == playerSide)
67.         {
68.             GameOver ();
69.         }
70.
71.         if (moveCount >= 9)
72.         {
73.             SetGameOverText ("It's a draw!");
74.         }
75.
76.         ChangeSides ();
77.     }
78.
79.     void ChangeSides ()
80.     {
81.         playerSide = (playerSide == "X") ? "O" : "X";
82.     }
83.
84.     void GameOver ()
85.     {
86.         for (int i = 0; i < buttonList.Length; i++)
87.         {
88.             buttonList [i].GetComponentInParent<Button> ().interactable = false;
89.         }
90.         SetGameOverText (playerSide + " Wins!");
91.     }
92.
93.     void SetGameOverText (string value)
94.     {
95.         gameOverPanel.SetActive (true);
96.         gameOverText.text = value;
97.     }
98. }
99.
The only issue I've had in testing is if X wins on the last square. Can you spot anything wrong with my code? Many thanks in advance!

21. ### PeaceLaced

Joined:
Jun 2, 2015
Posts:
53
Last edited: Jul 26, 2016
22. ### PeaceLaced

Joined:
Jun 2, 2015
Posts:
53
Page with Error: http://unity3d.com/learn/tutorials/tic-tac-toe/game-control

Place on Page: Using + click on Windows or + click on the Mac, select only the child Text GameObjects from every Grid Space GameObject.

Should Be: Using Ctrl + click on Windows or Command + click on the Mac...

AND...

Place on Page: buttonList.GetComponentInParent().SetGameControllerReference(this);

Should Be: buttonList.GetComponentInParent<GridSpace>().SetGameControllerReference(this);

Found under bullet: Add code to check each item in the Button List and set the GameController reference in the GridSpace component on the parent GameObject. >> It is correct in the final script review but missing in the walk through.

Last edited: Jul 26, 2016
23. ### Ithalendra

Joined:
Aug 1, 2016
Posts:
1
Hi, I'm having a problem fairly early on - right after adding the first script, I can't set up all the references. I'm using Version 5.3.5f1, so I don't know if this is a problem. There's no space for dragging and dropping the 'Grid Space' and 'Text' GameObjects under the Button component, only under the script; also no Player Side property. Furthermore, 'GridSpace' is unavailable from the function drop-down menu even though I've added the GridSpace script under the Button component.

***PROBLEM SOLVED - I just needed to Add Component > Scripts > GridSpace and then I was able to continue normally***

Last edited: Aug 3, 2016
ballz and lordstok like this.
24. ### lordstok

Joined:
Aug 3, 2016
Posts:
1
I am having a similar problem as Ithalendra. I already ran through the tutorial previously with no problems I couldn't overcome (in an earlier build of unity) but while going through it a second time (using 5.3.5f1) I am now getting stuck.

Problem 1: On Step 4 "Foundation Game Play" i encounter my first issue in the basic script. For some reason my monodevelop throws an error on "button.interactable = false" - 'Button' does not contain a definition for 'interactable' and no extension method 'interactable' accepting a first argument of type 'Button' could be found (are you missing a using directive or an assembly reference?)'.

Problem 2: To continue i commented the offending line, and encountered my second issue. When attempting to
• Select the Grid Space prefab in the Project Window.
• With the Grid Space prefab selected,
• ... drag the Grid Space prefab onto the Button property
I cannot drag the Grid Space prefab onto the Button property. I can move the Text in to the Button Text field without an issue, but the Button field refuses to update whether I use drag, or select it manually!

25. ### PeaceLaced

Joined:
Jun 2, 2015
Posts:
53
@lordstok

Make sure you have correctly defined the button variable as Button type.

Code (CSharp):
1. public Button button;

26. ### Nisa_11

Joined:
Nov 26, 2015
Posts:
1

Can someone help me? It doesnt wanna check the EndTurn();

public void EndTurn(){

moveCount ++;

if (buttonList [0].text == playerSide && buttonList [1].text == playerSide && buttonList [2].text == playerSide){
GameOver();
}

else if (buttonList [3].text == playerSide && buttonList [4].text == playerSide && buttonList [5].text == playerSide){
GameOver();
}

else if (buttonList [6].text == playerSide && buttonList [7].text == playerSide && buttonList [8].text == playerSide){
GameOver();
}

else if (buttonList [0].text == playerSide && buttonList [3].text == playerSide && buttonList [6].text == playerSide){
GameOver();
}

else if (buttonList [1].text == playerSide && buttonList [4].text == playerSide && buttonList [7].text == playerSide){
GameOver();
}

else if (buttonList [2].text == playerSide && buttonList [5].text == playerSide && buttonList [8].text == playerSide){
GameOver();
}

else if (buttonList [0].text == playerSide && buttonList [4].text == playerSide && buttonList [8].text == playerSide){
GameOver();
}

else if (buttonList [2].text == playerSide && buttonList [4].text == playerSide && buttonList [6].text == playerSide){
GameOver();
}

if (moveCount >= 9){
SetGameOverText("It's a draw!");
}

ChangeSide();
}

I already put all the condition, but it seems like just a couple of them can run .. why is it happen?

27. ### Phantamoss

Joined:
Sep 1, 2016
Posts:
1
I'm not sure if it's my version of Unity or the Maker's version, but creating a script, and dragging it to OnClick, does not allow me to select the GridSpace script from the function list. I had to Add Componenet -> New Script -> GridSpace.cs

28. ### Toomblercazz

Joined:
Oct 8, 2016
Posts:
2
Great tutorial! I've finished it and even added a running score and lines which go through the three winning symbols. If I knew how I would upload my version

29. ### Sungold

Joined:
Jan 13, 2013
Posts:
8
Great tutorial indeed!! I really learned a lot about GUI! I think I also had the double diagonal problem in which the following would return a draw.

xox
oxo
xox

I just fixed it by adding an extra boolean.

Joined:
Apr 14, 2016
Posts:
5

File size:
271.3 KB
Views:
216
31. ### MinecraftBoxGuy

Joined:
Jun 26, 2016
Posts:
1
I would like to know how to turn this game into multiplayer?

32. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854

It's the second line about the Transition: Highlighted colour and, according to the screen capture, it probably should read:

33. ### p4ndepravity

Joined:
Aug 31, 2016
Posts:
2
what a great tutorial. exactly what I needed to jump-start my personal project. Thank you! These kinds of write-ups make it easy for me to recommend unity to everyone I meet that is interested in starting out as a developer (gaming or otherwise)

Joined:
Jun 27, 2007
Posts:
5,670
Thank you. This type of feedback is always appreciated! I'm glad you liked it. We'll try to get you more.

Joined:
Jun 27, 2007
Posts:
5,670
Ah! Good catch. I'll try to see which one is wrong: the screen cap or the text.

36. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854
It's the text.

37. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854
I have a problem; I understand what the piece of code below does in game because I see what it does, but, I don't understand its syntax. Could someone explain it to me, please? Thank you!

Here is the piece of code:

Code (CSharp):
1. void ChangeSides ()
2.     {
3.         playerSide = (playerSide == "X") ? "O" : "X";
4.     }

38. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854

Sorry about that but there is another small mistake and this one is present on at least two pages; this one: https://unity3d.com/learn/tutorials/tic-tac-toe/restarting-game?playlist=17111 and another one I don't remember.

You must look for this piece of code:

Code (CSharp):
1. buttonList[i].GetComponentInParent() ...
As it is, it doesn't work as GetComponentInParent is not specified (at least it doesn't for me with 5.5.0f3 Personal). It should read:

Code (CSharp):
1. buttonList[i].GetComponentInParent <Button> () ...
Thanks for this great tutorial anyway!

Joined:
Jun 27, 2007
Posts:
5,670
The syntax is: a variable on the left hand side is equal to the value returned from the right hand side based in the comparison done at the start of the right hand side. I. The parentheses there is a true / false comparison. The ? Indicates what type of statement or expression this is, and based on what is returned from the comparison, the value of the variable is set to either on or the other value after the ?. If the comparison returns true, the value of the variable is set to the first value, if it's false it is set to the value following the :.

Another way to do this is:
Code (csharp):
1. if (playerSide == "X")
2. {
3.    playerSide = "O";
4. }
5. else
6. {
7.    playerSide = "X";
8. }

APSchmidt likes this.

Joined:
Jun 27, 2007
Posts:
5,670
I'll take a look when I'm back from holidays! Thanks for spotting these.

APSchmidt likes this.
41. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854
Wow! Thank you! Is this syntax

Code (CSharp):
1. playerSide = (playerSide == "X") ? "O" : "X";
much used? I had never seen it elsewhere before.

By the way, sorry for bothering you during your holidays.

42. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854
You're welcome!

Have a good holiday! Happy new year!

Joined:
Jun 27, 2007
Posts:
5,670
It's used often enough when trying to write less code. "One line says it all." (VS. the 8 lines I used above...)

You will find, however, much opinion and debate in the shorter more compact vs longer more self explanatory arena. Lots of bloodshed and amusement. For super compact but hard to read, look into lamda expressions. We cover this briefly in the new adventure game tutorial.

APSchmidt likes this.

Joined:
Jun 27, 2007
Posts:
5,670
This is on our list to do, but it has not yet been done.

Joined:
Jun 27, 2007
Posts:
5,670

Joined:
Jun 27, 2007
Posts:
5,670
I thought this was down to code order and if the code was completed as the tutorial, there would be no issue. I'll try to test this again when I'm back. You also may need to make sure you have an else if... Check this against the sample code on the learn page.

Joined:
Jun 27, 2007
Posts:
5,670
Fantastic!

Joined:
Jun 27, 2007
Posts:
5,670
The script needs to be on a game object to drag it into the slot. You can drag the script onto a game object, but then you add that game object to the on click object field.

Joined:
Jun 27, 2007
Posts:
5,670
Double check your code. I be,I've this is because you have either an order issue or you have a simple if when you need an else if.

50. ### APSchmidt

Joined:
Aug 8, 2016
Posts:
3,854
Thanks!

How hard would it be to turn this game into a player vs ai/game? The player chooses X or O, plays once and the game plays the next turn, etc

Last edited: Jan 4, 2017
unityunity