Last active
November 30, 2018 20:26
-
-
Save iczero/e81ea3811ca5c4f72e2afad55b3891fd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const SELECTOR = '.zr_zergling_container'; | |
/** | |
* Fire a mouse event on an element | |
* @param {Element} node | |
* @param {String} type | |
*/ | |
function triggerMouseEvent(node, type) { | |
let event = document.createEvent('MouseEvent'); | |
event.initEvent(type, true, true); | |
node.dispatchEvent(event); | |
} | |
/** | |
* Get nearest point of an element, also stolen from stackoverflow | |
* @param {Object} from From point | |
* @param {Object} to To point | |
* @param {Object} boxSize Box size | |
* @return {Object} | |
*/ | |
function getNearestPointOutside(from, to, boxSize) { | |
// which side does it hit? | |
// get the angle of to from from. | |
let theta = Math.atan2(boxSize.y, boxSize.x); | |
let phi = Math.atan2(to.y - from.y, to.x - from.x); | |
let nearestPoint = {}; | |
if (Math.abs(phi) < theta) { // crosses +x | |
nearestPoint.x = from.x + boxSize.x / 2.0; | |
nearestPoint.y = from.y + ((to.x === from.x) ? from.y : | |
((to.y - from.y) / (to.x - from.x) * boxSize.x / 2.0)); | |
} else if (Math.PI - Math.abs(phi) < theta) { // crosses -x | |
nearestPoint.x = from.x - boxSize.x / 2.0; | |
nearestPoint.y = from.y + ((to.x === from.x) ? from.y : | |
(-(to.y - from.y) / (to.x - from.x) * boxSize.x / 2.0)); | |
} else if (to.y > from.y) { // crosses +y | |
nearestPoint.y = from.y + boxSize.y / 2.0; | |
nearestPoint.x = from.x + ((to.y === from.y) ? 0 : | |
((to.x - from.x) / (to.y - from.y) * boxSize.y / 2.0)); | |
} else { // crosses -y | |
nearestPoint.y = from.y - boxSize.y / 2.0; | |
nearestPoint.x = from.x - ((to.y === from.y) ? 0 : | |
((to.x - from.x) / (to.y - from.y) * boxSize.y / 2.0)); | |
} | |
return nearestPoint; | |
} | |
/** A Zerg turret */ | |
class ZergTurret { | |
/** | |
* Start the thing | |
* @param {Number} speed How fast the turret shoots | |
* @param {Object} turret x, y location of turret | |
*/ | |
constructor(speed, turret) { | |
this.speed = speed; | |
this.turret = turret; | |
this.elements = this.target(SELECTOR); | |
this.lineElem = null; | |
this.started = false; | |
} | |
/** Start targetting */ | |
start() { | |
if (this.started) return; | |
this.intervalHandler = () => { | |
let next = this.elements.next(); | |
if (next.done) return clearInterval(this.interval); | |
this.runTargeting(); | |
}; | |
this.interval = setInterval(this.intervalHandler, this.speed); | |
this.started = true; | |
} | |
/** Stop targetting */ | |
stop() { | |
if (!this.started) return; | |
clearInterval(this.interval); | |
if (this.lineElem) { | |
document.body.removeChild(this.lineElem); | |
this.lineElem = null; | |
} | |
this.started = false; | |
} | |
/** | |
* Iterate over elements until no more exist | |
*/ | |
* target() { | |
for (;;) { | |
let elements; | |
do { | |
elements = document.querySelectorAll(SELECTOR); | |
for (let element of elements) { | |
while (document.body.contains(element)) yield element; | |
} | |
} while (elements.length); | |
yield false; | |
} | |
} | |
/** | |
* Stolen from stackoverflow, draws lines | |
* @param {Object} toXY { x, y } | |
*/ | |
drawLine(toXY) { | |
if (!this.lineElem) { | |
this.lineElem = document.createElement('canvas'); | |
this.lineElem.style.position = 'absolute'; | |
this.lineElem.style.zIndex = 1000; | |
/* | |
let duration = (this.speed / 1000).toString() + 's'; | |
this.lineElem.style.transition = [ | |
'width', 'height', 'left', 'top' | |
].map(prop => `${prop} ${duration}`).join(', '); | |
*/ | |
document.body.appendChild(this.lineElem); | |
} | |
let leftpoint; | |
let rightpoint; | |
if (this.turret.x < toXY.x) { | |
leftpoint = this.turret; | |
rightpoint = toXY; | |
} else { | |
leftpoint = toXY; | |
rightpoint = this.turret; | |
} | |
let lineWidthPix = 4; | |
let gutterPix = 10; | |
let origin = { x: leftpoint.x - gutterPix, | |
y: Math.min(this.turret.y, toXY.y) - gutterPix }; | |
this.lineElem.width = Math.max(rightpoint.x - leftpoint.x, lineWidthPix) + | |
2.0 * gutterPix; | |
this.lineElem.height = Math.abs(this.turret.y - toXY.y) + 2.0 * gutterPix; | |
this.lineElem.style.left = origin.x + 'px'; | |
this.lineElem.style.top = origin.y + 'px'; | |
let ctx = this.lineElem.getContext('2d'); | |
// Use the identity matrix while clearing the canvas | |
ctx.save(); | |
ctx.setTransform(1, 0, 0, 1, 0, 0); | |
ctx.clearRect(0, 0, this.lineElem.width, this.lineElem.height); | |
ctx.restore(); | |
ctx.lineWidth = 7; | |
ctx.strokeStyle = '#09f'; | |
ctx.beginPath(); | |
ctx.moveTo(this.turret.x - origin.x, this.turret.y - origin.y); | |
ctx.lineTo(toXY.x - origin.x, toXY.y - origin.y); | |
ctx.stroke(); | |
} | |
/** | |
* Target and attack a zergling | |
* @param {Object} this.turret x, y of turret position | |
* @param {Element} zergling | |
*/ | |
runTargeting() { | |
let zergling = this.elements.next().value; | |
if (!zergling) return; | |
let bounds = zergling.getBoundingClientRect(); | |
let center = { | |
x: bounds.left + bounds.width / 2, | |
y: bounds.top + bounds.height / 2 | |
}; | |
let nearest = getNearestPointOutside(center, this.turret, { | |
x: bounds.width, | |
y: bounds.height | |
}); | |
this.drawLine(nearest); | |
triggerMouseEvent(zergling, 'mousedown'); | |
} | |
} | |
let turret = new ZergTurret(150, { x: 300, y: 300 }); | |
turret.start(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment