Create a gist now

Instantly share code, notes, and snippets.

@gre /README.md
Last active Nov 10, 2015

What would you like to do?
Panzer Dragoon 1k

"Panzer Dragoon 1k" is a 2D remake of Panzer Dragoon in 1k of JavaScript for JS1K 2014 by @greweb

Goal

Use your Dragoon to prevent enemies from escaping.

How to play

Lock multiple enemies by hovering over them, then Launch your fire balls at them with a click.

Tips

  • Lock as many enemies as you can before firing.
  • Be careful with small enemies, they are hard to catch!
  • You can accelerate time by moving your Dragoon to the right, use it wisely.

Features

  • Smooth Moving with Dragon Animation.
  • Time Boost. (moving the dragon to the right)
  • Various Enemies Pop System. (different color and size)
  • Continuous Fire.
  • Rotating Cursor with Score display.
  • Lock System with Fire Balls Shooting. (on click)
  • Motion Blur. (when danger)
  • Screen Shaking. (when danger)
  • Levels. (there is a boss phase with a lot of enemies and then a new level)
  • Score.
  • Game Over Screen. (reached when an enemy reaches the left border)

Build

npm install
npm run build
_='t=g=D=U=X=Y=Q=8o^Cp^CImovexJX+99,yJY,tEL()},IupU=!g}ec)c[++(~E"")]=c[e];Lwith(c){setTimeout(L-18*x/ X=.98*X+ Y_3+`%9EgE6, 32] 1>t%Qzo[]^*,40+3e3*/(Q=30>Q?200:.98*Q -*(1`/1e4+K3e3,"#1"`%7`%5] HglobalAlpha=.8/(1+D G8cd",gzGe44"c( B6*D*,6*D*Ze=Ge44",i=f=X;14>i;i++)f-=+(i/20+.6)* -14,, 3==i,44+ 90);D=x/io){e=o[iC t>~z7]),f^x,yC(F=FEt)zHB,$ 0<sq,U2(-XK2($-YK24F=0])Zf=,(-=f[5C~=t+5,_9, <f[0];D_@max(.6-/ <18o[iC<0zg=gEt)}Bx,y sq2,2H gsq18OU=0}};fillNstrokeN@random()P*P+V*V<W*W,bgq arc(_3C$_4C,9()flc(f,9-i*14+Ya.width rt(-t/14 srR(-9,-9Oe[ Gffb", ), (x-XK3=function(e){20-(t-FK2*@cos(-i/2`/12)0,,180];for(delete &&(f[2](y-YK28-2*ix(gEt(p[]^X,Y, in p[j],a.height$1]@Math.B taqC],E||F5]G"#Hsv( IonmouseJ=e.pageK)/NStyle=O rse( P0]-)V1]-$)W2]+)Z)jp)^=[_+=`+tqa(z(~6] fl';for(Y in $='~zq`_^ZWVPONKJIHGFECB@$ ')with(_.split($[Y]))_=join(pop());eval(_)
<!doctype html>
<html>
<head>
<title>JS1k, [COMPO] demo submission [ID]</title>
<meta charset="utf-8" />
<style>
html, body { margin: 0; padding: 0; border: 0; }
#c { display: block; } /* kill scrollbars from hell */
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
var a = document.getElementsByTagName('canvas')[0];
var b = document.body;
var d = function(e){ return function(){ e.parentNode.removeChild(e); }; }(a);
// unprefix some popular vendor prefixed things (but stick to their original name)
var AudioContext =
window.AudioContext ||
window.webkitAudioContext;
var requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(f){ setTimeout(f, 1000/30); };
// fix bug in safari: http://qfox.nl/weblog/218
document.body.clientWidth;
// auto resize (original) canvas. call `onresize(w,h) to limit the size of the canvas
(window.onorientationchange = window.onresize = function(a){
var mw = false;
var mh = false;
var max = Math.max;
return function(w,h){
if (arguments.length === 2) {
mw = w;
mh = h;
}
a.style.width = (a.width = max(mw, innerWidth)) + 'px';
a.style.height = (a.height = max(mh, innerHeight)) + 'px';
};
}(a))();
var c = a.getContext('2d');
</script>
<script type="text/javascript" src="source.js"></script>
</body>
</html>
t=g=D=U=X=Y=0,Q=80,o=[],p=[],onmousemove=function(e){x=e.pageX+99,y=e.pageY,t||L()},onmouseup=function(e){U=!g};for(e in c)c[e[0]+e[2]+(e[6]||"")]=c[e];L=function(e){with(c){setTimeout(L,18-18*x/a.width),X=.98*X+(x-X)/30,Y+=(y-Y)/30,++t%9||g||(p[Math.random()]=[X,Y,6,(x-X)/30,(y-Y)/30,2]),1>t%Q&&(o[Math.random()]=[a.width,a.height*Math.random(),40+3e3*Math.random()/(Q=30>Q?200:.98*Q),-a.width*(1+t/1e4+Math.random())/3e3,0,0,0,"#1"+t%7+t%5]),sv(),globalAlpha=.8/(1+D),fillStyle=strokeStyle="#8cd",g&&(fillStyle=strokeStyle="#e44"),flc(0,0,a.width,a.height),fillStyle=strokeStyle="#ffb",taa(6*D*Math.random(),6*D*Math.random());for(j in p)e=p[j],bga(),arc(e[0]+=e[3],e[1]+=e[4],e[2],0,9),fl();for(fillStyle=strokeStyle="#e44",i=0,f=X;14>i;i++)f-=28-2*i+(i/20+.6)*(x-X)/30,flc(f,9*Math.cos(-i/2+t/12)-i*(y-Y)/14+Y-14,28-2*i,28-2*i),3==i&&flc(f,9*Math.cos(-i/2+t/12)-i*(y-Y)/14+Y,44+(x-X)/30,90*Math.cos(-i/2+t/12));D=x/a.width;for(i in o){e=o[i],fillStyle=strokeStyle="#ffb",t>e[6]&&(fillStyle=strokeStyle=e[7]),bga(),arc(e[0]+=e[3],e[1]+=e[4],e[2],0,9),fl(),f=[x,y,18],(e[5]=e[5]||(f[0]-e[0])*(f[0]-e[0])+(f[1]-e[1])*(f[1]-e[1])<(f[2]+e[2])*(f[2]+e[2])&&t)&&(sv(),fillStyle=strokeStyle="#ffb",taa(e[0],e[1]),0<20-(t-e[5])/2&&sa(20-(t-e[5])/2,20-(t-e[5])/2),rt(-t/14),srR(-9,-9,18,18),rse(),U&&(p[Math.random()]=[X,Y,20,(e[0]-X)/20,(e[1]-Y)/20,40,e[5]=0]));for(j in p)f=p[j],(f[0]-e[0])*(f[0]-e[0])+(f[1]-e[1])*(f[1]-e[1])<(f[2]+e[2])*(f[2]+e[2])&&(e[2]-=f[5],e[6]=t+5,e[0]+=9,delete p[j]),a.width<f[0]&&delete p[j];D+=Math.max(0,.6-e[0]/a.width),e[2]<18&&delete o[i],e[0]<0&&(g=g||t)}fillStyle=strokeStyle="#ffb",taa(x,y),sa(2,2),flx(g||t,18,18),rt(-t/14),srR(-9,-9,18,18),rse(),sv(),fillStyle=strokeStyle="#ffb",g&&sa(18,18),flx(g||t,18,18),rse(),U=0}};
{
"name": "gre-js1k-dragons",
"version": "1.0.0",
"devDependencies": {
"uglify-js": "2.4.x",
"jscrush": "0.0.0"
},
"repository": {
"type": "git",
"url": "https://gist.github.com/1c34c68cf81264e6c043.git"
},
"scripts": {
"build": "npm run uglify",
"uglify": "cat source.js | uglifyjs -c unused=false | tee minified.js | jscrush > crushed.js && wc -c *.js",
"closure": "cat source.js | curl -d compilation_level=ADVANCED_OPTIMIZATIONS -d output_format=text -d output_info=compiled_code --data-urlencode \"js_code@-\" http://closure-compiler.appspot.com/compile | tee minified.js | jscrush > minified.js && wc -c *.js"
}
}
/*jshint ignore:start */
/**
* "Panzer Dragoon 1k" by @greweb
* an entry for JS1K 2014 "Here Be Dragons"
*
* Blog Post: http://greweb.me/2014/03/panzer-dragoon-1k
*/
// window object is polluted like hell with one letter variables ;-)
// i, j, e, f : are temporary variables
// Game States
t = // Game frame current time.
g = // GameOver Time || 0 if no GameOver
D = // "Danger" variable: more it is high, more there is danger (means a lot of opponent are reaching the left part)
U = // mouseup flag. It represents a missile shoot request.
//x = y = // x,y: mouse position <- we don't need their declaration because the game can't be started without them
X = Y = // X,Y: player position
0;
// Q : the mob pop factor. More it is low, more there is opponent popping.
// Q ~ depends on t but in a non trivial way. it ~ follows a sawtooth curve. See the algorithm in the opponent creation code.
Q = 80; // We start a bit lower than the reset value.
// Here we create 2 collections, but those are used as objects not array! Each element of these is a vector
o = []; // an opponent: [ 0: x, 1: y, 2: health, 3: vx, 4: vy, 5: locked, 6: hitTime ]
p = []; // a particule: [ 0: x, 1: y, 2: size, 3: vx, 4: vy, 5: damage ]
// Game Input
//ontouchmove = // mobile support. I wish I had more bytes!
onmousemove = function (e) {
x = e.pageX+99; // We don't directly use the mouse coordinate but we translate/scale the cursor to avoid behind able to shoot behind. It is like a constraint of the dragoon.
y = e.pageY;
t || L(); // the mouse moved, we can start the game once.
//return e.touches ? ontouchmove(e.touches[0]) : !1;
}
//ontouchend =
onmouseup = function (e) {
U = !g; // We can only shoot if game is not over
}
// Programmatically alias Context2d functions. (WARNING some functions are overrided with different behavior on different browsers)
for (e in c) c[e[0]+e[2]+(e[6]||"")] = c[e];
// L is the render loop
L = function (e) { with (c) { // with(c){} allows to we make all functions of "c" available in the scope
// Call the next frame.
setTimeout(L, 18 - 18 * x / a.width); // The framerate increases when you are targetting far in order to improve the gameplay.
// Move player in a smooth way
X = .98 * X + (x-X)/30;
Y += (y-Y)/30;
// Fire bullet
++t % 9 || // Increment the ticker here! but don't trigger a bullet each frame!
g || // Don't trigger a bullet if game is over
// Trigger one fire by adding to p
(p[Math.random()] = [ // It is the f**king way to add an element! to be used with delete and for-in loops.
X,
Y,
6,
(x-X) / 30,
(y-Y) / 30,
2
]);
t % Q < 1 && // May happen for a few times t until t%Q isn't < 1, it makes opponents coming by waves
// Creates an opponent
(o[Math.random()] = [
// Following values are important part of game difficulty
a.width, // X
a.height * Math.random(), // Y
// Health
40+3e3*Math.random()/
(
Q = Q < 30 ? 200 : .98 * Q // Update Q <- decrease, and move back to initial value for each new level
),
-a.width*(1+t/1e4+Math.random())/3e3, // VX
0, // VY
0, // hold
0,
"#1"+t%7+t%5 // Random color
]);
// Save the state to be restored later
sv();
// Draw background
globalAlpha = .8/(1+D); // The cheap way of doing Motion Blur
fillStyle = strokeStyle = "#8cd";
if (g) fillStyle = strokeStyle = "#e44";
flc(0,0,a.width,a.height);
// Next color for drawing bullets.
fillStyle = strokeStyle = "#ffb";
// Shake the whole screen proportionally to D
taa(6*D*Math.random(), 6*D*Math.random());
// Bullets Update & Draw
for(j in p) { e = p[j]; // Foreach Bullet e
// Drawing a circle
bga();
arc(
// Update bullet position
e[0] += e[3],
e[1] += e[4],
e[2],
0, 9); // OMG trick to goes from 0 to 2π
fl();
}
// Player Update & Draw
fillStyle = strokeStyle = "#e44";
// Drawing the Dragoon
for(i=0,f=X; i<14; i++) {
f -= 28 - 2*i + (i/20+.6)*(x-X)/30;
flc(
f,
Math.cos(-i/2+t/12)*9 - i*(y-Y)/14 + Y - 14,
28 - 2*i,// + 9*!i,
28 - 2*i// + 9*!i
);
if (i == 3) flc(
f,
Math.cos(-i/2+t/12)*9 - i*(y-Y)/14 + Y,
44+(x-X)/30,
Math.cos(-i/2+t/12)*90
);
}
D = x / a.width; // Danger is recomputed in the following Opponents loop
// Opponents Update & Draw
for(i in o) { e = o[i]; // Foreach Opponent e
fillStyle = strokeStyle = "#ffb";
if (t > e[6]) {
fillStyle = strokeStyle = e[7];
}
// Drawing a circle (it is the same chunk of code previously used!)
bga();
arc(
// Update opponent position
e[0] += e[3],
e[1] += e[4],
e[2],
0, 9);
fl();
f = [x, y, 18]; // Cursor "tuple", used for factorizing the distance formula
// Cursor Targetting
if (
// Opponent is targetted if he was not yet and the cursor is near the opponent. e[5] becomes the time of the targetting
e[5] = e[5] ||
// cursor hits opponent
(f[0]-e[0])*(f[0]-e[0])+(f[1]-e[1])*(f[1]-e[1]) < (f[2]+e[2])*(f[2]+e[2]) &&
t
) {
// Drawing a scaling/rotating cursor for the targetting effect
sv();
fillStyle = strokeStyle = "#ffb";
taa(e[0], e[1]);
if (0 < 20-(t-e[5])/2) {
// From the targetting time, we scale down to make the targetting effect
sa(
20-(t-e[5])/2,
20-(t-e[5])/2
);
}
rt(-t/14);
srR(-9,-9,18,18);
rse();
// Missile Bullet
U && // If hold off and opponent targetted, trigger a missile to that opponent
(p[Math.random()] = [
X,
Y,
20,
(e[0]-X)/20,
(e[1]-Y)/20,
40,
e[5] = 0 // Also reset the "locked" state here.
]);
}
for(j in p) { f = p[j]; // Foreach Bullet f - N.B. it seems impossible to reconciliate to the previous for(i in p) loop here because there is better bytes save implied.
if ( // bullet hits opponent
(f[0]-e[0])*(f[0]-e[0])+(f[1]-e[1])*(f[1]-e[1]) < (f[2]+e[2])*(f[2]+e[2])
// ^ Intentionally, we have the exact same code that that previously!
) {
e[2] -= f[5]; // Apply bullet force from bullet size
e[6] = t+5; // Flash effect
e[0] += 9; // backwards effect on shot
delete p[j]; // And here is the way we remove an element!
}
// Out of Bound to prevent memory leaks!!!
if (a.width < f[0])
delete p[j];
}
// Accumulate Danger with the left opponent distance
D += Math.max(0, .6-e[0]/a.width);
// Destroy Opponent if his life is enough small
if (e[2]<18)
delete o[i];
// Game Over reached with an opponent reaches the left side
if (e[0]<0)
g = g || t;
}
// Draw the Cursor with its score text
fillStyle = strokeStyle = "#ffb";
taa(x, y);
sa(2, 2);
flx(g||t,18,18);
rt(-t/14);
srR(-9,-9,18,18);
rse();
// Draw the top-left Score
sv();
fillStyle = strokeStyle = "#ffb";
if (g) sa(18, 18); // Scale it up if game is over
flx(g||t,18,18);
rse();
U = 0; // reset the mouseup flag // FIXME we may find a place to move that somewhere!
}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment