Lights Out on a Hexagonal Grid (Monster in the Closet)

This example is the famous Lights Out game on a hex grid. All the patterns are procedurally generated.

[button url=”https://gamelogic.co.za/examples/grids/monster-hex/”]PLAY GAME[/button]

Note: You need the Unity Web Plugin to play this example.

Main Game Logic

using System;
using System.Linq;
using System.Collections.Generic;

using UnityEngine;

using Gamelogic.Grids;

public class LightsOutHex : GLMonoBehaviour, IResetable
{
   private const int Symmetry2 = 0;
   private const int Symmetry3 = 1;
   private const int Symmetry6 = 2;

   public Cell cellPrefab;
   public GameObject root;

   private Vector2 hexDimensions = new Vector2(74, 84);
   private PointyHexGrid grid;
   private IMap3D map;

   private Color offColor = ExampleUtils.colors[4];
   private Color onColor = ExampleUtils.colors[6];

   public void Start()
   {
      Reset();
   }

   public void Update()
   {      
      if(Input.GetMouseButtonDown(0))
      {      
         Vector3 worldPosition = ExampleUtils.ScreenToWorld_NGUI(root, Input.mousePosition);

         PointyHexPoint hexPoint = map[worldPosition];

         if(grid.Contains(hexPoint))
         {
            ToggleCellAt(hexPoint);
         }
      }
   }

   public void Reset()
   {
      root.transform.DestroyChildren();
      BuildGrid();
      InitGame();
   }

   private void BuildGrid()
   {      
      grid = PointyHexGrid.Hexagon(5);

      map = new PointyHexMap(hexDimensions)
         .WithWindow(ExampleUtils.ScreenRect)
         .AlignMiddelCenter(grid)
         .AnchorCellMiddelCenter()
         .To3DXY();

      foreach(PointyHexPoint point in grid)
      {
         Cell cell = Instantiate(cellPrefab);

         Vector3 worldPoint = map[point];

         cell.transform.parent = root.transform;
         cell.transform.localScale = Vector3.one;
         cell.transform.localPosition = worldPoint;

         cell.SetColor(offColor);
         cell.SetText("");

         grid[point] = cell;
      }
   }

   private void InitGame()
   {
      int pattern = UnityEngine.Random.Range(0, 3);

      switch(pattern)
      {
         case 0:
            InitPattern1();
            break;
         case 1:
            InitPattern2();
            break;
         case 2:
            InitPattern1();
            InitPattern2();
         break;
      }

      if(grid.All(p => !grid[p].HighlightOn))
      {
         Reset();
      }
   }

   private void InitPattern2()
   {
      int start = UnityEngine.Random.Range(0, 3);
      int end = UnityEngine.Random.Range(start, 3);
      int symmetry = UnityEngine.Random.Range(0, 3); 

      switch(symmetry)
      {
         case Symmetry6:
            for(int i = start; i <= end; i++)
            {         
               ToggleCellAt((PointyHexPoint.East + PointyHexPoint.NorthEast) * i);
               ToggleCellAt((PointyHexPoint.West + PointyHexPoint.SouthWest) * i);         
               ToggleCellAt((PointyHexPoint.NorthEast + PointyHexPoint.NorthWest) * i);
               ToggleCellAt((PointyHexPoint.SouthWest + PointyHexPoint.SouthEast) * i);
               ToggleCellAt((PointyHexPoint.NorthWest + PointyHexPoint.West) * i);
               ToggleCellAt((PointyHexPoint.SouthEast + PointyHexPoint.East) * i);
            }
         break;
         case Symmetry3:
            for(int i = start; i <= end; i++)
            {         
               ToggleCellAt((PointyHexPoint.East + PointyHexPoint.NorthEast) * i);
               ToggleCellAt((PointyHexPoint.SouthWest + PointyHexPoint.SouthEast) * i);
               ToggleCellAt((PointyHexPoint.NorthWest + PointyHexPoint.West) * i);

            }
         break;
         case Symmetry2:
            for(int i = start; i <= end; i++)
            {         
               ToggleCellAt((PointyHexPoint.East + PointyHexPoint.NorthEast) * i);
               ToggleCellAt((PointyHexPoint.West + PointyHexPoint.SouthWest) * i);         
            }
         break;
      }
   }

   private void InitPattern1()
   {   
      int start = UnityEngine.Random.Range(0, 5);
      int end = UnityEngine.Random.Range(start, 5);
      int symmetry = UnityEngine.Random.Range(0, 3); 

      switch(symmetry)
      {
         case Symmetry6:
            for(int i = start; i <= end; i++)
            {         
               ToggleCellAt(PointyHexPoint.East * i);
               ToggleCellAt(PointyHexPoint.West * i);         
               ToggleCellAt(PointyHexPoint.NorthEast * i);
               ToggleCellAt(PointyHexPoint.SouthWest * i);
               ToggleCellAt(PointyHexPoint.NorthWest * i);
               ToggleCellAt(PointyHexPoint.SouthEast * i);
            }
         break;
         case Symmetry3:
            for(int i = start; i <= end; i++)
            {         
               ToggleCellAt(PointyHexPoint.East * i);
               ToggleCellAt(PointyHexPoint.SouthWest * i);
               ToggleCellAt(PointyHexPoint.NorthWest * i);

            }
         break;
         case Symmetry2:
            for(int i = start; i <= end; i++)
            {         
               ToggleCellAt(PointyHexPoint.East * i);
               ToggleCellAt(PointyHexPoint.West * i);         
            }
         break;
      }
   }

   private void ToggleCellAt(PointyHexPoint hexPoint)
   {
      foreach(PointyHexPoint point in grid.GetNeighbors(hexPoint))
      {
         grid[point].HighlightOn = !grid[point].HighlightOn;
         grid[point].SetColor(grid[point].HighlightOn ? onColor : offColor);
      }
   }
}

Generic Cell Class

using System.Linq;

using UnityEngine;

public class Cell : CSMonoBehaviour 
{  
  public string[] spriteNames;

  protected UISprite image;
  protected UISprite highlight;
  protected UILabel spriteText;

  private bool highlightOn;

  public bool HighlightOn
  {
    set
    {
      highlightOn = value;
      highlight.enabled = value;
    }

    get
    {
      return highlightOn;
    }      
  }

  public void Awake()
  {
    image = GetComponentsInChildren().First(x => x.name == "Image");
    highlight = GetComponentsInChildren().First(x => x.name == "Highlight");
    spriteText = GetComponentInChildren();

    HighlightOn = false;
  }

  public void SetColor(Color color)
  {
    image.color = (color);
  }

  public void SetText(string newText)
  {
    spriteText.text = newText;
  }

  public void SetFrame(int frameIndex)
  {
    image.spriteName = spriteNames[frameIndex];
    image.MakePixelPerfect();
  }

  public void SetHighlightFrame(int frameIndex)
  {
    highlight.spriteName = spriteNames[frameIndex];
    image.MakePixelPerfect();
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top