- Grown on Modern Browser Standards
- Aims to be lightweight
- Modular build
INDEV
| /********************************************** | |
| * | |
| * MageJS ~ My awesome Game Lib in Javascript | |
| * | |
| * VERSION: 0.1 | |
| * LICENSE: MIT | |
| * | |
| * Base class | |
| * | |
| ***********************************************/ | |
| (function(){ | |
| var Mage = { | |
| version: "0.1", | |
| maxSkip: 10, | |
| fps: 60, | |
| } | |
| var timeout; | |
| Mage.running; | |
| Mage.paused; | |
| Mage.debug = true; | |
| /* Resize magic */ | |
| function resizeCanvas(){ | |
| if(game.fullscreen){ | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| } else { | |
| canvas.width = game.width; | |
| canvas.height = game.height; | |
| } | |
| if(game.resize != undefined){ | |
| game.resize(); | |
| } | |
| } | |
| function countFps(){ | |
| if((new Date).getSeconds() != ls){ | |
| Mage.fps = fps_count; | |
| ls = (new Date).getSeconds(); | |
| fps_count = 0; | |
| } else { | |
| fps_count++; | |
| } | |
| } | |
| Mage.clone = function(obj){ | |
| var clone = {}; | |
| for(var i in obj) { | |
| if(typeof(obj[i])=="object") | |
| clone[i] = cloneObject(obj[i]); | |
| else | |
| clone[i] = obj[i]; | |
| } | |
| return clone; | |
| } | |
| // This is supported by FF & Chrome > 21 | |
| Mage.retro = function(){ | |
| ctx.patternQuality = "fast"; | |
| ctx.mozImageSmoothingEnabled = false; | |
| ctx.webkitImageSmoothingEnabled = false; | |
| ctx.imageSmoothingEnabled = false; | |
| ctx.oImageSmoothingEnabled = false; | |
| ctx.msImageSmoothingEnabled = false; | |
| } | |
| Mage.random = function(_min,_max){ | |
| return Math.floor(Math.random()*(_max-_min+1)+_min); | |
| } | |
| Mage.range = function(start, end){ | |
| var foo = []; | |
| for (var i = start; i <= end; i++) | |
| foo.push(i); | |
| return foo; | |
| } | |
| Mage.clear = function() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| } | |
| Mage.log = function(msg){ | |
| if(Mage.debug){ | |
| console.log(msg); | |
| } | |
| } | |
| Mage.draw = function(obj) { | |
| obj.draw( ctx ); | |
| } | |
| Mage.getCanvas = function(){ | |
| return canvas; | |
| } | |
| Mage.collide = function(obj1,obj2,tolerance){ | |
| if (tolerance == undefined){ tolerance = 0; } | |
| if((obj1.x >= obj2.x-tolerance && obj1.x <= obj2.x + obj2.width + tolerance) | |
| && (obj1.y >= obj2.y-tolerance && obj1.y <= obj2.y + obj2.height + tolerance)){ | |
| return true; | |
| } else { return false; } | |
| } | |
| /* Starter */ | |
| Mage.run = function(gam){ | |
| Mage.running = true; | |
| game = gam; | |
| Mage.canvas_id = game.canvas; | |
| fps_count = 0; | |
| ls = (new Date).getSeconds(); | |
| canvas = document.getElementById(game.canvas) || document.getElementsByTagName('canvas')[0]; | |
| ctx = canvas.getContext("2d"); | |
| if(game.retro){ Mage.retro(); } | |
| resizeCanvas(); | |
| window.addEventListener('resize', resizeCanvas, false); // doesnt work :3 | |
| game.init(); | |
| _id = Mage.requestInterval( Mage.loop ); | |
| } | |
| /* Loop Job */ | |
| Mage.loop = function() { | |
| var loops = 0; | |
| var skipTicks = 500 / game.fps; | |
| var maxFrameSkip = 10; | |
| var nextGameTick = (new Date).getTime(); | |
| Mage.clear(); | |
| if(game.retro){ Mage.retro(); } | |
| loops = 0; | |
| if(game.lower_draw){ | |
| while ((new Date).getTime() > nextGameTick && loops < maxFrameSkip) { | |
| game.update(); | |
| nextGameTick += skipTicks; | |
| loops++; | |
| } | |
| } else { | |
| game.update(); | |
| } | |
| game.draw(); | |
| countFps(); | |
| //_id = Mage.requestInterval( Mage.loop() ); | |
| } | |
| /* Stop Animation */ | |
| Mage.stop = function(){ | |
| Mage.running = false; | |
| window.clearInterval(timeout); | |
| } | |
| /* Interval, try to get a browser native one (runs @~30 for me in chromium) */ | |
| Mage.requestInterval = function(callback){ | |
| if(game.auto_fps !== true){ | |
| timeout = window.setInterval(callback, 1000 / game.fps); | |
| } else if(window.requestAnimationFrame){ | |
| var _fu = function(){ callback(); if(Mage.running == true){ window.requestAnimationFrame(_fu) } }; | |
| _fu(); | |
| } else if(window.webkitRequestAnimationFrame){ | |
| var _fu = function(){ callback(); if(Mage.running == true){ window.webkitRequestAnimationFrame(_fu) } }; | |
| _fu(); | |
| } else if(window.mozRequestAnimationFrame){ | |
| var _fu = function(){ callback(); if(Mage.running == true){ window.mozRequestAnimationFrame(_fu) } }; | |
| _fu(); | |
| } else if(window.oRequestAnimationFrame){ | |
| var _fu = function(){ callback(); if(Mage.running == true){ window.oRequestAnimationFrame(_fu) } }; | |
| _fu(); | |
| } else if(window.msRequestAnimationFrame){ | |
| var _fu = function(){ callback(); if(Mage.running == true){ window.msRequestAnimationFrame(_fu) } }; | |
| _fu(); | |
| } else { | |
| timeout = window.setInterval(callback, 1000 / game.fps); | |
| } | |
| } | |
| // X, Y, WIDTH, HEIGHT, COLOR, OUTLINE, OUTLINE-SIZE | |
| Mage.drawRect = function(x,y,w,h,c,o,l){ | |
| var color = c || false; | |
| if(color !== false){ | |
| ctx.fillStyle = color; | |
| ctx.fillRect(x,y,w,h); | |
| } | |
| var outline = o || false; | |
| if(outline !== false){ | |
| ctx.strokeStyle = outline; | |
| ctx.lineWidth = l || 2; | |
| ctx.strokeRect(x, y, w, h); | |
| } | |
| } | |
| // X, Y, RADIUS, COLOR, OUTLINE, OUTLINE-SIZE | |
| Mage.drawArc = function(x,y,r,c,o,l){ | |
| var outline = o || false; | |
| if(outline !== false){ | |
| ctx.fillStyle = outline; | |
| lineWidth = l || 2; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, r, 0, Math.PI*2, true); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| var color = c || false; | |
| if(color !== false){ | |
| ctx.fillStyle = color; | |
| } | |
| ctx.beginPath(); | |
| if(lineWidth > 0){ r = r-(lineWidth) } | |
| ctx.arc(x, y, r, 0, Math.PI*2, true); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| // Return canvas context for own use | |
| Mage.getContext = function(){ | |
| return ctx | |
| } | |
| window.Mage = Mage; | |
| })() ; |
| /********************************************** | |
| * | |
| * MageJS ~ My awesome Game Lib in Javascript | |
| * | |
| * ~ Key Manager class | |
| * | |
| * Uses HTML5 <audio> API to create sound | |
| * elements and control them. | |
| * | |
| * Functions | |
| * MageKeyManager.init() | |
| * MageKeyManager.keys[] : current key map | |
| * MageKeyManager.keystrings[] : replace map (strings) | |
| * MageKeyManager.keyreplace[] : replace map (keycodes) | |
| * MageKeyManager.keyExists(key) : if string key is in map | |
| * MageKeyManager.getKeyCode(event) | |
| * MageKeyManager.isPressed(String|KeyCode) : true|false | |
| * MageKeyManager.returnKeys(keys) : create a true/false hash with the keys | |
| * | |
| ***********************************************/ | |
| (function(){ | |
| MageKeyManager = { | |
| version: "0.1", | |
| } | |
| function isNumber(n) { | |
| return !isNaN(parseFloat(n)) && isFinite(n); | |
| } | |
| MageKeyManager.keys = {}; | |
| MageKeyManager.keystrings = ["backspace","tab","enter","shift","ctrl","alt","caps","esc","page_up","page_down", | |
| "end","home","left","up","right","down","insert","delete","0","1","2","3","4","5", | |
| "6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p", | |
| "q","r","s","t","u","v","w","x","y","z","space","super","num0","num1","num2","num3", | |
| "num4","num5","num6","num7","num8","num9","f1","f2","f3","f4","f5","f6","f7","f8", | |
| "f9","f10","f11","f12"]; | |
| MageKeyManager.keyreplace = [8,9,13,16,17,18,20,27,33,34,35,36,37,38,39,40,45,46,48,49,50,10,52,53,54,55,56,57, | |
| 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,32, | |
| 91,96,97,98,99,100,101,102,103,104,105,112,113,114,115,116,117,118,119,120,121, | |
| 122,123]; | |
| MageKeyManager.init = function(keys){ | |
| MageKeyManager.keys = MageKeyManager.returnKeys( keys ); | |
| var body = document.getElementsByTagName('body')[0]; | |
| body.setAttribute('onkeydown','MageKeyManager.keyDown(event)'); | |
| body.setAttribute('onkeyup','MageKeyManager.keyUp(event)'); | |
| } | |
| MageKeyManager.keyExists = function(obj) { | |
| var i = MageKeyManager.keystrings.length; | |
| while (i--) { | |
| if (MageKeyManager.keystrings[i] === obj) { | |
| return i; | |
| } | |
| } | |
| return false; | |
| } | |
| MageKeyManager.returnKeys = function(keys){ | |
| var okeys = {}; | |
| for(var key in keys){ | |
| var con = MageKeyManager.keyExists(keys[key]); | |
| if(con != false){ | |
| okeys[MageKeyManager.keyreplace[con]] = false; | |
| } else { | |
| okeys[keys[key]] = false; | |
| } | |
| } | |
| return okeys; | |
| } | |
| MageKeyManager.getKeyCode = function(event){ | |
| xvent = event || window.event; | |
| return xvent.keyCode; | |
| } | |
| MageKeyManager.keyDown = function(event){ | |
| var keycode = MageKeyManager.getKeyCode(event); | |
| if(MageKeyManager.keys[keycode] != undefined){ | |
| if(MageKeyManager.keys[keycode] == false){ | |
| MageKeyManager.keys[keycode] = true; | |
| } | |
| } | |
| } | |
| MageKeyManager.keyUp = function(event){ | |
| var keycode = MageKeyManager.getKeyCode(event); | |
| if(MageKeyManager.keys[keycode] != undefined){ | |
| if(MageKeyManager.keys[keycode] == true){ | |
| MageKeyManager.keys[keycode] = false | |
| } | |
| } | |
| } | |
| MageKeyManager.isPressed = function(input){ | |
| if(!isNumber(input)){ | |
| var con = MageKeyManager.keyExists(input); | |
| if(con != false){ | |
| input = MageKeyManager.keyreplace[con]; | |
| } | |
| } | |
| return MageKeyManager.keys[input] | |
| } | |
| Mage.KeyManager = MageKeyManager; | |
| })(); |
| /********************************************** | |
| * | |
| * MageJS ~ My awesome Game Lib in Javascript | |
| * | |
| * ~ Mouse class | |
| * | |
| * Tracks mouse movements | |
| * | |
| * Functions | |
| * MageMouse.init() | |
| * MageMouse.x | |
| * MageMouse.y | |
| * | |
| ***********************************************/ | |
| (function(){ | |
| MageMouse = { | |
| version: "0.1" | |
| } | |
| MageMouse.curLeft = 0; | |
| MageMouse.curTop = 0; | |
| MageMouse.x = 0; | |
| MageMouse.y = 0; | |
| MageMouse.move = function(event){ | |
| event = (event) ? event : ((window.event) ? window.event : ""); | |
| MageMouse.x = (event.pageX - MageMouse.curleft) || (event.clientX - MageMouse.curleft); | |
| MageMouse.y = (event.pageY - MageMouse.curTop) || (event.clientY - MageMouse.curTop); | |
| } | |
| MageMouse.alert = function(){ | |
| alert(MageMouse.x +"/"+ MageMouse.y); | |
| } | |
| MageMouse.resize = function(){ | |
| body = document.getElementById(Mage.canvas_id) || document.getElementsByTagName('canvas')[0]; | |
| calcOffset(body); | |
| } | |
| function calcOffset(obj){ | |
| do { | |
| MageMouse.curLeft += obj.offsetLeft; | |
| MageMouse.curTop += obj.offsetTop; | |
| } while (obj = obj.offsetParent); | |
| } | |
| MageMouse.init = function(elem){ | |
| body = document.getElementById(elem) || document.getElementsByTagName('canvas')[0]; | |
| body.setAttribute('onmousemove','MageMouse.move(event)'); | |
| calcOffset(body); | |
| } | |
| Mage.Mouse = MageMouse; | |
| })(); |
| /********************************************** | |
| * | |
| * MageJS ~ My awesome Game Lib in Javascript | |
| * | |
| * ~ Sound class | |
| * | |
| * Uses HTML5 <audio> API to create sound | |
| * elements and control them. | |
| * | |
| * Functions | |
| * MageSound.init() | |
| * MageSound.volume(Container_Id, 0..1) | |
| * MageSound.play(Container_Id, Boolean loop) | |
| * MageSound.pause(Container_Id) | |
| * MageSound.remove(Container_Id) | |
| * MageSound.create(Container_Id, [Files Array], Boolean autoplay, Boolean loop) | |
| * | |
| ***********************************************/ | |
| (function(){ | |
| MageSound = { | |
| version: "0.1", | |
| container: "mage-sound", | |
| base_volume: 0.1 | |
| } | |
| MageSound.init = function(){ | |
| var body = document.getElementsByTagName('body')[0]; | |
| var div = document.createElement('div'); | |
| div.setAttribute("id",MageSound.container+"_box"); | |
| div.style.display = 'none'; | |
| body.appendChild(div); | |
| } | |
| // Set volume to container (Does not work with chrome? :3) | |
| MageSound.volume = function(container, volume){ | |
| var elem = document.getElementById(MageSound.container+"_audio_"+container); | |
| elem.volume = volume; | |
| } | |
| MageSound.play = function(container,loop){ | |
| var elem = document.getElementById(MageSound.container+"_audio_"+container); | |
| if(loop == true){ elem.setAttribute("loop","true"); } else { elem.removeAttribite('loop'); } | |
| elem.play(); | |
| } | |
| MageSound.pause = function(container){ | |
| var elem = document.getElementById(MageSound.container+"_audio_"+container); | |
| elem.pause(); | |
| } | |
| MageSound.remove = function(container){ | |
| var body = document.getElementsByTagName('body')[0]; | |
| var div = document.getElementById( MageSound.container+"_container_"+container ); | |
| body.removeChild(div); | |
| } | |
| // Play sound (String file, String container_id, Boolean loop) | |
| MageSound.create = function(container, files, play, loop) { | |
| if(document.getElementById( MageSound.container+"_container_"+container )) { | |
| MageSound.remove(container); | |
| } | |
| var box = document.getElementById(MageSound.container+"_box"); | |
| var dix = document.createElement('audio'); | |
| dix.setAttribute("id",MageSound.container+"_audio_"+container); | |
| dix.setAttribute("volume",""+MageSound.base_volume+""); | |
| dix.setAttribute("controls","false"); | |
| if(play == true){ dix.setAttribute("autoplay","true"); } | |
| dix.setAttribute("preload","true"); | |
| dix.setAttribute("autobuffer","true"); | |
| dix.volume = MageSound.base_volume; | |
| if(loop == true){ dix.setAttribute("loop","true"); } | |
| box.appendChild(dix); | |
| for(var file in files){ | |
| var srx = document.createElement('source'); | |
| var type = "audio/mpeg"; | |
| if(files[file].indexOf('.ogg')>0){ | |
| type = "audio/ogg"; | |
| } else if(files[file].indexOf('.wav')>0){ | |
| type = "audio/wav"; | |
| } | |
| srx.setAttribute('src',files[file]); | |
| srx.setAttribute('type',type); | |
| dix.appendChild(srx); | |
| } | |
| } | |
| Mage.Sound = MageSound; | |
| })(); |
| /********************************************** | |
| * | |
| * MageJS ~ My awesome Game Lib in Javascript | |
| * | |
| * ~ Sound class | |
| * | |
| * Uses HTML5 <audio> API to create sound | |
| * elements and control them. | |
| * | |
| * Functions | |
| * MageSprite.create(image,width,height,x,y,speed) | |
| * MageSprite.update() | |
| * MageSprite.draw() | |
| * MageSprite._log() | |
| * | |
| * Accessor | |
| * image | |
| * version | |
| * x | |
| * y | |
| * width | |
| * height | |
| * sprite_x | |
| * sprite_y | |
| * scale | |
| * animation[] | |
| * current_animation | |
| * current_frame | |
| * complete : loaded? | |
| * speed : Milliseconds | |
| * | |
| ***********************************************/ | |
| /** | |
| * Sprite Class | |
| * @class | |
| */ | |
| function MageSprite(){ | |
| this.image; | |
| this.version = "0.1"; | |
| this.x = 0; | |
| this.y = 0; | |
| this.width = 0; | |
| this.height = 0; | |
| this.sprite_x = 0; | |
| this.sprite_y = 0; | |
| this.scale = 1; | |
| this.animation = new Object(); | |
| this.current_animation = "ALL"; | |
| this.current_frame = 0; | |
| this.complete = true; | |
| this.lastmove = 0; | |
| this.speed = 500; | |
| /** | |
| Creates a Sprite | |
| @param {string} image - Source of the image | |
| @param {integer} width - Width of the *shown* image | |
| @param {integer} height - Height of the *shown* image | |
| @param {integer} x - X position on Canvas | |
| @param {integer} y - Y position on Canvas | |
| @param {integer} speed - Time for animation in Milliseconds | |
| */ | |
| this.create = function(image,width,height,x,y,speed){ | |
| this.image = new Image(); | |
| this.image.src = image; | |
| this.speed = speed || 500; | |
| this.height = height || 16; | |
| this.width = width || 16; | |
| this.x = x || 0; | |
| this.y = y || 0; | |
| this.image.width = 64; | |
| this.image.height = 64; | |
| this.animation["ALL"] = Mage.range(0,(this.image.width/this.width)*(this.image.height/this.height)-1); | |
| return this; | |
| } | |
| /** | |
| Updates Animation (calculates if needed) | |
| */ | |
| this.update = function(){ | |
| if(this.complete && this.lastmove < (new Date).getTime()-this.speed){ | |
| this.lastmove = (new Date).getTime(); | |
| var current = this.animation[this.current_animation][this.current_frame]; | |
| var row = Math.floor(current*this.height/this.image.height); | |
| this.sprite_y = row * this.height; | |
| this.sprite_x = Math.floor(current - ((this.image.width/this.width)*row) ) * this.width; | |
| if(this.current_frame >= this.animation[this.current_animation].length-1) | |
| { this.current_frame = 0; } else { this.current_frame++; } | |
| } | |
| } | |
| /** | |
| Draws a sprite | |
| @param {CanvasContext} ctx - Canvas Context to draw on | |
| */ | |
| this.draw = function(ctx){ | |
| if(this.complete){ | |
| ctx.drawImage(this.image,this.sprite_x,this.sprite_y,this.width,this.height,this.x,this.y,this.width*this.scale,this.height*this.scale); | |
| } | |
| } | |
| /** | |
| Dumps some Sprite info to the log | |
| */ | |
| this._log = function(){ | |
| console.log("X: "+this.x+" Y: "+this.y+" WIDTH: "+this.width+" HEIGHT: "+this.height) | |
| } | |
| } | |
| Mage.Sprite = MageSprite; |