Ahhh.. Tetris. How could I have forgotten to write this game.
Its a puzzle game that everyone was playing at one time.
Here’s my take on it. It took a little longer than expected and to be honest the code could do with a re-write.
Still… This is a game ‘sketch’ so I shouldn’t expect the code to be perfect.
It works and I learnt a lot for the future so job done.
Have fun.
<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <title>Tetrizza</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 = 2; var LAYER_BUTTON = 3; 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 = MainMenu(GameData()); InitBackground(); } 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; obj.playArea; return obj; } function SplashData() { var obj = {}; obj.finished = false; return obj; } function PlayData() { var obj = {}; obj.finished = false; obj.playArea; obj.scoreValue; return obj; } function Splash(data) { var data = GameData(); var splashData = SplashData(); var obj = GameSatePattern(splashData); obj.AddInnerState( SplashStatic(splashData) ); obj.SetNextState(MainMenu(data)); obj.UpdateCustom = function() { if (splashData.finished) obj.SetFinished(); } obj.TearDown = function() { InitBackground(); } 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("Tetrizza",GE.CanvasHeight/2+32,15,false,true); } obj.UpdateCustom=function() { countFrames++; if ( countFrames > 30*3 ) { data.finished = true; } } return obj; } function MainMenu(data) { var obj = GameSatePattern(data); var countFrames = 0; obj.Init = function () { var menuBitmap = Bitmap(140,20); var menuBitmap2 = Bitmap(220,160); menuBitmap.DrawRect(0,0,menuBitmap.width, menuBitmap.height,2); var textWidth = 16*8; var xoffset = (menuBitmap.width - textWidth)/2; menuBitmap.WriteString("Tetrizza",GE.CharSet(),xoffset-2,2,8,true,true); menuBitmap.WriteString("Tetrizza",GE.CharSet(),xoffset,4,14,true,true); var textColour = 15; var msg = "SpaceBar or click to Begin" var width = msg.length*8; menuBitmap2.DrawRect((menuBitmap2.width-width)/2,110,width,16,1); menuBitmap2.WriteStringCentered(msg,GE.CharSet(),110,textColour,false,true); var sp = Sprite((GE.CanvasWidth-menuBitmap.width)/2, 20, menuBitmap ); GE.SpriteAdd("MainMenu", sp, LAYER_MENU); sp = Sprite((GE.CanvasWidth-menuBitmap2.width)/2, 104, menuBitmap2 ); GE.SpriteAdd("MainMenu2", sp, LAYER_MENU); DisplayScore(data); } obj.UpdateCustom=function() { if ( FirePressed() ) { obj.SetFinished(); obj.SetNextState(Play(data)); } } obj.TearDown = function() { GE.SpriteDelete("MainMenu"); GE.SpriteDelete("MainMenu2"); } return obj; } function Play(data) { var obj = GameSatePattern(data); var playData = PlayData(); obj.Init=function() { data.score = 0; playData.scoreValue = 0; obj.AddInnerState(PlayInit(playData)); InitBackground(); DisplayScore(data); } obj.DrawCustom = function() { DisplayScore(data); DisplayStats(playData.playArea); } obj.UpdateCustom = function() { if ( playData.finished ) obj.SetFinished(); obj.SetNextState(MainMenu(data)); if ( playData.scoreValue != 0 ) { data.score += playData.scoreValue; if ( data.score > data.hiscore ) data.hiscore = data.score; playData.scoreValue = 0; } } return obj; } // the following are inner states to the play state function PlayArea (width, height) { var obj = {}; var currentShape = 1; var nextShape = 1; var shapeStats = [0,0,0,0,0,0,0,0] var currentRotation = 1; var currentShapeX = 2; var currentShapeY = -3; var grid; var blockCostumes; var tetronimos; var teronimoCostumes; var finished; var blockCount; obj.bitmap = Bitmap(10*width,10*height); obj.Init = function() { grid = new Array(); for ( var y = 0; y < height; y++ ) { var row = new Array(); for ( var x = 0; x < width; x++ ) { row.push(-1); } grid.push(row); } blockCostumes = CreateTetronimoBlockCostumes(); tetronimos = CreateTetrominos(); tetronimoCostumes = CreateTetronimoCostumes(); currentShape = PickRandomShape(); nextShape = PickRandomShape(); blockCount = 0; finished = false; } function PickRandomShape() { return Math.floor(Math.random()*7); } obj.RotateLeft=function() { var rotate = currentRotation - 1; if ( rotate < 0 ) rotate = 3; var shape = tetronimos[currentShape][rotate]; if ( !IsCollision(currentShapeX,currentShapeY,shape) ) { currentRotation = rotate; } } obj.RotateRight=function() { var rotate = currentRotation + 1; if ( rotate > 3 ) rotate = 0; var shape = tetronimos[currentShape][rotate]; if ( !IsCollision(currentShapeX,currentShapeY,shape) ) { currentRotation = rotate; } } obj.MoveLeft=function() { var shape = tetronimos[currentShape][currentRotation]; if ( !IsCollision(currentShapeX-1,currentShapeY,shape) ) { currentShapeX -= 1; } } obj.MoveRight=function() { var shape = tetronimos[currentShape][currentRotation]; if ( !IsCollision(currentShapeX+1,currentShapeY,shape) ) { currentShapeX += 1; } } obj.GetLevel=function() { return Math.floor(blockCount/20) } obj.GetBlockCount=function() { return blockCount; } obj.IsFinished=function() { return finished; } function IsCollision(xpos,ypos,shape) { for ( var rowPos=0; rowPos < shape.length; rowPos++ ) { var row = shape[rowPos]; for ( var charPos = 0; charPos < row.length; charPos++) { var chr = row.charAt(charPos); if ( chr != ' ' ) { if ( ypos+rowPos >= height ) return true; if ( xpos+charPos < 0 || xpos+charPos >= width ) return true; if ( ypos+rowPos >= 0 && ypos+rowPos < height) if ( grid[ypos+rowPos][xpos+charPos] != -1 ) { if ( ypos+rowPos == 0 ) finished = true; return true; } } } } return false; } obj.GetStatForShape = function(shape) { return shapeStats[shape]; } obj.GetNextShapeBitmap=function() { return tetronimoCostumes[nextShape].GetItem(0); } obj.Drop=function() { var scoreValue = 0; var shape = tetronimos[currentShape][currentRotation]; var canDrop = !IsCollision(currentShapeX,currentShapeY+1,shape); if ( !canDrop ) { scoreValue += 10; // paste shape onto grid for ( var rowPos=0; rowPos < shape.length; rowPos++ ) { if ( currentShapeY+rowPos >= 0 ) { var row = shape[rowPos]; for ( var charPos = 0; charPos < row.length; charPos++) { var chr = row.charAt(charPos); if ( chr != ' ' ) grid[currentShapeY+rowPos][currentShapeX+charPos]=currentShape; } } } // See if any rows can be removed // this is gonna be really slow in inefficient for now // I just want a working game for now var scoreMultiplier = 0; for ( var y = grid.length-1; y > 0; y-- ) { var counter = 0; var row = grid[y]; for ( var x = 0; x < row.length; x++ ) { if ( row[x] != -1 ) counter++; } if ( counter == row.length ) { scoreMultiplier++; // blank out the row for ( var x = 0; x < row.length; x++ ) row[x] = -1; // shift down 1 row var newGrid = new Array (); newGrid.push ( row ); for ( var ynew = 0; ynew < grid.length; ynew++ ) { if (ynew != y ) { newGrid.push(grid[ynew]); } } grid = newGrid; y+= 1; } } scoreValue += 100*scoreMultiplier * scoreMultiplier; // create a new shape shapeStats[currentShape]++; currentShape = nextShape; currentRotation = 0; currentShapeY = -4; currentShapeX = ( width -4 ) / 2 ; blockCount++; nextShape = PickRandomShape(); } currentShapeY += 1; return scoreValue; } obj.Draw=function() { obj.bitmap.DrawRect(0,0,width*10,height*10,-1); for ( var y=0; y < grid.length; y++ ) { var row = grid[y]; for ( var x = 0; x < row.length; x++ ) { if ( row[x] != -1 ) { obj.bitmap.Paste(x*10,y*10,blockCostumes.GetItem(row[x])); } } } // now draw the current shape obj.bitmap.Paste(currentShapeX*10,currentShapeY*10,tetronimoCostumes[currentShape].GetItem(currentRotation)); } obj.Init(); return obj; } function PlayInit(data) { var obj = GameSatePattern(data); var waitTimer = 4*30; obj.Init=function() { data.score = 0; var xPos = (GE.CanvasWidth / 2 ) - 5*10; var yPos = (GE.CanvasHeight / 2 ) - 10*10; data.playArea = PlayArea(10,20); var sp = Sprite(xPos,yPos,data.playArea.bitmap); GE.SpriteAdd("PlayArea",sp,1); obj.SetNextState(PlayNewGame(data)); var cs=Costume() var menuBitmap = Bitmap(8*10,16); menuBitmap.DrawRect(0,0,8*10,16,0); var blankBitmap = menuBitmap.Clone(); menuBitmap.WriteString("GET READY",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("GetReady", sp, LAYER_MENU); InitBackground(); } obj.UpdateCustom=function() { waitTimer--; if ( waitTimer == 0 ) obj.SetFinished(); } obj.TearDown=function() { GE.SpriteDelete("GetReady"); } return obj; } function PlayNewGame(data) { var obj = GameSatePattern(data); obj.Init = function() { if ( GE.Tiltable()) GE.TiltCalibrate(); obj.SetNextState(PlayGame(data)); obj.SetFinished(); } return obj; } function PlayGame(data) { var obj = GameSatePattern(data); var player; var tetronimos = CreateTetrominos(); var rotation = 0; var pauseTimer = 30; var leftPressed; var rightPressed; var zPressed; var yPressed; obj.Init=function() { obj.SetNextState(PlayGameOver(data)); leftPressed = false; rightPressed = false; zPressed = false; yPressed = false; } obj.DrawCustom=function() { data.playArea.Draw(); } obj.UpdateCustom=function() { if ( GE.GetKeyState(GE.KEY_DOWN)) { data.scoreValue += data.playArea.Drop(); if (data.playArea.IsFinished()) { obj.SetFinished(); } } else { pauseTimer--; if ( pauseTimer == 0 ) { var level = data.playArea.GetLevel(); if ( level < 20 ) pauseTimer = 20-level; else pauseTimer = 1; data.scoreValue += data.playArea.Drop(); if (data.playArea.IsFinished()) { obj.SetFinished(); } } } if ( GE.GetKeyState(GE.KEY_LEFT) ) { if ( !leftPressed ) { data.playArea.MoveLeft(); leftPressed = true; } } else { leftPressed = false; } if ( GE.GetKeyState(GE.KEY_RIGHT) ) { if ( !rightPressed ) { data.playArea.MoveRight(); rightPressed = true; } } else { rightPressed = false; } if ( GE.GetKeyState(GE.KEY_Z) ) { if ( !zPressed ) { data.playArea.RotateLeft(); zPressed = true; } } else { zPressed = false; } if ( GE.GetKeyState(GE.KEY_X) ) { if ( !xPressed ) { data.playArea.RotateRight(); xPressed = true; } } else { xPressed = false; } } 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 tmpStr = "000000" + data.score; tmpStr = tmpStr.substring(tmpStr.length-7); GE.DrawRect(32,0,13*8,16,0); GE.WriteString("SCORE:"+tmpStr,32,0,15,false,true); tmpStr = "000000" + data.hiscore; tmpStr = tmpStr.substring(tmpStr.length-7); GE.DrawRect(GE.CanvasWidth-14*8-32,0,16*8,16,0); GE.WriteString("HI-SCORE:"+tmpStr,GE.CanvasWidth-14*8-32,0,15,false,true); } function DisplayStats(playArea) { if ( playArea != undefined ) { for ( var s = 0; s < 7; s++ ) { var stat = playArea.GetStatForShape(s); if (stat != undefined ) { GE.DrawRect (44,102+16*s,6*8,8,0); GE.WriteString (" : "+playArea.GetStatForShape(s),44,102+16*s,15); } } GE.DrawRect (44,102+16*7,6*8,8,0); GE.WriteString (" : "+playArea.GetBlockCount(),44,102+16*7,15); // also display what the next shape is going to be GE.DrawRect (34,44,40,40,0); GE.Paste (34,44,playArea.GetNextShapeBitmap()); GE.DrawRect (0,GE.CanvasHeight-8,GE.CanvasWidth,8,0); GE.WriteStringCentered ("Level "+playArea.GetLevel(),GE.CanvasHeight-8,15); } } function InitBackground(data) { GE.DrawRect(0,0,GE.CanvasWidth, GE.CanvasHeight,0 ); var blocks = CreateTetronimoBlockCostumes(); var gridXPos = (GE.CanvasWidth / 2 ) - 5*10; var gridYPos = (GE.CanvasHeight / 2 ) - 10*10; GE.DrawRect(gridXPos-10,gridYPos,10*10+20,20*10+10,2); GE.DrawRect(gridXPos,gridYPos,10*10,20*10,0); // show next block GE.WriteString ("Next",36,22,15); GE.DrawRect ( 25,36-2,54,54,2); GE.DrawRect ( 25+2,36,50,50,0); GE.WriteString ("Stats",32,90,15); for ( var s = 0; s < 7; s++ ) { GE.Paste(8,100+16*s,blocks.GetItem(s)); GE.WriteString (" :",44,102+16*s,15); } GE.WriteString ("Total :",4,102+16*7,15); var leftPos = GE.CanvasWidth - 98; var top = 32; GE.WriteString ( "Controls", leftPos+16,top,15); top+=32; GE.WriteString ( "Left/Right", leftPos,top,15); top+=16; GE.WriteString ( "Move block", leftPos,top,7); top+=16; GE.WriteString ( "Down", leftPos,top,15); top+=16; GE.WriteString ( "Drop", leftPos,top,7); top+=16; GE.WriteString ( "Z", leftPos,top,15); top+=16; GE.WriteString ( "Rotate Left", leftPos,top,7); top+=16; GE.WriteString ( "X", leftPos,top,15); top+=16; GE.WriteString ( "Rotate Right", leftPos,top,7); } function CreateTetrominos() { var tetronimos = new Array(); // I tetronimos.push( [[ " ", "****", " ", " " ], [ " * ", " * ", " * ", " * " ], [ " ", "****", " ", " " ], [ " * ", " * ", " * ", " * " ]]); // J tetronimos.push([[ "* ", "*** ", " ", " " ], [ " ** ", " * ", " * ", " " ], [ " ", "*** ", " * ", " " ], [ " * ", " * ", "** ", " " ]]); // L tetronimos.push([[ " * ", "*** ", " ", " " ], [ " * ", " * ", " ** ", " " ], [ " ", "*** ", "* ", " " ], [ "** ", " * ", " * ", " " ]]); // O tetronimos.push([[ " ", " ** ", " ** ", " " ], [ " ", " ** ", " ** ", " " ], [ " ", " ** ", " ** ", " " ], [ " ", " ** ", " ** ", " " ]]); // S tetronimos.push([[ " ** ", "** ", " ", " " ], [ " * ", " ** ", " * ", " " ], [ " ", " ** ", "** ", " " ], [ " * ", " ** ", " * ", " " ]]); // T tetronimos.push([[ " * ", "*** ", " ", " " ], [ " * ", " ** ", " * ", " " ], [ " ", "*** ", " * ", " " ], [ " * ", "** ", " * ", " " ]]); // Z tetronimos.push([[ "** ", " ** ", " ", " " ], [ " * ", " ** ", " * ", " " ], [ " ", "** ", " ** ", " " ], [ " * ", " ** ", " * ", " " ]]); return tetronimos; } function CreateTetronimoBlockCostumes() { // for tetronimo's IJLOSTZ use colours as used onb the PC port by Vadim Gerisimov var cs= Costume(); cs.SetItem(0,CreateBlockBitmap(1)); cs.SetItem(1,CreateBlockBitmap(7)); cs.SetItem(2,CreateBlockBitmap(5)); cs.SetItem(3,CreateBlockBitmap(3)); cs.SetItem(4,CreateBlockBitmap(2)); cs.SetItem(5,CreateBlockBitmap(4)); cs.SetItem(6,CreateBlockBitmap(6)); return cs; } function CreateBlockBitmap(blockColour) { var bm = Bitmap(10,10); bm.DrawRect(0,0,10,10,blockColour); bm.DrawLine(0,9,9,9,8); bm.DrawLine(9,0,9,9,8); bm.DrawLine(0,0,9,0,blockColour+8); bm.DrawLine(0,0,0,9,blockColour+8); return bm; } function CreateTetronimoCostumes() { var tetronimos = CreateTetrominos (); var blockCostumes = CreateTetronimoBlockCostumes(); var tetronimoCostumes = Array(); for ( var currentShape = 0; currentShape < tetronimos.length; currentShape++ ) { var tetronimo = tetronimos[currentShape]; var tetronimoCostume = Costume(); for ( var currentRotation = 0; currentRotation < tetronimo.length; currentRotation++ ) { var bm = Bitmap(40,40); var shape = tetronimos[currentShape][currentRotation]; for ( var rowPos=0; rowPos < shape.length; rowPos++ ) { var row = shape[rowPos]; for ( var charPos = 0; charPos < row.length; charPos++) { var chr = row.charAt(charPos); if ( chr != ' ' ) bm.Paste(charPos*10,rowPos*10,blockCostumes.GetItem(currentShape)); } } tetronimoCostume.SetItem(currentRotation,bm); } tetronimoCostumes.push(tetronimoCostume); } return tetronimoCostumes; } // 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; } // ctx.imageSmoothingEnabled = false; 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>