Skip to content

Instantly share code, notes, and snippets.

@stryju
Created November 1, 2012 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stryju/3993018 to your computer and use it in GitHub Desktop.
Save stryju/3993018 to your computer and use it in GitHub Desktop.
// hey there! ;-)
(function() {
var doc = document,
body = doc.body,
atan2 = Math.atan2,
cos = Math.cos,
sin = Math.sin,
sqrt = Math.sqrt,
PI = Math.PI,
random = Math.random,
max = Math.max;
function Zergling(x, y, rush) {
this.rush = rush; // ZergRush instance
this.speed = 3;
this.x = x;
this.y = y;
this.width = 34;
this.height = 42;
this.isKilling = false;
this.isFinished = false;
this.dPulsate = 0;
this.dom = $('<zergling>').css({
width: this.width,
height: this.height,
position: 'absolute',
display: 'block',
background: 'url(http://i.imgur.com/nvBbE.gif)',
'background-size': '34px 42px',
left: x,
top: y,
zIndex: 9999
}).appendTo(body);
}
Zergling.DATA_KEY = 'zergTargetData';
Zergling.MAX_TARGET_AREA = 50000;
Zergling.VISION = 1000; // 1000 pixels in any direction
Zergling.LIFE = 50;
Zergling.isSuitableTarget = function isSuitableTarget(candidate) {
var targetData;
if (!candidate) {
return false;
}
// Make sure none of its ancestors are currently targets:
for (var parent = candidate; parent = parent.parentNode;) {
if ($.data(parent, Zergling.DATA_KEY) || /antiZerg/i.test(parent.className)) {
return false;
}
}
targetData = $.data(candidate, Zergling.DATA_KEY);
candidate = $(candidate);
return !/zergling/i.test(candidate[0].nodeName) &&
!/antiZerg/i.test(candidate[0].className) &&
// Make sure it's either yet-to-be-a-target or still alive:
(!targetData || targetData.life > 0) &&
// Make sure it's not too big
candidate.width() * candidate.height() < Zergling.MAX_TARGET_AREA;
};
Zergling.prototype = {
calcMovement: function() {
var target = this.target,
// Move towards random position within the target element:
xDiff = (target.position.left + random() * target.width) - this.x,
yDiff = (target.position.top + random() * target.height) - this.y,
angle = atan2(yDiff, xDiff);
this.dx = this.speed * cos(angle);
this.dy = this.speed * sin(angle);
},
draw: function() {
if (this.isFinished) {
return;
}
var target = this.target;
if (this.isKilling) {
if (target.life > 0) {
// It's still alive! Pulsate and continue to kill:
target.life--;
this.pulsate();
target.dom.css('opacity', target.life / Zergling.LIFE);
} else {
// It's DEAD!
target.dom.css('visibility', 'hidden');
this.pulsate(0);
this.isKilling = false;
this.target = null;
}
return;
}
// If we have no target or if current target is dead:
if (!this.target || this.target.life <= 0) {
if (this.findTarget()) {
target = this.target;
this.calcMovement();
} else {
this.isFinished = true;
this.dom.fadeOut(100, function() {
$(this).remove();
});
return;
}
}
if (this.hasReachedTarget()) {
this.isKilling = true;
return;
}
this.x += this.dx;
this.y += this.dy;
this.dom.css({
left: this.x,
top: this.y
});
},
hasReachedTarget: function() {
var target = this.target,
pos = target.position;
return this.x >= pos.left &&
this.y >= pos.top &&
this.x <= pos.left + target.width &&
this.y <= pos.top + target.height;
},
findTarget: function() {
// Try to locate nearby elements, going further afield (increasing radius)
// until we've found a viable target:
var targetData, radius, degree, x, y, el,
halfWidth = this.width / 2,
halfHeight = this.height / 2,
scrollTop = max(body.scrollTop, doc.documentElement.scrollTop),
scrollLeft = max(body.scrollLeft, doc.documentElement.scrollLeft);
for (radius = 10; radius < Zergling.VISION; radius += 50) {
for (degree = 0; degree < 360; degree += 45) {
x = this.x + halfWidth + radius * cos(PI/180 * degree) - scrollLeft;
y = this.y + halfHeight + radius * sin(PI/180 * degree) - scrollTop;
if (Zergling.isSuitableTarget(el = doc.elementFromPoint(x, y))) {
el = $(el);
targetData = this.target = el.data(Zergling.DATA_KEY);
if (!targetData) {
el.data(
Zergling.DATA_KEY,
this.target = {
dom: el,
position: el.offset(),
width: el.width(),
height: el.height(),
life: Zergling.LIFE,
initialCSS: {
visibility: '',
opacity: el.css('opacity') || ''
}
}
);
this.rush.registerTarget(this.target);
}
return true;
}
}
}
},
pulsate: function() {
if (this.dPulsate = !this.dPulsate) {
this.dom.css({
left: this.x - 2,
top: this.y - 2
});
} else {
this.dom.css({
left: this.x,
top: this.y
});
}
}
};
function ZergRush(nZerglings) {
var me = this,
zerglings = this.zerglings = [],
targets = this.targets = [];
for (var i = 0; i < nZerglings; ++i) {
zerglings.push(
new Zergling(
random() * 100,
random() * 100,
this
)
);
}
this.intervalID = setInterval(function() {
me.step();
}, 30);
}
ZergRush.prototype = {
step: function() {
var areFinished = true;
for (var i = 0; i < this.zerglings.length; ++i) {
this.zerglings[i].draw();
areFinished = areFinished && this.zerglings[i].isFinished;
}
if (areFinished) {
clearInterval(this.intervalID);
}
},
destroy: function() {
var i;
clearInterval(this.intervalID);
for (i = 0; i < this.zerglings.length; ++i) {
this.zerglings[i].dom.remove();
}
for (i = 0; i < this.targets.length; ++i) {
this.targets[i].dom.css(this.targets[i].initialCSS);
this.targets[i].dom.removeData(Zergling.DATA_KEY);
}
},
registerTarget: function(target) {
this.targets.push(target);
}
};
var kcode = [ 38, 38, 40, 40, 37, 39, 37, 39, 66, 65 ].join( "" ),
input = [];
$(document).on( "keyup", function(e){
input.push( e.which );
var input_joined = input.join( "" );
if ( kcode === input_joined ) {
alert( "all ur base r belong 2 us!" );
new ZergRush( 20 );
} else if ( kcode.indexOf( input_joined )) {
input = [];
}
console.log( input );
});
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment