Its a puzzle game thats appeared recently and seems to have that certain something.
I figured its something I could write quite quickly…So I did.
This should work on mobiles or tablets as there is no sound. I also implemented rudimentary swipe logic.
Have fun.
<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <title>2048</title> <style> Body { background-color: #181818; color: #ffffff; margin: 0px; } Canvas { position:fixed; } #counter { position:absolute; bottom:0; right:0; color:#ffffff; display:none; } </style> </head> <body> <input id="focus" type="text" style="position:fixed; width:0px;height=0px;" /> <canvas id="myCanvas">Sorry... your browser does not support the canvas element.</canvas> <p id="counter">counter</p> </body> <script> // Global variables // used for calculating and showing the frames per second var dwFrames=0; var dwCurrentTime=0; var dwLastUpdateTime=0; var dwElapsedTime=0; var fpsText; // The game engine needs to persist var GE; var LAYER_TILE = 1; var LAYER_MENU = 1; var skipSplash = false; var currentStage; init = function() { var canvas = document.getElementById('myCanvas'); if (canvas.getContext) { // got to have the game engine GE = GameEngine16Colour(canvas,Update,Draw); if ( skipSplash ) currentStage = GameInitBackground(); else currentStage = Splash(GameData()); // when the window resizes we want to resize the canvas window.onresize = function() { doResize(); }; window.onmouseover = function () { getFocus(); }; doResize(); } } function getFocus() { var f = document.getElementById("focus"); f.focus(); } // This gets called every time the engine redraws the canvas // For slow machines this may be less that the actual fps Draw = function() { currentStage.Draw(); // calculate and show the fps dwFrames++; dwCurrentTime = (new Date).getTime(); dwElapsedTime = dwCurrentTime - dwLastUpdateTime; if(dwElapsedTime >= 1000) { fpsText = "FPS " + dwFrames; dwLastUpdateTime = dwCurrentTime; dwFrames = 0; } var l = document.getElementById('counter'); l.textContent = fpsText; } // This gets called every game update frame Update = function() { currentStage = currentStage.Update(); } // This just makes sure the canvas is as big as possible // given the window size and centered function doResize() { var canvas = document.getElementById('myCanvas'); var screenHeight = window.innerHeight; var screenWidth = window.innerWidth; var ratioX = GE.CanvasWidth / screenWidth; var ratioY = GE.CanvasHeight / screenHeight; var ratio = ratioX if ( ratioX < ratioY ) ratio = ratioY; var width = GE.CanvasWidth / ratio; var height = GE.CanvasHeight / ratio; canvas.style.height = height+"px"; canvas.style.width = width+"px"; canvas.style.marginLeft = (screenWidth-width)/2; canvas.style.marginTop = (screenHeight-height)/2; } // Splash screen stages function GameData() { var obj = {}; obj.score = 0; obj.hiscore = 0; return obj; } function SplashData() { var obj = {}; obj.finished = false; return obj; } function PlayData() { var obj = {}; obj.finished = false; obj.tilesMoved = false; obj.tileSet; obj.tileSetUndo; obj.scoreValue = 0; return obj; } function Splash(data) { var data = GameData(); var splashData = SplashData(); var obj = GameSatePattern(splashData); obj.AddInnerState( SplashStatic(splashData) ); obj.SetNextState(GameInitBackground(data)); obj.UpdateCustom = function() { if (splashData.finished) obj.SetFinished(); } return obj; } // the following are inner states for the splash function SplashStatic(data) { var obj = GameSatePattern(data); var countFrames = 0; obj.UpdateCustom = function() { countFrames++; if ( countFrames > 30*2 ) obj.SetFinished(); } obj.DrawCustom=function() { for ( var y = 0; y < GE.CanvasHeight; y++) { for ( var x = 0; x < GE.CanvasWidth; x++ ) { GE.DrawPixel(x,y,Math.floor(Math.random()*16)); } } } obj.SetNextState(SplashLogo(data)); return obj; } function SplashLogo(data) { var obj = GameSatePattern(data); var countFrames = 0; obj.Init = function () { data.finished = false; GE.DrawRect(0,0,GE.CanvasWidth, GE.CanvasHeight,0); GE.WriteStringCentered("QuietBloke Productions",GE.CanvasHeight/2-32-8,15,false,true); GE.WriteStringCentered("Presents",GE.CanvasHeight/2,15); GE.WriteStringCentered("2048",GE.CanvasHeight/2+32,15,false,true); } obj.UpdateCustom=function() { countFrames++; if ( countFrames > 30*3 ) { data.finished = true; } } obj.TearDown=function() { GE.DrawRect(0,0,GE.CanvasWidth, GE.CanvasHeight,0); } return obj; } function GameInitBackground(data) { var obj = GameSatePattern(data); obj.Init = function () { if (!data) data = GameData(); GE.DrawRect(18,18,50*4+4,50*4+4,8); // draw tiles for score and hi score var scoreXPos = 18+50*4+2+8; GE.DrawRect(scoreXPos,18+1,75,75-2,2); GE.DrawRect(scoreXPos+1,18,75-2,75,2); GE.DrawRect(scoreXPos,18+80+1,75,75-2,2); GE.DrawRect(scoreXPos+1,18+80,75-2,75,2); GE.WriteString("SCORE",scoreXPos + 16,18+4,14,false,true); GE.WriteString("HI-SCORE",scoreXPos + 5,98+4,14,false,true); // restart GE.DrawRect(scoreXPos,180+1,75,16-2,2); GE.DrawRect(scoreXPos+1,180,75-2,16,2); GE.WriteString("Undo",scoreXPos + 24,180+4,14,false,false); //redo GE.DrawRect(scoreXPos,205+1,75,16-2,2); GE.DrawRect(scoreXPos+1,205,75-2,16,2); GE.WriteString("Restart",scoreXPos + 12,205+4,14,false,false); obj.SetNextState(MainMenu(data)); obj.SetFinished(); } return obj; } function MainMenu(data) { var obj = GameSatePattern(data); obj.Init = function () { var menuBitmap = Bitmap(204,204); menuBitmap.DrawRect(0,0,menuBitmap.width, menuBitmap.height,7); menuBitmap.WriteStringCentered("2048",GE.CharSet(),4,0,true,true); var textColour = 0; menuBitmap.WriteString("Instructions",GE.CharSet(),4,30,textColour); menuBitmap.WriteString("============",GE.CharSet(),4,40,textColour); menuBitmap.WriteString("Slide tiles",GE.CharSet(),4,50,textColour); menuBitmap.WriteString("Combine same tiles",GE.CharSet(),4,60,textColour); menuBitmap.WriteString("Reach 2048",GE.CharSet(),4,70,textColour); menuBitmap.WriteString("Simple!",GE.CharSet(),4,80,textColour); menuBitmap.WriteString("Controls",GE.CharSet(),4,100,textColour); menuBitmap.WriteString("========",GE.CharSet(),4,110,textColour); menuBitmap.WriteString("Cursor keys",GE.CharSet(),4,120,textColour); menuBitmap.WriteString("Swipe",GE.CharSet(),4,130,textColour); menuBitmap.WriteStringCentered("Press Space, Tap or click",GE.CharSet(),160,textColour,false,true); menuBitmap.WriteStringCentered("to Begin",GE.CharSet(),180,textColour,false,true); var sp = Sprite(18, 18, menuBitmap ); GE.SpriteAdd("MainMenu", sp, LAYER_MENU); } obj.UpdateCustom=function() { if ( FirePressed() ) obj.SetFinished(); obj.SetNextState(Play(data)); } obj.TearDown = function() { GE.SpriteDelete("MainMenu"); } return obj; } function Play(data) { var obj = GameSatePattern(data); var playData = PlayData(); obj.AddInnerState(PlayInit(playData)); obj.Init=function() { data.score = 0; DisplayScore(data); obj.SetNextState(MainMenu(data)); } obj.UpdateCustom = function() { if ( playData.finished ) obj.SetFinished(); if ( playData.scoreValue != 0 ) { data.score += playData.scoreValue; playData.scoreValue = 0; if ( data.score > data.hiscore ) data.hiscore = data.score; DisplayScore(data); } } return obj; } // the following are inner states to the play state function PlayInit(data) { var obj = GameSatePattern(data); obj.Init=function() { obj.SetFinished(); obj.SetNextState(PlayNewGame(data)); } return obj; } var TILES_TOP = 20; var TILES_LEFT = 20; var TILE_SIZE = 50; function boardCell(x,y) { var obj = {}; obj.costumeIndex = 0; obj.merged = false; var sprite = Sprite(TILES_LEFT + TILE_SIZE * x, TILES_TOP + TILE_SIZE * y, CreateTilesCostume()); GE.SpriteAdd("Tile:"+x+"/"+y,sprite,1); obj.SetSprite=function(index) { sprite.SetAnimator([index]); sprite.pos.x = TILES_LEFT + TILE_SIZE * x; sprite.pos.y = TILES_TOP + TILE_SIZE * y; obj.costumeIndex = index; } return obj; } function PlayNewGame(data) { var obj = GameSatePattern(data); obj.Init = function() { data.scoreValue = 0; data.tilesMoved = false; data.tileSet = new Array(); for ( var y = 0; y < 4; y++ ) { var tileRow = new Array(); for ( var x=0; x < 4; x++ ) { tileRow.push(boardCell(x,y)); } data.tileSet.push(tileRow); } AddTile(data.tileSet) // Create the undo tileset as well data.tileSetUndo = new Array(); for ( var y = 0; y < 4; y++ ) { var tileRow = new Array(); for ( var x=0; x < 4; x++ ) { tileRow.push(data.tileSet[y][x].costumeIndex); } data.tileSetUndo.push(tileRow); } if ( GE.Tiltable()) GE.TiltCalibrate(); obj.SetNextState(PlayGame(data)); obj.SetFinished(); } function AddTile(tileSet) { var counter = Math.floor(Math.random()*16)+1; var xp=0; var yp=0; var available = 0; var found = false; for ( y = 0; y < 4; y++ ) { for ( x = 0; x < 4; x++ ) { if ( tileSet[y][x].costumeIndex == 0 ) available++; } } if (available == 0 ) return false; while (!found) { if ( tileSet[yp][xp].costumeIndex == 0 ) { counter--; if ( counter == 0 ) { found=true; break; } } xp++; if ( xp > 3 ) { xp=0; yp++; if ( yp > 3 ) yp = 0; } } tileSet[yp][xp].SetSprite(1); return true; } return obj; } function PlayGame(data) { var obj = GameSatePattern(data); var player; var shot; var aKeyPressed = true; var undoButton = Vector (18+50*4+2+8,180); var restartButton = Vector (18+50*4+2+8,205); // obj.AddInnerState(PlayerPlay(data.playerData)); function AddTile(tileSet) { var counter = Math.floor(Math.random()*16)+1; var xp=0; var yp=0; var available = 0; var found = false; for ( y = 0; y < 4; y++ ) { for ( x = 0; x < 4; x++ ) { if ( tileSet[y][x].costumeIndex == 0 ) available++; } } if (available == 0 ) return false; while (!found) { if ( tileSet[yp][xp].costumeIndex == 0 ) { counter--; if ( counter == 0 ) { found=true; break; } } xp++; if ( xp > 3 ) { xp=0; yp++; if ( yp > 3 ) yp = 0; } } tileSet[yp][xp].SetSprite(1); return true; } obj.Init=function() { if ( data.tilesMoved ) { if ( AddTile(data.tileSet)) { // if all tiles are onscreen var tileCount = 0; for ( var y =0; y < 4; y++ ) { for ( var x = 0; x < 4; x++ ) { if ( data.tileSet[y][x].costumeIndex != 0 ) tileCount++ } } if ( tileCount == 16 ) { // and no move is available var moveAvailable = false; for ( var y =0; y < 4; y++ ) { for ( var x = 0; x < 4; x++ ) { if ( y < 3 ) if ( data.tileSet[y][x].costumeIndex == data.tileSet[y+1][x].costumeIndex ) moveAvailable = true; if ( x < 3 ) if ( data.tileSet[y][x].costumeIndex == data.tileSet[y][x+1].costumeIndex ) moveAvailable = true; } } // then end the game if ( !moveAvailable ) { obj.SetNextState(PlayGameOver(data)); obj.SetFinished(); } } } } } var PRESSED_NONE = 0; var PRESSED_UP = 1; var PRESSED_DOWN = 2; var PRESSED_LEFT = 3; var PRESSED_RIGHT = 4; var PRESSED_UNDO = 5; var PRESSED_RESTART = 6; function Control() { if ( aKeyPressed ) { if ( !GE.GetKeyState(GE.KEY_UP) && !GE.GetKeyState(GE.KEY_DOWN) && !GE.GetKeyState(GE.KEY_LEFT) && !GE.GetKeyState(GE.KEY_RIGHT) && !GE.GetKeyState(GE.KEY_U) && !GE.GetKeyState(GE.KEY_R) ) aKeyPressed = false; } else { if ( GE.GetKeyState(GE.KEY_UP)) { aKeyPressed = true; return PRESSED_UP; } if ( GE.GetKeyState(GE.KEY_DOWN)) { aKeyPressed = true; return PRESSED_DOWN; } if ( GE.GetKeyState(GE.KEY_LEFT)) { aKeyPressed = true; return PRESSED_LEFT; } if ( GE.GetKeyState(GE.KEY_RIGHT)) { aKeyPressed = true; return PRESSED_RIGHT; } if ( GE.mouseUnclicked ) { var xdist = Math.abs(GE.mouseSwipe.x); var ydist = Math.abs(GE.mouseSwipe.y); if ( xdist > ydist ) { if ( GE.mouseSwipe.x < -20 ) return PRESSED_LEFT; if ( GE.mouseSwipe.x > 20 ) return PRESSED_RIGHT; } else { if ( GE.mouseSwipe.y < -20 ) return PRESSED_UP; if ( GE.mouseSwipe.y > 20 ) return PRESSED_DOWN; } } if ( GE.GetKeyState(GE.KEY_U ) ) { aKeyPressed = true; return PRESSED_UNDO; } if ( GE.GetKeyState(GE.KEY_R ) ) { aKeyPressed = true; return PRESSED_RESTART; } if ( GE.mouseClicked ) { if ( GE.mousePos.x >= undoButton.x && GE.mousePos.y >= undoButton.y && GE.mousePos.x <= undoButton.x+75 && GE.mousePos.y <= undoButton.y+20) { return PRESSED_UNDO; } if ( GE.mousePos.x >= restartButton.x && GE.mousePos.y >= restartButton.y && GE.mousePos.x <= restartButton.x+75 && GE.mousePos.y <= restartButton.y+20) { return PRESSED_RESTART; } } } return PRESSED_NONE; } obj.UpdateCustom=function() { var control = Control(); if ( control == PRESSED_NONE ) return; if ( control == PRESSED_UNDO ) { obj.SetNextState(PlayUndo(data)); obj.SetFinished(); return; } if ( control == PRESSED_RESTART ) { obj.SetFinished(); data.finished = true; return; } // take a copy of the tileset before we move for ( var y = 0; y < 4; y++ ) { for ( var x = 0; x < 4; x++ ) { data.tileSetUndo[y][x] = data.tileSet[y][x].costumeIndex; } } if ( control == PRESSED_UP) { obj.SetNextState(PlayRollUp(data)); obj.SetFinished(); } if ( control == PRESSED_DOWN) { obj.SetNextState(PlayRollDown(data)); obj.SetFinished(); } if ( control == PRESSED_LEFT) { obj.SetNextState(PlayRollLeft(data)); obj.SetFinished(); } if ( control == PRESSED_RIGHT) { obj.SetNextState(PlayRollRight(data)); obj.SetFinished(); } } return obj; } function PlayUndo(data) { var obj = GameSatePattern(data); obj.Init=function() { obj.SetNextState(PlayGame(data)); for ( var y = 0; y < 4; y++ ) { for ( var x = 0; x < 4; x++ ) { data.tileSet[y][x].SetSprite(data.tileSetUndo[y][x]); } } data.tilesMoved = false; } obj.UpdateCustom=function() { obj.SetFinished(); } return obj; } function PlayRollUp(data) { var obj = GameSatePattern(data); obj.Init=function() { obj.SetNextState(PlayGame(data)); for ( var y = 0; y < 4; y++ ) { for ( var x = 0; x < 4; x++ ) { data.tileSet[y][x].merged = false; } } data.tilesMoved = false; } obj.UpdateCustom=function() { var tileSet = data.tileSet; var tileMoved = false; for ( var x = 0; x < 4; x++ ) { for ( var y = 1; y < 4; y++ ) { if ( tileSet[y][x].costumeIndex != 0 && !tileSet[y][x].merged ) { if ( tileSet[y-1][x].costumeIndex == 0 ) { tileSet[y-1][x].SetSprite(tileSet[y][x].costumeIndex); tileSet[y][x].SetSprite(0); tileMoved = true; } else { if ( tileSet[y][x].costumeIndex == tileSet[y-1][x].costumeIndex ) { tileSet[y-1][x].SetSprite(tileSet[y][x].costumeIndex+1); tileSet[y][x].SetSprite(0); tileMoved = true; tileSet[y-1][x].merged = true; data.scoreValue += 1 << tileSet[y-1][x].costumeIndex; } } } } } if ( tileMoved ) data.tilesMoved = true; if ( !tileMoved ) obj.SetFinished(); } return obj; } function PlayRollDown(data) { var obj = GameSatePattern(data); obj.Init=function() { obj.SetNextState(PlayGame(data)); for ( var y = 0; y < 4; y++ ) { for ( var x = 0; x < 4; x++ ) { data.tileSet[y][x].merged = false; } } data.tilesMoved = false; } obj.UpdateCustom=function() { var tileSet = data.tileSet; var tileMoved = false; for ( var x = 0; x < 4; x++ ) { for ( var y = 2; y >= 0; y-- ) { if ( tileSet[y][x].costumeIndex != 0 && !tileSet[y][x].merged ) { if ( tileSet[y+1][x].costumeIndex == 0 ) { tileSet[y+1][x].SetSprite(tileSet[y][x].costumeIndex); tileSet[y][x].SetSprite(0); tileMoved = true; } else { if ( tileSet[y][x].costumeIndex == tileSet[y+1][x].costumeIndex ) { tileSet[y+1][x].SetSprite(tileSet[y][x].costumeIndex+1); tileSet[y][x].SetSprite(0); tileMoved = true; tileSet[y+1][x].merged = true; data.scoreValue += 1 << tileSet[y+1][x].costumeIndex; } } } } } if ( tileMoved ) data.tilesMoved = true; if ( !tileMoved ) obj.SetFinished(); } return obj; } function PlayRollLeft(data) { var obj = GameSatePattern(data); obj.Init=function() { obj.SetNextState(PlayGame(data)); for ( var x = 0; x < 4; x++ ) { for ( var y = 0; y < 4; y++ ) { data.tileSet[y][x].merged = false; } } data.tilesMoved = false; } obj.UpdateCustom=function() { var tileSet = data.tileSet; var tileMoved = false; for ( var y = 0; y < 4; y++ ) { for ( var x = 1; x < 4; x++ ) { if ( tileSet[y][x].costumeIndex != 0 && !tileSet[y][x].merged ) { if ( tileSet[y][x-1].costumeIndex == 0 ) { tileSet[y][x-1].SetSprite(tileSet[y][x].costumeIndex); tileSet[y][x].SetSprite(0); tileMoved = true; } else { if ( tileSet[y][x].costumeIndex == tileSet[y][x-1].costumeIndex ) { tileSet[y][x-1].SetSprite(tileSet[y][x].costumeIndex+1); tileSet[y][x].SetSprite(0); tileMoved = true; tileSet[y][x-1].merged = true; data.scoreValue += 1 << tileSet[y][x-1].costumeIndex; } } } } } if ( tileMoved ) data.tilesMoved = true; if ( !tileMoved ) obj.SetFinished(); } return obj; } function PlayRollRight(data) { var obj = GameSatePattern(data); obj.Init=function() { obj.SetNextState(PlayGame(data)); for ( var x = 0; x < 4; x++ ) { for ( var y = 0; y < 4; y++ ) { data.tileSet[y][x].merged = false; } } data.tilesMoved = false; } obj.UpdateCustom=function() { var tileSet = data.tileSet; var tileMoved = false; for ( var y = 0; y < 4; y++ ) { for ( var x = 2; x >= 0; x-- ) { if ( tileSet[y][x].costumeIndex != 0 && !tileSet[y][x].merged ) { if ( tileSet[y][x+1].costumeIndex == 0 ) { tileSet[y][x+1].SetSprite(tileSet[y][x].costumeIndex); tileSet[y][x].SetSprite(0); tileMoved = true; } else { if ( tileSet[y][x].costumeIndex == tileSet[y][x+1].costumeIndex ) { tileSet[y][x+1].SetSprite(tileSet[y][x].costumeIndex+1); tileSet[y][x].SetSprite(0); tileMoved = true; tileSet[y][x+1].merged = true; data.scoreValue += 1 << tileSet[y][x+1].costumeIndex; } } } } } if ( tileMoved ) data.tilesMoved = true; if ( !tileMoved ) obj.SetFinished(); } return obj; } function PlayGameOver(data) { var obj = GameSatePattern(data); var countFrames = 0; obj.Init = function () { var cs=Costume() var menuBitmap = Bitmap(8*10,16); menuBitmap.DrawRect(0,0,8*10,16,0); var blankBitmap = menuBitmap.Clone(); menuBitmap.WriteString("GAME OVER",GE.CharSet(),4,4,15); cs.SetItem(0,menuBitmap); cs.SetItem(1,blankBitmap); var sp = Sprite((GE.CanvasWidth-menuBitmap.width)/2, 32, cs ); sp.SetAnimatorLoop(); sp.SetAnimatorUpdateRate(.1); GE.SpriteAdd("GameOver", sp, LAYER_MENU); } obj.UpdateCustom=function() { countFrames++; if ( countFrames > 30*3 ) { obj.SetFinished(); data.finished = true; } } obj.TearDown = function() { GE.SpriteDelete("GameOver"); } return obj; } // helper functions function DisplayScore(data) { var scoreXPos = 18+50*4+2+8; var tmpStr = "00000" + data.score; tmpStr = tmpStr.substring(tmpStr.length-5); GE.DrawRect(scoreXPos + 16,18+4+30,5*8,16,2); GE.WriteString(tmpStr,scoreXPos + 16,18+4+30,15,false,true); tmpStr = "00000" + data.hiscore; tmpStr = tmpStr.substring(tmpStr.length-5); GE.DrawRect(scoreXPos + 16,98+4+30,5*8,16,2); GE.WriteString(tmpStr,scoreXPos + 16,98+4+30,15,false,true); } function CreateTilesCostume() { var cs=Costume(); var bm = Bitmap(48,48); cs.SetItem(0,bm); var scIndex = 1; for ( var shift=1; shift <13; shift++ ) { var num = 1 << shift; var bm = Bitmap(48,48); bm.DrawRect(2,0,44,48,(scIndex & 7)+1); bm.DrawRect(0,2,48,44,(scIndex & 7)+1); bm.WriteStringCentered(""+num,GE.CharSet(),18,15,false,true); cs.SetItem(scIndex,bm); scIndex++; } return cs; } // Handle various ways to press fire var firePressed = false; var spacekeyDown = false; function FirePressed () { if (GE.mouseClicked ) return true; if ( GE.GetKeyState(GE.KEY_SPACE)) { if ( !spacekeyDown ) { spacekeyDown = true; return true; } } else { spacekeyDown = false; } return false; } GameEngine16Colour = function(canvasIn,updateFunction,drawFunction) { "use strict"; var obj = {}; var useWebFont = false; if ( typeof(updateFunction) != "function" ) updateFunction = function(){}; if ( typeof(drawFunction) != "function" ) drawFunction = function(){}; var CANVAS_WIDTH = 320; //320; var CANVAS_HEIGHT = 240; // 240; var FPS = 30; var updateRate = Math.floor(1000 / FPS); var canvas = canvasIn; var colours = new Array(); var charSet = {}; obj.mousePos = new Vector(); obj.mouseClicked = false; obj.mouseTouchFire = false; obj.mouseUnclicked = false; obj.mouseDown = false; obj.CanvasWidth = CANVAS_WIDTH; obj.CanvasHeight = CANVAS_HEIGHT; canvas.width = CANVAS_WIDTH; canvas.height = CANVAS_HEIGHT; obj.sprites = new Array(); // key = spritename, value = layer obj.layers = new Array(); // key = spritename, value = sprite obj.collisionRules = new Array(); var ctx = null; if(canvas.getContext ) { ctx = canvas.getContext('2d'); } if (ctx === null ) { return null; } var screenImageData = ctx.getImageData(0,0,CANVAS_WIDTH,CANVAS_HEIGHT); for ( var pixel = 0; pixel < CANVAS_WIDTH*CANVAS_HEIGHT; pixel+=1) { screenImageData.data[pixel*4+3] = 255; } var screenBitmap = Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); screenBitmap.DrawRect(0,0,CANVAS_WIDTH,CANVAS_HEIGHT,0); var tempScreenBitmap= Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); var prevScreenBitmap= Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); function InitColours() { colours[0] = Colour(0,0,0); colours[1] = Colour(128,0,0); colours[2] = Colour(0,128,0); colours[3] = Colour(0,0,128); colours[4] = Colour(128,128,0); colours[5] = Colour(128,0,128); colours[6] = Colour(0,128,128); colours[7] = Colour(128,128,128); colours[8] = Colour(64,64,64); colours[9] = Colour(255,0,0); colours[10] = Colour(0,255,0); colours[11] = Colour(0,0,255); colours[12] = Colour(255,255,0); colours[13] = Colour(255,0,255); colours[14] = Colour(0,255,255); colours[15] = Colour(255,255,255); // experimental colours // mid black and dark primary colours[16] = TertiaryMix(colours[7],colours[7],32); colours[17] = TertiaryMix(colours[1],colours[1],64); colours[18] = TertiaryMix(colours[2],colours[2],64); colours[19] = TertiaryMix(colours[3],colours[3],64); // secondary colours[20] = TertiaryMix(colours[4],colours[4],64); colours[21] = TertiaryMix(colours[5],colours[5],64); colours[22] = TertiaryMix(colours[6],colours[6],64); // tertiary colours colours[23] = TertiaryMix(colours[1],colours[4],128); colours[24] = TertiaryMix(colours[1],colours[5],128); // colours[18] = TertiaryMix(colours[1],colours[6],128); colours[25] = TertiaryMix(colours[2],colours[4],128); // colours[20] = TertiaryMix(colours[2],colours[5],128); colours[26] = TertiaryMix(colours[2],colours[6],128); // colours[22] = TertiaryMix(colours[3],colours[4],128); colours[27] = TertiaryMix(colours[3],colours[5],128); colours[28] = TertiaryMix(colours[3],colours[6],128); colours[29] = TertiaryMix(colours[4],colours[5],128); colours[30] = TertiaryMix(colours[4],colours[6],128); // colours[28] = TertiaryMix(colours[5],colours[4],128); // colours[29] = TertiaryMix(colours[5],colours[6],128); // colours[30] = TertiaryMix(colours[6],colours[4],128); colours[31] = TertiaryMix(colours[6],colours[5],128); // bright colours[32] = TertiaryMix(colours[15],colours[15],192); colours[33] = TertiaryMix(colours[9],colours[9],192); colours[34] = TertiaryMix(colours[10],colours[10],192); colours[35] = TertiaryMix(colours[11],colours[11],192); // secondary colours[36] = TertiaryMix(colours[12],colours[12],192); colours[37] = TertiaryMix(colours[13],colours[13],192); colours[38] = TertiaryMix(colours[14],colours[14],192); // colours[31] = TertiaryMix(colours[7],colours[7],96); colours[39] = TertiaryMix(colours[9],colours[12],255); colours[40] = TertiaryMix(colours[9],colours[13],255); // colours[34] = TertiaryMix(colours[9],colours[14],255); colours[41] = TertiaryMix(colours[10],colours[12],255); // colours[36] = TertiaryMix(colours[10],colours[13],255); colours[42] = TertiaryMix(colours[10],colours[14],255); // colours[38] = TertiaryMix(colours[11],colours[12],255); colours[43] = TertiaryMix(colours[11],colours[13],255); colours[44] = TertiaryMix(colours[11],colours[14],255); colours[45] = TertiaryMix(colours[12],colours[13],255); colours[46] = TertiaryMix(colours[12],colours[14],255); // colours[44] = TertiaryMix(colours[13],colours[12],255); // colours[45] = TertiaryMix(colours[13],colours[14],255); // colours[46] = TertiaryMix(colours[14],colours[12],255); colours[47] = TertiaryMix(colours[14],colours[13],255); // colours[47] = TertiaryMix(colours[15],colours[15],192); function TertiaryMix (col1,col2,maxValue) { var red = col1.red + col2.red; var green = col1.green + col2.green; var blue = col1.blue + col2.blue; var br = red; if(green > br) br = green; if(blue > br) br = blue; red = Math.floor(red / br * maxValue); green = Math.floor(green / br * maxValue); blue = Math.floor(blue / br * maxValue); return Colour(red,green,blue); } } InitColours(); function InitCharSet() { charSet = CharSet(8,8); for ( var charVal = 32; charVal < 128; charVal++) { var charArray = new Array(); var character = String.fromCharCode(charVal); ctx.fillStyle = "#000000"; ctx.fillRect(0,0,10,10); ctx.font = "7px lucida console"; // ctx.font = "14px impact"; ctx.fillStyle = "#FFFFFF"; ctx.font = "Bold 9px monospace"; // ctx.font = "Normal 9px Arial"; ctx.fillText(character,0,7); var lineZeroBlank = true; for ( var y = 0; y < 10; y++) { var charLine = ""; for ( var x = 0; x < 8; x++) { var p = ctx.getImageData(x, y, 2, 2).data; if ( p[0] > 125 ) charLine += "*"; else charLine += " "; } charArray.push(charLine); // if ( y == 0 && charLine != " ") // lineZeroBlank = false; if ( y == 8 && charLine != " ") { var tmp = new Array(); for ( var l = 1; l < 9; l++) tmp.push(charArray[l]); charArray = tmp; } } charSet.SetChar(character,charArray); } if ( !useWebFont ) { charSet.SetChar("!",[ " * ", " * ", " * ", " * ", " * ", " ", " * ", " "]); charSet.SetChar("?",[ " ***** ", "* * ", " ** ", " * ", " * ", " ", " * ", " "]); charSet.SetChar("\\",[ "* ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("\"",[ " * * ", " * * ", " ", " ", " ", " ", " ", " "]); charSet.SetChar("#",[ " * * ", "******* ", " * * ", " * * ", " * * ", "******* ", " * * ", " "]); charSet.SetChar("$",[ " * ", " ***** ", "* * ", " ***** ", " * * ", " ***** ", " * ", " "]); charSet.SetChar("%",[ " * * ", "* * * ", " * * ", " * ", " * * ", " * * * ", "* * ", " "]); charSet.SetChar("&",[ " *** ", " * * ", " * * ", " ** ", " * * ", "* * ", " **** * ", " "]); charSet.SetChar("'",[ " * ", " * ", " ", " ", " ", " ", " ", " "]); charSet.SetChar("(",[ " * ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar(")",[ " * ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("*",[ " ", "* * ", " * * ", " * ", " * * ", "* * ", " ", " "]); charSet.SetChar("+",[ " ", " * ", " * ", " ***** ", " * ", " * ", " ", " "]); charSet.SetChar(",",[ " ", " ", " ", " ", " ", " * ", " * ", " * "]); charSet.SetChar("-",[ " ", " ", " ", " ***** ", " ", " ", " ", " "]); charSet.SetChar(".",[ " ", " ", " ", " ", " ", " ", " * ", " "]); charSet.SetChar("/",[ " * ", " * ", " * ", " * ", " * ", " * ", "* ", " "]); charSet.SetChar("0",[ " ***** ", "* * ", "* * * ", "* * *", "* * * ", "* * ", " ***** ", " "]); charSet.SetChar("1",[ " * ", " ** ", " * ", " * ", " * ", " * ", " *** ", " "]); charSet.SetChar("2",[ " ***** ", "* * ", " * ", " * ", " ** ", " * ", "******* ", " "]); charSet.SetChar("3",[ " ***** ", "* * ", " * ", " **** ", " * ", "* * ", " ***** ", " "]); charSet.SetChar("4",[ " * ", " * ", " * ", " * * ", " ****** ", " * ", " * ", " "]); charSet.SetChar("5",[ "******* ", "* ", "* ", "****** ", " * ", "* * ", " ***** ", " "]); charSet.SetChar("6",[ " ***** ", "* * ", "* ", "****** ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("7",[ "******* ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("8",[ " ***** ", "* * ", "* * ", " ***** ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("9",[ " ***** ", "* * ", "* * ", " ****** ", " * ", "* * ", " ***** ", " "]); charSet.SetChar(":",[ " ", " ", " * ", " ", " * ", " ", " ", " "]); charSet.SetChar(";",[ " ", " ", " * ", " ", " * ", " * ", " ", " "]); charSet.SetChar("<",[ " ", " ** ", " ** ", " * ", " ** ", " ** ", " ", " "]); charSet.SetChar("=",[ " ", " ", " ***** ", " ", " ***** ", " ", " ", " "]); charSet.SetChar(">",[ " ", " ** ", " ** ", " * ", " ** ", " ** ", " ", " "]); charSet.SetChar("A",[ " ***** ", "* * ", "* * ", "******* ", "* * ", "* * ", "* * ", " "]); charSet.SetChar("B",[ "****** ", "* * ", "* * ", "******* ", "* * ", "* * ", "****** ", " "]); charSet.SetChar("C",[ " ***** ", "* * ", "* ", "* ", "* ", "* * ", " ***** ", " "]); charSet.SetChar("D",[ "****** ", "* * ", "* * ", "* * ", "* * ", "* * ", "****** ", " "]); charSet.SetChar("E",[ "******* ", "* ", "* ", "***** ", "* ", "* ", "******* ", " "]); charSet.SetChar("F",[ "******* ", "* ", "* ", "***** ", "* ", "* ", "* ", " "]); charSet.SetChar("G",[ " ***** ", "* * ", "* ", "* **** ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("H",[ "* * ", "* * ", "* * ", "******* ", "* * ", "* * ", "* * ", " "]); charSet.SetChar("I",[ " *** ", " * ", " * ", " * ", " * ", " * ", " *** ", " "]); charSet.SetChar("J",[ "******* ", " * ", " * ", " * ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("K",[ "* * ", "* ** ", "* ** ", "** ", "* ** ", "* ** ", "* * ", " "]); charSet.SetChar("L",[ "* ", "* ", "* ", "* ", "* ", "* ", "******* ", " "]); charSet.SetChar("M",[ "* * ", "** ** ", "* * * * ", "* * * ", "* * ", "* * ", "* * ", " "]); charSet.SetChar("N",[ "* * ", "** * ", "* * * ", "* * * ", "* * * ", "* ** ", "* * ", " "]); charSet.SetChar("O",[ " ***** ", "* * ", "* * ", "* * ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("P",[ " ***** ", "* * ", "* * ", "****** ", "* ", "* ", "* ", " "]); charSet.SetChar("Q",[ " ***** ", "* * ", "* * ", "* * ", "* * * ", "** * ", " **** * ", " "]); charSet.SetChar("R",[ "****** ", "* * ", "* * ", "****** ", "* * ", "* * ", "* * ", " "]); charSet.SetChar("S",[ " ***** ", "* * ", "* ", " ***** ", " * ", "* * ", " ***** ", " "]); charSet.SetChar("T",[ "******* ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("U",[ "* * ", "* * ", "* * ", "* * ", "* * ", "* * ", "* * ", " ****** "]); charSet.SetChar("V",[ "* * ", "* * ", " * * ", " * * ", " * * ", " * * ", " * ", " "]); charSet.SetChar("W",[ "* * ", "* * ", "* * ", "* * ", "* * * ", "* * * * ", "** ** ", " "]); charSet.SetChar("X",[ "* * ", " * * ", " * * ", " * ", " * * ", " * * ", "* * ", " "]); charSet.SetChar("Y",[ "* * ", " * * ", " * * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("Z",[ "******* ", " * ", " * ", " * ", " * ", " * ", "******* ", " "]); // [\]^_`abcdefg.....z{|}~ charSet.SetChar("[",[ " *** ", " * ", " * ", " * ", " * ", " * ", " *** ", " "]); charSet.SetChar("\\",[ "* ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("]",[ " *** ", " * ", " * ", " * ", " * ", " * ", " *** ", " "]); charSet.SetChar("^",[ " * ", " * * ", " * * ", " ", " ", " ", " ", " "]); charSet.SetChar("_",[ " ", " ", " ", " ", " ", " ", " ", "********"]); charSet.SetChar("`",[ " * ", " * ", " ", " ", " ", " ", " ", " "]); charSet.SetChar("a",[ " ", " ", " **** ", " * ", " ***** ", "* * ", " **** * ", " "]); charSet.SetChar("b",[ "* ", "* ", "***** ", "* * ", "* * ", "* * ", "***** ", " "]); charSet.SetChar("c",[ " ", " ", " **** ", "* ", "* ", "* ", " **** ", " "]); charSet.SetChar("d",[ " * ", " * ", " ***** ", "* * ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("e",[ " ", " ", " **** ", "* * ", "****** ", "* ", " **** ", " "]); charSet.SetChar("f",[ " *** ", " * ", " * ", "**** ", " * ", " * ", " * ", " "]); charSet.SetChar("g",[ " ", " ", " **** ", "* * ", "* * ", " ***** ", " * ", " **** "]); charSet.SetChar("h",[ "* ", "* ", "* ", "***** ", "* * ", "* * ", "* * ", " "]); charSet.SetChar("i",[ " ", " * ", " ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("j",[ " ", " * ", " ", " ** ", " * ", " * ", " * ", " **** "]); charSet.SetChar("k",[ "* ", "* ", "* * ", "* * ", "*** ", "* * ", "* * ", " "]); charSet.SetChar("l",[ "* ", "* ", "* ", "* ", "* ", "* ", " *** ", " "]); charSet.SetChar("m",[ " ", " ", "*** ** ", "* * * ", "* * * ", "* * * ", "* * * ", " "]); charSet.SetChar("n",[ " ", " ", "***** ", "* * ", "* * ", "* * ", "* * ", " "]); charSet.SetChar("o",[ " ", " ", " **** ", "* * ", "* * ", "* * ", " **** ", " "]); charSet.SetChar("p",[ " ", " ", "***** ", "* * ", "* * ", "***** ", "* ", "* "]); charSet.SetChar("q",[ " ", " ", " ***** ", "* * ", "* * ", " ***** ", " * ", " * "]); charSet.SetChar("r",[ " ", " ", " **** ", "* ", "* ", "* ", "* ", " "]); charSet.SetChar("s",[ " ", " ", " **** ", "* ", " **** ", " * ", " **** ", " "]); charSet.SetChar("t",[ " ", " * ", "*** ", " * ", " * ", " * ", " *** ", " "]); charSet.SetChar("u",[ " ", " ", "* * ", "* * ", "* * ", "* * ", " ***** ", " "]); charSet.SetChar("v",[ " ", " ", "* * ", "* * ", " * * ", " * * ", " ** ", " "]); charSet.SetChar("w",[ " ", " ", "* * * ", "* * * ", "* * * ", "* * * ", " ** ** ", " "]); charSet.SetChar("x",[ " ", " ", "* * ", " * * ", " ** ", " * * ", "* * ", " "]); charSet.SetChar("y",[ " ", " ", "* * ", "* * ", "* * ", " ***** ", " * ", " **** "]); charSet.SetChar("z",[ " ", " ", "***** ", " * ", " * ", " * ", "***** ", " "]); charSet.SetChar("{",[ " * ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("|",[ " * ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("}",[ " * ", " * ", " * ", " * ", " * ", " * ", " * ", " "]); charSet.SetChar("~",[ " ", " ", " * ", " ***** ", "* ", " ", " ", " "]); } } obj.CharSet = function() { return charSet; } InitCharSet(); var dwCurrentTime=0; var dwLastUpdateTime=(new Date).getTime(); var dwTimeCarriedOver = 0; var dwElapsedTime=0; obj.Main = function() { dwCurrentTime = (new Date).getTime(); dwElapsedTime = dwCurrentTime - dwLastUpdateTime + dwTimeCarriedOver; if(dwElapsedTime >= updateRate) { drawFunction(); obj.Draw(); var frames = Math.floor(dwElapsedTime / updateRate ); dwTimeCarriedOver = dwElapsedTime % updateRate; dwLastUpdateTime = dwCurrentTime; for ( var f = 0; f < frames; f++) { updateFunction(); obj.Update(); obj.mouseClicked = false; obj.mouseUnclicked = false; obj.mouseTouchFire = false; obj.mouseSwipe.x = 0; obj.mouseSwipe.y = 0; obj.CheckCollisions(); } } } var timer = Timer(FPS, obj.Main); obj.Stop = function() { timer.Stop(); } obj.writeToCanvas = function(bitmap) { var sourceArray = bitmap.GetPixelArray(); var prevArray = prevScreenBitmap.GetPixelArray(); var offset = 0; for ( var p = 0; p < sourceArray.length; p++ ) { if ( sourceArray[p] != prevArray[p]) { prevArray[p] = sourceArray[p]; var colour = colours[sourceArray[p]]; screenImageData.data[offset] = colour.red; screenImageData.data[offset+1] = colour.green; screenImageData.data[offset+2] = colour.blue; } // else // { // screenImageData.data[offset] = 0; // screenImageData.data[offset+1] = 0; // screenImageData.data[offset+2] = 0; // } offset+=4; } ctx.putImageData(screenImageData,0,0); } obj.Update = function() { for ( var l in obj.layers ) { var currentLayer = obj.layers[l]; for ( var i in currentLayer ) { var s = currentLayer[i]; if ( s ) { s.Update(tempScreenBitmap.width, tempScreenBitmap.height); if( s.died ) SpriteDeleteForReal(s.name); } } } } obj.CustomResolution=function(width, height) { CANVAS_WIDTH = width; CANVAS_HEIGHT = height; obj.CanvasWidth = CANVAS_WIDTH; obj.CanvasHeight = CANVAS_HEIGHT; canvas.width = CANVAS_WIDTH; canvas.height = CANVAS_HEIGHT; screenImageData = ctx.getImageData(0,0,CANVAS_WIDTH,CANVAS_HEIGHT); for ( var pixel = 0; pixel < CANVAS_WIDTH*CANVAS_HEIGHT; pixel+=1) { screenImageData.data[pixel*4+3] = 255; } screenBitmap = Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); screenBitmap.DrawRect(0,0,CANVAS_WIDTH,CANVAS_HEIGHT,0); tempScreenBitmap= Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); prevScreenBitmap= Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); } obj.PortraitMode = function() { if (CANVAS_WIDTH > CANVAS_HEIGHT ) { var tmp = CANVAS_WIDTH; CANVAS_WIDTH = CANVAS_HEIGHT; CANVAS_HEIGHT = tmp; obj.CanvasWidth = CANVAS_WIDTH; obj.CanvasHeight = CANVAS_HEIGHT; canvas.width = CANVAS_WIDTH; canvas.height = CANVAS_HEIGHT; screenImageData = ctx.getImageData(0,0,CANVAS_WIDTH,CANVAS_HEIGHT); for ( var pixel = 0; pixel < CANVAS_WIDTH*CANVAS_HEIGHT; pixel+=1) { screenImageData.data[pixel*4+3] = 255; } screenBitmap = Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); screenBitmap.DrawRect(0,0,CANVAS_WIDTH,CANVAS_HEIGHT,0); tempScreenBitmap= Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); prevScreenBitmap= Bitmap(CANVAS_WIDTH,CANVAS_HEIGHT); } } obj.CheckCollisions = function() { for ( var r in obj.collisionRules ) { var currentLayer = obj.layers[r]; CheckCollisionsForLayer(currentLayer, obj.collisionRules[r]); } } function CheckCollisionsForLayer(layer, collisionRule) { for ( var spritePos in layer ) { var sprite = layer[spritePos]; if ( sprite ) { sprite.collided = false; for ( var targetLayer in collisionRule) { CheckSpriteCollisionWithLayer(sprite, obj.layers[targetLayer]); } } } } function CheckSpriteCollisionWithLayer(sprite, layer) { if ( layer ) { for ( var spritePos in layer ) { var targetSprite = layer[spritePos]; if( sprite.IsCollidedWith(targetSprite.name)) { sprite.collided = true; targetSprite.collided = true; } } } } obj.CountSpritesInLayer=function(layerName) { var count = 0; var layer = obj.layers[layerName]; for ( var spritePos in layer ) { var sprite = layer[spritePos]; if ( sprite ) { count++; } } return count; } obj.Draw = function() { // copy the screenBitmap and place all the sprites on it // Cloning has been replaced with a permanent temp bitmap and // contents just copied over. This seems to yield significant // speed improvement in chrome. // var bitmap = screenBitmap.Clone(); var size = screenBitmap.width * screenBitmap.height; var targetArray = tempScreenBitmap.GetPixelArray(); var sourceArray = screenBitmap.GetPixelArray(); for ( var p = 0; p < size; p++) { targetArray[p] = sourceArray[p]; } for ( var l in obj.layers ) { var currentLayer = obj.layers[l]; for ( var i in currentLayer ) { var spr = currentLayer[i]; if ( spr ) tempScreenBitmap.Paste(spr.pos.x,spr.pos.y, spr.bitmap ) // bitmap.Paste(s.pos.x,s.pos.y, s.bitmap ) } } obj.writeToCanvas(tempScreenBitmap); // obj.writeToCanvas(bitmap); } obj.DrawPixel = function(pixelX, pixelY,colour) { screenBitmap.SetPixel(Math.floor(pixelX),Math.floor(pixelY),colour); } obj.Clear = function(colour) { screenBitmap.Clear(colour); } obj.DrawLine = function(startX, startY, endX, endY, colour) { screenBitmap.DrawLine(startX, startY, endX, endY, colour) } obj.DrawRect = function(xPos,yPos,width,height,colour) { screenBitmap.DrawRect(xPos, yPos, width, height, colour) } obj.DrawCircle = function(xPos,yPos,radius,colour) { screenBitmap.DrawCircle(xPos,yPos,radius,colour) } obj.Scroll = function(xMovement,yMovement) { screenBitmap.Scroll(xMovement,yMovement); } obj.FlipX = function() { screenBitmap = screenBitmap.FlipX(); } obj.FlipY = function() { screenBitmap = screenBitmap.FlipY(); } obj.Paste = function(xPos,yPos,bitmap) { screenBitmap.Paste(xPos,yPos,bitmap); } obj.DefineColour = function(colour,r,g,b) { colours[colour] = Colour(r,g,b); } function CleanUpArray(arrayObj) { var returnArray = new Array(); for ( var i in arrayObj) { if ( arrayObj[i] != null ) { returnArray[i] = arrayObj[i]; } } return returnArray; } function CountItemsInArray(arrayObj) { var count = 0; for ( var i in arrayObj ) { count++; } return count; } obj.SpriteAdd = function(name,sprite, layer) { obj.SpriteDelete(name); obj.sprites[name] = layer; if (obj.layers[layer] == null ) { obj.layers[layer] = new Array(); } var newLayer = obj.layers[layer]; newLayer[name] = sprite; sprite.name = name; } function SpriteDeleteForReal(name) { var spriteLayer = obj.sprites[name]; if ( spriteLayer ) { obj.layers[spriteLayer][name] = null; obj.layers[spriteLayer] = CleanUpArray(obj.layers[spriteLayer]); if ( CountItemsInArray(obj.layers[spriteLayer]) == 0 ) { obj.layers[spriteLayer] = null; obj.layers = CleanUpArray(obj.layers); } obj.sprites[name] = null; obj.sprites = CleanUpArray(obj.sprites); } } obj.SpriteDelete=function(name) { var spriteLayer = obj.sprites[name]; if ( spriteLayer ) { if ( obj.layers[spriteLayer] ) obj.layers[spriteLayer][name].died = true; } } obj.DeleteSpritesInLayer=function(spriteLayer) { if ( spriteLayer ) { if ( obj.layers[spriteLayer] ) { for ( var i in obj.layers[spriteLayer] ) { obj.layers[spriteLayer][i].died = true; } } } } // obj.GetSpritesInLayer = function(spriteLayer) // { // if ( spriteLayer ) // { // if ( obj.layers[spriteLayer] ) // { // return obj.layers[spriteLayer] // } // } // return null; // } /* obj.WriteChar = function(char, charset, xPos,yPos,colour) { screenBitmap.WriteChar(char, charset, xPos,yPos,colour); } obj.WriteString = function(text,charset, xPos,yPos,colour) { screenBitmap.WriteString(text,charset, xPos,yPos,colour); } */ obj.SpriteGet = function(name) { var spriteLayer = obj.layers[obj.sprites[name]]; if ( spriteLayer ) return spriteLayer[name]; return null; } obj.CollisionRuleAdd = function(sourceLayer, targetLayer) { if ( obj.collisionRules[sourceLayer] == null ) { obj.collisionRules[sourceLayer] = new Array(); } if (obj.collisionRules[sourceLayer][targetLayer] == null ) { obj.collisionRules[sourceLayer][targetLayer] = targetLayer; } } obj.CollisionRuleDelete = function(sourceLayer, targetLayer) { if ( obj.collisionRules[sourceLayer] ) { if ( obj.collisionRules[sourceLayer][targetLayer] ) { obj.collisionRules[sourceLayer][targetLayer] = null; obj.collisionRules[sourceLayer] = CleanUpArray(obj.collisionRules[sourceLayer]); } if ( CountItemsInArray(obj.collisionRules[sourceLayer]) == 0 ) { obj.collisionRules[sourceLayer] = null; obj.collisionRules = CleanUpArray(obj.collisionRules); } } } obj.WriteChar = function(char,xPos,yPos,colour,xbig,ybig) { charSet.WriteChar(char,screenBitmap,xPos,yPos,colour,xbig,ybig) } obj.WriteString = function(text,xPos,yPos,colour,xbig,ybig) { charSet.WriteString(text,screenBitmap,xPos,yPos,colour,xbig,ybig) } obj.WriteStringCentered=function(text,yPos,colour,xbig,ybig) { screenBitmap.WriteStringCentered(text,charSet, yPos,colour,xbig,ybig); } var mouseDownPos = Vector(0,0); var mouseUpPos = Vector(0,0); obj.mouseSwipe = Vector(0,0); function SetMousePos(xp,yp) { var bbox = canvas.getBoundingClientRect(); obj.mousePos.x = (xp - bbox.left) * ( canvas.width / bbox.width); obj.mousePos.y = (yp - bbox.top) * ( canvas.height / bbox.height); } canvas.addEventListener("mousemove", function(evt){ SetMousePos(evt.clientX,evt.clientY); evt.preventDefault(); }); canvas.addEventListener("touchmove", function(evt){ SetMousePos(evt.targetTouches[0].pageX,evt.targetTouches[0].pageY); evt.preventDefault(); }); canvas.addEventListener("mousedown", function(evt){ obj.mouseClicked = true; obj.mouseDown = true; mouseDownPos.x = obj.mousePos.x; mouseDownPos.y = obj.mousePos.y; evt.preventDefault(); }); canvas.addEventListener("touchstart", function(evt){ SetMousePos(evt.targetTouches[0].pageX,evt.targetTouches[0].pageY); obj.mouseClicked = true; obj.mouseDown = true; mouseDownPos.x = obj.mousePos.x; mouseDownPos.y = obj.mousePos.y; if ( evt.targetTouches > 1 ) obj.mouseTouchFire = true; evt.preventDefault(); }); canvas.addEventListener("mouseup", function(evt){ obj.mouseDown = false; obj.mouseUnclicked = true; mouseUpPos.x = obj.mousePos.x; mouseUpPos.y = obj.mousePos.y; obj.mouseSwipe.x = mouseUpPos.x - mouseDownPos.x; obj.mouseSwipe.y = mouseUpPos.y - mouseDownPos.y; evt.preventDefault(); }); canvas.addEventListener("touchend", function(evt){ obj.mouseDown = false; obj.mouseUnclicked = true; mouseUpPos.x = obj.mousePos.x; mouseUpPos.y = obj.mousePos.y; obj.mouseSwipe.x = mouseUpPos.x - mouseDownPos.x; obj.mouseSwipe.y = mouseUpPos.y - mouseDownPos.y; evt.preventDefault(); }); var tiltable = false; obj.tiltX = null; obj.tiltY = null; obj.tiltZ = null; var tiltXBase = 0; var tiltYBase = 0; var tiltZBase = 0; obj.Tilt=function(values) { obj.tiltX = values[0]; obj.tiltY = values[1]; obj.tiltZ = values[2]; if ( tiltable == false && obj.tiltX != null ) { tiltable = true; obj.TiltCalibrate(); } } obj.TiltCalibrate = function() { tiltXBase = obj.tiltX; tiltYBase = obj.tiltY; tiltZBase = obj.tiltZ; } obj.Tiltable = function() { return tiltable; } obj.GetTiltX=function() { var upsidedown = 1; if(obj.tiltZ > 0 ) upsidedown = -1; if ( window.innerWidth < window.innerHeight ) return (obj.tiltX-tiltXBase); else return ( obj.tiltY - tiltYBase )*upsidedown; } // Tilt events if (window.DeviceOrientationEvent) { window.addEventListener("deviceorientation", function () { obj.Tilt([event.gamma,event.beta, event.gamma]); }, true); } // keyboard handler var keycodes = []; obj.GetKeyState=function(keycode) { return keycodes[keycode]; } document.addEventListener("keydown", function(evt){ keycodes[evt.keyCode] = true; }); document.addEventListener("keyup", function(evt){ keycodes[evt.keyCode] = false; }); obj.KEY_ENTER = 13; obj.KEY_ESCAPE = 27; obj.KEY_SPACE = 32; obj.KEY_LEFT = 37; obj.KEY_UP = 38; obj.KEY_RIGHT = 39; obj.KEY_DOWN = 40; obj.KEY_0 = 48; obj.KEY_1 = 49; obj.KEY_2 = 50; obj.KEY_3 = 51; obj.KEY_4 = 52; obj.KEY_5 = 53; obj.KEY_6 = 54; obj.KEY_7 = 55; obj.KEY_8 = 56; obj.KEY_9 = 57; obj.KEY_A = 65; obj.KEY_B = 66; obj.KEY_C = 67; obj.KEY_D = 68; obj.KEY_E = 69; obj.KEY_F = 70; obj.KEY_G = 71; obj.KEY_H = 72; obj.KEY_I = 73; obj.KEY_J = 74; obj.KEY_K = 75; obj.KEY_L = 76; obj.KEY_M = 77; obj.KEY_N = 78; obj.KEY_O = 79; obj.KEY_P = 80; obj.KEY_Q = 81; obj.KEY_R = 82; obj.KEY_S = 83; obj.KEY_T = 84; obj.KEY_U = 85; obj.KEY_V = 86; obj.KEY_W = 87; obj.KEY_X = 88; obj.KEY_Y = 89; obj.KEY_Z = 90; return obj; } Timer = function(fps,callFunction) { var obj = {} var fps = fps; var callFunction = callFunction var timerId = setInterval ( callFunction, Math.floor(1000/fps)); obj.Stop = function() { clearInterval(timerId); } return obj; } Colour = function(red,green,blue) { obj = {} obj.red = red; obj.green = green; obj.blue = blue; return obj; } var BaseBitmap = {}; Bitmap = function(width,height) { var obj = Object.create(BaseBitmap); obj.width = width; obj.height = height; var pixels = new Array() var scrollXFraction = 0.0; var scrollYFraction = 0.0; obj.GetPixelArray = function () { return pixels; } obj.SetPixelArray = function (newArray) { pixels = newArray; } obj.GetPixel = function (xpos, ypos) { if (xpos >= 0 && xpos < obj.width && ypos >= 0 && ypos < obj.height) { return pixels[ypos*width+xpos]; } return 0; } obj.SetPixel = function (xpos,ypos,colour) { if (xpos >= 0 && xpos < obj.width && ypos >= 0 && ypos < obj.height) { pixels[Math.floor(ypos)*width+Math.floor(xpos)] = colour; } } obj.Clear = function (colour) { for ( var ypos = 0; ypos < obj.height; ypos++) { for ( var xpos = 0; xpos < obj.width; xpos++) { obj.SetPixel(xpos,ypos,colour); } } } obj.PixelsFromArray = function(pixelsIn) { var minPixels = Math.min(obj.width*obj.height,pixelsIn.length); for(var p = 0; p < minPixels; p++) { pixels[p] = pixelsIn[p]; } return obj; } obj.DrawLine = function(startX, startY, endX, endY, colour) { var xLen = endX - startX; var yLen = endY - startY; var maxPoints = Math.max(Math.abs(xLen), Math.abs(yLen)) var xDisp = xLen / maxPoints; var yDisp = yLen / maxPoints; for ( var p = 0; p <= maxPoints; p++) { obj.SetPixel(startX + p*xDisp+0.5, startY + p*yDisp+0.5, colour) } } obj.DrawRect = function(xPos,yPos,width,height,colour) { for(var yDisp = 0; yDisp < height; yDisp++ ) { obj.DrawLine(xPos, yPos+yDisp, xPos+width-1, yPos+yDisp,colour) } } obj.DrawCircle = function(xPos,yPos,radius,colour) { var radiusSquared = radius * radius; var xOff; for( var yOff = 0.0; yOff < radius; yOff+= 0.5) { xOff = Math.sqrt(radiusSquared-(yOff*yOff)); obj.DrawLine(xPos-xOff+.5,yPos+yOff+.5,xPos+xOff+.5,yPos+yOff,colour) obj.DrawLine(xPos-xOff+.5,yPos-yOff+.5,xPos+xOff+.5,yPos-yOff,colour) } } obj.Scroll = function(xMovement,yMovement) { scrollXFraction += xMovement; scrollYFraction += yMovement; var xMove = Math.round(scrollXFraction); var yMove = Math.round(scrollYFraction); if(xMove == 0 && yMove == 0) { return; } scrollXFraction -= xMove; scrollYFraction -= yMove; var newPixels = new Array(); var targetXPos = xMove; if(targetXPos < 0) { targetXPos += obj.width; } var targetYPos = yMove if(targetYPos < 0) { targetYPos += obj.height; } for(var yPos = 0; yPos < obj.height; yPos++) { for(var xPos = 0; xPos < obj.width; xPos++) { newPixels[yPos*obj.width+xPos] = pixels[targetYPos*obj.width+targetXPos]; targetXPos += 1 if(targetXPos >= obj.width) { targetXPos -= obj.width; } } targetYPos += 1 if(targetYPos >= obj.height) { targetYPos -= obj.height; } } pixels = newPixels; } // Not ready for relacing scroll function yet. Does not wrap pixels. obj.ScrollNew = function(xMovement,yMovement) { scrollXFraction -= xMovement; scrollYFraction -= yMovement; var xMove = Math.round(scrollXFraction); var yMove = Math.round(scrollYFraction); if(xMove == 0 && yMove == 0) { return; } scrollXFraction -= xMove; scrollYFraction -= yMove; var newBitmap = obj.Clone(); obj.Clear(-1); var targetXPos = xMove; if(targetXPos < 0) { targetXPos += obj.width; } var targetYPos = yMove if(targetYPos < 0) { targetYPos += obj.height; } obj.Paste(xMove,yMove,newBitmap); if(targetYPos > 0 ) obj.Paste(xMove,yMove-obj.height,newBitmap); if(targetYPos < 0 ) obj.Paste(xMove,yMove+obj.height,newBitmap); // obj.Paste(0,0,newBitmap); } obj.FlipX = function () { var newBitmap = Bitmap(obj.width,obj.height); for(var yPos = 0; yPos < obj.height; yPos++) { for(var xPos = 0; xPos < obj.width; xPos++) { newBitmap.SetPixel(xPos,yPos,obj.GetPixel(obj.width-1-xPos,yPos)); } } return newBitmap; } obj.FlipY = function() { var newBitmap = Bitmap(obj.width,obj.height); for(var yPos = 0; yPos < obj.height; yPos++) { for(var xPos = 0; xPos < obj.width; xPos++) { newBitmap.SetPixel(xPos,yPos,obj.GetPixel(xPos,obj.height-1-yPos)); } } return newBitmap; } obj.RotateRight = function() { var newBitmap = Bitmap(obj.width,obj.height); for(var yPos = 0; yPos < obj.height; yPos++) { for(var xPos = 0; xPos < obj.width; xPos++) { newBitmap.SetPixel(yPos,xPos,obj.GetPixel(xPos,obj.height-1-yPos)); } } return newBitmap; } obj.RotateLeft = function() { var newBitmap = Bitmap(obj.width,obj.height); for(var yPos = 0; yPos < obj.height; yPos++) { for(var xPos = 0; xPos < obj.width; xPos++) { newBitmap.SetPixel(yPos,xPos,obj.GetPixel(obj.width-1-xPos,yPos)); } } return newBitmap; } obj.Clone = function() { var newBitmap = Bitmap(obj.width,obj.height); newBitmap.SetPixelArray([].concat(pixels)); // for(var yPos = 0; yPos < obj.height; yPos++) // { // for(var xPos = 0; xPos < obj.width; xPos++) // { // newBitmap.SetPixel(xPos,yPos,obj.GetPixel(xPos,yPos)); // } // } return newBitmap; } obj.Paste = function(xp,yp,bitmap) { var xdisp = Math.round(xp); var ydisp = Math.round(yp); // find the area of overlap // calculate the start y pixel in source and target var srcY = 0; var destY = 0; if (ydisp>0) destY = ydisp; if (ydisp<0) srcY = -ydisp; // calculate the start x pixel in source and target var srcX = 0; var destX = 0; if (xdisp>0) destX = xdisp; if (xdisp<0) srcX = -xdisp; // calculate the height of the overlap var ydist = obj.height-destY; if(bitmap.height-srcY < ydist) ydist = bitmap.height-srcY; // calculate the width of the overlap var xdist = obj.width-destX; if(bitmap.width-srcX < xdist) xdist = bitmap.width-srcX; if ( ydist > 0 && xdist > 0) { for ( var y = 0; y < ydist; y++) { for(var xPos = 0; xPos < bitmap.width; xPos++) { if ( bitmap.GetPixel(xPos,srcY) >= 0 ) { obj.SetPixel(xPos+xdisp,destY,bitmap.GetPixel(xPos,srcY)); } } srcY++; destY++; } } /* for(var yPos = 0; yPos < bitmap.height; yPos++) { if ( yPos +ydisp >= 0 && yPos+ydisp < obj.height) for(var xPos = 0; xPos < bitmap.width; xPos++) { if ( bitmap.GetPixel(xPos,yPos) >= 0 ) obj.SetPixel(xPos+xdisp,yPos+ydisp,bitmap.GetPixel(xPos,yPos)); } } */ } obj.WriteChar = function(char, charset, xPos,yPos,colour,xbig,ybig) { charSet.WriteChar(char,obj,xPos,yPos,colour,xbig,ybig); } obj.WriteString = function(text,charSet, xPos,yPos,colour,xbig,ybig) { charSet.WriteString(text,obj,xPos,yPos,colour,xbig,ybig); } obj.WriteStringCentered = function(text, charset, yPos,colour,xbig,ybig) { if (xbig == undefined) xbig = false; if ( xbig ) charset.WriteString(text,obj,width/2-charset.GetWidth()/2*text.length*2,yPos, colour,xbig,ybig); else charset.WriteString(text,obj,width/2-charset.GetWidth()/2*text.length,yPos, colour,xbig,ybig); } obj.Clear(-1); return obj; } CharSet = function (width, height) { if (width == undefined) width = 8; if (height == undefined) height = 8; var obj = {}; var charData = {}; obj.GetWidth = function () { return width; } obj.GetHeight = function () { return height; } obj.SetChar = function(char, chardata ) { charData[char] = chardata; } obj.WriteChar = function(char,bitmap,xPos,yPos,colour,xbig,ybig) { if(typeof(xbig)==='undefined') xbig = false; if(typeof(ybig)==='undefined') ybig = false; var rowData = charData[char]; if ( rowData != undefined ) { for ( var row = 0; row < rowData.length; row++) { var line = rowData[row]; for ( var charPos = 0; charPos < line.length; charPos++) { var chr = line.charAt(charPos); if ( chr != " " ) { if ( !xbig && !ybig) bitmap.SetPixel(charPos+xPos, row+yPos, colour ); if ( xbig && !ybig) { bitmap.SetPixel(charPos*2+xPos, row+yPos, colour ); bitmap.SetPixel(charPos*2+xPos+1, row+yPos, colour ); } if ( !xbig && ybig) { bitmap.SetPixel(charPos+xPos, row*2+yPos, colour ); bitmap.SetPixel(charPos+xPos, row*2+yPos+1, colour ); } if ( xbig && ybig) { bitmap.SetPixel(charPos*2+xPos, row*2+yPos, colour ); bitmap.SetPixel(charPos*2+xPos+1, row*2+yPos, colour ); bitmap.SetPixel(charPos*2+xPos, row*2+yPos+1, colour ); bitmap.SetPixel(charPos*2+xPos+1, row*2+yPos+1, colour ); } } } } } } obj.WriteString = function(text,bitmap,xPos,yPos,colour,xbig,ybig) { if(typeof(xbig)==='undefined') xbig = false; for ( var charPos = 0; charPos < text.length; charPos++) { var chr = text.charAt(charPos); if ( xbig) obj.WriteChar(chr,bitmap,xPos+charPos*2*width, yPos, colour,xbig,ybig ); else obj.WriteChar(chr,bitmap,xPos+charPos*width, yPos, colour,xbig,ybig ); } } return obj; } Sprite = function (xp,yp,costumeOrBitmap) { if (costumeOrBitmap === null ) return null; var costume = costumeOrBitmap; if ( BaseBitmap.isPrototypeOf(costumeOrBitmap)) { costume = Costume(); costume.SetItem(0,costumeOrBitmap); } else { if ( !BaseCostume.isPrototypeOf(costumeOrBitmap)) return null; } var obj = {}; var lifeSpan = -1; obj.died = false; obj.name = ""; obj.pos = Vector(xp,yp); obj.vel = Vector(0,0); obj.costume = costume; obj.costumeAnimator = Animator([0]); obj.bitmap = costume.GetItem(0); obj.wrap = false; obj.collided = false; obj.collidedList = new Array(); obj.SetLifeSpan = function(newLifeSpan) { lifeSpan = newLifeSpan; } obj.SetCostume = function(costume) { obj.costume = costume; } obj.SetWrapOn = function() { obj.wrap = true; } obj.SetWrapOff = function() { obj.wrap = false; } obj.SetAnimator = function(frameList) { obj.costumeAnimator = Animator(frameList); } obj.SetAnimatorBounce = function () { obj.costumeAnimator.Bounce(obj.costume.Length()); } obj.SetAnimatorLoop = function () { obj.costumeAnimator.Loop(obj.costume.Length()); } obj.SetAnimatorFrame = function(frame) { obj.costumeAnimator.Set(frame); obj.bitmap = obj.costume.GetItem(obj.costumeAnimator.Get()); } obj.GetAnimatorFrame = function(frame) { return obj.costumeAnimator.Get(); } obj.SetCostumeAnimator = function(animator) { obj.costumeAnimator = animator; } obj.SetAnimatorUpdateRate = function (updateRate) { obj.costumeAnimator.SetUpdateRate(updateRate); } obj.SetAnimatorStop = function () { obj.costumeAnimator.Stop(); } obj.SetMovement = function(xm,ym) { obj.vel.x = xm; obj.vel.y = ym; return obj; } obj.IsCollidedWith = function(targetSpriteName) { var target = GE.SpriteGet(targetSpriteName); if ( target == undefined ) return false; // simple bounding box check will do for now if ( obj.pos.x < target.pos.x + target.bitmap.width && obj.pos.x + obj.bitmap.width > target.pos.x && obj.pos.y < target.pos.y + target.bitmap.height && obj.pos.y + obj.bitmap.height > target.pos.y ) { // return true; var collided = false; // now lets do a pixel perfect collision check // get the biggest left var boxLeftPos = obj.pos.x; if ( boxLeftPos < target.pos.x ) boxLeftPos = target.pos.x; // get the smallest right var boxRightPos = obj.pos.x + obj.bitmap.width; if ( boxRightPos > target.pos.x + target.bitmap.width) boxRightPos = target.pos.x + target.bitmap.width; // get the biggest top var boxTopPos = obj.pos.y; if ( boxTopPos < target.pos.y ) boxTopPos = target.pos.y; // get the smallest bottom var boxBottomPos = obj.pos.y + obj.bitmap.height; if ( boxBottomPos > target.pos.y + target.bitmap.height) boxBottomPos = target.pos.y + target.bitmap.height; var overlapWidth = boxRightPos - boxLeftPos; var overlapHeight = boxBottomPos - boxTopPos; var sx = Math.floor(boxLeftPos - obj.pos.x); var sy = Math.floor(boxTopPos - obj.pos.y); var tx = Math.floor(boxLeftPos - target.pos.x); var ty = Math.floor(boxTopPos - target.pos.y); for ( var y = 0; y < overlapHeight; y++) { for ( var x = 0; x < overlapWidth; x++ ) { var p1 = obj.bitmap.GetPixel(sx+x,sy+y); var p2 = target.bitmap.GetPixel(tx+x,ty+y); if (p1 != -1 && p2 != -1 ) collided = true; } } return collided; } return false; } obj.Update = function (scrWidth, scrHeight) { obj.pos.x += obj.vel.x; obj.pos.y += obj.vel.y; if ( obj.wrap ) { if ( obj.pos.x < 0 ) obj.pos.x += scrWidth; if ( obj.pos.y < 0 ) obj.pos.y += scrHeight; if ( obj.pos.x >= scrWidth ) obj.pos.x -= scrWidth; if ( obj.pos.y >= scrHeight ) obj.pos.y -= scrHeight; } obj.costumeAnimator.Update(); obj.bitmap = obj.costume.GetItem(obj.costumeAnimator.Get()); obj.layerChanged = false; if ( lifeSpan != -1 ) { lifeSpan--; if (lifeSpan == 0 ) obj.died = true; } } // obj.Draw = function () // { // // } return obj; } Vector = function(x,y) { var obj = {}; obj.x = x; obj.y = y; obj.Add = function(v1) { return Vector(obj.x+v1.x, obj.y+v1.y); } obj.Subtract = function(v1) { return Vector(obj.x-v1.x, obj.y-v1.y); } obj.Multiply = function(v1) { return Vector(obj.x*v1.x, obj.y*v1.y); } obj.Magnitude = function() { return Math.sqrt(obj.x*obj.x + obj.y*obj.y); } obj.Normalise = function() { var mag = obj.Magnitude(); obj.x /= mag; obj.y /= mag; } obj.SetMagnitude = function(newMagnitude) { obj.Normalise(); obj.x *= newMagnitude; obj.y *= newMagnitude; } obj.DotProduct = function(v) { return obj.x * v.x + obj.y * v.y; } obj.ScalarMultiply = function(scalar) { obj.x *= scalar; obj.y *= scalar; } return obj; } var BaseCostume = {}; Costume = function() { var obj = Object.create(BaseCostume); obj.bitmaps = Array(); obj.SetItem = function (frame, bitmap) { // try to set a frame to something other than a bitmap will result in nothing happening if ( !BaseBitmap.isPrototypeOf(bitmap)) return; obj.bitmaps[frame] = bitmap; }; obj.SetItems = function (bitmaps,startFrame) { var frame = startFrame; for(var bitmapPos = 0; bitmapPos < bitmaps.length; bitmapPos++) { obj.SetItem(frame, bitmaps[bitmapPos]); frame++; } }; obj.Length = function () { return obj.bitmaps.length; } obj.GetItem = function (frame) { return obj.bitmaps[frame]; } obj.Update = function() { } return obj; } Animator = function (frameList) { var obj = {}; obj.frame = 0; obj.updateRate = 1; obj.repeat = true; if (frameList == null ) { obj.frameList = new Array(); } else { obj.frameList = frameList; } var paused = false; obj.Bounce = function (frames) { var list = new Array(); var f = 0; for ( var i = 0; i < frames; i++) { list[f] = i; f++; } for ( var i = frames-2; i > 0; i--) { list[f] = i; f++; } obj.frameList = list; } obj.Loop = function (frames) { var list = new Array(); var f = 0; for ( var i = 0; i < frames; i++) { list[f] = i; f++; } obj.frameList = list; } obj.Update = function () { if ( paused == false ) { var prevFrame = obj.frame; obj.frame = (obj.frame + obj.updateRate) % obj.frameList.length; if ( obj.frame < prevFrame ) if ( !obj.repeat ) { obj.frame = prevFrame; obj.Pause(); } } } obj.Get = function() { return obj.frameList[Math.floor(obj.frame)]; } obj.Set = function(frame) { obj.frame = Math.floor(frame % obj.frameList.length); } obj.SetUpdateRate = function(updateRate) { obj.updateRate = updateRate; obj.waitTime = 0; } obj.Start = function () { frame = 0; paused = false; } obj.Resume = function () { paused = false; } obj.Stop = function () { frame = 0; paused = true; } obj.Pause = function () { paused = true; } obj.Resume = function () { paused = false; } return obj; } // Experimental code to create sounds. // Once this is stable the GameEngine will assimilate it var channels = new Array(); var soundOn = true; function customSound(bitrate) { this.bitrate = bitrate; this.angle = 0; this.customSoundData=[]; this.totalDuration = 0; this.dataPos = 0; customSound.prototype.add = function(duration, startFreq, endFreq, startVol, endVol, randomFreq, randomRate, square ) { var vol = startVol; var freq = startFreq; var angleInc = (2*Math.PI)/this.bitrate * freq; var freqRand = 0; var randomCount = 0; if ( randomFreq == undefined ) randomFreq = 0; for ( var x=0; x < this.bitrate*duration; x++) { vol = (startVol + (endVol - startVol)*x/(this.bitrate*duration)); this.customSoundData[this.dataPos] = Math.sin(this.angle) * vol; if (square ) if ( this.customSoundData[this.dataPos] < 0) this.customSoundData[this.dataPos] = -vol; else this.customSoundData[this.dataPos] = vol freq = startFreq + (endFreq - startFreq)*x/(this.bitrate*duration); if ( randomRate > 0 ) { randomCount--; if ( randomCount <= 0 ) { freqRand = Math.random()*randomFreq; randomCount=randomRate; } } angleInc = (2*Math.PI)/this.bitrate * (freq+freqRand); this.angle+=angleInc; if ( this.angle > Math.PI * 2 ) { this.angle -= Math.PI * 2; } this.dataPos++; } } customSound.prototype.createSound = function(channel) { var n = this.customSoundData.length; var header = "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00********\x01\x00\x08\x00data****"; // ChunkSize var numval = n + 36; header=insertLong(header,4,numval); numval = this.bitrate; // byterate header = insertLong(header,24,numval); // BitRate numval = this.bitrate * 8; //44100; header = insertLong(header,28,numval); // Subchunk2Size // insertLong(n); numval = n; header = insertLong(header,40,numval); // Output sound data for (var i = 0; i < n; ++i) { var charCode = Math.round(Math.min(127, Math.max(-127, this.customSoundData[i]))+127); header += String.fromCharCode(charCode); } // var o= document.getElementById('output'); var h = btoa(header); h = 'data:audio/wav;base64,' + h; var a = new Audio(); a.src = h; if ( channels[channel] ) channels[channel].pause(); channels[channel] = a; return a; } } function soundPlay(channel,loop) { if ( !soundOn ) return; if ( loop ) channels[channel].loop = loop; if (channels[channel].readyState < 1 ) return; // channels[channel].pause(); channels[channel].currentTime=0; channels[channel].play(); } function soundStop(channel) { if (channels[channel].readyState < 1 ) return; channels[channel].pause(); } function insertLong(inString, index, inValue) { var retString = inString.substr(0,index); for (i = 0; i < 4; ++i) { retString += String.fromCharCode(inValue & 255); inValue = inValue >> 8; } retString += inString.substr(index+4); return retString; } GameSatePattern = function (data) { var obj = {}; var innerStates = new Array(); var finished = false; var nextState; var doInit = true; obj.Draw = function() { for( var state in innerStates ) if ( innerStates[state] ) innerStates[state].Draw(); if ( obj.DrawCustom ) obj.DrawCustom(); } obj.Update = function() { if ( doInit ) { doInit = false; if ( obj.Init ) obj.Init(); } if ( obj.UpdateCustom) obj.UpdateCustom(); if ( finished ) { for( var state in innerStates ) { if ( innerStates[state] ) { innerStates[state].SetFinished(); innerStates[state] = innerStates[state].Update(); } } if ( obj.TearDown ) obj.TearDown(); if ( nextState) return nextState; return undefined; } else for( var state in innerStates ) if ( innerStates[state] ) innerStates[state] = innerStates[state].Update(); return this; } obj.AddInnerState=function(state) { innerStates.push(state); } obj.SetNextState=function(state) { nextState = state; } obj.SetFinished=function() { finished = true; } return obj; } // last piece of code is to start the game init(); </script> </html>