using System;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
///
/// Handles the logic of a single tile
///
public class TileScript : MonoBehaviour {
#region Enums
///
/// Type of tile (bomb or mine)
///
public enum EType {
Safe,
Mine
}
///
/// Number of the tile (can be correctly casted to an integer)
///
public enum ENumber {
Empty,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight
}
#endregion
#region Fields
///
/// References to unrevealed tiles
///
public Sprite TileUnknown,
TilePressed;
///
/// References to revealed empty tiles
///
public Sprite Tile0,
Tile1,
Tile2,
Tile3,
Tile4,
Tile5,
Tile6,
Tile7,
Tile8;
///
/// References to mine-related tiles
///
public Sprite TileMine,
TileFlag,
TileQuestion,
TileQuestionPressed;
///
/// References to revealed or wrongly placed flag tiles
///
public Sprite TileDead,
TileWrong;
public float LocalScale = 1;
///
/// What type is this
///
private EType _type = EType.Safe;
private ENumber _num = ENumber.Empty;
private bool _flagged;
private bool _revealed;
private Sprite _sprRevealed;
private SpriteRenderer _sprRend;
private bool _enabled = true;
// Tile container
private ControlScript _parent;
private GameObject[,] _container;
private Vector2i _gridPos;
private List _neighbours = new List();
// Tile mouse fields
private bool _leftDown;
private bool _rightDown;
private bool _middleDown;
#endregion
#region Properties
///
/// What type is this tile (safe or not)?
///
public EType Type {
get { return _type; }
set {
_type = value;
AssignTexture();
}
}
///
/// What number does this tile have? Only applicable if not a mine
///
public ENumber Number {
get { return _num; }
set {
_num = value;
AssignTexture();
}
}
///
/// Reference to the control script
///
public ControlScript Parent {
get { return _parent; }
set { _parent = value; }
}
///
/// Reference to the tiles container
///
public GameObject[,] Container {
get { return _container; }
set { _container = value; }
}
///
/// Position of this tile within the grid
///
public Vector2i GridPos {
get { return _gridPos; }
set { _gridPos = value; }
}
///
/// Is the tile revealed? Setting it will apply its value.
///
public bool Revealed {
get { return _revealed; }
set {
if (_revealed && !value) {
Unreveal();
_revealed = false;
} else if (!_revealed && value) {
Reveal();
}
}
}
///
/// Is the tile flagged? Setting it will apply or remove the flag
///
public bool Flagged {
get { return _flagged; }
set {
if (value)
Flag();
else
Unflag();
}
}
///
/// All neighbours of this tile
///
public List Neighbours {
get { return _neighbours; }
}
///
/// Adds a neighbour. Strange that this is a property...
///
public TileScript NewNeighbour {
set { _neighbours.Add(value); }
}
///
/// Should the tile react to user input
///
public bool Enabled {
get { return _enabled; }
set { _enabled = value; }
}
#endregion
#region Unity Methods
///
/// First initailization, called before all Start methods
///
void Awake() {
_sprRevealed = Tile0; // default reveal tile
}
///
/// Use this for initialization
///
void Start() {
_sprRend = GetComponent();
_sprRend.sprite = TileUnknown;
transform.localScale = new Vector3(LocalScale, LocalScale, LocalScale);
}
///
/// Update is called once per frame
///
void Update() {
// Left mouse button released
if (_parent.Controls[EControls.TileReleased].IsActive() && _leftDown) {
_leftDown = false;
if (!_revealed)
TileRelease();
}
// Right mouse button released
if (_parent.Controls[EControls.TileFlagReleased].IsActive() && _rightDown)
_rightDown = false;
// Middle mouse button released
if (_parent.Controls[EControls.TileSquareReleased].IsActive() && _middleDown) {
_middleDown = false;
foreach (var neighbour in _neighbours.Where(neighbour => !neighbour._flagged && !neighbour._revealed))
neighbour.TileRelease();
}
}
///
/// Is called every frame that the mouse is over this objects bounding box
///
void OnMouseOver() {
if (!_enabled)
return;
// Left mouse button behaviour
if (!_revealed && _parent.Controls[EControls.TilePressed].IsActive()) {
_leftDown = true;
TilePress();
}
if (_parent.Controls[EControls.TileReleased].IsActive() && _leftDown)
_parent.OnTileClick(gameObject);
// Right mouse button behaviour
if (!_revealed && _parent.Controls[EControls.TileFlagPressed].IsActive())
_rightDown = true;
if (_parent.Controls[EControls.TileFlagReleased].IsActive() && _rightDown)
_parent.OnTileRightClick(gameObject);
// Middle mouse button behaviour
if (_revealed && _parent.Controls[EControls.TileSquarePressed].IsActive()) {
_middleDown = true;
foreach (var neighbour in _neighbours.Where(neighbour => !neighbour._flagged && !neighbour._revealed))
neighbour.TilePress();
}
if (_parent.Controls[EControls.TileSquareReleased].IsActive() && _middleDown)
_parent.OnTileMiddleClick(gameObject);
}
#endregion
#region Methods
///
/// Removes all neighbours
///
public void ClearNeighbours() {
_neighbours.Clear();
}
///
/// Reveals current tile and nearby ones if ENumber == Empty
///
public void Reveal() {
// skip if already revealed or flagged
if (_revealed || _flagged)
return;
_revealed = true;
_sprRend.sprite = _sprRevealed;
if (_type != EType.Mine && _num == ENumber.Empty)
Neighbours.ForEach(neighbour => neighbour.Revealed = true);
_parent.OnTileReveal(gameObject);
}
///
/// Used when the user reveals this mine
///
public void SetAsDeadMine() {
_sprRend.sprite = TileDead;
}
///
/// Hides the tile again
///
public void Unreveal() {
// Skip if already hidden
if (!_revealed)
return;
_revealed = false;
_sprRend.sprite = TileUnknown;
}
///
/// Reveals the tile as if the game was lost (only mines are revealed, empty tiles and correctly flagged mines are
/// unaffected, incorrectly flagged mines are tagged)
///
public void RevealAsLoseState() {
if (_type == EType.Mine && !_flagged && !_revealed) {
_sprRend.sprite = TileMine;
} else if (_type != EType.Mine && _flagged) {
_sprRend.sprite = TileWrong;
}
}
///
/// Swap the flag state
///
public void FlagSwap() {
if (_flagged)
Unflag();
else
Flag();
}
///
/// Forces a flag on the tile
///
public void Flag() {
// skip if already flagged or revealed
if (_flagged || _revealed)
return;
_flagged = true;
_sprRend.sprite = TileFlag;
}
///
/// Forces to remove the flag
///
public void Unflag() {
// skip if already unflagged
if (!_flagged)
return;
_flagged = false;
_sprRend.sprite = TileUnknown;
}
#endregion
#region Helper functions
///
/// Visual feedback when the user clicks a mine
///
private void TilePress() {
if (!_revealed && !_flagged)
_sprRend.sprite = TilePressed;
}
///
/// Visual feedback for when the user releases the click
///
private void TileRelease() {
if (!_revealed && !_flagged)
_sprRend.sprite = TileUnknown;
}
///
/// Assigns the correct texture for when the tile is revealed
///
private void AssignTexture() {
switch (_type) {
case EType.Safe:
switch (_num) {
case ENumber.Empty:
_sprRevealed = Tile0;
break;
case ENumber.One:
_sprRevealed = Tile1;
break;
case ENumber.Two:
_sprRevealed = Tile2;
break;
case ENumber.Three:
_sprRevealed = Tile3;
break;
case ENumber.Four:
_sprRevealed = Tile4;
break;
case ENumber.Five:
_sprRevealed = Tile5;
break;
case ENumber.Six:
_sprRevealed = Tile6;
break;
case ENumber.Seven:
_sprRevealed = Tile7;
break;
case ENumber.Eight:
_sprRevealed = Tile8;
break;
default:
throw new ArgumentOutOfRangeException();
}
break;
case EType.Mine:
_sprRevealed = TileMine;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
#endregion
}