├── README.md ├── example ├── img │ ├── .DS_Store │ ├── bg.jpg │ ├── reptile.png │ └── reptile2.png ├── index-minifiedLib.html └── index.html ├── mibbu-min.js └── mibbu.js /README.md: -------------------------------------------------------------------------------- 1 | Mibbu 2 | ======== 3 | 4 | #### First Javascript Game MicroFramework #### 5 | 6 | Mibbu gives you everything you need for fast prototyping your Javascript game in less than 2.5KB of gzipped code. Games created with Mibbu can be displayed using Canvas or DOM mode (you can change it with one single function, or use feature detection to use DOM where it is no canvas, like in IE family). Mibbu supports also CSS animations in Webkit ([blogpost](http://michalbe.blogspot.com/2011/05/css3-animations-in-mibbu.html)) and in Firefox BETA (5.0). 7 | 8 | 9 | [Documentation](http://mibbu.eu) 10 | 11 | 12 | ### Features of Mibbu ### 13 | * Rendering game using both - Canvas or DOM 14 | * Animation of the sprites (using Canvas, DOM or CSS Animation in Webkit & Firefox 5+) 15 | * Collisions detection with collision zones 16 | * Simple background manager 17 | * Callbacks after given number of frames 18 | * Method's chaining 19 | * Check [example](https://github.com/michalbe/mibbu/tree/master/example) for more 20 | 21 | ### Change Log ### 22 | 23 | 2011 08 09 - **0.3.2/nagasaki** (5.62 KB, gzip 2.29 KB) 24 | 25 | * one pixel background margin bug in Canvas Mode fixed. 26 | 27 | 2011 08 07 - **0.3.1/victor** (5.91 KB, gzip 2.36 KB) by [end3r](https://github.com/end3r) 28 | 29 | * it's now possible to switch background image using .img() function 30 | 31 | 2011 06 12 - **0.3/arkansas** (5.89 KB, gzip 2.37 KB) 32 | 33 | * every method now return itself when you call it with parameters (like .speed(3)) so it's possile to connect multiple methods into one chain (like background.speed(4).direction(-20)). Methods called without arguments returns value of given metod (like background.speed() return the speed of the background) 34 | 35 | 2011 06 12 - **0.2.4/annefrank** (5.57 KB, gzip 2.30 KB) by [MartinDoms](https://github.com/MartinDoms) 36 | 37 | * background direction could be now specified in both, strings ("N", "S", "E", "W") and numbers (radians) 38 | * it is possible to change background direction 'on the fly' without resetting the background position 39 | 40 | 2011 06 11 - **0.2.3/kamehameha** (5.42 KB, gzip 2.12 KB) 41 | 42 | * FPS module optimization 43 | 44 | 2011 06 05 - **v0.2.2/blackwater** (5.43 KB, gzip 2.12 KB) 45 | 46 | * Animation structure changed according to Marek Stepien's research on CSS Animations in Firefox [[blogpost](http://michalbe.blogspot.com/2011/06/css-animation-in-firefox.html#update)] 47 | 48 | 2011 06 04 - **v0.2.1/birthdayAfterparty** (5.46 KB, gzip 2.12 KB) 49 | 50 | * CSS3 Animations support in Firefox (tested in 5.0/BETA) 51 | * .indexOf() name changed for minimization and compatibility with other solutions [[blogpost](http://michalbe.blogspot.com/2011/06/css-animation-in-firefox.html)] 52 | 53 | 2011 05 23 - **v0.2/suiko** (5.54 KB, gzip 2.13 KB) [[blogpost](http://michalbe.blogspot.com/2011/05/css3-animations-in-mibbu.html)] 54 | 55 | * CSS3 Animations support in Webkit browsers (tested on Chrome 11 & Safari 5.03) 56 | * .cssAnimationOff() function added (works the same as .canvasOff() but for CSS Animations) 57 | * some major & minor bug fixes 58 | 59 | 2011 05 19 - **v0.1.2/guanabhadra** (4.36 KB, gzip: 1.81 KB) 60 | 61 | * Changes in Array#indexOf - we don't need full spec implementation here. This one is faster and smaller. 62 | 63 | 2011 05 09 - **v0.1.1/atilla** (4.45 KB, gzip: 1.83 KB) 64 | 65 | * Array#indexOf fix by [killdream](https://github.com/killdream) 66 | * Proper declaration of MB_mainCanvasStyle variable 67 | 68 | 2011 05 05 - **v0.1/odoacer** (4.35 KB, gzip: 1.81 KB) 69 | 70 | * First release 71 | 72 | ---- 73 | 74 | ### License ### 75 | 76 | ####The MIT License#### 77 | 78 | Copyright (c) 2011 [Michal Budzynski](https://profiles.google.com/michal.budzynski.js/about). All rights reserved. 79 | 80 | Permission is hereby granted, free of charge, to any person obtaining a copy 81 | of this software and associated documentation files (the "Software"), to deal 82 | in the Software without restriction, including without limitation the rights 83 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 84 | copies of the Software, and to permit persons to whom the Software is 85 | furnished to do so, subject to the following conditions: 86 | 87 | The above copyright notice and this permission notice shall be included in 88 | all copies or substantial portions of the Software. 89 | 90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 92 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 93 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 95 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 96 | THE SOFTWARE. 97 | -------------------------------------------------------------------------------- /example/img/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalbe/mibbu/52bbde1ac98def0f8644566a126ad1e2f079fc2f/example/img/.DS_Store -------------------------------------------------------------------------------- /example/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalbe/mibbu/52bbde1ac98def0f8644566a126ad1e2f079fc2f/example/img/bg.jpg -------------------------------------------------------------------------------- /example/img/reptile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalbe/mibbu/52bbde1ac98def0f8644566a126ad1e2f079fc2f/example/img/reptile.png -------------------------------------------------------------------------------- /example/img/reptile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalbe/mibbu/52bbde1ac98def0f8644566a126ad1e2f079fc2f/example/img/reptile2.png -------------------------------------------------------------------------------- /example/index-minifiedLib.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mibbu test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mibbu test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /mibbu-min.js: -------------------------------------------------------------------------------- 1 | var l=void 0,mibbu=function(J,K,A){function q(){for(var c=n.length,e,d,f,g,b,h,a,B,C;c--;)for(e in d=n[c],g=d.d+d.b.A,b=d.d+d.height-d.b.q,h=d.c+d.b.u,d=d.c+d.width-d.b.w,n[c].t)if(f=D[e],a=f.d+f.b.A,B=f.d+f.height-f.b.q,C=f.c+f.b.u,f=f.c+f.width-f.b.w,!(g>B||bf||d=1E3&&(G=v,v=0,u=c);c="FPS: "+G;if(k)o.fillText(c,4,15);else if(s)s.innerHTML=c;v++}w&&(H=I(E,g))}function L(){g=m.createElement("canvas");o=g.getContext("2d");o.j=o.drawImage;e.sort(function(c,e){return c.h-e.h})}function M(){F=k?function(){o.clearRect(0,0,x,y)}:function(){};r&&(u=new Date);I=function(){return window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(c){setTimeout(c,1E3/60)}}();p=g.style;g.width=x;g.height=y;p.width=x+"px";p.height=y+"px";p.position="absolute";p.overflow="hidden";z.appendChild(g)}var k=!0,j=!1,m=document,e=[],z=A?m.getElementById(A):m.body,g,o,x=J||400,y=K||300,i=[],H,F,u=new Date,r=!1,s,n=[],D=[],I,p,t,h;Array.prototype.j=Array.prototype.indexOf||function(c){for(var e=this.length;e--&&this[e]!==c;);return e};var v=0,G=0,w=!0;m.createElement("canvas").getContext||(k=!1);return{fps:function(){r=!0;return this},init:function(){k?L():(g=m.createElement("div"),r&&(s=m.createElement("div"),g.appendChild(s)));M();return this},on:function(){w=!0;E();if(j)for(var c=e.length;c--;)e[c].k&&(e[c].k.style[h+"AnimationDuration"]=~~(1/(60/e[c].e)*100)/100*(e[c].g+1)+"s");return this},off:function(){clearTimeout(H);w=!1;if(j)for(var c=e.length;c--;)e[c].k&&(e[c].k.style[h+"AnimationDuration"]=0);return this},canvas:function(){return g},ctx:function(){return o},canvasOff:function(){k=!1;typeof z.style.WebkitAnimation!=="undefined"?(t="-webkit-",h="Webkit",j=!0):typeof z.style.MozAnimation!=="undefined"&&(t="-moz-",h="Moz",j=!0);return this},cssAnimationOff:function(){j=!1;return this},hitsOn:function(){i.j(q)===-1&&i.push(q);return this},hitsOff:function(){i.j(q)!==-1&&i.splice(i.j(q),1);return this},spr:function(c,i,d,f,p){function b(){for(var b="@"+t+"keyframes s"+a.id+" {\n",c=100/(a.g+1),e="% { "+t+"transform: translate(",d=0;d0){if(a.p==a.e&&a.e!==0){if(a.l==a.g){if(a.l=0,typeof a.s==="function"&&(a.r++,a.r===a.B))a.s(),a.r=0}else a.l++;a.p=0}a.e!==0&&a.p++;q()}};return{position:function(b,c,d){return b!==l?(a.c=b||a.c,a.d=c||a.d,a.h=d||a.h,k?d&&e.sort(function(a,b){return b.h-a.h}):(a.f.left=b+"px",a.f.top=c+"px",a.f.zIndex=d||a.h),this):{x:a.c,y:a.d,J:a.h}},hit:function(b,c){n.j(a)===-1&&n.push(a);a.t[b.id()]=c;n.j(a)===-1&&n.push(a);return this},zone:function(b,c,d,e){return b!==l?(a.b.u=e,a.b.A=b,a.b.w=c,a.b.q=d,this):a.b},noHits:function(){a.t={};return this},callback:function(b,c){a.s=b;a.B=c;return this},change:function(c,d,e,f,g){a.k.src=c;a.width=d;a.height=e;a.F=d;a.D=e;a.g=f;a.i=g;a.p=0;a.l=0;a.s=null;a.r=0;a.B=0;if(!k&&(a.a.width=d*(a.i+1)+"px",a.a.height=e*(a.g+1)+"px",a.f.width=d+"px",a.f.height=e+"px",j))a.a[h+"AnimationName"]="",a.o.innerHTML=b(),a.a[h+"AnimationName"]="s"+a.id;a.b={A:0,u:0,q:0,w:0};return this},size:function(c,d){if(c!==l){if(!k)a.f.width=c+"px",a.f.height=d+"px",a.a.width=c*(a.H+1)+"px",a.a.height=d*(a.g+1)+"px";a.width=c;a.height=d;if(j)a.a[h+"AnimationName"]="",a.o.innerHTML=b(),a.a[h+"AnimationName"]="s"+a.id;return this}else return{width:a.width,height:a.height}},speed:function(b){return b!==l?(a.e=b,a.p=0,j&&(a.a[h+"AnimationDuration"]=~~(1/(60/b)*100)/100*(a.g+1)+"s"),this):a.e},animation:function(c){if(c!==l){a.i=c;if(j)a.a[h+"AnimationName"]="",a.o.innerHTML=b(),a.a[h+"AnimationName"]="s"+a.id;return this}else return a.i},frame:function(b){return b!==l?(a.l=b,this):a.l},id:function(){return a.id}}},bg:function(c,i,d,f){function h(a){b.m=0;b.n=0;if(typeof a==="string")switch(a){case "N":b.m=0;b.n=-1;break;case "W":b.m=-1;b.n=0;break;case "S":b.m=0;b.n=1;break;case "E":b.m=1,b.n=0}else if(typeof a==="number")a*=j,b.m=Math.cos(a),b.n=Math.sin(a)}var b=this;g.style.backgroundImage="url("+c+")";b.e=i||3;var j=Math.PI/180;h(d);b.h=f.z||0;b.c=f.x||0;b.d=f.y||0;b.id=e.push(b);b.v=0;b.G=function(){b.c+=b.e*b.m*b.v;b.d+=b.e*b.n*b.v;var a=b.c,c=b.d;a.toString().indexOf("e")!=-1&&(a=0);c.toString().indexOf("e")!=-1&&(c=0);g.style.backgroundPosition=a+"px "+c+"px"};return{on:function(){b.v=1;return this},off:function(){b.v=0;return this},dir:function(a){h(a);return this},speed:function(a){return a!==l?(b.e=a,this):b.e},img:function(a){return a!==l?(g.style.backgroundImage="url("+a+")",this):c},position:function(a,c){return a!==l?(b.c=a||b.c,b.d=c||b.d,this):{x:b.c,y:b.d}}}},hook:function(c){i.push(c);return this},unhook:function(c){i.j(c)!==-1&&i.splice(i.j(c),1);return this}}}; -------------------------------------------------------------------------------- /mibbu.js: -------------------------------------------------------------------------------- 1 | /*global document, setInterval, setTimeout, Image, clearTimeout*/ 2 | 3 | /** 4 | * 5 | * mibbu - javascript canvas/DOM game framework 6 | * by Michal Budzynski 7 | * http://michalbe.blogspot.com 8 | * http://twitter.com/michalbe 9 | * http://mibbu.eu 10 | * http://onGameStart.com 11 | * 12 | */ 13 | 14 | var mibbu = function(Cwidth, Cheight, _parent){ 15 | var MB_usingCanvas = true, //use canvas or DOM? 16 | MB_usingCSSAnimations = false, 17 | document = window['document'], //document declaration for Closure Compiler 18 | MB_elements = [], //all drawable elements 19 | MB_parentElement = _parent ? document.getElementById(_parent) : document.body, //parent element the canvas will be appended to 20 | MB_mainCanvas, 21 | MB_mainContext, 22 | MB_mainCanvasWidth = Cwidth || 400, 23 | MB_mainCanvasHeight = Cheight || 300, 24 | MB_addedLoops=[], //functions added to each loop frame 25 | MB_drawLoop, //main loop 26 | MB_preClear, 27 | MB_lastTime = new Date(), //time for FPS counter 28 | MB_fpsMeasure=false, 29 | MB_ftpsDiv, 30 | MB_collides=[], //array with references to objects with enabled collisions 31 | MB_fixedIndexColl = [], //workaround for collisions 32 | MB_Animate, 33 | MB_mainCanvasStyle, 34 | MB_prefixCSS, 35 | MB_prefixJS; 36 | /** 37 | * Older browser's fixes 38 | */ 39 | // Fallback for Array#indexOf, where the implementation does not support it 40 | // natively 41 | // 42 | // Follows the algorithm described in ES-262 15.4.4.14 43 | // 44 | /* 45 | //MDC spec-like implementation 46 | Array.prototype.indexOf = Array.prototype.indexOf 47 | || function (value, start) { 48 | var key; 49 | var obj = Object(this); 50 | var len = obj.length >>> 0; 51 | 52 | start = +start || 0; 53 | if (!len || start >= len){ 54 | return -1; 55 | } 56 | if (start < 0){ 57 | start = Math.max(0, len - Math.abs(start)); 58 | } 59 | 60 | for (key = start; key < len; ++key){ 61 | if (key in obj && obj[key] === value){ 62 | return key; 63 | } 64 | } 65 | return -1; 66 | } 67 | */ 68 | // lastIndexOf implementation by Andrea Giammarchi 69 | // form Falsy Values conference 70 | // http://webreflection.blogspot.com 71 | Array.prototype.i = Array.prototype.indexOf || 72 | function(value){ 73 | for (var i = this.length; i-- && this[i]!== value;) {} 74 | return i; 75 | }; 76 | 77 | //and custom remove() method 78 | var rm = function(value, array) { 79 | if (array.i(value)!==-1) { 80 | array.splice(array.i(value), 1); 81 | return true; 82 | } else { 83 | return false; 84 | } 85 | } ; 86 | 87 | 88 | /** 89 | * DEBUG FUNCTIONS 90 | **/ 91 | 92 | var frameCount=0; 93 | var fps = 0; 94 | var MeasureFPS = function(){ 95 | var newTime = +(new Date()); 96 | var diffTime = ~~((newTime - MB_lastTime)); 97 | 98 | if (diffTime >= 1000) { 99 | fps = frameCount; 100 | frameCount = 0; 101 | MB_lastTime = newTime; 102 | } 103 | var stringFps = 'FPS: ' + fps; 104 | if (MB_usingCanvas) { 105 | //MB_mainContext.fillStyle = "#fff"; 106 | //MB_mainContext.font = "12px Arial"; 107 | MB_mainContext.fillText(stringFps, 4, 15); 108 | } else { 109 | if (MB_ftpsDiv) { 110 | MB_ftpsDiv.innerHTML = stringFps; 111 | } 112 | } 113 | frameCount++; 114 | }; 115 | 116 | /** 117 | * end of debug functions 118 | * 119 | * Start/Stop functions 120 | **/ 121 | 122 | var calculateSpeed = function(speed, frames) { 123 | return (~~((1/(60/speed))*100)/100)*(frames+1); 124 | }; 125 | //main drawing function 126 | var DrawAll = function(){ 127 | 128 | MB_preClear(); 129 | 130 | //draw all element 131 | var loopIndex = MB_elements.length; 132 | while (loopIndex--) { 133 | MB_elements[loopIndex].draw(); 134 | } 135 | 136 | //run other functions 137 | loopIndex = MB_addedLoops.length; 138 | while (loopIndex--) { 139 | MB_addedLoops[loopIndex](); 140 | } 141 | 142 | if (MB_fpsMeasure) { 143 | MeasureFPS(); 144 | } 145 | 146 | }; 147 | //check if it is possible to use canvas 148 | var MB_detectCanvas = function() { 149 | if(!document.createElement('canvas').getContext) { 150 | MB_usingCanvas = false; 151 | } 152 | }; 153 | 154 | var MB_InitCore = function() { 155 | //common part of both modes 156 | 157 | MB_preClear = MB_usingCanvas ? function(){MB_mainContext.clearRect(0, 0, MB_mainCanvasWidth, MB_mainCanvasHeight);} : function(){}; 158 | 159 | if (MB_fpsMeasure) { 160 | MB_lastTime = new Date(); 161 | } 162 | 163 | //use requestAnimationFrame() if possible 164 | //inspired by Paul Irish Blog 165 | //http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 166 | //support only for moz & webkit now - Opera or IE are no 167 | //interested in it so far. 168 | MB_Animate = (function(){ 169 | return window['webkitRequestAnimationFrame'] || 170 | window['mozRequestAnimationFrame'] || 171 | function(/* function */ callback, /* DOMElement */ element){ 172 | setTimeout(callback, 1000 / 60); 173 | }; 174 | })(); 175 | 176 | //inline styling, not using setAttribute() 177 | //because of IE7 & IE8 bugs 178 | MB_mainCanvasStyle = MB_mainCanvas.style; 179 | MB_mainCanvas.width = MB_mainCanvasWidth; 180 | MB_mainCanvas.height = MB_mainCanvasHeight; 181 | MB_mainCanvasStyle.width = MB_mainCanvasWidth+'px'; 182 | MB_mainCanvasStyle.height =MB_mainCanvasHeight+'px'; 183 | MB_mainCanvasStyle.position ='absolute'; 184 | MB_mainCanvasStyle.overflow = 'hidden'; 185 | 186 | MB_parentElement.appendChild(MB_mainCanvas); 187 | 188 | }; 189 | 190 | var MB_InitCanvas = function() { 191 | MB_mainCanvas = document.createElement('canvas'); 192 | 193 | MB_mainContext = MB_mainCanvas.getContext('2d'); 194 | MB_mainContext.i = MB_mainContext.drawImage; 195 | 196 | //sorting all elements is like Z-Index for canvas 197 | MB_elements.sort(function(a,b){return a.zOrder - b.zOrder;}); 198 | 199 | }; 200 | 201 | var MB_InitDOM = function() { 202 | 203 | MB_mainCanvas = document.createElement('div'); 204 | 205 | //MB_mainCanvas.style.overflow = 'hidden'; 206 | 207 | if (MB_fpsMeasure) { 208 | 209 | MB_ftpsDiv = document.createElement('div'); 210 | MB_mainCanvas.appendChild(MB_ftpsDiv); 211 | 212 | } 213 | 214 | }; 215 | 216 | //initiation of main loop 217 | var running = true, 218 | MB_Start = function() { 219 | DrawAll(); 220 | 221 | if(running) 222 | MB_drawLoop = MB_Animate(MB_Start, MB_mainCanvas); 223 | }; 224 | 225 | var MB_Stop = function() { 226 | clearTimeout(MB_drawLoop); 227 | running=false; 228 | }; 229 | 230 | /** 231 | * End of Start/Stop functions 232 | **/ 233 | //collisions 234 | var MB_checkCollides = function() { 235 | var loopIndex = MB_collides.length, 236 | element, 237 | p1, p2, 238 | p1Top, p1Bottom, p1Left, p1Right, 239 | p2Top, p2Bottom, p2Left, p2Right; 240 | 241 | while(loopIndex--) { 242 | p1 = MB_collides[loopIndex]; 243 | p1Top = p1.posY + p1.cZ.t; 244 | p1Bottom = p1.posY + p1.height - p1.cZ.b; 245 | p1Left = p1.posX + p1.cZ.l; 246 | p1Right = p1.posX + p1.width - p1.cZ.r; 247 | 248 | //UNCOMMENT THSE TWO BLOCKS FOR COLLISION BOXES. 249 | //IN CANVAS MODE ONLY! 250 | /* 251 | MB_mainContext.moveTo(p1Right, p1Top); 252 | 253 | MB_mainContext.lineTo(p1Right, p1Bottom); 254 | MB_mainContext.lineTo(p1Left, p1Bottom); 255 | MB_mainContext.lineTo(p1Left, p1Top); 256 | MB_mainContext.lineTo(p1Right, p1Top); 257 | */ 258 | for(element in MB_collides[loopIndex].hits){ 259 | p2 = MB_fixedIndexColl[element]; 260 | p2Top = p2.posY + p2.cZ.t; 261 | p2Bottom = p2.posY + p2.height - p2.cZ.b; 262 | p2Left = p2.posX + p2.cZ.l; 263 | p2Right = p2.posX + p2.width - p2.cZ.r; 264 | /* 265 | MB_mainContext.moveTo(p2Right, p2Top); 266 | 267 | MB_mainContext.lineTo(p2Right, p2Bottom); 268 | MB_mainContext.lineTo(p2Left, p2Bottom); 269 | MB_mainContext.lineTo(p2Left, p2Top); 270 | MB_mainContext.lineTo(p2Right, p2Top); 271 | MB_mainContext.stroke(); 272 | */ 273 | if (!( 274 | (p1Top > p2Bottom) || 275 | (p1Bottom < p2Top) || 276 | (p1Left > p2Right) || 277 | (p1Right < p2Left) 278 | )){ 279 | //console.dir(MB_collides[loopIndex].hits) 280 | MB_collides[loopIndex].hits[element](); 281 | } 282 | } 283 | 284 | } 285 | }; 286 | 287 | /** 288 | * SPRITES 289 | **/ 290 | 291 | var MB_Sprite = function(_image, _width, _height, _frames, _animations) { 292 | 293 | var draw = MB_usingCanvas ? function(){ 294 | //draw canvas 295 | try { 296 | MB_mainContext.i(t.image, 297 | t.iWidth * t.animation, 298 | t.iHeight * t.f, 299 | t.iWidth, 300 | t.iHeight, 301 | t.posX, 302 | t.posY, 303 | t.width, 304 | t.height); 305 | } catch(e) { 306 | //if image is not ready yet try to display it on another frame 307 | //delete this and build preLoader 308 | } 309 | } : MB_usingCSSAnimations ? function(){ /*css animations*/ } : function(){ 310 | //draw DOM 311 | t.si.top = t.height * t.f*-1+'px'; 312 | t.si.left = t.width * t.animation*-1+'px'; 313 | }, 314 | t = {}, 315 | //prepare class for CSS animation 316 | constructAnimationClass = function(){ 317 | var animationClass = "@" + MB_prefixCSS + "keyframes s"+t.id+" {\n", 318 | step = 100/(t.fs+1), 319 | str = "% { " + MB_prefixCSS + "transform: translate("; 320 | for (var q = 0; q < t.fs+1; q++) { 321 | animationClass += ~~((step*q)*100)/100+ str +t.animation*t.width*-1+'px,'+q*t.height*-1+'px); }\n'; 322 | animationClass += ~~((step*(q+1)-0.01)*100)/100+ str +t.animation*t.width*-1+'px,'+q*t.height*-1+'px); }\n'; 323 | } 324 | 325 | return animationClass += '100'+ str +t.animation*t.width+'px, 0px); }\n}'; 326 | 327 | }; 328 | 329 | 330 | t.id = MB_elements.length; 331 | 332 | t.image = new Image(); 333 | t.image.src = _image; 334 | 335 | t.speed = 1; 336 | t.width = _width; 337 | t.iWidth = _width; 338 | t.height = _height; 339 | t.iHeight = _height; 340 | t.fs = _frames; 341 | t.animations = _animations; 342 | t.colllides = false; 343 | t.hits = {}; 344 | 345 | t.f = 0; 346 | t.animation = 0; 347 | t.speed = 1; 348 | t.interval = 0; 349 | 350 | t.posX = 0; 351 | t.posY = 0; 352 | 353 | t.zOrder = 1; 354 | 355 | t.callback = null; 356 | t.callIters=0; 357 | t.callMaxIters=0; 358 | 359 | //collision zones 360 | t.cZ = { 361 | t: 0, 362 | l: 0, 363 | b:0, 364 | r: 0 365 | } 366 | 367 | if (!MB_usingCanvas) { 368 | //document.createElement('img') not allowed in IE6 369 | t.div = document.createElement('div'); 370 | t.s = t.div.style; 371 | 372 | t.s.overflow = 'hidden'; 373 | t.s.width = _width+'px'; 374 | t.s.height = _height+'px'; 375 | t.s.position = 'absolute'; 376 | t.s.zIndex = t.zOrder; 377 | 378 | t.si = t.image.style; 379 | 380 | t.si.position="absolute"; 381 | 382 | if (MB_usingCSSAnimations) { 383 | //calculate keyframes for CSS animation 384 | 385 | 386 | //append keyframe class to the document 387 | t.animStyle = document.createElement('style'); 388 | t.animStyle.innerHTML = constructAnimationClass(); 389 | //document.getElementsByTagName('head')[0] 390 | document.body.appendChild(t.animStyle); 391 | 392 | //additional style attribute for the image, 393 | t.si[ MB_prefixJS + "Animation" ] = "s"+t.id+" "+calculateSpeed(t.speed, t.fs)+"s linear 0s infinite"; 394 | 395 | 396 | } 397 | 398 | t.div.appendChild(t.image); 399 | 400 | MB_mainCanvas.appendChild(t.div); 401 | } 402 | 403 | t.id = MB_elements.push(t)-1; 404 | MB_fixedIndexColl.push(t); //for collisions, temporary 405 | 406 | var setPosition = function(x, y, z) { 407 | //there is at least one argument, 408 | //set position and return 'this' for chaining 409 | if (x !== undefined) { 410 | t.posX = x || t.posX; 411 | t.posY = y || t.posY; 412 | t.zOrder = z || t.zOrder; 413 | 414 | if (MB_usingCanvas) { 415 | if (z) { 416 | MB_elements.sort(function(a, b){ 417 | 418 | return b.zOrder - a.zOrder; 419 | } 420 | ); 421 | 422 | } 423 | } else { 424 | t.s.left = x+'px'; 425 | t.s.top = y+'px'; 426 | t.s.zIndex = z || t.zOrder; 427 | } 428 | return this; 429 | } else { 430 | //method called without parameters, return 431 | //actual position 432 | return {x:t.posX, y:t.posY, z:t.zOrder} 433 | } 434 | }, 435 | 436 | setCollide = function(e) { 437 | if (e && MB_collides.i(t) === -1) { 438 | MB_collides.push(t); 439 | } else if (!e && MB_collides.i(t) !== -1){ 440 | rm(t, MB_collides); 441 | } 442 | }, 443 | 444 | onHit = function (object, callback) { 445 | setCollide(true); 446 | t.hits[object.id()] = callback; 447 | if (MB_collides.i(t) === -1) { 448 | MB_collides.push(t); 449 | } 450 | return this; 451 | }; 452 | 453 | t.draw = function() { 454 | 455 | if (t.fs > 0) { 456 | if (t.interval == t.speed && t.speed !== 0) { 457 | if (t.f == t.fs) { 458 | t.f = 0; 459 | 460 | if (typeof t.callback === "function") { 461 | t.callIters++; 462 | if (t.callIters === t.callMaxIters) { 463 | t.callback(); 464 | t.callIters = 0; 465 | } 466 | 467 | } 468 | 469 | } 470 | else { 471 | t.f++; 472 | } 473 | t.interval = 0; 474 | } 475 | if (t.speed !== 0) { 476 | t.interval++; 477 | } 478 | 479 | draw(); 480 | 481 | } 482 | }; 483 | var reSize = function(w, h){ 484 | //there are some arguments 485 | //so change size of the sprite 486 | //and return 'this' for chaining 487 | if (w !== undefined) { 488 | if (!MB_usingCanvas){ 489 | 490 | t.s.width = w+'px'; 491 | t.s.height = h+'px'; 492 | 493 | t.si.width = w*(t.animations+1)+'px'; 494 | t.si.height = h*(t.fs+1)+'px'; 495 | 496 | } 497 | t.width = w; 498 | t.height = h; 499 | if (MB_usingCSSAnimations) { 500 | //any smarter way to refresh cssAnimation than clearing the name of it? 501 | t.si[ MB_prefixJS+ "AnimationName" ] = ''; 502 | t.animStyle.innerHTML = constructAnimationClass(); 503 | t.si[ MB_prefixJS+ "AnimationName" ] = 's'+t.id; 504 | 505 | }; 506 | 507 | return this; 508 | 509 | } else { 510 | 511 | return {width:t.width,height:t.height}; 512 | } 513 | }; 514 | 515 | return { 516 | 'position':setPosition, 517 | 'hit':onHit, 518 | 'zone': function(top, right, bottom, left) { 519 | if (top !== undefined) { 520 | t.cZ.l = left; 521 | t.cZ.t = top; 522 | t.cZ.r = right; 523 | t.cZ.b = bottom; 524 | 525 | return this; 526 | } else { 527 | return t.cZ; 528 | } 529 | }, 530 | 'noHits':function() { 531 | t.hits = {}; 532 | return this; 533 | }, 534 | 'callback':function(fn, iteration) { 535 | t.callback = fn; 536 | t.callMaxIters = iteration; 537 | return this; 538 | }, 539 | 'change': function(image, width, height, frames, animation) { 540 | t.image.src = image; 541 | t.width = width; 542 | t.height = height; 543 | t.iWidth = width; 544 | t.iHeight = height; 545 | t.fs = frames; 546 | t.animation = animation; 547 | t.interval = 0; 548 | t.f = 0; 549 | t.callback = null; 550 | t.callIters=0; 551 | t.callMaxIters=0; 552 | 553 | if (!MB_usingCanvas) { 554 | t.si.width = width*(t.animation+1)+'px'; 555 | t.si.height = height*(t.fs+1)+'px'; 556 | t.s.width = width+'px'; 557 | t.s.height = height+'px'; 558 | if (MB_usingCSSAnimations) { 559 | //any smarter way to refresh cssAnimation than clearing it's name? 560 | t.si[ MB_prefixJS+ "AnimationName" ] = ''; 561 | t.animStyle.innerHTML = constructAnimationClass(); 562 | t.si[ MB_prefixJS+ "AnimationName" ] = 's'+t.id; 563 | } 564 | } 565 | 566 | t.cZ = { 567 | t: 0, 568 | l: 0, 569 | b: 0, 570 | r: 0 571 | } 572 | 573 | return this; 574 | }, 575 | 576 | 'size':reSize, 577 | 'speed':function(e) { 578 | if (e !== undefined) { 579 | t.speed=e; 580 | t.interval=0; 581 | if (MB_usingCSSAnimations){ 582 | t.si[ MB_prefixJS+ "AnimationDuration" ] = calculateSpeed(e, t.fs)+'s'; 583 | } 584 | 585 | return this; 586 | } else { 587 | return t.speed; 588 | } 589 | }, 590 | 'animation':function(e) { 591 | if (e !== undefined) { 592 | 593 | t.animation=e; 594 | 595 | if (MB_usingCSSAnimations) { 596 | //any smarter way to refresh cssAnimation than clearing the name of it? 597 | t.si[ MB_prefixJS+ "AnimationName" ] = ''; 598 | t.animStyle.innerHTML = constructAnimationClass(); 599 | t.si[ MB_prefixJS+ "AnimationName" ] = 's'+t.id; 600 | } 601 | 602 | return this; 603 | } else { 604 | return t.animation; 605 | } 606 | }, 607 | 'frame':function(e) { 608 | if (e !== undefined) { 609 | t.f=e; 610 | return this; 611 | } else { 612 | return t.f; 613 | } 614 | }, 615 | 'id': function() { return t.id; } 616 | }; 617 | }; 618 | 619 | /** 620 | * SPRITES END 621 | **/ 622 | 623 | /** 624 | * START BACKGROUNDS 625 | **/ 626 | var MB_Background = function(image, speed, direction, options) { 627 | 628 | var draw = function(){ 629 | //draw DOM & Canvas 630 | // If the values are too close to 0 JS will print them as exponentials 631 | // which won't work on the DOM. There's probably a more efficient way to 632 | // do this. 633 | var posX = t.posX, 634 | posY = t.posY; 635 | 636 | if (posX.toString().indexOf('e') != -1) posX = 0; 637 | if (posY.toString().indexOf('e') != -1) posY = 0; 638 | MB_mainCanvas.style.backgroundPosition = posX +"px "+posY+"px"; 639 | }, 640 | t = this; 641 | 642 | var setImage = function(img) { 643 | MB_mainCanvas.style.backgroundImage = 'url('+img+')'; 644 | }; 645 | 646 | setImage(image); 647 | 648 | t.speed = speed || 3; 649 | 650 | var radsPerDegree = Math.PI / 180, 651 | direcionFromParameter = function(dir){ 652 | t.dX = 0; 653 | t.dY = 0; 654 | if (typeof dir === "string") { 655 | switch (dir) { 656 | case 'N': 657 | t.dX = 0; 658 | t.dY = -1; 659 | break; 660 | case 'W': 661 | t.dX = -1; 662 | t.dY = 0; 663 | break; 664 | case 'S': 665 | t.dX = 0; 666 | t.dY = 1; 667 | break; 668 | case 'E': 669 | t.dX = 1; 670 | t.dY = 0; 671 | break; 672 | default: 673 | break; 674 | } 675 | } 676 | else if (typeof dir === "number") { 677 | dir = radsPerDegree * dir; // convert from degrees to radians 678 | t.dX = Math.cos(dir); 679 | t.dY = Math.sin(dir); 680 | } 681 | } 682 | 683 | direcionFromParameter(direction); 684 | 685 | t.zOrder = options['z'] || 0; 686 | t.posX = options['x'] || 0; 687 | t.posY = options['y'] || 0; 688 | 689 | t.id = MB_elements.push(t); 690 | t.moving = 0; 691 | 692 | var setPosition = function(x, y) { 693 | if (x !== undefined) { 694 | t.posX = x || t.posX; 695 | t.posY = y || t.posY; 696 | 697 | return this; 698 | } else { 699 | return {x:t.posX, y:t.posY} 700 | } 701 | }; 702 | 703 | t.draw = function() { 704 | t.posX += t.speed*t.dX*t.moving; 705 | t.posY += t.speed*t.dY*t.moving; 706 | 707 | draw(); 708 | } 709 | 710 | return { 711 | 'on': function() { t.moving = 1; return this;}, 712 | 'off': function() { t.moving = 0; return this;}, 713 | 'dir': function(direction) { direcionFromParameter(direction); return this;}, 714 | 'speed':function(e) { if (e !== undefined) { t.speed=e; return this;} else return t.speed;}, 715 | 'img': function(img) { if (img !== undefined) { setImage(img); return this;} else return image;}, 716 | 'position':setPosition 717 | } 718 | 719 | } 720 | 721 | 722 | /** 723 | * Constructor functions 724 | */ 725 | MB_detectCanvas(); 726 | 727 | 728 | return { 729 | //config 730 | 'fps': function() {MB_fpsMeasure=true; return this;}, 731 | 'init': function() { MB_usingCanvas ? MB_InitCanvas() : MB_InitDOM(); MB_InitCore(); return this;}, 732 | 'on': function() { 733 | running=true; 734 | MB_Start(); 735 | if (MB_usingCSSAnimations){ 736 | //this solution is really stupid and temporary ( I hope ) 737 | //unfortunatelly any other didn't really work 738 | var i = MB_elements.length; 739 | for (;i--;){ 740 | if (MB_elements[i].image) 741 | MB_elements[i].image.style[ MB_prefixJS+ "AnimationDuration" ] = calculateSpeed(MB_elements[i].speed, MB_elements[i].fs)+'s'; 742 | } 743 | } 744 | return this; 745 | }, 746 | 'off': function(){ 747 | MB_Stop(); 748 | if (MB_usingCSSAnimations){ 749 | //this solution is really stupid and temporary ( I hope ) 750 | //unfortunatelly any other didn't really work 751 | var i = MB_elements.length; 752 | for (;i--;){ 753 | if (MB_elements[i].image) 754 | MB_elements[i].image.style[ MB_prefixJS+ "AnimationDuration" ] = 0; 755 | } 756 | } 757 | return this; 758 | }, 759 | 'canvas': function(){ return MB_mainCanvas; }, 760 | 'ctx': function() {return MB_mainContext; }, 761 | 'canvasOff': function() { 762 | 763 | MB_usingCanvas=false; 764 | 765 | 766 | if (typeof MB_parentElement.style.WebkitAnimation !== "undefined") { 767 | 768 | //we have webkit CSS3 animation support 769 | MB_prefixCSS = "-webkit-"; 770 | MB_prefixJS = "Webkit"; 771 | MB_usingCSSAnimations = true; 772 | 773 | } else if (typeof MB_parentElement.style['MozAnimation'] !== "undefined") { 774 | //stupid Closure Compiler don't understand style.MozAnimation so I had to use brackets here 775 | 776 | //and in Firefox 777 | MB_prefixCSS = "-moz-"; 778 | MB_prefixJS = "Moz"; 779 | MB_usingCSSAnimations = true; 780 | } 781 | return this; 782 | }, 783 | 784 | 'cssAnimationOff': function() { 785 | MB_usingCSSAnimations=false; 786 | return this; 787 | }, 788 | 789 | 'hitsOn': function() { 790 | if (MB_addedLoops.i(MB_checkCollides) === -1) 791 | MB_addedLoops.push(MB_checkCollides); 792 | return this; 793 | }, 794 | 795 | 'hitsOff': function() { 796 | rm(MB_checkCollides, MB_addedLoops); 797 | return this; 798 | }, 799 | 800 | //elements 801 | 'spr':MB_Sprite, 802 | 'bg': MB_Background, 803 | 804 | //loops 805 | 'hook': function(e){ 806 | MB_addedLoops.push(e); 807 | return this; 808 | }, 809 | 810 | 'unhook': function(e){ 811 | rm(e, MB_addedLoops); 812 | return this; 813 | } 814 | 815 | }; 816 | }; 817 | //declaration of mibbu object for Closure Compiler 818 | window['mibbu'] = mibbu; 819 | --------------------------------------------------------------------------------