Advertisement
Guest User

Epihaumut HTML5 Library

a guest
Apr 25th, 2014
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.     Filename: framework.js
  3.     Version: 0.1
  4.    
  5.     Description:
  6.         Framework written by Julian Reid aka Epihaumut / Jools64.
  7.        
  8.     Use:
  9.         You are free to use this code for any project that you like
  10.         be it commercial or not.
  11.        
  12.         I have not yet made any documentation so this code would be
  13.         best used as an example rather than as a library in an actual
  14.         game.
  15.    
  16.     Todo:
  17.         Particles
  18.             Emitter (Can be attached to entity)
  19.         Bitmap Font Graphic
  20.         Pixel Mask
  21.         Line Mask
  22.         MaskList
  23.         OgmoLoader
  24.         Sound
  25.             Stop sound
  26.             Pitch shift
  27.             3D
  28.         Input
  29.             Key bindings
  30. */
  31.  
  32. window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
  33.                                window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
  34.                                
  35. Function.prototype.subclass = function()
  36. {
  37.     SubClass.prototype = this.prototype;
  38.     return new SubClass();
  39. }; function SubClass(){};
  40.  
  41. window.startupFunctions = [];
  42.  
  43. window.onload = function()
  44. {
  45.     for(var f in window.startupFunctions)
  46.     {
  47.         window.startupFunctions[f]();
  48.     }
  49. }
  50.  
  51. function Sound()
  52. {
  53.     this.globalVolume = 0.3;
  54.     this.music = null;
  55.  
  56.     try
  57.     {
  58.         window.AudioContext = window.AudioContext||window.webkitAudioContext;
  59.         this.context = new AudioContext();
  60.     }
  61.     catch(e) {
  62.         alert('Your browser does not support the Web Audio API. Please update to the latest version of Chrome, Firefox, Opera or Safari. IE is currently not supported.');
  63.     }
  64. }
  65.  
  66. Sound.prototype.play = function(url, loop, volume, pan)
  67. {
  68.     if(loop === undefined)
  69.         loop = false;
  70.     if(volume === undefined)
  71.         volume = 1;
  72.     if(pan === undefined)
  73.         pan = 0;
  74.     pan = Utils.clamp(pan, -1, 1);
  75.        
  76.     volume *= this.globalVolume;
  77.  
  78.     var buffer = Assets.getSound(url);
  79.     var gain = this.context.createGain();
  80.     var panner = this.context.createPanner();
  81.     var source = this.context.createBufferSource();
  82.    
  83.     panner.connect(gain);
  84.     panner.coneOuterGain = 1;
  85.     panner.coneOuterAngle = 0;
  86.     panner.coneInnerAngle = 0;
  87.     var angle = (pan*90)+90;
  88.     panner.setPosition(Math.cos(Utils.toRad(angle)), 0, Math.sin(Utils.toRad(angle)))
  89.    
  90.     gain.connect(this.context.destination);
  91.     gain.gain.value = volume;
  92.    
  93.     source.buffer = buffer;
  94.     source.connect(panner);
  95.     source.loop = loop;
  96.     source.start(0);
  97.    
  98.     return source;
  99. }
  100.  
  101. Sound.prototype.stop = function(sound)
  102. {
  103.     sound.stop();
  104. }
  105.  
  106. Sound.prototype.playMusic = function(url, loop, volume)
  107. {
  108.     if(this.music != null)
  109.         this.music.stop();
  110.        
  111.     if(loop === undefined)
  112.         loop = false;
  113.     if(volume === undefined)
  114.         volume = 1;
  115.        
  116.     this.music = this.play(url, loop, volume);
  117. }
  118.  
  119. window.Sound = new Sound();
  120.  
  121. function Utils()
  122. {
  123.  
  124. }
  125.  
  126. Utils.prototype.clamp = function(number, min, max)
  127. {
  128.     if(number > max)
  129.         number = max;
  130.     if(number < min)
  131.         number = min;
  132.     return number;
  133. }
  134.  
  135. Utils.prototype.loop = function(number, min, max)
  136. {
  137.     var d = (max-min);
  138.    
  139.     while(number > max)
  140.         number -= d;
  141.     while(number < min)
  142.         number += d;
  143.     return number;
  144. }
  145.  
  146. Utils.prototype.toRad = function(degrees)
  147. {
  148.     return (2*Math.PI)-((2*Math.PI)/360)*degrees;
  149. }
  150.  
  151. Utils.prototype.distance = function(x1, y1, x2, y2)
  152. {
  153.     var dx = x2 - x1;
  154.     var dy = y2 - y1;
  155.     return Math.abs(Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)));
  156. }
  157.  
  158. Utils.prototype.sign = function(number)
  159. {
  160.     return number > 0 ? 1 : number < 0 ? -1 : number;
  161. }
  162.  
  163. Utils.prototype.signApply = function(number, neg, zer, pos)
  164. {
  165.     var sign = this.sign(number);
  166.     if(sign < 0) return neg;
  167.     if(sign == 0) return zer;
  168.     if(sign > 0) return pos;
  169. }
  170.  
  171. Utils.prototype.direction = function(sx, sy, dx, dy)
  172. {
  173.     var deltaX = dx - sx;
  174.     var deltaY = dy - sy;
  175.    
  176.     var dir = (Math.atan2(deltaY, deltaX) * 180 / Math.PI);
  177.    
  178.     return 360 - (dir < 0 ? dir + 360 : dir);
  179. }
  180.  
  181. Utils.prototype.padNumber = function(n, zeros)
  182. {
  183.     var string = n.toString();
  184.     while(string.length <= zeros-1)
  185.     {
  186.         string = "0" + string;
  187.     }
  188.     return string;
  189. }
  190.  
  191. window.Utils = new Utils();
  192.  
  193. function Input()
  194. {
  195.     this.canvas = null;
  196. }
  197.  
  198. Input.prototype.init = function(canvas)
  199. {
  200.     this.canvas = canvas;
  201.     this.keys = [];
  202.     for(var i = 0; i < 128; i++)
  203.         this.keys[i] = false;
  204.     this.keysLast = this.keys.slice(0);
  205.    
  206.     this.mouse = [];
  207.     for(var i = 0; i < 3; i++)
  208.         this.mouse[i] = false;
  209.     this.mouseLast = this.mouse.slice(0);
  210.     this.mouseX = 0;
  211.     this.mouseY = 0;
  212.    
  213.     this.touches = null;
  214.    
  215.     var that = this;
  216.    
  217.     canvas.addEventListener("contextmenu", function(e){
  218.         e.preventDefault();
  219.         return false;
  220.     }, false);
  221.    
  222.     canvas.addEventListener("mousedown", function(e){
  223.         that.mouse[e.button] = true;
  224.     }, false);
  225.    
  226.     canvas.addEventListener("mouseup", function(e){
  227.         that.mouse[e.button] = false;
  228.     }, false);
  229.    
  230.     canvas.addEventListener("mousemove", function(e){
  231.         var rect = canvas.getBoundingClientRect();
  232.         that.mouseX = e.clientX - rect.left;
  233.         that.mouseY = e.clientY - rect.top;
  234.         that.mouseX = (that.mouseX / rect.width)*game.width;
  235.         that.mouseY = (that.mouseY / rect.height)*game.height;
  236.     }, false);
  237.    
  238.     window.addEventListener("keydown", function(e){
  239.         that.keys[e.keyCode] = true;
  240.        
  241.         if(e.keyCode == 70)
  242.         {
  243.             game.fullscreen();
  244.         }
  245.        
  246.         if(e.keyCode == that.keyToCode("UP") ||
  247.            e.keyCode == that.keyToCode("DOWN") ||
  248.            e.keyCode == that.keyToCode("LEFT") ||
  249.            e.keyCode == that.keyToCode("RIGHT") ||
  250.            e.keyCode == that.keyToCode("ESCAPE") ||
  251.            e.keyCode == that.keyToCode("ENTER"))
  252.         {
  253.             e.preventDefault();
  254.             return false;
  255.         }
  256.     }, false);
  257.    
  258.     window.addEventListener("keyup", function(e){
  259.         that.keys[e.keyCode] = false;
  260.         e.preventDefault();
  261.         return false;
  262.     }, false);
  263.    
  264.     canvas.addEventListener('touchstart', function(e){
  265.         that.setTouch(e);
  266.     }, false);
  267.    
  268.     canvas.addEventListener('touchcancel', function(e){
  269.         that.setTouch(e);
  270.     }, false);
  271.    
  272.     canvas.addEventListener('touchend', function(e){
  273.         that.setTouch(e);
  274.     }, false);
  275.    
  276.     canvas.addEventListener('touchmove', function(e){
  277.         that.setTouch(e);
  278.     }, false);
  279. }
  280.  
  281. Input.prototype.setTouch = function(e)
  282. {
  283.     e.preventDefault();
  284.     this.touches = e.touches;
  285. }
  286.  
  287. Input.prototype.isTouched = function(x, y, w, h)
  288. {
  289.     if(this.touches != null)
  290.     {
  291.         for(var t in this.touches)
  292.         {
  293.             var touch = this.touches[t];
  294.            
  295.             if(typeof touch.clientX !== "undefined")
  296.             {
  297.                 var rect = game.canvas.getBoundingClientRect();
  298.                 var tx = touch.clientX - rect.left;
  299.                 var ty = touch.clientY - rect.top;
  300.                 tx = (tx / rect.width) * game.width;
  301.                 ty = (ty / rect.height) * game.height;
  302.                
  303.                 if(tx > x &&
  304.                    ty > y &&
  305.                    tx < x + w &&
  306.                    ty < y + h)
  307.                 {
  308.                     return new Point(tx, ty);
  309.                 }
  310.             }
  311.         }
  312.     }
  313.    
  314.     return null;
  315. }
  316.  
  317. Input.prototype.mouseButtonToCode = function(button)
  318. {
  319.     var code;
  320.     switch(button)
  321.     {
  322.         case "LEFT":
  323.             code = 0;
  324.             break;
  325.         case "MIDDLE":
  326.             code = 1;
  327.             break;
  328.         case "RIGHT":
  329.             code = 2;
  330.             break;
  331.     }
  332.     return code;
  333. }
  334.  
  335. Input.prototype.checkMouse = function(button)
  336. {
  337.     return(this.mouse[this.mouseButtonToCode(button)]);
  338. }
  339.  
  340. Input.prototype.checkKeyPressed = function(key)
  341. {
  342.     return(this.mouse[this.mouseButtonToCode(key)] && !this.mouseLast[this.mouseButtonToCode(key)]);
  343. }
  344.  
  345. Input.prototype.checkKeyReleased = function(key)
  346. {
  347.     return(!this.mouse[this.mouseButtonToCode(key)] && this.mouseLast[this.mouseButtonToCode(key)]);
  348. }
  349.  
  350. Input.prototype.checkKey = function(key)
  351. {
  352.     return(this.keys[this.keyToCode(key)]);
  353. }
  354.  
  355. Input.prototype.checkKeyPressed = function(key)
  356. {
  357.     return(this.keys[this.keyToCode(key)] && !this.keysLast[this.keyToCode(key)]);
  358. }
  359.  
  360. Input.prototype.checkKeyReleased = function(key)
  361. {
  362.     return(!this.keys[this.keyToCode(key)] && this.keysLast[this.keyToCode(key)]);
  363. }
  364.  
  365. Input.prototype.keyToCode = function(key)
  366. {
  367.     switch(key.toUpperCase())
  368.     {
  369.         case "SPACE":
  370.             return 32;
  371.             break;
  372.         case "ENTER":
  373.             return 13;
  374.             break;
  375.         case "ESCAPE":
  376.             return 27;
  377.             break;
  378.         case "CONTROL":
  379.             return 17;
  380.             break;
  381.         case "SHIFT":
  382.             return 16;
  383.             break;
  384.         case "ALT":
  385.             return 18;
  386.             break;
  387.         case "TAB":
  388.             return 9;
  389.             break;
  390.         case "LEFT":
  391.             return 37;
  392.             break;
  393.         case "UP":
  394.             return 38;
  395.             break;
  396.         case "DOWN":
  397.             return 40;
  398.             break;
  399.         case "RIGHT":
  400.             return 39;
  401.             break;
  402.         default:
  403.             return key.charCodeAt(0);
  404.             break;
  405.     }
  406. }
  407.  
  408. Input.prototype.update = function()
  409. {
  410.     if(this.keys == null)
  411.         this.keys = [];
  412.     this.keysLast = this.keys.slice(0);
  413.     this.mouseLast = this.mouse.slice(0);
  414. }
  415. window.Input = new Input();
  416.  
  417. function Assets()
  418. {
  419.     this.images = [];
  420.     this.imagePath = "images/";
  421.     this.sounds = [];
  422.     this.soundPath = "sounds/";
  423.     this.data = [];
  424.     this.dataPath = "data/";
  425.    
  426.     this.callback = null;
  427. }
  428.  
  429. Assets.prototype.setCallback = function(callback)
  430. {
  431.     this.callback = callback;
  432. }
  433.  
  434. Assets.prototype.loadImage = function(paths)
  435. {
  436.     for(var path in paths)
  437.     {
  438.         var image = new Image();
  439.        
  440.         var that = this;
  441.         image.onload = function(){
  442.             that.images[this.path] = this;
  443.             that.isDone();
  444.         }
  445.        
  446.         image.src = this.imagePath + paths[path];
  447.         image.path = paths[path];
  448.         this.images[paths[path]] = null;
  449.     }
  450. }
  451.  
  452. Assets.prototype.loadSound = function(paths)
  453. {
  454.     for(var path in paths)
  455.     {
  456.         var sound = new XMLHttpRequest();
  457.         sound.open('GET', this.soundPath + paths[path], true);
  458.         sound.responseType = 'arraybuffer';
  459.        
  460.         var that = this;
  461.         sound.onload = function(e)
  462.         {
  463.             var snd = this;
  464.             Sound.context.decodeAudioData(this.response, function(buffer) {
  465.                 that.sounds[snd.path] = buffer;
  466.                 that.isDone();
  467.             }, function(){console.log('An error occured decoding audio.');});
  468.         }
  469.        
  470.         sound.path = paths[path];
  471.         this.sounds[paths[path]] = null;
  472.        
  473.         sound.send();
  474.     }
  475. }
  476.  
  477. Assets.prototype.loadData = function(paths)
  478. {
  479.     for(var path in paths)
  480.     {
  481.         var data = new XMLHttpRequest();
  482.         data.open('GET', this.dataPath + paths[path], true);
  483.        
  484.         var that = this;
  485.         data.onload = function(e)
  486.         {
  487.             that.data[this.path] = this.response;
  488.             that.isDone();
  489.         }
  490.        
  491.         data.path = paths[path];
  492.         this.data[paths[path]] = null;
  493.        
  494.         data.send();
  495.     }
  496. }
  497.  
  498. Assets.prototype.isDone = function()
  499. {
  500.     for(var image in this.images)
  501.     {
  502.         if(this.images[image] == null)
  503.             return false;
  504.     }
  505.    
  506.     for(var sound in this.sounds)
  507.     {
  508.         if(this.sounds[sound] == null)
  509.             return false;
  510.     }
  511.    
  512.     for(var data in this.data)
  513.     {
  514.         if(this.data[data] == null)
  515.             return false;
  516.     }
  517.  
  518.     this.callback();
  519. }
  520.  
  521. Assets.prototype.getImage = function(path)
  522. {
  523.     var image = this.images[path];
  524.     if(image === undefined)
  525.         console.log("Image not yet loaded: " + path);
  526.     else
  527.         return image;
  528.     return null;
  529. }
  530.  
  531. Assets.prototype.getSound = function(path)
  532. {
  533.     var sound = this.sounds[path];
  534.     if(sound === undefined)
  535.         console.log("Sound not yet loaded: " + path);
  536.     else
  537.         return sound;
  538.     return null;
  539. }
  540.  
  541. Assets.prototype.getData = function(path)
  542. {
  543.     var data = this.data[path];
  544.     if(data === undefined)
  545.         console.log("Data file has not yet loaded: " + path);
  546.     else
  547.         return data;
  548.     return null;
  549. }
  550.  
  551.  
  552. Assets.prototype.scaleImage = function(path, scale)
  553. {
  554.     var image = this.images[path];
  555.     if(image === undefined)
  556.         console.log("Image not yet loaded: " + path);
  557.     else
  558.     {
  559.         var scaled = document.createElement("canvas");
  560.         scaled.width = image.width*scale;
  561.         scaled.height = image.height*scale;
  562.         scaledCtx = scaled.getContext("2d");
  563.        
  564.         scaledCtx.imageSmoothingEnabled = false;
  565.         scaledCtx.mozImageSmoothingEnabled  = false;
  566.         scaledCtx.webkitImageSmoothingEnabled  = false;
  567.        
  568.         scaledCtx.drawImage(image, 0, 0, image.width, image.height,
  569.                             0, 0, scaled.width, scaled.height);
  570.         this.images[path] = scaled;
  571.     }
  572.     return null;
  573. }
  574.  
  575. window.Assets = new Assets();
  576.  
  577. function Game(canvas, width, height, smoothing)
  578. {
  579.     this.canvas = canvas;
  580.     this.width = width === undefined ? 640 : width;
  581.     this.height = height === undefined ? 360 : height;
  582.     this.clearColor = new Color(50, 50, 50);
  583.     this.smoothing = smoothing === undefined ? false : smoothing;
  584.    
  585.     this.images = [];
  586.     this.sounds = [];
  587.     this.data = [];
  588.    
  589.     this.ctx = canvas.getContext("2d");
  590.     if(!smoothing)
  591.     {
  592.         this.ctx.imageSmoothingEnabled = false;
  593.         this.ctx.mozImageSmoothingEnabled  = false;
  594.         this.ctx.webkitImageSmoothingEnabled  = false;
  595.     }
  596.    
  597.     this.lastTime = Date.now();
  598.     this.maxDelta = 0.2;
  599.    
  600.     this.world = null;
  601. }
  602.  
  603. Game.prototype.start = function()
  604. {
  605.     //setup global reference
  606.     window.game = this;
  607.    
  608.     this.canvas.width = this.width;
  609.     this.canvas.height = this.height;
  610.    
  611.     Assets.setCallback(function(){
  612.         game.init();
  613.     });
  614.     Assets.loadImage(this.images);
  615.     Assets.loadSound(this.sounds);
  616.     Assets.loadData(this.data);
  617. }
  618.  
  619. Game.prototype.init = function()
  620. {
  621.     Input.init(this.canvas);
  622.     requestAnimationFrame(this.loop.bind(this));
  623. }
  624.  
  625. Game.prototype.loop = function()
  626. {
  627.     requestAnimationFrame(this.loop.bind(this));
  628.  
  629.     var currentTime = Date.now();
  630.     var delta = (currentTime - this.lastTime)/1000;
  631.     if(delta > this.maxDelta)
  632.         delta = this.maxDelta;
  633.     if(delta < 0)
  634.         delta = 0;
  635.     this.update(delta);
  636.     this.draw();
  637.     this.lastTime = currentTime;
  638. }
  639.  
  640. Game.prototype.update = function(delta)
  641. {
  642.    
  643.     if(this.world != null)
  644.         this.world.update(delta);
  645.     Input.update();
  646. }
  647.  
  648. Game.prototype.draw = function()
  649. {
  650.     this.ctx.fillStyle = this.clearColor.toHex();
  651.     this.ctx.beginPath();
  652.     this.ctx.rect(0, 0, this.width, this.height);
  653.     this.ctx.fill();
  654.    
  655.     if(this.world != null)
  656.         this.world.draw();
  657. }
  658.  
  659. Game.prototype.setWorld = function(world)
  660. {
  661.     world.init();
  662.     this.world = world;
  663. }
  664.  
  665. Game.prototype.fullscreen = function()
  666. {
  667.     console.log("fullscreen");
  668.     if(this.canvas.webkitRequestFullScreen)
  669.         this.canvas.webkitRequestFullScreen();
  670.     else if(this.canvas.mozRequestFullScreen)
  671.         this.canvas.mozRequestFullScreen();
  672.     else if(this.canvas.requestFullScreen)
  673.         this.canvas.requestFullScreen()
  674. }
  675.  
  676. Game.prototype.showCursor = function(show)
  677. {
  678.     if(show)
  679.         this.canvas.style.cursor = "";
  680.     else
  681.         this.canvas.style.cursor = "none";
  682. }
  683.  
  684. function World()
  685. {
  686.     this.entities = [];
  687.     this.removeList = [];
  688.     this.addList = [];
  689.     this.camera = null;
  690.     this.nextUpdateSort = true;
  691. }
  692.  
  693. World.prototype.init = function()
  694. {
  695.     this.camera = new Camera();
  696. }
  697.  
  698. World.prototype.update = function(delta)
  699. {
  700.     this.camera.update(delta);
  701.  
  702.     for(var entity in this.entities)
  703.         this.entities[entity].update(delta);
  704.    
  705.     if(this.addList.length > 0)
  706.     {
  707.         for(var entity in this.addList)
  708.             this.entities.push(this.addList[entity]);
  709.         this.addList.length = 0;
  710.         this.depthSort();
  711.     }
  712.    
  713.     if(this.removeList.length > 0)
  714.     {
  715.         for(var entity in this.removeList)
  716.             this.entities.splice(this.entities.indexOf(this.removeList[entity]), 1);
  717.         this.removeList.length = 0;
  718.     }
  719.    
  720.     if(this.nextUpdateSort)
  721.     {
  722.         this.entities.sort(this.depthSortCompare);
  723.         this.nextUpdateSort = false;
  724.     }
  725. }
  726.  
  727. World.prototype.draw = function()
  728. {
  729.     for(var entity in this.entities)
  730.         this.entities[entity].draw();
  731. }
  732.  
  733. World.prototype.add = function(entity)
  734. {
  735.     entity.world = this;
  736.     entity.init();
  737.     this.addList.push(entity);
  738. }
  739.  
  740. World.prototype.remove = function(entity)
  741. {
  742.     this.removeList.push(entity);
  743. }
  744.  
  745. World.prototype.depthSortCompare = function(a, b)
  746. {
  747.     if(a.depth > b.depth)
  748.         return -1;
  749.     if(a.depth < b.depth)
  750.         return 1;
  751.     return 0;
  752. }
  753.  
  754. World.prototype.depthSort = function()
  755. {
  756.     this.nextUpdateSort = true;
  757. }
  758.  
  759. World.prototype.collide = function(entity, type, offsetX, offsetY)
  760. {
  761.     var entity1 = entity;
  762.    
  763.     offsetX = offsetX === undefined ? 0 : offsetX;
  764.     offsetY = offsetY === undefined ? 0 : offsetY;
  765.    
  766.     entity1.x += offsetX;
  767.     entity1.y += offsetY;
  768.    
  769.     for(var e in this.entities)
  770.     {
  771.         var entity2 = this.entities[e];
  772.         if(entity2.type == type)
  773.             if(entity1.mask != null && entity2.mask != null && entity1.mask.collide(entity2.mask))
  774.             {
  775.                 entity1.x -= offsetX;
  776.                 entity1.y -= offsetY;
  777.                
  778.                 return entity2;
  779.             }
  780.     }
  781.    
  782.     entity1.x -= offsetX;
  783.     entity1.y -= offsetY;
  784.                
  785.     return null;
  786. }
  787.  
  788. World.prototype.typeCount = function(type)
  789. {
  790.     var count = 0;
  791.     for(var e in this.entities)
  792.         if(this.entities[e].type == type)
  793.             ++count;
  794.     return count;
  795. }
  796.  
  797. World.prototype.getFirstOfType = function(type)
  798. {
  799.     for(var e in this.entities)
  800.     {
  801.         if(this.entities[e].type == type)
  802.                 return this.entities[e];
  803.     }
  804.        
  805.     return null;
  806. }
  807.  
  808. function Camera()
  809. {
  810.     this.x = 0;
  811.     this.y = 0;
  812.    
  813.     this.offsetX = game.width/2;
  814.     this.offsetY = game.height/2;
  815.    
  816.     this.targetX = this.x + this.offsetX;
  817.     this.targetY = this.y + this.offsetY;
  818.     this.target = null;
  819.    
  820.     this.easeSpeed = 4;
  821. }
  822.  
  823. Camera.prototype.setPosition = function(x, y)
  824. {
  825.     this.x = x;
  826.     this.y = y;
  827. }
  828.  
  829. Camera.prototype.setTarget = function()
  830. {
  831.     if(arguments.length == 1)
  832.     {
  833.         //Target entity
  834.         this.target = arguments[0];
  835.     }
  836.     else if(arguments.length == 2)
  837.     {
  838.         //Target position
  839.         this.targetX = arguments[0];
  840.         this.targetY = arguments[1];
  841.         this.target = null;
  842.     }
  843. }
  844.  
  845. Camera.prototype.update = function(delta)
  846. {
  847.     if(this.target)
  848.     {
  849.         this.targetX = this.target.x;
  850.         this.targetY = this.target.y;
  851.     }
  852.     this.x += ((this.targetX - this.offsetX) - this.x) * delta * this.easeSpeed;
  853.     this.y += ((this.targetY - this.offsetY) - this.y) * delta * this.easeSpeed;
  854. }
  855.  
  856. function Entity()
  857. {
  858.     this.graphic = null;
  859.     this.depth = 0;
  860.     this.mask = null;
  861.     this.type = "";
  862.    
  863.     this.x = 0;
  864.     this.y = 0;
  865.    
  866.     this.deltaCounter = 0;
  867.     this.stepInterval = 1/60;
  868.     this.fixedTimeStep = false;
  869.     this.maxSteps = 8;
  870. }
  871.  
  872. Entity.prototype.init = function()
  873. {
  874.    
  875. }
  876.  
  877. Entity.prototype.update = function(delta)
  878. {
  879.     if(this.graphic != null)
  880.         this.graphic.update(delta);
  881.    
  882.     if(this.fixedTimeStep)
  883.     {
  884.         this.deltaCounter += delta;
  885.         var steps = 0;
  886.         while(this.deltaCounter >= this.stepInterval)
  887.         {
  888.             this.step();
  889.             this.deltaCounter -= this.stepInterval;
  890.             if(++steps >= this.maxSteps)
  891.                 break;
  892.         }
  893.     }
  894. }
  895.  
  896. Entity.prototype.step = function()
  897. {
  898.    
  899. }
  900.  
  901. Entity.prototype.draw = function()
  902. {
  903.     if(this.graphic != null && this.graphic.visible)
  904.         this.graphic.draw();
  905. }
  906.  
  907. Entity.prototype.setGraphic = function(graphic)
  908. {
  909.     this.graphic = graphic;
  910.     this.graphic.setOwner(this);
  911.     this.graphic.init();
  912. }
  913.  
  914. Entity.prototype.setMask = function(mask)
  915. {
  916.     this.mask = mask;
  917.     this.mask.owner = this;
  918. }
  919.  
  920. Entity.prototype.setDepth = function(depth)
  921. {
  922.     if(this.depth != depth)
  923.     {
  924.         this.depth = depth;
  925.         this.world.depthSort();
  926.     }
  927. }
  928.  
  929. Entity.prototype.collide = function(type)
  930. {
  931.     return this.world.collide(this, type);
  932. }
  933.  
  934. function Graphic()
  935. {
  936.     this.owner = null;
  937.     this.xOffset = 0;
  938.     this.yOffset = 0;
  939.    
  940.     this.xOrigin = 0;
  941.     this.xOrigin = 0;
  942.    
  943.     this.angle = 0;
  944.     this.xScale = 1;
  945.     this.yScale = 1;
  946.    
  947.     this.width = 0;
  948.     this.height = 0;
  949.     this.image = null;
  950.    
  951.     this.visible = true;
  952.    
  953.     this.effectsApplied = false;
  954. }
  955.  
  956. Graphic.prototype.setOwner = function(owner)
  957. {
  958.     this.owner = owner;
  959. }
  960.  
  961. Graphic.prototype.init = function()
  962. {
  963.    
  964. }
  965.  
  966. Graphic.prototype.update = function(delta)
  967. {
  968.    
  969. }
  970.  
  971. Graphic.prototype.applyEffects = function()
  972. {
  973.     if(this.angle != 0 || this.xScale != 1 || this.yScale != 1)
  974.     {
  975.         this.effectsApplied = true;
  976.        
  977.         var transformX = this.getX() + this.xOrigin;
  978.         var transformY = this.getY() + this.yOrigin;
  979.  
  980.         game.ctx.save();
  981.         game.ctx.translate(transformX, transformY);
  982.         game.ctx.rotate(Utils.toRad(this.angle));
  983.         game.ctx.scale(this.xScale, this.yScale);
  984.         game.ctx.translate(-transformX, -transformY);
  985.     }
  986. }
  987.  
  988. Graphic.prototype.resetEffects = function()
  989. {
  990.     if(this.effectsApplied)
  991.     {
  992.         this.effectsApplied = false;
  993.         game.ctx.restore();
  994.     }
  995. }
  996.  
  997. Graphic.prototype.draw = function()
  998. {
  999.    
  1000. }
  1001.  
  1002. Graphic.prototype.getX = function()
  1003. {
  1004.     return Math.floor(this.owner.x - this.xOffset - this.owner.world.camera.x);
  1005. }
  1006.  
  1007. Graphic.prototype.getY = function()
  1008. {
  1009.     return Math.floor(this.owner.y - this.yOffset - this.owner.world.camera.y);
  1010. }
  1011.  
  1012. Graphic.prototype.centerOffset = function()
  1013. {
  1014.     this.xOffset = this.width/2;
  1015.     this.yOffset = this.height/2;
  1016. }
  1017.  
  1018. Graphic.prototype.centerOrigin = function()
  1019. {
  1020.     this.xOrigin = this.width/2;
  1021.     this.yOrigin = this.height/2;
  1022. }
  1023.  
  1024. Graphic.prototype.drawTile = function(x, y, width, height, id)
  1025. {
  1026.     var sx = (id*width)%this.image.width;
  1027.     var sy = (((id*width) - sx)/this.image.width)*height;
  1028.    
  1029.     try
  1030.     {
  1031.         game.ctx.drawImage(this.image, sx, sy,
  1032.                            width, height,
  1033.                            x, y,
  1034.                            width, height);
  1035.     }
  1036.     catch(IndexSizeError){
  1037.         console.log("Error: Tile id goes outside sheet: " + id);
  1038.     }
  1039. }
  1040.  
  1041. function GraphicList(graphics)
  1042. {
  1043.     Graphic.call(this);
  1044.     this.graphics = graphics;
  1045. }
  1046.  
  1047. GraphicList.prototype = Graphic.subclass();
  1048.  
  1049. GraphicList.prototype.setOwner = function(owner)
  1050. {
  1051.     for(var g in this.graphics)
  1052.         this.graphics[g].setOwner(owner);
  1053. }
  1054.  
  1055. GraphicList.prototype.init = function()
  1056. {
  1057.     for(var g in this.graphics)
  1058.         this.graphics[g].init();
  1059. }
  1060.  
  1061. GraphicList.prototype.draw = function()
  1062. {
  1063.     for(var g in this.graphics)
  1064.         if(this.graphics[g].visible)
  1065.             this.graphics[g].draw();
  1066. }
  1067.  
  1068. GraphicList.prototype.update = function(delta)
  1069. {
  1070.     for(var g in this.graphics)
  1071.         this.graphics[g].update(delta);
  1072. }
  1073.  
  1074. function Sprite(imagePath, width, height)
  1075. {
  1076.     Graphic.call(this);
  1077.     this.image = Assets.getImage(imagePath);
  1078.     this.width = width === undefined ? this.image.width : width;
  1079.     this.height = height === undefined ? this.image.height : height;
  1080.  
  1081.     this.centerOrigin();
  1082.    
  1083.     this.frame = 0;
  1084.     this.frames = [0];
  1085.     this.frameRate = 0;
  1086.     this.animations = [];
  1087.     this.animationDone = false;
  1088.     this.loop = true;
  1089.    
  1090.     this.onScreen = true;
  1091. }
  1092.  
  1093. Sprite.prototype = Graphic.subclass();
  1094.  
  1095. Sprite.prototype.draw = function()
  1096. {
  1097.     var x = this.getX();
  1098.     var y = this.getY();
  1099.     if(x > -this.width &&
  1100.        y > -this.height &&
  1101.        x < game.width + this.width &&
  1102.        y < game.height + this.height)
  1103.     {
  1104.         this.onScreen = true;
  1105.         this.applyEffects();
  1106.         var frame;
  1107.         if(this.frames.length > 0)
  1108.             frame = this.frames[Math.floor(this.frame)];
  1109.         else
  1110.             frame = 0;
  1111.            
  1112.         this.drawTile(this.getX(), this.getY(),
  1113.                       this.width, this.height, frame);
  1114.         this.resetEffects();
  1115.     }
  1116.     else
  1117.         this.onScreen = false;
  1118. }
  1119.  
  1120. Sprite.prototype.update = function(delta)
  1121. {
  1122.     this.frame += this.frameRate*delta;
  1123.     if(this.frame < 0)
  1124.         this.frame = this.frames.length-1;
  1125.     if(this.frame >= this.frames.length)
  1126.     {
  1127.         if(this.loop)
  1128.             this.frame = 0;
  1129.         else this.frame = this.frames.length-1;
  1130.         this.animationDone = true;
  1131.     }
  1132. }
  1133.  
  1134. Sprite.prototype.add = function(name, frames, frameRate)
  1135. {
  1136.     this.animations[name] = new Animation(frames, frameRate);
  1137. }
  1138.  
  1139. Sprite.prototype.play = function(name, frameRate, reset, loop)
  1140. {
  1141.     this.frames = this.animations[name].frames;
  1142.     if(frameRate && frameRate >= 0)
  1143.         this.frameRate = frameRate;
  1144.     else
  1145.         this.frameRate = this.animations[name].frameRate;
  1146.        
  1147.     if(reset !== undefined && reset)
  1148.         this.frame = 0;
  1149.        
  1150.     if(loop !== undefined)
  1151.         this.loop = loop;
  1152.     else this.loop = true;
  1153.        
  1154.     this.animationDone = false;
  1155.     if(this.frame < 0)
  1156.         this.frame = this.frames.length-1;
  1157.     if(this.frame >= this.frames.length)
  1158.     {
  1159.         if(this.loop)
  1160.             this.frame = 0;
  1161.         else this.frame = this.frames.length-1;
  1162.     }
  1163. }
  1164.  
  1165. function TileMap(imagePath, tileSize, width, height)
  1166. {
  1167.     Graphic.call(this);
  1168.     this.image = Assets.getImage(imagePath);
  1169.  
  1170.     this.map = [];
  1171.     for(var i = 0; i < width; i++)
  1172.     {
  1173.         this.map[i] = [];
  1174.         for(var t = 0; t < height; t++)
  1175.             this.map[i][t] = -1;
  1176.     }
  1177.    
  1178.     this.tileSize = tileSize;
  1179.     this.width = width;
  1180.     this.height = height;
  1181. }
  1182.  
  1183. TileMap.prototype = Graphic.subclass();
  1184.  
  1185. TileMap.prototype.draw = function()
  1186. {
  1187.     this.applyEffects();
  1188.    
  1189.     var fx, fy, tx, ty;
  1190.     fx = Math.floor(this.owner.world.camera.x/this.tileSize);
  1191.     fy = Math.floor(this.owner.world.camera.y/this.tileSize);
  1192.     tx = Math.ceil((this.owner.world.camera.x + game.width)/this.tileSize);
  1193.     ty = Math.ceil((this.owner.world.camera.y + game.height)/this.tileSize);
  1194.    
  1195.     fx = Utils.clamp(fx, 0, this.width);
  1196.     tx = Utils.clamp(tx, 0, this.width);
  1197.     fy = Utils.clamp(fy, 0, this.height);
  1198.     ty = Utils.clamp(ty, 0, this.height);
  1199.    
  1200.     for(var i = fx; i < tx; i++)
  1201.         for(var t = fy; t < ty; t++)
  1202.             if(this.map[i][t] != -1)
  1203.             {
  1204.                 this.drawTile(this.getX() + (i*this.tileSize), this.getY() + (t*this.tileSize),
  1205.                               this.tileSize, this.tileSize, this.map[i][t]);
  1206.             }
  1207.                
  1208.     this.resetEffects();
  1209. }
  1210.  
  1211. TileMap.prototype.fill = function(id)
  1212. {
  1213.     for(var i = 0; i < this.width; i++)
  1214.         for(var t = 0; t < this.height; t++)
  1215.                 this.map[i][t] = id;
  1216. }
  1217.  
  1218. TileMap.prototype.set = function(x, y, id)
  1219. {
  1220.     this.map[x][y] = id;
  1221. }
  1222.  
  1223. function Background(imagePath, xRepeat, yRepeat)
  1224. {
  1225.     Graphic.call(this);
  1226.     this.image = Assets.getImage(imagePath);
  1227.     this.xRepeat = xRepeat === undefined ? true : xRepeat;
  1228.     this.yRepeat = yRepeat === undefined ? true : yRepeat;
  1229. }
  1230.  
  1231. Background.prototype = Graphic.subclass();
  1232.  
  1233. Background.prototype.draw = function()
  1234. {
  1235.     var scrollX, scrollY;
  1236.     if(this.xRepeat)
  1237.     {
  1238.         scrollX = (this.getX()%this.image.width);
  1239.         if(scrollX > 0)
  1240.             scrollX -= this.image.width;
  1241.     }
  1242.     else
  1243.         scrollX = this.getX();
  1244.        
  1245.     if(this.yRepeat)
  1246.     {
  1247.         var scrollY = (this.getY()%this.image.height);
  1248.         if(scrollY > 0)
  1249.             scrollY -= this.image.height;
  1250.     }
  1251.     else
  1252.         scrollY = this.getY();
  1253.        
  1254.     var toX = this.xRepeat ? (game.width + this.image.width) : 1;
  1255.     var toY = this.yRepeat ? (game.height + this.image.height) : 1;
  1256.        
  1257.     for(var x = 0; x < toX; x += this.image.width)
  1258.         for(var y = 0; y < toY; y += this.image.height)
  1259.         {
  1260.             game.ctx.drawImage(this.image,
  1261.                                this.width + x + scrollX,
  1262.                                this.height + y + scrollY);
  1263.         }
  1264. }
  1265.  
  1266. function Animation(frames, frameRate)
  1267. {
  1268.     this.frames = frames;
  1269.     this.frameRate = frameRate === undefined ? 0 : frameRate;
  1270. }
  1271.  
  1272. function Mask()
  1273. {
  1274.     this.type = "";
  1275.     this.owner = null;
  1276.    
  1277.     this.x = 0;
  1278.     this.y = 0;
  1279.    
  1280.     this.BOX = 0;
  1281.     this.GRID = 1;
  1282. }
  1283.  
  1284. Mask.prototype.collide = function(other)
  1285. {
  1286.    
  1287. }
  1288.  
  1289. Mask.prototype.getX = function()
  1290. {
  1291.     return this.x + this.owner.x;
  1292. }
  1293.  
  1294. Mask.prototype.getY = function()
  1295. {
  1296.     return this.y + this.owner.y;
  1297. }
  1298.  
  1299. function Grid(gridSize, width, height)
  1300. {
  1301.     Mask.call(this);
  1302.     this.type = this.GRID;
  1303.        
  1304.     this.gridSize = gridSize;
  1305.     this.width = width;
  1306.     this.height = height;
  1307.     this.map = [];
  1308.     this.clear();
  1309. }
  1310.  
  1311. Grid.prototype = Mask.subclass();
  1312.  
  1313. Grid.prototype.collide = function(other)
  1314. {
  1315.     switch(other.type)
  1316.     {
  1317.         case this.BOX:
  1318.             var fx = Math.floor(other.getX()/this.gridSize);
  1319.             var fy = Math.floor(other.getY()/this.gridSize);
  1320.             var tx = Math.ceil((other.getX() + other.width)/this.gridSize);
  1321.             var ty = Math.ceil((other.getY() + other.width)/this.gridSize);
  1322.            
  1323.             fx = Utils.clamp(fx, 0, this.width);
  1324.             tx = Utils.clamp(tx, 0, this.width);
  1325.             fy = Utils.clamp(fy, 0, this.height);
  1326.             ty = Utils.clamp(ty, 0, this.height);
  1327.            
  1328.             for(var x = 0; x < this.width; x++)
  1329.                 for(var y = 0; y < this.height; y++)
  1330.                 {
  1331.                     var bx = (x*this.gridSize) + this.getX();
  1332.                     var by = (y*this.gridSize) + this.getY();
  1333.                    
  1334.                     if(this.map[x][y])
  1335.                     {
  1336.                         if(!(other.getX() >  bx + this.gridSize ||
  1337.                                  other.getX() + other.width < bx ||
  1338.                                  other.getY() > by + this.gridSize ||
  1339.                                  other.getY() + other.height < by))
  1340.                             return true;
  1341.                     }
  1342.                 }
  1343.             break;
  1344.         default:
  1345.             console.log("Error: Collision not implemented: " + this.type + " with " + other.type);
  1346.             return false;
  1347.             break;
  1348.     }
  1349.    
  1350.     return false;
  1351. }
  1352.  
  1353. Grid.prototype.clear = function()
  1354. {
  1355.     for(var x = 0; x < this.width; x++)
  1356.     {
  1357.         this.map[x] = [];
  1358.         for(var y = 0; y < this.height; y++)
  1359.         {
  1360.             this.map[x][y] = false;
  1361.         }
  1362.     }
  1363. }
  1364.  
  1365. Grid.prototype.set = function(x, y, value)
  1366. {
  1367.     this.map[x][y] = value;
  1368. }
  1369.  
  1370. function Box(width, height, x, y)
  1371. {
  1372.     Mask.call(this);
  1373.     this.type = this.BOX;
  1374.    
  1375.     this.x = x === undefined ? 0 : x;
  1376.     this.y = y === undefined ? 0 : y;
  1377.     this.width = width;
  1378.     this.height = height;
  1379. }
  1380.  
  1381. Box.prototype = Mask.subclass();
  1382.  
  1383. Box.prototype.collide = function(other)
  1384. {
  1385.     switch(other.type)
  1386.     {
  1387.         case this.BOX:
  1388.             return(!(other.getX() > this.getX() + this.width ||
  1389.                      other.getX() + other.width < this.getX() ||
  1390.                      other.getY() > this.getY() + this.height ||
  1391.                      other.getY() + other.height < this.getY()));
  1392.             break;
  1393.         case this.GRID:
  1394.             return(other.collide(this));
  1395.             break;
  1396.         default:
  1397.             console.log("Error: Collision not implemented: " + this.type + " with " + other.type);
  1398.             return false;
  1399.             break;
  1400.     }
  1401. }
  1402.  
  1403. function Point(x, y)
  1404. {
  1405.     this.x = x;
  1406.     this.y = y;
  1407. }
  1408.  
  1409. function Color(r, g, b)
  1410. {
  1411.     this.r = r;
  1412.     this.g = g;
  1413.     this.b = b;
  1414. }
  1415.  
  1416. Color.prototype.toHex = function()
  1417. {
  1418.     return "#" + this.r.toString(16) + this.g.toString(16) + this.b.toString(16);
  1419. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement