From 4265d64e5766b4b51bba3c0c8cd7cd1ad8e75b42 Mon Sep 17 00:00:00 2001 From: tebarius Date: Sat, 13 Jan 2024 18:20:27 +0100 Subject: [PATCH] Initial commit --- .idea/.gitignore | 3 + .idea/dbnavigator.xml | 405 ++++++++++++++++++ .idea/inspectionProfiles/Project_Default.xml | 15 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + 404_games/index.html | 28 ++ 404_games/pacman/data/map.png | Bin 0 -> 217 bytes 404_games/pacman/images/32_dot.png | Bin 0 -> 564 bytes 404_games/pacman/images/32_player_close.png | Bin 0 -> 583 bytes 404_games/pacman/images/32_player_open.png | Bin 0 -> 530 bytes 404_games/pacman/images/bg_center.png | Bin 0 -> 898 bytes 404_games/pacman/images/bg_down.png | Bin 0 -> 902 bytes 404_games/pacman/images/bg_left.png | Bin 0 -> 775 bytes 404_games/pacman/images/bg_right.png | Bin 0 -> 765 bytes 404_games/pacman/images/bg_up.png | Bin 0 -> 904 bytes 404_games/pacman/images/enemy_red.png | Bin 0 -> 294 bytes 404_games/pacman/index.html | 23 + 404_games/pacman/js/ai.js | 23 + 404_games/pacman/js/assets.js | 20 + 404_games/pacman/js/collision.js | 71 +++ 404_games/pacman/js/controls.js | 21 + 404_games/pacman/js/draw.js | 87 ++++ 404_games/pacman/js/game.js | 21 + 404_games/pacman/js/objects.js | 12 + 404_games/pacman/js/objectsLoad.js | 75 ++++ 404_games/pacman/js/update.js | 50 +++ 404_games/pacman/js/utils.js | 48 +++ 404_games/snake/data/map.png | Bin 0 -> 269 bytes 404_games/snake/index.html | 15 + 404_games/snake/js/controls.js | 20 + 404_games/snake/js/draw.js | 43 ++ 404_games/snake/js/framework.js | 34 ++ 404_games/snake/js/logic.js | 140 ++++++ 404_games/snake/js/utils.js | 47 ++ 404_games/space-invaders/enemies.json | 24 ++ 404_games/space-invaders/images/32_enemy.png | Bin 0 -> 1770 bytes .../space-invaders/images/32_laser_blue.png | Bin 0 -> 597 bytes .../space-invaders/images/32_laser_red.png | Bin 0 -> 460 bytes 404_games/space-invaders/images/32_player.png | Bin 0 -> 1694 bytes 404_games/space-invaders/images/64_1.png | Bin 0 -> 29503 bytes 404_games/space-invaders/images/64_2.png | Bin 0 -> 23312 bytes .../space-invaders/images/64_laser_blue.png | Bin 0 -> 12491 bytes .../space-invaders/images/64_laser_red.png | Bin 0 -> 10254 bytes .../space-invaders/images/background.png | Bin 0 -> 1098 bytes 404_games/space-invaders/index.html | 20 + 404_games/space-invaders/js/ai.js | 41 ++ 404_games/space-invaders/js/assets.js | 45 ++ 404_games/space-invaders/js/controls.js | 40 ++ 404_games/space-invaders/js/draw.js | 45 ++ 404_games/space-invaders/js/game.js | 28 ++ 404_games/space-invaders/js/objects.js | 29 ++ 404_games/space-invaders/js/update.js | 45 ++ 404_games/space-invaders/js/utils.js | 11 + Docker-404-games.iml | 8 + Dockerfile | 17 + readme.md | 49 +++ 57 files changed, 1623 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/dbnavigator.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 404_games/index.html create mode 100644 404_games/pacman/data/map.png create mode 100644 404_games/pacman/images/32_dot.png create mode 100644 404_games/pacman/images/32_player_close.png create mode 100644 404_games/pacman/images/32_player_open.png create mode 100644 404_games/pacman/images/bg_center.png create mode 100644 404_games/pacman/images/bg_down.png create mode 100644 404_games/pacman/images/bg_left.png create mode 100644 404_games/pacman/images/bg_right.png create mode 100644 404_games/pacman/images/bg_up.png create mode 100644 404_games/pacman/images/enemy_red.png create mode 100644 404_games/pacman/index.html create mode 100644 404_games/pacman/js/ai.js create mode 100644 404_games/pacman/js/assets.js create mode 100644 404_games/pacman/js/collision.js create mode 100644 404_games/pacman/js/controls.js create mode 100644 404_games/pacman/js/draw.js create mode 100644 404_games/pacman/js/game.js create mode 100644 404_games/pacman/js/objects.js create mode 100644 404_games/pacman/js/objectsLoad.js create mode 100644 404_games/pacman/js/update.js create mode 100644 404_games/pacman/js/utils.js create mode 100644 404_games/snake/data/map.png create mode 100644 404_games/snake/index.html create mode 100644 404_games/snake/js/controls.js create mode 100644 404_games/snake/js/draw.js create mode 100644 404_games/snake/js/framework.js create mode 100644 404_games/snake/js/logic.js create mode 100644 404_games/snake/js/utils.js create mode 100644 404_games/space-invaders/enemies.json create mode 100644 404_games/space-invaders/images/32_enemy.png create mode 100644 404_games/space-invaders/images/32_laser_blue.png create mode 100644 404_games/space-invaders/images/32_laser_red.png create mode 100644 404_games/space-invaders/images/32_player.png create mode 100644 404_games/space-invaders/images/64_1.png create mode 100644 404_games/space-invaders/images/64_2.png create mode 100644 404_games/space-invaders/images/64_laser_blue.png create mode 100644 404_games/space-invaders/images/64_laser_red.png create mode 100644 404_games/space-invaders/images/background.png create mode 100644 404_games/space-invaders/index.html create mode 100644 404_games/space-invaders/js/ai.js create mode 100644 404_games/space-invaders/js/assets.js create mode 100644 404_games/space-invaders/js/controls.js create mode 100644 404_games/space-invaders/js/draw.js create mode 100644 404_games/space-invaders/js/game.js create mode 100644 404_games/space-invaders/js/objects.js create mode 100644 404_games/space-invaders/js/update.js create mode 100644 404_games/space-invaders/js/utils.js create mode 100644 Docker-404-games.iml create mode 100644 Dockerfile create mode 100644 readme.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml new file mode 100644 index 0000000..257f3c7 --- /dev/null +++ b/.idea/dbnavigator.xml @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..5e4ea0c --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3126876 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/404_games/index.html b/404_games/index.html new file mode 100644 index 0000000..0cd5560 --- /dev/null +++ b/404_games/index.html @@ -0,0 +1,28 @@ + + +ups.. Page not Found !!! 404-Alarm!!!! + + +
+

404 - Alert

+

... page not found ...

+ + + + + +
+ + + diff --git a/404_games/pacman/data/map.png b/404_games/pacman/data/map.png new file mode 100644 index 0000000000000000000000000000000000000000..050e46355747935bf61dede4e53dafb94d5986b5 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#KD&&l4wp;RWjCNug{O;Sh{pM;lf3yF3^-iwOT2q~vG8KYRHwyD6k8sev#vOD zH}gnCi`T?yi&b;vMgBERX<~V6GSOZrZSJabzg~Eh?^!D&esHCf)ZSy&yY64(l1=TM zS=F>=F~_XPJrZmG3x9hRvh$*Ubw&B-JoRgH&))n0IO^$rNrnQ(4TZ7cOV2s21-gO3 M)78&qol`;+0ELZEr2qf` literal 0 HcmV?d00001 diff --git a/404_games/pacman/images/32_dot.png b/404_games/pacman/images/32_dot.png new file mode 100644 index 0000000000000000000000000000000000000000..78e2a33cdd54c9b7ff926f3aad59ccc7285c0b29 GIT binary patch literal 564 zcmV-40?Yl0P)p zl1c78=ggd$fBy5&B!xl&R4NtFYPCSS-3HZa^-BMuTFMQ#^!TGvc|SGqPyYWFfz<+5 z3rMor{J&9#^R#-smJ0NeFpV(Gum`8g2DGkA?|flZP%0IZ z;7bOZc#9ppi@p=K&4@|In1zur6=!}QkMJCC@G|_La1tnd!*TH9*CMMR!7Z%gA)dsJ z;b+*^BPLm984hB%CpZe*_)@o}y$h=V3ws0000RtJ53A)3HBD81;m7!gb>ch$^IzRikbOfO~J|J`IU!iGzS}?*|goc_NPi?-h{@6VQwZ|C^4O1y{H* ztv`C;Bjwn4;Fr`N{b~tOpGd4rj7u;mpdAtXTVhk9;=z3aBxWPRze+qF1o!$_*4snd zA+QeY+d%m~9_7gmk%Bb4 zYPYYFf{;acEU_YCiU^3&1;0r=%_|^QBl0)n{!jt6S}k@fK9hJWadQw}tyY1Bg|Z%_ z9}=(oqF-DDDiuEol{E`|k$5C^*%s&6uqFjwlr#@K2WH;guyA>aMdFS`!>|Kvmmpxf zVfb{!Ol5{q5Cd33@K2LB%%e>8-{cYFuJ5!MU}JOBlcUU~;nbuUTzs>Uw-m&Hw(M{{eo( V#hZD1mJVqff$|%DUp+ z6-4jzZr)vwB8aCx${Y=e#}cOz#Z&(-QO>gSO^DAWdJ;&B0Y;k^zZW1U_X-ak)U43@Scz6rob+7ZDAxnJTREgF(jTy z^c|mpaS;%G2Rq(hU&GF9c6+o3{3rs#fX-}&wY|pyrE9V&@M1#{$La1%fCJjzS@&fK-cnjw# zxcU(|lADjY#Yf%%ADbJe2t|s5lqhjFRxdI3%;fU7)f#Lwjv$DZN;KVFT~&Wo|5Fai z-Q69!e^VpF9gm!wRI6{t9=vY<{v$Bys8qHB|NrgnH}S1I zAfrhEh%1$?7>I#*5@%95P^-NQYBd5NtF*bl0|$Tz2!W_l*$UG-l1XD+=kmZbFbm8B z3&5geL2I)*lLs=%Gz}YpF|S5$TD#|>cE$^mX<*6=AObFdF7QXv1$sbe%w{}s3S`_x zUI6Bt%gkkQPe+xZ_+~r z*_TAdlwxc5ub_|{&Tyq+@Gr~wGvFz(rlJFA0}nk!La!!VEd=$tjnmdZviKI{z`Be- z2UZd(nD^!vLZziUvO?neXXufQd+$?1VM(yB$@l}UEor`@y;ZFhq&wh@Vb5|L0?rA) z80Q50jF9p5XS6q`dEV3aS@V8;jAD;oBNb6cIc;lR@XmL&*4CMhbez7sFC7zFyO$Nj z^U7}#cmlitUXCcj-@r%UJ@5he3^aff@j=&^&2SO~LPgP4RUhk}JEP6SGyD#G(wSrF z4Cr_i0=bQi;+3Aym;wAf@p?;_X1$1ijUb{gI@^-2OGUi1vz@L6tlf`|DTST`xdg*q zDB^Kc>^l$+W5H{B!cr{q=z34cFGpxxeFIWILp2kA8k$~|4dAN^ z?X%_$?VaiD0RD3Mb^K2aiJWjzcRVLfR0F=8c*Z-@3C9^vMMMcCx~ll5;C7$g3$3-i z%8$~tWT|>WUE~_iKzR)kJ>l&&rAbF_vMmqXZ^L4-cq?4rXf(#&f9D^gv0d^1721t~)B>Dz$Kp}Dcey?a6h;8Cr=jMO~paXP)HDFz`rr$a` zGY8mmnyQw`ve&hnd43X5w}3^-lAN?71}DG`a1DG1en@VCBFo`zrD;xu zIgz+5+xwa4XZKi0t0&x@0J=iG1H1xWDuAvSLb={lu=ApS0*n>h7?_-%=DukSgxoKy z!ncHeSMo%`B|2XSc}ufkto(mb3a%BTd$0}FI-%_rMfEdaJEDF`&QeKBzlBt7OJ^fW zNo8Bs&4IY}Ix@5YtO|K5-7pPpl(N<6d?#WiX*!5P?*|4}WHcB{q7huB7lK}uZeXBN zZ`veGR0m-IwIk%yCTps*L2teeJwO^>JbzZN%tBj6S~bY4m}p6-T}EH_XB%8rX@uN9 z5QK@&#k%zlc6Yb#y!pCa!nK-2Or-JEJH?)l0!d3YJm3!x4;mGrDIqd5zMgDJw`_OX zo3Q62G+sldjBZ*A;nI)Ns0!%m^_u~((t-(4^o4XJ27Q^CeVbHLOTwFS&*H1tgv zh$D6t#WgKmF;Z7$rJSykSM3<6lSO?|8P0BX&{M^q{171%n6QOCsfYbM+ cg3&wc7YaG};i@LIL;wH)07*qoM6N<$f&;*cFaQ7m literal 0 HcmV?d00001 diff --git a/404_games/pacman/images/bg_left.png b/404_games/pacman/images/bg_left.png new file mode 100644 index 0000000000000000000000000000000000000000..3f5edd929f31bc91b64582bc9e36f5bb9f5b2ec8 GIT binary patch literal 775 zcmV+i1Ni)jP)!uV06>vbxBk%_JNS}d=`xIRJ z2$4ATmLrdlE4LioTZDuZsR)Ils)kTPX}+4+9uA$2w$?f!ZK42{M*HcV|BU}Lvo=u_ z0Z^~k0cf||0CYMX02+;kcYRe)z=ofS?bPdU=WblI{?B^AfCPYC_h&7hx#F6A4}eAFb!?oqTqOfi-J351#(+F8Sm~_I=7Pc;j`Arm0j^XgI+xXIhw>)? zUO9(L2}i8ufwM1Dg=1g<^i?i^kIU<#oYI1yqBkue3H0FQxtI&X+{UG5g6 zZ|a#bklPyI1Mq&$@Q{H1?JVfgaDsD`(GeghEXWd>8jSFr#9002ovPDHLk FV1llZM+pD` literal 0 HcmV?d00001 diff --git a/404_games/pacman/images/bg_right.png b/404_games/pacman/images/bg_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3b28cac5c0d98840fc7335a1323add5c2617b9dd GIT binary patch literal 765 zcmVb?x50000PbVXQnLvL+uWo~o;Lvm$dbY)~9 zcWHEJAV*0}P*;Ht7XSbPcS%G+R9M5+mqBt8K@^6+9)^S{Mq?7eXenit3(EsAOOL@V z*v=8Mb;r_OSaO4G@dhkeDOG9}YAi4?Gj9I2x`qZqAfR3Ks(Yq~{{Mdc-v1iYXfyz5 zwORo5dOZO8{XPJlPRBdHsTQ!~7TQ6p^%hk>is}Xl^w;KYyRaaWfGhPIA_y#G> zr%3CMkTP^G`3Nr4k@C_&$^#T(2oEa{{0MPu$M#Y%YsTxl^IZWMX?3f+nc4sTXLfeZ zR4Nq!YPA{wtE;yRa09ppJO-Wu&wz*W?j}$I46|Z^5pV|l06qe5fp@@rd3PR$dsZ72 zm=`0XAPcR?a|tN2Sc;;nZ41ipjFjA@R(mb8P3r+P;xN%k0{A60pR%;O8uh(rB2CSEmM$H$=L;;?7zUCR&+4-~cD2f0G zf|(;@RPiwx;_8R5=rLzDHa0B4{(hK?fvmgtSy;@#-wNnt-60-}!B}d%%~1#3y`X*Q z+{m2WBQ+*T#U!SPO+4FN#}I}366ga1V3_4xi_TDN`r>1pWShpoSe*1^^c53nu^)-9 zvm1!7T!qN(z6W%Hj@c#DxUOo%SQbA4K1l}@0Uv-bz%g(Z1TRL34M|Ka z2f#0&1vI5iTb83V1Xh7-qCW)Mz;~bl9Ewd#d<>Fur?j?Kp6LmrC?W`^=lDV#FAG=) ztP9*077)Et0q|J?XseLf?d>fxF%X7(HVD=ofUfH6Tw#5$3X=n$L>FdgVpIt`8RDAEenhii9$r9Iy66gHf+|;}h2Ir#G#FEq$h4Rdj3T;#i8Y1l^2e%A%li&|RrnOvVvsyy48%$oFGWsb1G11*)(u844!Gu$&KPP^Uz zdE>onPlI!AP42YlJFt&e@%GysmvU#RmIL*A60riTE{uT<&6Nwx?5@X5y4bjF;(77L l?OH7@&)ij}pPzGp_5L+I2gSCELqNAOc)I$ztaD0e0szWTYCiw~ literal 0 HcmV?d00001 diff --git a/404_games/pacman/index.html b/404_games/pacman/index.html new file mode 100644 index 0000000..a2e150c --- /dev/null +++ b/404_games/pacman/index.html @@ -0,0 +1,23 @@ + + + + + 404 Pacman + + + + + + + + + + + + + + + + + + diff --git a/404_games/pacman/js/ai.js b/404_games/pacman/js/ai.js new file mode 100644 index 0000000..b93f34c --- /dev/null +++ b/404_games/pacman/js/ai.js @@ -0,0 +1,23 @@ +var updateEnemies = function(modifier){ + + for (var i= 0; i < enemies.length; i++){ + var enemy = enemies[i]; + if (isCollidingBlocks(enemy,enemy.direction)){ + changeDirection(enemy); + + } else { + move(enemy, modifier); + } + } +} + +var changeDirection = function(enemy){ + var tol = p(-5,0); + var randomDirection = randomBetween(0, 3); + switch(randomDirection){ + case 0: if (!isCollidingBlocks(enemy, LEFT, tol)) enemy.direction = LEFT;break; + case 1: if (!isCollidingBlocks(enemy, RIGHT, tol)) enemy.direction = RIGHT;break; + case 2: if (!isCollidingBlocks(enemy, UP, tol)) enemy.direction = UP;break; + default: if (!isCollidingBlocks(enemy, DOWN, tol)) enemy.direction = DOWN;break; + } +} diff --git a/404_games/pacman/js/assets.js b/404_games/pacman/js/assets.js new file mode 100644 index 0000000..8873734 --- /dev/null +++ b/404_games/pacman/js/assets.js @@ -0,0 +1,20 @@ +var setImage = function(img){ + var i = new Image(); + i.src = img; + return i; +}; + +// Hero image +var playerImageClose = setImage("images/32_player_close.png"); +var playerImageOpen = setImage("images/32_player_open.png"); + +var monsterImage = setImage("images/enemy_red.png"); + +var dotImage = setImage("images/32_dot.png"); + +var backgroundImage = {}; +backgroundImage.center = setImage("images/bg_center.png"); +backgroundImage.left = setImage("images/bg_left.png"); +backgroundImage.right = setImage("images/bg_right.png"); +backgroundImage.down = setImage("images/bg_down.png"); +backgroundImage.up = setImage("images/bg_up.png"); diff --git a/404_games/pacman/js/collision.js b/404_games/pacman/js/collision.js new file mode 100644 index 0000000..d5b2686 --- /dev/null +++ b/404_games/pacman/js/collision.js @@ -0,0 +1,71 @@ +//http://gamedev.stackexchange.com/questions/13774/how-do-i-detect-the-direction-of-2d-rectangular-object-collisions +var collision = new Collision(); + +var RIGHT = { x: 1, y: 0}; +var LEFT = { x: -1, y: 0}; +var UP = { x: 0, y: -1}; +var DOWN = { x: 0, y: 1}; + +function Collision(){ + + this.onCollisionChange = function(ojb1, obj2, size, callback) { + var isColliding = false; + setInterval( + function(){ + var beforeStatus = isColliding; + isColliding = collision(obj1, obj2, size); + if (beforeStatus != isColliding) callback(); + }, 100); + } + + this.isCollidingDirection = function(obj1, obj2, direction, offset){ + switch(direction){ + case LEFT: return collision.containsLeft(obj1, obj2, SIZE, offset); break; + case RIGHT: return collision.containsRight(obj1, obj2, SIZE, offset); break; + case UP: return collision.containsUp(obj1, obj2, SIZE, offset); break; + case DOWN: return collision.containsDown(obj1, obj2, SIZE, offset); break; + default: console.log("Undefined direction"); + } + } + + this.contains = function(obj, p, size){ + var contains = p.x > obj.x && p.x < (obj.x + size) && + p.y > obj.y && p.y < (obj.y + size); + return contains; + } + + this.collision = function(obj1, obj2, size){ + return obj1.x <= (obj2.x + size) + && obj2.x <= (obj1.x + size) + && obj1.y <= (obj2.y + size) + && obj2.y <= (obj1.y + size) + } + + this.containsLeft = function(obj1, obj2, size, offset){ + return this.contains(obj1, addCoords(middlePoints(obj2, size).left, offset) , size); + } + this.containsRight = function(obj1, obj2, size, offset){ + return this.contains(obj1, addCoords(middlePoints(obj2, size).right, offset), size); + } + this.containsUp = function(obj1, obj2, size, offset){ + return this.contains(obj1, addCoords(middlePoints(obj2, size).top, offset), size); + } + this.containsDown = function(obj1, obj2, size, offset){ + return this.contains(obj1, addCoords( middlePoints(obj2, size).bottom, offset), size); + } + + var addCoords = function(point, offset) { + return p(point.x + offset.x, point.y + offset.y); + } + + var middlePoints = function(obj, size){ + var middleX = (obj.x + obj.x + size) / 2; //(obj.x *2 + size) / 2; ? + var middleY = (obj.y + obj.y + size) / 2; + return { + left: p(obj.x, middleY), + right: p(obj.x + size , middleY), + top: p(middleX, obj.y), + bottom: p(middleX, obj.y + size), + } + } +} diff --git a/404_games/pacman/js/controls.js b/404_games/pacman/js/controls.js new file mode 100644 index 0000000..7712aa0 --- /dev/null +++ b/404_games/pacman/js/controls.js @@ -0,0 +1,21 @@ +// Handle keyboard controls +var keysDown = {}; + +var KEY_UP =38, KEY_DOWN =40, KEY_LEFT =37, KEY_RIGHT =39; + +addEventListener("keydown", function (e) { + keysDown[e.keyCode] = true; +}, false); + +addEventListener("keyup", function (e) { + delete keysDown[e.keyCode]; +}, false); + + +//Called from update.js +var controls = function(modifier){ + if (KEY_LEFT in keysDown && !isCollidingBlocks(player, LEFT, p(-5,0))) player.direction = LEFT; + if (KEY_RIGHT in keysDown && !isCollidingBlocks(player,RIGHT, p(5,0))) player.direction = RIGHT; + if (KEY_UP in keysDown && !isCollidingBlocks(player,UP, p(0,-5))) player.direction = UP; + if (KEY_DOWN in keysDown && !isCollidingBlocks(player,DOWN, p(0,5))) player.direction = DOWN; +} diff --git a/404_games/pacman/js/draw.js b/404_games/pacman/js/draw.js new file mode 100644 index 0000000..52d03ff --- /dev/null +++ b/404_games/pacman/js/draw.js @@ -0,0 +1,87 @@ +// Create the canvas +var canvas = document.getElementById("canvas"); +var ctx = canvas.getContext("2d"); + +var SIZE = 32; + +var directionToRotation = function(direction){ + switch(direction){ + case RIGHT : return 0; + case LEFT: return 180; + case DOWN: return 90; + case UP: return 270; + + } +} +// Draw everything +var render = function () { + // ctx.clearRect(0,0,canvas.width,canvas.height); +/* + if (bgReady) { + ctx.drawImage(bgImage,0 , 0); + }*/ + ctx.fillStyle="black"; + ctx.fillRect(0,0,canvas.width,canvas.height); + + drawBackground(); + + if (!player.dead) { + var image; + if(player.sprite == 0) image = playerImageClose; + else image = playerImageOpen; + //TODO rotate with direction + // ctx.drawImage(image, player.x, player.y, SIZE, SIZE); + var rotation = directionToRotation(player.direction); + drawRotated(image, player.x, player.y, rotation); + } + + for (var i=0; i < dots.length; i++){ + var dot = dots[i]; + ctx.drawImage(dotImage, dot.x, dot.y ,SIZE, SIZE); + } + + for (var i=0; i < enemies.length; i++){ + var enemy = enemies[i]; + ctx.drawImage(monsterImage, enemy.x, enemy.y,SIZE, SIZE); + + } + if (false) //DEBUG + for (var i=0; i < blocks.length; i++){ + var block = blocks[i]; + ctx.drawImage(monsterImage, block.x, block.y ,SIZE, SIZE); + } + + + + if (player.dead){ + ctx.fillStyle = "red"; + ctx.font = "48px Helvetica"; + ctx.textAlign = "center"; + ctx.textBaseline = "top"; + ctx.fillText("Game Over", canvas.width / 2, canvas.height/ 2); + } +}; + +function drawBackground(){ + for (var i= 0; i < background.length; i++){ + var b = background[i]; + + //ctx.drawImage(backgroundImage.center, b.x, b.y ,SIZE, SIZE); + for (var j= 0; j < b.directions.length; j++){ + var d = b.directions[j]; + ctx.drawImage(backgroundImage[d], b.x, b.y ,SIZE, SIZE); + } + } +} +var TO_RADIANS = Math.PI/180; + +//http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/ +function drawRotated(image, x, y, angle) { + var halfWidth = image.width/2; + var halfHeight = image.height/2; + ctx.save(); + ctx.translate(x +halfWidth, y + halfHeight); + ctx.rotate(angle * TO_RADIANS); + ctx.drawImage(image, -halfWidth, -halfHeight); + ctx.restore(); + } diff --git a/404_games/pacman/js/game.js b/404_games/pacman/js/game.js new file mode 100644 index 0000000..325ec7f --- /dev/null +++ b/404_games/pacman/js/game.js @@ -0,0 +1,21 @@ +// The main game loop +var main = function () { + var now = Date.now(); + var delta = now - then; + + update(delta / 1000); + render(); + + then = now; + + // Request to do this again ASAP + requestAnimationFrame(main); +}; + +// Cross-browser support for requestAnimationFrame +var w = window; +requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame; + +// Let's play this game! +var then = Date.now(); +main(); diff --git a/404_games/pacman/js/objects.js b/404_games/pacman/js/objects.js new file mode 100644 index 0000000..b4916a9 --- /dev/null +++ b/404_games/pacman/js/objects.js @@ -0,0 +1,12 @@ +// Game objects +var player = { + direction: LEFT, + speed: 100, + sprite: 0 +} + +var enemies = []; +var dots = []; +var blocks = []; + +var background = []; diff --git a/404_games/pacman/js/objectsLoad.js b/404_games/pacman/js/objectsLoad.js new file mode 100644 index 0000000..21f8400 --- /dev/null +++ b/404_games/pacman/js/objectsLoad.js @@ -0,0 +1,75 @@ +var BLACK = {r: 0, g: 0, b: 0}; +var WHITE = {r: 255, g: 255, b: 255}; +var YELLOW = {r: 255, g: 255, b: 0}; +var GREEN = {r: 0, g: 255, b: 0}; +var ORANGE = {r: 255, g: 127, b: 0}; +var CYAN = {r: 0, g: 255, b: 255}; +var RED = {r: 255, g: 0, b: 0}; +var PINK = {r: 255, g: 0, b: 255}; + +var addEnemy = function(x, y){ + var enemy = { + direction: DOWN, + speed: 100, + x: x, + y: y + }; + enemies.push(enemy); +} + +var bg = function(x, y , dirs) { + return { + x: x * SIZE, + y: y * SIZE, + directions: dirs + } +} + +loadImagePixels("data/map.png", function(pixels){ + + pixelBackground(pixels); + + for(i=0;i canvas.height ) obj.y = 0 ; +} + +var isCollidingBlocks = function(obj, direction, offset){ + if (!offset) offset = p(0,0); + for (var i=0; i < blocks.length; i++){ + var block = blocks[i]; + + var isColliding = collision.isCollidingDirection(block, obj, direction, offset); + if (isColliding) return true; + } + return false; +} diff --git a/404_games/pacman/js/utils.js b/404_games/pacman/js/utils.js new file mode 100644 index 0000000..4154892 --- /dev/null +++ b/404_games/pacman/js/utils.js @@ -0,0 +1,48 @@ +var loadJSON = function (path, success, error) +{ + var oReq = new XMLHttpRequest(); + oReq.onload = function reqListener () { + jsonData = JSON.parse(this.responseText); + //console.log("Loading JSON data", jsonData); + success(jsonData); + };; + oReq.open("get", path, true); + oReq.send(); +} + +var p = function(x,y){ return {x: x, y: y}; } + +var loadImagePixels = function(image, callback){ + + var img = new Image(); + img.src = image; + img.onload = function() { + console.log("Image " + image + " loaded " + img.width + "x" +img.height); + var canvas = document.createElement('canvas'); + document.body.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + img.style.display = 'none'; + var imgData = ctx.getImageData(0,0,canvas.width, canvas.height); + + var pixels = []; + for(i=0;ijA5L~c#`DCC7XMsm# zF#`j)FbFd;%$g$s6l5>)^mS#w&%r9npjqJS76%lPEOCt}an8@pP0cG|a4t$sEJ;mK zD9lFz@i_i=Y9QAE1s>+O%Lj-V1JDI8L0n z^H00tdgVdKT_T@NO%BXwd}8_G;RYLrwdWXjA7H2y*I@L!SubgoKebm4=l}*!S3j3^ HP6 + + + + 404 snake + + + + + + + + + + diff --git a/404_games/snake/js/controls.js b/404_games/snake/js/controls.js new file mode 100644 index 0000000..b19e01c --- /dev/null +++ b/404_games/snake/js/controls.js @@ -0,0 +1,20 @@ +// Handle keyboard controls +var keysDown = {}; + +var KEY_UP =38, KEY_DOWN =40, KEY_LEFT =37, KEY_RIGHT =39; + +addEventListener("keydown", function (e) { + keysDown[e.keyCode] = true; +}, false); + +addEventListener("keyup", function (e) { + delete keysDown[e.keyCode]; +}, false); + +//Called from update.js +var controls = function(){ + if (KEY_LEFT in keysDown) GAME_STATE.snake.move('l'); + if (KEY_RIGHT in keysDown) GAME_STATE.snake.move('r'); + if (KEY_UP in keysDown) GAME_STATE.snake.move('u'); + if (KEY_DOWN in keysDown) GAME_STATE.snake.move('d'); +} diff --git a/404_games/snake/js/draw.js b/404_games/snake/js/draw.js new file mode 100644 index 0000000..73f00fc --- /dev/null +++ b/404_games/snake/js/draw.js @@ -0,0 +1,43 @@ +// Create the canvas +var canvas = document.getElementById("canvas"); +var ctx = canvas.getContext("2d"); + +var SIZE = 32; + +Cell.prototype.draw = function(){ + switch(this.content){ + case 'SNAKE': + ctx.fillStyle="gray"; + break; + case 'BLOCK': + ctx.fillStyle="black"; + break; + case 'FOOD': + ctx.fillStyle="silver"; + break; + } + if (this.content && this.content != 'INVALID'){ + ctx.fillRect(this.x*BLOCK_SIZE, this.y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE) + } +} + +// Draw everything +var render = function () { + if (GAME_STATE.game_over) { + ctx.fillStyle = "rgb(250, 0, 0)"; + ctx.font = "48px Helvetica"; + ctx.textAlign = "center"; + ctx.textBaseline = "top"; + ctx.fillText("Game Over", canvas.width / 2, canvas.height * 2 / 3); + } + else { + // draw the background + ctx.fillStyle="white"; + ctx.fillRect(0,0,canvas.width,canvas.height); + + // draw game state + Object.keys(GAME_STATE.grid).forEach(function(key){ + GAME_STATE.grid[key].draw(); + }); + } +}; diff --git a/404_games/snake/js/framework.js b/404_games/snake/js/framework.js new file mode 100644 index 0000000..2613715 --- /dev/null +++ b/404_games/snake/js/framework.js @@ -0,0 +1,34 @@ +// The main game loop +var main = function () { + var now = Date.now(); + var delta = now - then; + + controls(); + render(); + + then = now; + + // Request to do this again ASAP + requestAnimationFrame(main); +}; + +//var canvas = document.createElement('canvas'); +//document.body.appendChild(canvas); + + + +setInterval(function(){update()}, 300); + +// Cross-browser support for requestAnimationFrame +var w = window; +requestAnimationFrame = + ( + w.requestAnimationFrame || + w.webkitRequestAnimationFrame || + w.msRequestAnimationFrame || + w.mozRequestAnimationFrame + ); + +// Let's play this game! +var then = Date.now(); +initGameState(main); diff --git a/404_games/snake/js/logic.js b/404_games/snake/js/logic.js new file mode 100644 index 0000000..0370d01 --- /dev/null +++ b/404_games/snake/js/logic.js @@ -0,0 +1,140 @@ +var BLOCK_SIZE = 16; + +function update(){ + if (GAME_STATE.complete) GAME_STATE.snake.update(); +} + +function initGameState(callback){ + GAME_STATE.grid = {}; + loadImagePixels("data/map.png", function(rows){ + rows.forEach(function(row, i){ + row.forEach(function(pixel, j){ + var cell = new Cell(i,j); + if (isColor(pixel, BLACK)) + cell.content = 'BLOCK'; + else if (isColor(pixel, GREEN)) + cell.content = 'INVALID'; + else if (isColor(pixel, RED)){ + cell.content = 'SNAKE'; + GAME_STATE.snake = new Snake(cell); + } + GAME_STATE.grid[[i,j]] = cell; + GAME_STATE.gameHeight = i; + GAME_STATE.gameWidth = j; + }); + }); + Grid.newFood(); + GAME_STATE.complete = true; + callback(); + }); +} + +var GAME_STATE = { + snake: null, + grid: null, + gameOver: false, + gameHeight: 0, + gameWidth: 0, +} + +function Grid(){} + +Grid.get = function(x,y){ + return GAME_STATE.grid[[x,y]]; +} + +Grid.set = function(x, y, content){ + var cell = GAME_STATE.grid[[x,y]]; + cell.content = content; + return cell; +} + +Grid.unset = function(x, y){ + var cell = GAME_STATE.grid[[x,y]]; + cell.content = null; + return cell; +} + +Grid.randomFree = function(){ + do{ + var row = Math.floor(Math.random() * GAME_STATE.gameHeight); + var col = Math.floor(Math.random() * GAME_STATE.gameWidth); + var cell = this.get(row,col); + } while (cell.content); + return cell; +} + +Grid.newFood = function (){ + var freeCell = this.randomFree(); + freeCell.content = 'FOOD'; +} + +function Cell(x,y){ + this.x = x; + this.y = y; + this.content = null; +} + + +function Snake(initCell){ + this.body = [initCell]; + this.dir = {x: -1, y: 0}; // start moving to the left +} + +Snake.prototype.head = function(){ + return this.body[0]; +} + +Snake.prototype.tail = function(){ + return this.body[-1]; +} + +Snake.prototype.move = function(dir){ + switch(dir){ + case 'l': + this.dir = {x: -1, y: 0}; + break; + case 'r': + this.dir = {x: 1, y: 0}; + break; + case 'u': + this.dir = {x: 0, y: -1}; + break; + case 'd': + this.dir = {x: 0, y: 1}; + break; + } +} + +Snake.prototype.update = function(dir){ + // compute new position of the head + var head = this.head(); + var dir = this.dir; + var newX = head.x + dir.x; + var newY = head.y + dir.y; + var newHead = Grid.get(newX, newY); + + // check collisions + + // if food, grow (on the head) + if (newHead.content == 'FOOD') { + newHead.content = 'SNAKE'; + this.body.unshift(newHead); + Grid.newFood(); + } + + // if block, die + else if (newHead.content != null){ + GAME_STATE.game_over = true; + } + + // else, move + else { + oldTail = this.body.pop(); + oldTail.content = null; + + newHead.content = 'SNAKE'; + this.body.unshift(newHead); + } + +} diff --git a/404_games/snake/js/utils.js b/404_games/snake/js/utils.js new file mode 100644 index 0000000..11ee39e --- /dev/null +++ b/404_games/snake/js/utils.js @@ -0,0 +1,47 @@ +var loadImagePixels = function(image, callback){ + + var img = new Image(); + img.src = image; + img.onload = function() { + console.log("Image " + image + " loaded " + img.width + "x" +img.height); + var canvas = document.createElement('canvas'); + document.body.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + img.style.display = 'none'; + var imgData = ctx.getImageData(0,0,canvas.width, canvas.height); + + var pixels = []; + for(i=0;ioe2(Ae@LZEWHu;2H<_L7^DamKJQ2l(w|cM=FY4TJ*`G#x(v=Qd}BC zaMZM`5Ehv%**niCgwuJ zQp!}dEz&`P7QmEWayN6Mp{}M{q)evM=@pAs)UAfDx;Y=N>tVt|3pgjm}Q+EE$6R%0_Xgj=j&K^CPk9Y(0v)mV6Ucn>}# z#uHB$XNq4fgIc@8m!rmDhgg%Z7W_5B>2wbJE&h)xId$H5zU05_p91RXQ&F@TUF1+bxa z!_R7xRVwFQgYMK2RE-5-I!sJT0TgTVy#C(xhXJIJ*@_PgM2X0oN5a4l?%KL_>ucM0 zY(Ibip#`d_K%y&~nod)D;d*6T84LogiVC3x2zdCBhaca#apRfL4_7T-1qB$`FmR-= zuW!qf$DZ7S3#y=q+z1>bUU{AkA}J6n1)^DiTc&6wRSq(8Bb2AWg`+<|`h`uKHa&QM z|NTFua614Z?li%T;KGR$Csw6My$7Hj9Y-KpE;WEWSkl7WZ7>}MTiP)Z0j>Z^P(_7y z5#!aBT!^IP0B#0eG+I6q^xXl!;j{=6K?~mmdcXj@~H0RcCh8?C^Vk^IQ-ZjyRI04~V9lmI%bS7KrS6-NRA3dCiBA+{mFXoI+1 z9#ir0j8$G|KxcI$fXqpWeLDaKxCrLDSpy(!QQN9bTv}>WQEDt9rssx5UQlW(p~lo4 z7pgaLqy?Zq&}+F=xxyEUKn9F!N&wqBxAipWh8lvJKboU@JT5`$$vE5*$h-s%(RhS; z(VVC*!)%mgbNl9d;tvY7-C}`WpoCINsfYIL-Sgd@ojacud2va2!V^BGP^4Z;F$~0;79)E!NI{l z4IUr-bB(w$0;x-Sj+Ywte`f!#d_M0F4-fZdGMRb#RI|z_6^Fh;LLwjyYFf>c#OZXJ z)2C1Oc%B#R+qG|3rIG-QZ(K=4Lp6XP2(Awe4fS_*b=}D2a`OP_NGnz@q@6$qTHR{S z=ks)Rbrpt&hWezG*Q)^#Q7;Xqu3Da)dgatpz}usvqYDZM+qG+0TwNu0!d`Gq+1I6$ zFP;2FwFEMlloW`X%TX5PJB#WxjlZCljxVZUQ9At`#@CCOe&6 zoit8^^U|G^a=ofwFZ-q86V$x2Uz&PV-+QO^PNVa(yV^CGwoD#KDj;fE(Q>7&sqMAN z@ySEUWRfrpZ|k6Fic^m5+#98$KIJQ9Br(e1Ty>uJX1rr}P}vk`izj>6^#)NPdOnxS z{e8**3YEK|uDR}j{V7{J4>%^-n*3(v&-wrQINO|GIuAI%`Coke7r^^=G)WBqm;e9( M07*qoM6N<$f;tjTuK)l5 literal 0 HcmV?d00001 diff --git a/404_games/space-invaders/images/32_laser_blue.png b/404_games/space-invaders/images/32_laser_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..58a38e0bd1b32588781ae0ba015088aa80b5f0dd GIT binary patch literal 597 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 literal 0 HcmV?d00001 diff --git a/404_games/space-invaders/images/64_2.png b/404_games/space-invaders/images/64_2.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a026f6fe35fa53d49f9886de0fd869756a8fa3 GIT binary patch literal 23312 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 VzwqI9kw^dl002ovPDHLkV1o8Po}&N& literal 0 HcmV?d00001 diff --git a/404_games/space-invaders/images/64_laser_red.png b/404_games/space-invaders/images/64_laser_red.png new file mode 100644 index 0000000000000000000000000000000000000000..07123eddf31c4a6b67445178ade23008fb5f7ddf GIT binary patch literal 10254 zcmV+pDDl^cP) zO{`_hb=QBj&%XC|_v?QBKJfFi69>mOF?NE%*cJ*z$Vv!_5sXlfKmrAX3_^$@Q#%8g zFbktFFcK34Qw9hL8w-gK5dk8JF?l4hv5m>IpZnu=_r2$wy{n2rtyQ(EcI|V{?Pm`l zx1@8=xqI)bRsZ!>t3EgUz?0J-5#IF#{>%igyaN9cc*8*eU<-fx8*uq8*vV)6P57@7 z1{Y!c-|+YxE;drChv*@^4xbo-%>|r|Fq|ctZh||whR1X@B!m7GTsQ?5LCV2}qwG$q76JR4w^I=CnhGl?0VZD3Z( zhD0lqV1g$B_S7hH32}zE16(+%gWRlOJ{sX7mP$s~l{q_$aQ#Y180Mj5FiY~sKF&pzU9;ByFq@>@ZDU(L-@|iaE3{jrjpF?&9A|2 zOX7b)$aeAnXHwlCfggVWKXVRWzYAY<@OX@H@eTOK2JQpy3U~-pginmm;4fXkE2EK` zhvA#>pT+<`ewKWI+lYZqN%zhN#0QMvZUblF1}SAk%xEGzh8RR^#~J*T9&oeJoYTW$ z3^47%4+R$Tz&v``?_e5=%}4QE`*GXcjAH9E?8X^(Gwg(0&NVmpJJ^g;E5|1NrW)LlQF<{hPS1rgWB^1Psc56 zr(~`9Eufs2n5zZgOXGeH#gw2q=07G4?C~ZabaPHx!fj_8W#F_dR^I;IG z;v}LM>ylgJz%`TQ*eDE{#hXQ+*c@B0qtzBGDWOS#c?Rzj``u=RVZIdPH8T@T;;9(Y z|BK9|nrR^u+Rl2|?_sY&iR&njxIPfyh>1n^Q;LbAaZ5SLKN@A>lgrF4{B93hms(Vf z6BaesATK1ZnZu;r9P?v^pCb{Co zoWBh(zaKVd(zXJO;=3%i57mwg?0=Gxtc7)e7qqfo3gX+kJT-ZeT zQBp103_`&r_B)pfaE|0Xv>+KUa6=NM8xf!7N=FKfh9tAoaKebl+00pPQV5zE^0-3I zt4-2K2^VbSAy*Z51TEMr6!=3v{X zl?YI4Su%TRdnk%hISGq9rY>Ho_6$Czkrx-5xU;1!oSrMnE*0RUyPFNeHtbSBa4B=N znP>GL3y#&4{a`82sk`VU_5`E9uBdMm#qq7E<{^D@Ga3!{rt02X$^qs8Q;=?v$WrkF__GALwOtEJf>kTrRD%^q;FjB&WdUqWrWz~4)QwWVsGhFhPMXt0+#KzJMC8?gU!8JK7Z(7PU+@0)a! zZqiKx`TJC2o82-u*{$zj` zU1~bDDZw?wLQLmqiR2j{7hnudjAc{0(>c42+~pym=65y9Gt`yHvQ@&8Pp7k-ljvIGUz_#X6Kke2?#;aCzpXiGMP=+L4u%0^d7dz*(V!S*Fbl(4QXzS)rbTSotG^AKLo~xr6{~{`LrJg0 z*^yCoB9;?|Q`MBA>PM`9D>o~|kUAWGPNPfSm{U}9(wb^c%W}P@Wi^3#6fycyhP^7p zq~RSOr6bVs7@saS{t3^T%+5zClEMU}8;Vs#!6)(8BYRw;O^(H&xIERW3(RV=j<9i3dVT8BBM^sK;E z#;RDZ{9h5Y$Std50;S3ot>?;wrBL;LmF+t6cwA0HLDu7d%6OW4h=uSZHPcp#xO5uM zmTGDk^%=`*3u!DK1l$tJdm} zWW0AW5JqiIT}RR((yN3H9_x^At<^zB97CB6&4nK!+;f?gDGRIjb5E;9vGyC-$J8qI z5Fb^p7OfKYsY_GI7?S6jJ?uT~2fB-cu5C{GJD9RDGLC}S%gr54lY1g!Yrhq%rR<$A zGOhxFIi$h!Gh-G`yCH{=TT`+GO$6d&65*27)Pw`%wJHl@acN>*KOGILLt3&_u^Ng4 z*@e_$3$Db}t~YqUpi+KEdr88g*{7xQeZ)SE*^fHwsYsjE`HFJUEDE7$9*hzi2LV;d zI4a_hRx@oj&B8M&F#pyChZdEokR2V!!}~Fny>uWk#ap`w8wpW#Ns*S4?YeD`4bh+# zGL;E2A>PKGR!?bB{Vzt;^+@=WOO4eKqbJLU1Rk)qrg(7X6#C$CztC?I6@zWF&T?JVH z0C~GoPD3ZAwnW-%8}cM$3^4Dd<#U$scM{@f5yo>F>(b#TQ#d`uJ)$y2hAg>^`=mox zn1v-ci2od}{sTN7;Z~HTOaK?pIWi<0x{wVX@e<~%w9YjM&5}M3!?)qq%W!rZoY`A; zGVxmwWy={mh*uE53t@!qKPnOIYIEm+;S)me1M=MK=J{8_eb2D?w}89y|L@56J&0dU z2-iIAO}a@p=_cKzn{<h~m^#Nz50+6Sbau;Qy z?1)*d#Mm)};gehV%oaWo;a#z8owrNX?C4IAUgFa;c;gm)@kRL8XYftnkq{3H!h-Z3@ZJaT zbC>WJgKSt3V%>Gk)MFlb{sDM&8~)WR@J~nhpTI-Xs6fmGh)nMSKlBj(>@)bq06#Ps zMe2?Ew4JnA6ZgQA3;5Ej@P!e+3OsOTu_7dmedRIy)Fu4o06(nj1uW4{ccQ9{FYH&5 zytsou^$@l%!LOX9;Rx@*kAn8j3_o%Oe?GwP-^g+d>6Yf9hc(+%*duxCgp)4n=-}=S ze)bZ6^L|pcE7BZPlI=726EplFS&FgIjkKardDW%%k@eI5Z&qhIWP447mv`{f6TF6W z3iG<23I4E4JAyWwQXtw@)rAS0hKRlAOhw0XZx~>l;X`})Fv&Lz>XmLsczrM~(XM*Y z!g}nEMbT8iF`6MN8L}FHS0;GB=#$e0DCfvA8_p2bPI#{Zt$c-`9T$tSRNlq3$mKS6 zTad_N@HNr};;s>w@4SLS?&r-es&Io@N|FcCj7%+|yz<2$*THj3JTJp=wMWbOLuuWB zBwq(*NsL9+w1dw4uF&duXGnfq(MQ`GclA$ahYm3;T4l9u5490C9B`qa&Cq4E$W9ez z&sA-SX=SMd2lLw!4$brC-)PH?=8+7*%CSwZ`Q0KvRO#5yUbtk2dl#uuq-xTkeZIZ! z`q`@y`s%K0zO`ZlbtMl}!Y<2LRH9O@STbmn=Ol9+ik&VH8d)!hK_2<5wA>Dq>k1?q zh0t%^_)w`qG{m%G?X_NI?A}u?7?&!d%ipT$09QQIn(QsnXt-eN)mca;PQX!Eo{8DU z;1KFw1$wMjtGrmfgWTZ!2IK zVzoL%Q8HO=rr@#*)c>uFT`4U;7b(+026f(HS|OH;L6j*5LsSnp)BoFM(Qu$;bLJ*x z6gMlE=F<}pLXEG_k1 znYNW}r1k;S3ai8yh;?DEF2%_5)e6KCjkc_|w%h(6XyjWFws!2w{GSqb=D9^`Y&^5r zmaQhG_p4>jidb7Fleto^meoDaWiIJ4m#eLl64e%}jfb@)>p}IVjZ#~$rwZ#2nv=3Q zcDhL#mDqx{wX)vM5^uD6i5Q~f-S?;hQ?Hd&q1svUb#E^kV22^|VVvVS&Ot>Lae+DPclxPr3nE%uOFKOGMs zjwD|i6!lPi#DZw6#y!Fq!oqIv>*!{wTrSltkILz{bt*046{X78MY()5VR=PZKdMm1 zkyuEJUTO>1MjuVtxv0vHjT|h2oy6IYL(9#QeSF<-qn~}WhWWnl;Sd?HM(g|!8QTZny5!IsY zD4Sjip_IE&E->a41+fNs7@L;wOxz%C3FgoinL+o|8zxn`LX>lwLOBPfTEecVTPhuU z&W>a-+_cXvJeN<(Rnh7-{!L|UMIw~ZKMCSz*@w}0AhEE-PI#Q^E;DVT(MX&=Q#@Bj zteU1#<}4M-a&6b!n(pgDr($WJE9Hu7h`rHjRTvF(Tf|1=SDQrrEyR3W(dvkxRVA=p zmL|llyhsygSDQ1We-+|V#?c0Q-qy@hmN=WHu}7>zY?LY=4r_F$k2s`NE1M{dgesZv z^yrFX?eH~S)EMOqv$mV6No{S$96@EA#zDf0PEn}16jV%Rx>T;YDAzQk(OXB;Nc7yL z5Uo~~H&G^YLOi#u&gLX&GpkkO%)DcDw4JF?Mr-WXPWwzTZFyPlKQ@R5R}iflb4L-hWPRiz3^eMYaOQ?09!LZbDpc=gu|38`D<6dDkrrbk#u_*M4W9`BlFQImH`7Moy@4oA#r(UGEz;2EWx zV>*zg>#OGo(^<1FuictrQLnMt*24j^mulWNF;`}_OSU!)OW7_^_bAGKnP8rYLn1y0 zn9tXg%O`f=>qTQHxl4gsxp5<7AJguir8&*A2i*AODxN+Tg%sLVvd&4i#x$F7hO|3p zKS10p5yOht(j+Whw9j6glTR{Un$uj4h-4Ny+d|xmk_pUws-C^3+m4*bxvSM@;HRVn zaWo5#Ea7N=TT~*RR^OD(`d*ZMv|6psJS2APr7{E5(ORc_=J?3M5_Etss0P2dcoi&X~e}aeU|8x+CC$PUI zZ`lc?7x+Y$TYx?FnVzjuLD}5}X@}Py!oFFDn-SlF-7~lt<&>%*%GHZH<__eBGeL>U z_Z(pNQM1D>tC`3vhNJo9QAjt$3}G`rLk-wD}99{cMlHKZL7a==Byq2mUX> z)l2E-M)$K_fZJZ93uAq??rD1l)BBqh$8DqTJ_+LoV0;MfM7#8TtGjgdB!rKDKdlel&Siu`ON0Nm*=m|fRg|lkoN5g=cJ9xw}9I- z+})>r#qXZs-5y?!>70QVNIR=_bG)UigXhtuncMA<-YNb>&LVj8JbfOF=~%5R(h+J~ z>XR7)oOVRSLBO#FsQ_Of?NNXC9)4sGADG~M0bcX)N=Sz+ybxsXw4qT=ndCfG@_0 zsn6hef%FQ^AKt>puHaKMd?di{ll%59RMmOnu2jCe63I3H(^O8LS?n{^6)Y~j1p3?O z@Rf7;FSp^V7w|0s{*0vdGmWa-i7H1?-4{qNnt1OXK7Iv1>C?+e-WB0uD3jTP%%WFi z88FY&3M|&{nrl%e)be6RlGNWkhyQj9{^K3^wK2VqUBS=3g4w_83M&z3DgPZ<$L z>q#Sb1AKU&zV8RPbr*iUVUX8p(lgR&5%+fRqgU|9C-`_MXRU0UnLu_%at5SjLIs}Y zcas)OXc$#(o{QuixvEt;unFKiyl;SMmyWM}`=Yezo-`lLKslA@g*|+Dh7X1$*%47; z^}JSEy}2E0&n;69pp>XW1lX<<_3tWLV`D_>cn68aVcOgaNg{%8*v((sp zRiiehG~W?QH)&uYVY?5~IqH))3^OVQ=%+gN!(?bB*|Xn;(`r>(*=s2`v=-oXy^;XU zs;eJIy-rQ)+n$w?PkL%ew<>Mb_K+=B46)MeX@dgjrA9jK`3u=T8_md)ZR=;G-%YKA zGk4AT3$2YV?6@Upe|Iz>Ck4`ps4Tz*h9jVy=8GK#J9+WQ4=Np!M(>d$9{*@+C7d0G zz1BE_2-Qlte$6@s_bO`^AulVkQqB=3X(u7?!?#(+_CamnrB||6>C6Ok&mKQh#ng1Z zE20e$M*WK&A9{5K3arx*HaDFIKpQ2+b zoK07o5Lq&vfrUn;d$zs?xVhE_6suB>4ZtY%8apO$ce-SHk-Ya=|JSzAS>W1h(F-c| zHkz`LQ4iZODfjHws&pgLsOy+}w0d4TLbd3*B4~bS`y35eP2C<;Y%0+UGc5>vuXRXG zU8?hWHwi!>)Cu&Z==TcoQ;gHYs2Pn9X+`tSe!tAIN9-$S$8MlU2dq|9VX%=GuF`vY?i5d#`m^ zEoiAT#(t{<%=E!U;Ni`~D&1fl$FXmlPK~qmey_{d$zMrX^NE!6c~){N->MC3-mKCF zXo!@7vzF_w`F+egA4*nbTL!j(%@1vdgZx&Y`l<3PY&eilU(+eb!I8amgzDVj%A^~v zw-r5@O#I%>*ZK-r#?H|I4%jHUq}EHTa|{}IM9P_o&OBg1w zl|Le3Tj3DoG!Bt&KK0ZLnN}5#ro*6L4XR@U6$@#0R6EDamO0iFOP%fEP7Ba>@3zet z1Nkhw;7Ic}v2J1(PS{R{H3+Lv^H^#;Z}(nD>iOV5{ciTLMd*Z<-emFuS|r$xf7!wu zWYw)~+NRLKY@@Wcz((o|r)Io*7L;nHJmTA8*80Q2L)cIqZEGD;E5%kLUGHM=(gDX* zF`{8W>#(4xaWrOGIjk127UV-wq#vI$@{PfZQF__(9K2ZSnOaoNd@}$w3~z$%HN7b_#Q) z?LCybfK4-3(Y5NWpC}8~0#&4S*oH#^?V~uYp|rW#Hro-7)}uBK>bff4v-Q~CFy6d! zTH>MeX&yFPJEm2ErAS&k?hAF6)bqYwsUG7(uQ^g+=67{HmXD9+c$)Tn(S=H94{g<1 z7@#y3aq}8rdFE96wFMnowzQz_DIqXMonsAn-AiNK`j9xb>8Y^&5u5*WLDvM_hLgSP zo!jcPG=|ob%uWg|_4rF`_+GrUr-YCWszLYMF1OOLwtpaXI|_|s>N+r!KVS~23(I&q zf;sw03su#K!X-yu=QucH%eDfY3cAkqp=!Uv000NcNklLe zYUxQ{I+PRhLM&2lC0t3=fW5Ai4*}5!7SD99<<+&ucEh}EhnG%^q}F;=qjxg2BhEp+ zv3<2o3!(??I;rch*KBxArPtKD8%txjB`fkOV3xRbWQW@7Yap!DxmEE_UhAP1Xx30x z0B0$;nTJkuw1#7?`8le$D_BV45WZIIl*H%YehRBYW-rlaO}6t=wD-LKaS|8Pm#TA602r z9cbEhNXI}O1-&A<-g9djQ1yqkEk3zfvKfP{osMNU%e4WW^2`dDqxX$t3XOEDQ`9xJ zYdmrsEfSs``3Tua-TPRy$)^C5ht`g&T*0*dzm~J2(%tT1RfsFnonqQQFpGqPmGFu~ zItlQpNPCYqjEd%3403k5INIv4SWUe_ynyl02uP817&?+&v*V8bcY8}VEo#U?`;L&u z$Zbzaz4U1|te$!(>VXUdw8sM;Y>KWS$wh%yl1(}GdNxPvv^ueLPF)FyBHb~TeR~7c z!>`R6%$`jj!gbQ4R=RCB(Up2bvSB?Xd|n&Z>J8II3YTWBoHkD@-9jxSzkTHtFo%*E zy6L8-O;*jE8wnq8hgHJJ$;6}$P#JJDz+MF&(v5t_fFp}l19@?p{%_Wt!&ac?CcPCUn4sBN5o4q)lMYd0D%*Q?mwiR%aw|g2Oh97Z2ynOGZ?} zk=%wJ1msdV&n4w{O;}s5RMY|mKn4J2QR~?i31@7uV#CI1ZCa;=*l7!>Wq^34YYBQN zJ|w4}qzzMS{E%O|Ai%4aTk7{B(h6xTNHcDN*su%)C>Hy@S}}d*m`11?_m0}_6j)7$ zn+yRt`Xa(SH}781EDH&X-skr*i09ozqta6PNp|YUN9(Vuxa&xEEj8`4&11W>Jsa+O zXIWJv?2 zX$EiKxu9t=^C0#*8^9oO^w8LG%YF6MD-}CA>F)5h{9b4o%eQuXW<<)<(uS83o~1n- z0rMS9^3) zj>t}V*v7|)GUz=W3^3n8m^Dieuaz*+={!s#VOL)45LCK|*H#dxNbyujpAtt)MWbO( zc3P$_o&)(Ec-DqjL(8}q2}{8Nb2JSUz^$~Km+W0D^|<0Y*8+9iZSC1hw{}i10t)*R zyfh@R`qmodrac9X4HT^4%>n8QYEmMO5EX|m9{{5~Q0C03x#BU_5+@;sYjFG%JcF_;M&Zx$b9@R3YT)2f%YZIwSunY6c&ZMf7uSKwqXtW-@KeyvDzZRkgxmaZUl>Enmg7dYMy zUnXPMSJ&x6>#WMXW@)@eNO|3O8em=xvWiNJZ3i8#+{1ji7HOFghqx&-4^u2dpIwzU z6}lGa>!ee`2J+xV45{N_L(6<}MR%Rnki47%)|Vj-aL^Mwso?j;iH${7Pf?0IuPyJj z3b)DY%??LeGx#gmZ()?zPE~-{x`4`vO$tBXF=&a6SHW6F$Z$^7_i1fY%d)?-G5`Qn zYCS!I&7Cy(eikI8+<@C6FFZW}Xnco~R>|&;NLB&glHWl-v-F7{!T!}$-TpzInj&oe zjvNXY;Ot$nIRkfQq_A>}J^gij3aa zd_BMpaDPJ%27Ec4X*t{~&kg|R2Y?)6$llyLUja590lYV0_Yk-8@eoFs?!)vsPB@#^ zrU>qrzS7fP4q)~?jFQ1LA(X=I`3$E9>-!k4G!Sb*C^-5 zf_8H0Se>E?C5Pf95vXcq0=IC97x&s(8nKl&YADtd*(a8`LZQ`o;q4aS^%IU z_7VjEU_?urAZrk1?|SbrQ3Mj7AP-H3Ce46O=V-A$HZWvrnRuF+`I}ow_PE{>xMm1k zGX?lXTW=>bADLf}t3@P=)+_ycp7=|bdY!xsu#35KNRVH^Aw+6|*w=$PPGuV~`Bv

rd}L;<^P3TzgZ?sRoc^PEB7h|U`c^Gq-$^YcimwN=HC$-LyrdS_@r8;k zw+$n)4ZUa77}!oZ7!B}^WqVV5EiN+jvMtx=UV~kB0K6+~#L4O+t`+;QlgNUt-8dTY zEvR~)x!$E~2G(a-IGE~Shn>@Id%$BsbmkZr_Z`aq^~bU5wVfe|pVF~%q%u^npHxO| zy&TzA;Cs>XAjX=~F9T%pXXtw`g4ef`p=~gXA=B2vB8a6(orR>=b+#P<_ww$#UuBS; zHrY79iFiWy*{0}~T$|-{gdpj+M&M#ZKA(iK?||beh4w5z#9HxY@`urxMY23GD6X21 z{|8sz`3tV0@Njn)NPEIwnTP=p_KZU!*Yr*eb^R_cT3z~_&PA~ZmOiC(6^^0pqIhrN zj$P}xttNG6|JeG4xnV4MO%}*#?N~a7rb&@@JOskI3w-J<;8D5a_n+MLm)SViGDu`7 z8VT-jD|q@So&UH2OK7B+ zmZ@%%pGJ_abX@{xk_ItQIBq;SG{lTDHY7}(F}c+Jg$rq9*Tms_P^BHV5X@4MdJp*y zY;KO;xHOgWbE+PW0)q}n({BCWISS!Lz=I9jyZepbm2BbJq|vbTCIk^w?uSVZ=$ z`(8dEPrvS|?o)10bnp8h>s)SF!Tyn#hAR90RECy#F6bDQsj?}=*joPmMw*@w-NzD` z6Y8yF9&E3L*(oj65eo)6pAo(gb`Wd+azHcjz{=aT;!r{XsFk(mVl;{BZAO$^ zY+>xP57w}VgIh2yF-!p%~>G`^G=Yqcz1?R z)hE$05hMD09)R9&N7rk}wB03xL(=L440g#Y5E_=NUT9Drs%z>1t4MM>XWU(ou@%nY zZq<;#GL25lj?rz5)92!e{zOCo6iHSC2__VPVdoSYh@LTVfTmTAmwS#C2gUHph!-IC L@Dn|8kG}ao`pBwy literal 0 HcmV?d00001 diff --git a/404_games/space-invaders/index.html b/404_games/space-invaders/index.html new file mode 100644 index 0000000..019abaa --- /dev/null +++ b/404_games/space-invaders/index.html @@ -0,0 +1,20 @@ + + + + + 404 Space Invaders + + + + + + + + + + + + + + + diff --git a/404_games/space-invaders/js/ai.js b/404_games/space-invaders/js/ai.js new file mode 100644 index 0000000..f8c5cfd --- /dev/null +++ b/404_games/space-invaders/js/ai.js @@ -0,0 +1,41 @@ +var updateEnemies = function(){ + + if (hasReachedEnd()) { + changeEnemyDirection(); + return; + } + var enemyMovement; + if (enemyDirection == LEFT) enemyMovement = -10; + else enemyMovement = 10; + + for (var i = 0 ; i < enemies.length; i++){ + var enemy = enemies[i]; + enemy.x = enemy.x + enemyMovement ; + } +} + +var hasReachedEnd = function(){ + var threshold = 32; + + for (var i = 0 ; i < enemies.length; i++){ + var enemy = enemies[i]; + if (enemyDirection == RIGHT && enemy.x > canvas.width - threshold - 32) return true; + else if (enemyDirection == LEFT && enemy.x < threshold) return true; + } + return false; +} + +var changeEnemyDirection = function(){ + if (enemyDirection == LEFT) enemyDirection = RIGHT; + else enemyDirection = LEFT; + + for (var i = 0 ; i < enemies.length; i++){ + var enemy = enemies[i]; + enemy.y = enemy.y + 30 ; + } +} + +var enemyShot = function(){ + var enemy = enemies[Math.floor(Math.random()*enemies.length)]; + enemyShots.push({x:enemy.x, y: enemy.y}); +} diff --git a/404_games/space-invaders/js/assets.js b/404_games/space-invaders/js/assets.js new file mode 100644 index 0000000..b427a80 --- /dev/null +++ b/404_games/space-invaders/js/assets.js @@ -0,0 +1,45 @@ +/** +Ship and laser assets by Cpt_Flash +Available at: http://opengameart.org/content/space-ships-2-units +License: GPL 3.0 +**/ + +// Background image +var bgReady = false; +var bgImage = new Image(); + +bgImage.onload = function () { + bgReady = true; +}; +bgImage.src = "images/background.png"; + +// Hero image +var heroReady = false; +var heroImage = new Image(); +heroImage.onload = function () { + heroReady = true; +}; +heroImage.src = "images/32_player.png"; + +// Monster image +var monsterReady = false; +var monsterImage = new Image(); +monsterImage.onload = function () { + monsterReady = true; +}; +monsterImage.src = "images/32_enemy.png"; + +// Hero image +var shotReady = false; +var shotImage = new Image(); +shotImage.onload = function () { + shotReady = true; +}; +shotImage.src = "images/32_laser_blue.png"; + +var shotRedReady = false; +var shotRedImage = new Image(); +shotRedImage.onload = function () { + shotRedReady = true; +}; +shotRedImage.src = "images/32_laser_red.png"; diff --git a/404_games/space-invaders/js/controls.js b/404_games/space-invaders/js/controls.js new file mode 100644 index 0000000..a437955 --- /dev/null +++ b/404_games/space-invaders/js/controls.js @@ -0,0 +1,40 @@ +// Handle keyboard controls +var keysDown = {}; + +var KEY_UP =38, KEY_DOWN =40, KEY_LEFT =37, KEY_RIGHT =39; + +addEventListener("keydown", function (e) { + keysDown[e.keyCode] = true; +}, false); + +addEventListener("keyup", function (e) { + delete keysDown[e.keyCode]; +}, false); + +addEventListener("mousemove", function(evt) { + hero.x = evt.pageX - 24 ; +}, false); + +var lastShot = 0; +var SHOT_DELAY = 1000; + +addEventListener("click", function(evt) { + if (!hero.dead) { + var now = new Date().getTime(); + if (lastShot +SHOT_DELAY < now ) { + lastShot = now; + playerShots.push({x:evt.pageX, y: hero.y}); + } + } +}, false); + + +//Called from update.js +var controls = function(modifier){ + if (KEY_LEFT in keysDown) { // Player holding left + hero.x -= hero.speed * modifier; + } + if (KEY_RIGHT in keysDown) { // Player holding right + hero.x += hero.speed * modifier; + } +} diff --git a/404_games/space-invaders/js/draw.js b/404_games/space-invaders/js/draw.js new file mode 100644 index 0000000..184af78 --- /dev/null +++ b/404_games/space-invaders/js/draw.js @@ -0,0 +1,45 @@ +// Create the canvas +var canvas = document.getElementById("canvas"); +var ctx = canvas.getContext("2d"); + +var SIZE = 32; + +var vy = 0; +// Draw everything +var render = function () { + if (bgReady) { + + ctx.drawImage(bgImage, 0, vy); + ctx.drawImage(bgImage, 0, bgImage.height-Math.abs(vy)); + + if (Math.abs(vy) > bgImage.height) vy = 0; + vy -= 2; + } + + if (heroReady && !hero.dead) { + ctx.drawImage(heroImage, hero.x, hero.y,SIZE, SIZE); + } + + for (var i=0; i < enemies.length; i++){ + var enemy = enemies[i]; + ctx.drawImage(monsterImage, enemy.x, enemy.y,SIZE, SIZE); + + } + for (var i=0; i < enemyShots.length; i++){ + var shot = enemyShots[i]; + ctx.drawImage(shotRedImage, shot.x, shot.y ,SIZE, SIZE); + } + + for (var i=0; i < playerShots.length; i++){ + var shot = playerShots[i]; + ctx.drawImage(shotImage, shot.x, shot.y ,SIZE, SIZE); + } + + if (hero.dead){ + ctx.fillStyle = "rgb(250, 0, 0)"; + ctx.font = "48px Helvetica"; + ctx.textAlign = "center"; + ctx.textBaseline = "top"; + ctx.fillText("Game Over", canvas.width / 2, canvas.height/ 2); + } +}; diff --git a/404_games/space-invaders/js/game.js b/404_games/space-invaders/js/game.js new file mode 100644 index 0000000..f6a5848 --- /dev/null +++ b/404_games/space-invaders/js/game.js @@ -0,0 +1,28 @@ +// Reset the game when the player catches a monster +var reset = function () { + hero.x = canvas.width / 2; + hero.y = canvas.height - 64; +}; + +// The main game loop +var main = function () { + var now = Date.now(); + var delta = now - then; + + update(delta / 1000); + render(); + + then = now; + + // Request to do this again ASAP + requestAnimationFrame(main); +}; + +// Cross-browser support for requestAnimationFrame +var w = window; +requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame; + +// Let's play this game! +var then = Date.now(); +reset(); +main(); diff --git a/404_games/space-invaders/js/objects.js b/404_games/space-invaders/js/objects.js new file mode 100644 index 0000000..776c3ec --- /dev/null +++ b/404_games/space-invaders/js/objects.js @@ -0,0 +1,29 @@ +// Game objects +var hero = {}; +var playerShots = []; +var enemyShots = []; + +var shotSpeed = 200; + +var RIGHT = 1, LEFT = 0; +var enemies = []; +var enemyDirection = RIGHT; +var loadEnemy = function(offset, json){ + var size = 32; + + for (var i = 0; i< json.length; i++){ + var pos = json[i]; + var enemy = {x: offset.x + pos.x * size, y: offset.y + pos.y * size} ; + enemies.push(enemy); + } +} + +loadJSON('enemies.json', + function(data) { + + loadEnemy({ x: 50, y: 50 }, data.four); + loadEnemy({ x: 180, y: 50 }, data.zero); + loadEnemy({ x: 300, y: 50 }, data.four); + }, + function(xhr) { console.error(xhr); } +); diff --git a/404_games/space-invaders/js/update.js b/404_games/space-invaders/js/update.js new file mode 100644 index 0000000..6ab20c8 --- /dev/null +++ b/404_games/space-invaders/js/update.js @@ -0,0 +1,45 @@ + +// Update game objects +var update = function (modifier) { + controls(modifier); + + for (var i = 0; i< playerShots.length; i++){ + var shot = playerShots[i]; + shot.y = shot.y - modifier * shotSpeed; + + for (var e= 0; e < enemies.length; e++){ + var enemy = enemies[e]; + if (collision(shot, enemy)) { + console.log("Collision with enemy ", shot, enemy); + playerShots.splice(i, 1); + enemies.splice(e, 1); + break; + } + } + } + + for (var i = 0; i< enemyShots.length; i++){ + var shot = enemyShots[i]; + shot.y = shot.y + modifier * shotSpeed; + + if (collision(shot, hero)) { + console.log("Collision with hero ", shot, hero); + enemyShots.splice(i, 1); + hero.dead = true; + } + } + //updateEnemies(); + // Are they touching? +}; + +var collision = function(shot, enemy){ + return shot.x <= (enemy.x + 32) + && enemy.x <= (shot.x + 32) + && shot.y <= (enemy.y + 32) + && enemy.y <= (shot.y + 32) +} + +//AI METHODS +setInterval(function(){updateEnemies()}, 500); + +setInterval(function(){enemyShot()}, 1000); diff --git a/404_games/space-invaders/js/utils.js b/404_games/space-invaders/js/utils.js new file mode 100644 index 0000000..f17f8b3 --- /dev/null +++ b/404_games/space-invaders/js/utils.js @@ -0,0 +1,11 @@ +var loadJSON = function (path, success, error) +{ + var oReq = new XMLHttpRequest(); + oReq.onload = function reqListener () { + jsonData = JSON.parse(this.responseText); + console.log("Loading JSON data", jsonData); + success(jsonData); + };; + oReq.open("get", path, true); + oReq.send(); +} diff --git a/Docker-404-games.iml b/Docker-404-games.iml new file mode 100644 index 0000000..9a5cfce --- /dev/null +++ b/Docker-404-games.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..008ebd9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:slim + +LABEL authors="tebarius" +LABEL version="1.2.1" +LABEL description="QR-Code-Generator-Server with Flask-App" + +WORKDIR /app +COPY ./app /app/ + +RUN pip install --upgrade pip +RUN pip install --trusted-host pypi.python.org -r requirements.txt + +EXPOSE 8002 + +ENV HTTP_METHOD POST + +CMD ["sh", "-c", "python ${HTTP_METHOD}-Flask-QR.py"] \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..03ee291 --- /dev/null +++ b/readme.md @@ -0,0 +1,49 @@ +# Flask QR-Code-Generator +Sorry folks, because this project startet as experiment for Flask and Docker only german description and manual. + +HTTP-Server auf Port 8002 mit QR-Code-Generator zur Generierung verschiedener Arten von QR-Codes (Text, URL, Mail, Tel., WIFI, Kalender-Event, vCard, MeCard). + +Eigentlich ist das Projekt für mich ein Experimentierfeld gewesen um mal Flask ein bisschen auszuprobieren + +## ohne Docker +Um lokal das ganze zu testen werden nur die Dateien aus dem app-Verzeichnis benötigt. +Voraussetzung ist eine funktionierende Python Installation (ich habe nur mit Python 3.11 und 3.12 getestet) und das Flask-Framework inclusive Flask-QRcode welches sich recht einfach über die Konsole mit ... + + pip install Flask-QRcode +... installieren lässt. + +Zum Starten dann eine der beiden .py Dateien benutzen, je nachdem welcher +HTTP-Modus gewollt ist. Im Zweifelsfall POST ... nehmen und wenn ein Doppelklick nicht geht dann halt über die Konsole: `python POST-Flask-QR.py` + +Der Server ist dann via http://localhost:8002 zu erreichen + +## Docker +Es gibt 2 unterschiedliche Dockerfile's, da obwohl bei beiden python:slim als Basis genutzt wird, +noch die Installation von ein paar packages zusätzlich notwendig ist, damit flask auch auf +dem RaspberryPi 3 via pip install integriert werden kann. + +In der Standardeinstellung werden die Formulare mit HTTP-POST-Anfragen gesendet/verarbeitet. +Sollte es Gründe geben, warum gewünscht wird, dass dies der HTTP-GET-Variante zu machen, lässt sich das über die Enviroment Variable HTTP_METHOD ändern. + +## Enviroment-Variablen + +- `HTTP_METHOD` GET oder POST (default: POST) + +## Docker Installation/Start +https://hub.docker.com/r/tebarius/flask-qrcode-generator +### Linux/AMD64 +- einfacher Start: + `docker run -d -p 8002:8002 ghcr.io/tebarius/flask-qrcode-generator:latest` + erreichbar dann z.B. via http://localhost:8002 +- mit HTTP-Methode GET auf Port 80: + `docker run -d -p 80:8002 -e HTTP_METHOD=GET ghcr.io/tebarius/flask-qrcode-generator:latest` + erreichbar dann z.B. via http://localhost + +### Linux/ARMv7 (getestet mit RaspberryPi 3) +- einfacher Start: + `docker run -d -p 8002:8002 ghcr.io/tebarius/flask-qrcode-generator:armv7-latest` + erreichbar dann z.B. via http://localhost:8002 +- mit HTTP-Methode GET auf Port80: + `docker run -d -p 80:8002 -e HTTP_METHOD=GET ghcr.io/tebarius/flask-qrcode-generator:armv7-latest` + erreichbar dann z.B. via http://localhost +