Created
January 26, 2014 15:55
-
-
Save thompson4822/8634757 to your computer and use it in GitHub Desktop.
Simple Memory Game For Lenny
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:html' as html; | |
import 'dart:math'; | |
import 'package:stagexl/stagexl.dart'; | |
Stage stage = null; | |
RenderLoop renderLoop; | |
/** | |
* Tracks all of the glyphs and can create new ones on demand. | |
*/ | |
class GlyphManager { | |
List<BitmapData> glyphs = []; | |
/** | |
* Build a GlyphManager with [TextureAtlas] glyphs | |
*/ | |
GlyphManager(TextureAtlas glyphAtlas) { | |
glyphs = glyphAtlas.getBitmapDatas("glyph"); | |
} | |
/** | |
* Returns a new glyph based on the glyph atlas [index] | |
* | |
* multiple calls with the same [index] will result in different [Bitmap] items. | |
*/ | |
Bitmap newGlyph(int index) { | |
var dropShadow = new DropShadowFilter(4, 45, 0x000000, 0.6, 10, 10, 2); | |
var glyph=glyphs[index]; | |
return new Bitmap(glyph) | |
..filters = [dropShadow] | |
..applyCache(0, 0, glyph.width, glyph.height); // IMPORTANT - This is necessary to apply the filters! | |
} | |
/// A convenience method for finding the number of glyphs in the atlas | |
int get length => glyphs.length; | |
} | |
/** | |
* Represents a single tile (rectangular region) with a single glyph. | |
*/ | |
class Tile extends Sprite { | |
/// The glyph shown on this tile | |
Bitmap glyph; | |
/// The id of the glyph, which can be used to determine if tiles match | |
int glyphId; | |
/// Creates a new [glyph] with the given [glyphId] | |
Tile(var this.glyph, var this.glyphId) { | |
var gradient = new GraphicsGradient.linear(6, 6, 88, 88); | |
gradient.addColorStop(0, Color.White); | |
gradient.addColorStop(1, Color.Bisque); | |
graphics | |
..beginPath() | |
..rectRound(6, 6, 88, 88, 8, 8) | |
..closePath() | |
..fillGradient(gradient) | |
..strokeColor(Color.Black, 1); | |
glyph | |
..x = (this.width - glyph.width) / 2 | |
..y = (this.height - glyph.height) / 2 | |
..alpha = 1.0 | |
..addTo(this); | |
} | |
/// Is the glyph on this tile in any way visible? | |
bool get isVisible => glyph.alpha > 0; | |
/// Toggle the visibility of the glyph between visible and invisible. | |
void flip() { | |
var alphaSetting = glyph.alpha == 0 ? 1.0 : 0.0; | |
var tween = new Tween(glyph, 0.3, TransitionFunction.linear) | |
..animate.alpha.to(alphaSetting); | |
renderLoop.juggler.add(tween); | |
} | |
} | |
/** | |
* Grid manages the tiles shown on the screen | |
*/ | |
class Grid extends DisplayObjectContainer { | |
/// The tiles that the grid tracks. | |
List<Tile> tiles; | |
/// The number of columns and rows the grid is in size | |
int columns, rows; | |
/// The current user selection (one or two tile indices) | |
List<int> selected = []; | |
/** | |
* Returns a new Grid based on the given [GlyphManager] with optional size. | |
* | |
* Note that at this time, the columns and rows should be left with their defaults. | |
* Anything else would not work very well. | |
*/ | |
Grid(GlyphManager glyphManager, {var this.columns: 5, var this.rows: 4} ) { | |
var rand = new Random(new DateTime.now().millisecondsSinceEpoch); | |
List<int> initialList = []; | |
tiles = new List<Tile>(columns * rows); | |
// Create a list like [0, 0, 1, 1, 2, 2, ...] | |
for(int glyphIndex = 0; glyphIndex < glyphManager.length; glyphIndex++) { | |
initialList.add(glyphIndex); | |
initialList.add(glyphIndex); | |
} | |
// Using the previous list, pick glyphs and populate the tiles | |
for(int index = 0; index < tiles.length; index++) { | |
var randomIndex = rand.nextInt(initialList.length); | |
var glyphId = initialList[randomIndex]; | |
var tile = new Tile(glyphManager.newGlyph(glyphId), glyphId) | |
// wonky math because of Dart's lack of 2D arrays | |
..x = (index % columns) * 100 | |
..y = (index / columns).floor() * 100 | |
..onMouseClick.listen((e) => updateSelected(index)) | |
..addTo(this); | |
tiles[index] = tile; | |
initialList.removeAt(randomIndex); | |
} | |
} | |
/// Updates the appearance of the currently selected tiles, where the [index] of the last selection is given. | |
void updateSelected(int index) { | |
// This check eliminates the cheat that my son found! | |
if(selected.contains(index) == false) { | |
selected.add(index); | |
tiles[index].flip(); | |
if(selected.length == 2) { | |
var tile1 = tiles[selected[0]]; | |
var tile2 = tiles[selected[1]]; | |
if(tile1.glyphId != tile2.glyphId) { | |
// Make the following part of a stream! | |
updateIncorrectGuesses(); | |
var delayedAction = new DelayedCall(() { | |
tile1.flip(); | |
tile2.flip(); | |
}, 1.0); | |
renderLoop.juggler.add(delayedAction); | |
} | |
else { | |
// Great place to use a stream! | |
// var gameWon = tiles.where((tile) => tile.isVisible).length == tiles.length - 1; | |
// if(gameWon) { | |
// playAgain(); | |
// } | |
} | |
selected = []; | |
} | |
} | |
} | |
/// Briefly shows what the puzzle will look like when solved. | |
void showSolved() { | |
for(int index = 0; index < tiles.length; index++) { | |
var delayedAction = new DelayedCall(() => tiles[index].flip(), 3.0); | |
renderLoop.juggler.add(delayedAction); | |
} | |
} | |
} | |
/// Main entry point | |
void main() { | |
setupStage(); | |
var resourceManager = new ResourceManager() | |
..addTextureAtlas("glyphs", "images/glyphAtlas.json", TextureAtlasFormat.JSONARRAY); | |
resourceManager.load().then((result) => startGame(resourceManager)); | |
} | |
/// General purpose method of getting the canvas, stage and render loop ready. | |
void setupStage() { | |
// setup the Stage and RenderLoop | |
var canvas = html.querySelector('#stage'); | |
stage = new Stage('myStage', canvas); | |
renderLoop = new RenderLoop(); | |
renderLoop.addStage(stage); | |
} | |
/// Kicks off the game with the given [ResourceManager] | |
void startGame(ResourceManager manager) { | |
var glyphManager = new GlyphManager(manager.getTextureAtlas("glyphs")); | |
html.querySelector("button") | |
..onClick.listen((e){ | |
if(stage.numChildren > 0) | |
stage.removeChildren(); | |
var grid = new Grid(glyphManager) | |
..addTo(stage); | |
grid.showSolved(); | |
html.querySelector("#incorrectGuesses").innerHtml="0"; | |
}); | |
} | |
/// Bumps the number of incorrect guesses shown on the screen up by 1. | |
void updateIncorrectGuesses() { | |
var incorrectGuesses = html.querySelector("#incorrectGuesses"); | |
incorrectGuesses.innerHtml = "${int.parse(incorrectGuesses.text) + 1}"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment