Just like with the Colorful rating system, the inspiration for this demo was a blog post I wrote almost 8 (!) years ago. The article called “Lights Off – A puzzle game using HTML5 canvas” was essentially a clone of Lights Off, but built using the HTML <canvas>
-element.
Lights Off is a clone itself, based on the 1995 game Lights Out by Tiger Electronics. For today, I’ll show you how to create a clone of this puzzle game using Xamarin.Forms. Can you solve the puzzle? Simply click on a tile to flip it along with the four adjacent tiles.
If you’re like me, you can’t wait for the Marvels Avengers: Infinity War movie to hit the cinemas. Because it’ll be in theaters April 27th, I’ve given this sample a slight Avenger-theme! Let’s dive in.
The idea
I named the game XamLights (short for Xamarin Lights Out). The idea is exactly the same as the canvas
-version.
We’ll start off by creating the playing field using a Grid
. This Grid will have a 5×5 dimension filled with tiles which we’ll get back to later.
Next, we’ll need to apply logic for flipping the tiles. As you can see in the example, it simply flips the tile together with the direct surrounding tiles. The red arrows show where the user would have clicked with an empty playing field.
Now create some levels that set the starting position and let the user try to flip the tiles in the correct position! Of course, after each click we need to check if all the lights are off and the player is done.
Levels
To create the levels, I once again used a two dimensional array that represents the playing field. It’s easy to work with (in code), but also great to see how the field is going to look like eventually, since the code exactly represents the field.
new char[5, 5] {
{'o', 'x', 'o', 'x', 'o'},
{'o', 'o', 'o', 'o', 'o'},
{'o', 'o', 'x', 'o', 'o'},
{'o', 'o', 'o', 'o', 'o'},
{'o', 'x', 'o', 'x', 'o'},
}
We’ll use this structure under the hood to know which tiles need to be flipped to start the game. An 'x'
means “frontside-up” while 'o'
means “backside-up”. Now, let’s see how we can create the tiles!
Tiles
The tiles that are part of the grid have some of the same logic we used in the Xamarin.Forms animated profile cards. The setup is a base class with a an background and Image that are placed “on top” of each other. On top of that, there’s another invisible frame that can receive the Tap-events using a TapGestureRecognizer
. These are simply all the elements we need in order to make the sample look like cards.
Important parts to know:
- The Tile itself knows which X & Y coordinates it holds in the Grid.
- The added
TapGestureRecognizer
throws aTileTappedEventArgs
when tapped and includes these coordinates. - The animation is handled here as well.
Check out the full implementation as well.
Animation
The exact same animation has been used as the Flip-animation in the Xamarin.Forms animated profile cards. You can easily change this with other animations if needed, but it gives the game a neat effect.
public async Task Flip()
{
if (_frontIsShowing)
{
await _foreground.RotateYTo(-90, 400, Easing.CubicIn);
_foreground.Opacity = 0;
await _background.RotateYTo(0, 400, Easing.CubicOut);
_frontIsShowing = false;
}
else
{
await _background.RotateYTo(90, 400, Easing.CubicIn);
_foreground.Opacity = 1;
await _foreground.RotateYTo(0, 400, Easing.CubicOut);
_frontIsShowing = true;
}
}
The image
Sadly, there is no background-position
property available in Xamarin.Forms like CSS. Therefore, we can’t re-use an image and we’ll have to split it. I took the Avengers: Infinity War movie poster and splitted the image in equal parts.
The images are named row-#-col-#.jpg
which we can easily use in our Tile since we know our X & Y coordinates. I’ve used Embedded Images for ease of use.
_foreground = new Image
{
RotationY = -90,
Source = ImageSource.FromResource($"XamLights.images.row-{yPos + 1}-col-{xPos + 1}.jpg")
};
Since the X & Y coordinates are 0-based, we’ll need to add one since the images aren’t.
Game logic
Now to put all the pieces together! The game logic ties all the pieces of the puzzle (no pun intended) together. This is just a part of all the code.
public class GameViewModel : ViewModelBase {
// Two dimensional array that represents the playing field
private Tile[,] _tiles = new Tile[5,5];
List<Task> _fieldsToFlip = new List<Task>();
public void AddTile(Tile tile) {
tile.Tapped += TileTapped;
_tiles[tile.XPos, tile.YPos] = tile;
}
private async void StartGame() {
var game = Games.RandomGame();
for (var x = 0; x < 5; x++) {
for (var y = 0; y < 5; y++) {
if(game[x, y] == 'x') {
_fieldsToFlip.Add(_tiles[x, y].Flip());
}
}
}
await FlipFields();
}
private async void TileTapped(object sender, TileTappedEventArgs e) {
// Check which fields we need to flip
// The field itself
_fieldsToFlip.Add(_tiles[e.XPos, e.YPos].Flip());
// The field above
if (e.YPos - 1 >= 0) {
_fieldsToFlip.Add(_tiles[e.XPos, e.YPos - 1].Flip());
}
// Other fields to flip
await FlipFields();
}
private async Task FlipFields() {
await Task.WhenAll(_fieldsToFlip);
_fieldsToFlip.Clear();
}
}
Some important parts to point out:
- Because of the
async/await
-pattern and animations we want at the same time, the_fieldsToFlip
holds a list of animations we stack together and execute in theFlipFields
-method. - The
AddTile
-method holds a reference to all tiles created by the View. - One
StartGame
, aRandomGame
is selected and flipped based on the value. TileTapped
handles the logic to determine which tiles need to be flipped.
This class also includes the check if all the Tiles are facing upward (meaning the game is finished) and that’s about it.
Conclusion & Download
There you have it, a simple (but addicting) puzzle game using Xamarin.Forms. Download the source and challenge yourself to solve all the levels. I also added a custom app icon to tribute Xamarin and the Avengers. I know the code can be improved, so feel free to send me a pull request with improvements!
If you like creating puzzle games with Xamarin.Forms, I recommend you to check out Xuzzle by Charles Petzol as well. A next step would be to run this sample in the browser using Ooui by Frank Krueger. Let me know what you think in the comments and feel free to improve the code!
1 comments On How to build a “Lights Out” puzzle clone with Xamarin.Forms
Hi, thanks for sharing the app! It looks and feels great.