More Os and Xs

Previously on STR.

With the -amazing gameplay- sorted out I need to work out the rest of the stuff. This means UI and graphics and possibly sound, and whatnot.

I think it would be great for the game to actually end when a player wins, and to restart after finishing. Additionally I want a line to be shown indicating where the win has occurred and some pop-up text declaring who's won or not. A score counter would be useful too.

Right, the easiest thing to do would be to implement finish and restart. Simply adding in a check for the game running does this.
//only place block if game is still running
if (gStatus == GameStatus.Running)
{
    PlaceBlock(x, y, gridPos);
    CheckGameCondition();
    ...
And this can be seen on the debug log, as verifying that things are being clicked but no action is taken.

NOTE: Unity editor changes colour when in playmode to remind you changes you make while running are temporary. Mine is washed out pinkish-purple because its noticeable, unobtrusive and not too harsh on the eyes when working past midnight. To change this colour (in Unity 4.5.1f3) you navigate to Edit > Preferences > Colors> Playmode Tint

Then for restarting, I considered having an invisible plane appear over the top of the screen that called for a board wipe when clicked (so anywhere you clicked would hit the invisible plane first). But that would be mostly pointless and probably makes things more complicated than they need to be. Again, Unity's documentation is good for answering these problems. With this I can just monitor the mouse down and call a restart from there if the game has ended.

For removing the actual 3D blocks on restart I was tempted to track all blocks placed and remove then by deleting each tracked block. However I was sure there was a way to just select all objects in game with an attribute (in this case being a block). The solution was tags. Tags are great. They let you find things from the editor and reference them in code.


The code looks something like this:
Debug.Log("Initialising gameboard");
//true is noughts, false is crosses
turn = true;
//the grid is going to be 3x3
grid = new int[3, 3];
gStatus = GameStatus.Running;

//find and remove all noughts and crosses from the grid
GameObject[] tagRespawn = GameObject.FindGameObjectsWithTag("Respawn");
foreach(GameObject go in tagRespawn)
{
    Debug.Log("Destroyed object "+go.name);
    GameObject.Destroy(go);
}
Debug.Log("Finished Initialisation");

One thing that's problematic is that once the last block is placed it immediately resets, as you can see on the logs:


The problem is most likely that clicking the mouse is triggering the block placing, then triggering the mouse being clicked once the game has finished. My solution (rather brute forced and doesn't really solve the problem) is to have a boolean that toggles when clicked the first time, then actually resets when toggled back, done here:

if (!clickGameEnd)
{
    clickGameEnd = true;
    //show something here
}
else
{
    Debug.Log("Initialising gameboard");
    ...
    //this stops the game from resetting from a click the first time clicked
    clickGameEnd = false;
    ...
}

Since I'm only making a simple UI, I'll probably just place objects on the scene, but there is a UnityGUI scripting guide that covers another way of making UIs that's much better for more powerful or complex UI systems.

NOTE: UI based objects use the viewport for positioning rather than the worldspace, so they will typically have an X Y position between 0 and 1, with Z representing the layer. Also 13 is the default font size, even though it starts at 0.

The way I've seen this next part done is to have public GUIText variables assigned in editor to the various texts I want to show, then show them as they need to appear from the code. It's simple and it works.
NOTE: While you can click the small circle to assign scene objects to scripts, its much quicker to drag and drop.




The final thing to add is the fancy line. A great component called the Line Renderer can draw 3D lines on the game window like rope or chain textures in other game engines. Although the positions are assigned manually, I reduced the amount of brute forcing by, rather than checking every possible line position, checking for the line direction and the position.

float z = 1.1f;
float p1X = 0;
float p1Y = 0;
float p2X = 0;
float p2Y = 0;

if (lDir == LineDirection.Horizontal)
{
    p1X = -4f;
    p2X = 4f;

    p1Y = -linePos * 3;
    p2Y = -linePos * 3;
}
if (lDir == LineDirection.Vertical)
{
    p1Y = -4f;
    p2Y = 4f;

    p1X = linePos * 3;
    p2X = linePos * 3;
}
if (lDir == LineDirection.DiagonalLR)
{
    p1X = -3.5f;
    p2X = 3.5f;

    p1Y = 3.5f;
    p2Y = -3.5f;
}
if (lDir == LineDirection.DiagoanlRL)
{
    p1X = -3.5f;
    p2X = 3.5f;

    p1Y = -3.5f;
    p2Y = 3.5f;
}

Vector3 pos1 = new Vector3(p1X, z, p1Y);
Vector3 pos2 = new Vector3(p2X, z, p2Y);
GUILine.SetPosition(0, pos1);
GUILine.SetPosition(1, pos2);

The results are something that look like an actual game?

Player 1 Diagonal win
Player 2 Horizontal win
Draw, so no line
Player 1 Vertical win
Next up, actually making it something you run on a desktop, then possibly making it run on the phone.

No comments:

Post a Comment