Created
January 22, 2015 18:22
-
-
Save chrahunt/954b0a4510df9fe71698 to your computer and use it in GitHub Desktop.
Show arrows indicating current velocity.
This file contains hidden or 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
// ==UserScript== | |
// @name Velocity Arrows | |
// @version 0.1.0 | |
// @description Shows an arrow indicating the player's current velocity. Example of a graphics object drawn static relative to the player. | |
// @include http://tagpro-*.koalabeast.com:* | |
// @include http://tangent.jukejuice.com:* | |
// @include http://*.newcompte.fr:* | |
// @author snaps | |
// ==/UserScript== | |
function scriptContent() { | |
var Point = function(x, y) { | |
this.x = x; | |
this.y = y; | |
} | |
Point.prototype.mul = function(f) { | |
return new Point(this.x * f, this.y * f); | |
} | |
Point.prototype.add = function(p) { | |
if (typeof p == "number") | |
return new Point(this.x + p, this.y + p); | |
return new Point(this.x + p.x, this.y + p.y); | |
} | |
Point.prototype.dot = function(p) { | |
return (this.x * p.x + this.y * p.y); | |
} | |
Point.prototype.sub = function(p) { | |
if (typeof p == "number") | |
return new Point(this.x - p, this.y - p); | |
return new Point(this.x - p.x, this.y - p.y); | |
} | |
Point.prototype.len = function() { | |
return this.dist(new Point(0, 0)); | |
} | |
Point.prototype.dist = function(p) { | |
var diff = this.sub(p); | |
return Math.sqrt(diff.dot(diff)); | |
} | |
Point.prototype.normalize = function() { | |
var n = this.dist(new Point(0, 0)); | |
if (n > 0) return this.div(n); | |
return new Point(0, 0); | |
} | |
Point.prototype.div = function(f) { | |
return new Point(this.x / f, this.y / f); | |
} | |
var DrawUtils = function() { | |
this.init(); | |
}; | |
// Initialize drawing functions. | |
DrawUtils.prototype.init = function() { | |
if (typeof tagpro.renderer == "undefined") { | |
console.log("Can't handle old canvas!"); | |
return; | |
} | |
// Store current player object. | |
this.self = tagpro.players[tagpro.playerId]; | |
// Store items to be drawn. | |
this.vectors = {}; | |
// Add vectors container to player sprites object, which is used for holding information about | |
this.self.sprites.vectors = new PIXI.Graphics(); | |
// sprite is the DisplayObjectContainer that holds items displayed in static positions relative to the character. | |
this.self.sprite.addChild(this.self.sprites.vectors); | |
// Center vectors on player (the default origin, (0, 0) is the top-left corner of the player sprite. | |
this.self.sprites.vectors.position.x = 20; | |
this.self.sprites.vectors.position.y = 20; | |
} | |
DrawUtils.prototype.hideVector = function(name) { | |
this.vectors[name].container.visible = false; | |
} | |
DrawUtils.prototype.showVector = function(name) { | |
this.vectors[name].container.visible = true; | |
} | |
/** | |
* Adds a vector to be drawn over the current player. | |
* @param {string} name - The name used to refer to the vector. | |
* @param {number} [color=0x000000] - The color used when drawing the | |
* vector. | |
*/ | |
DrawUtils.prototype.addVector = function(name, color) { | |
var vector = { | |
name: name, | |
container: new PIXI.Graphics(), | |
color: color || 0x000000 | |
} | |
this.vectors[name] = vector; | |
this.self.sprites.vectors.addChild(vector.container); | |
} | |
/** | |
* Updates the vector identified with `name` with the values from | |
* point `p`. | |
* @param {string} name - The name of the vector to update. | |
* @param {Point} p - The point to use to update the vector. | |
*/ | |
DrawUtils.prototype.updateVector = function(name, p) { | |
this.vectors[name].x = p.x; | |
this.vectors[name].y = p.y; | |
this._drawVector(this.vectors[name]); | |
} | |
/** | |
* Represents a 2d vector emanating from the center of the player, | |
* along with attributes for drawing. | |
* @typedef VectorInfo | |
* @type {object} | |
* @property {string} name - An identifier for the vector (unique | |
* relative to the other vectors.) | |
* @property {PIXI.Graphics} container - The graphics container to | |
* draw the vector on. | |
* @property {integer} color - Number representing color to use (e.g. | |
* 0x000000.) | |
* @property {?number} [x] - Number representing the x coordinate of | |
* the vector, relative to the center of the player. | |
* @property {?number} [y] - Number representing the y coordinate of | |
* the vector, relative to the center of the player. | |
*/ | |
/** | |
* Draw a vector as a small arrow based at the center of the current | |
* player. | |
* @private | |
* @param {VectorInfo} vector | |
*/ | |
DrawUtils.prototype._drawVector = function(vector) { | |
var v = new Point(vector.x, vector.y); | |
if (v.len() < 2) { | |
this.hideVector(vector.name); | |
return; | |
} else { | |
this.showVector(vector.name); | |
var v_n = v.normalize(); | |
} | |
var vectorWidth = 4; | |
// For arrowhead. | |
var vectorAngle = Math.atan2(v.y, v.x); | |
var headAngle = Math.PI / 6; | |
var headLength = 10; | |
var leftHead = (new Point( | |
Math.cos((Math.PI - headAngle + vectorAngle) % (2 * Math.PI)), | |
Math.sin((Math.PI - headAngle + vectorAngle) % (2 * Math.PI)))); | |
leftHead = leftHead.mul(headLength).add(v); | |
var rightHead = (new Point( | |
Math.cos((Math.PI + headAngle + vectorAngle) % (2 * Math.PI)), | |
Math.sin((Math.PI + headAngle + vectorAngle) % (2 * Math.PI)))); | |
rightHead = rightHead.mul(headLength).add(v); | |
// For fat vector body. | |
var leftBase = (new Point( | |
Math.cos((Math.PI / 2 + vectorAngle) % (2 * Math.PI)), | |
Math.sin((Math.PI / 2 + vectorAngle) % (2 * Math.PI)))); | |
var rightBase = leftBase.mul(-1); | |
leftBase = leftBase.mul(vectorWidth / 2); | |
rightBase = rightBase.mul(vectorWidth / 2); | |
var end = v_n.mul(v_n.dot(leftHead)); | |
var leftTop = leftBase.add(end); | |
var rightTop = rightBase.add(end); | |
// Add shapes to container. | |
var c = vector.container; | |
c.clear(); | |
c.lineStyle(2, 0x000000, 1); | |
c.beginFill(vector.color, 1); | |
c.moveTo(leftBase.x, leftBase.y); | |
c.lineTo(leftTop.x, leftTop.y); | |
c.lineTo(leftHead.x, leftHead.y); | |
c.lineTo(v.x, v.y); | |
c.lineTo(rightHead.x, rightHead.y); | |
c.lineTo(rightTop.x, rightTop.y); | |
c.lineTo(rightBase.x, rightBase.y); | |
var v_n_l = v_n.mul(vectorWidth / 2); | |
var cp1 = rightBase.sub(v_n_l); | |
var cp2 = leftBase.sub(v_n_l); | |
c.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, leftBase.x, leftBase.y); | |
c.endFill(); | |
} | |
var updateVelocity = function(player, predicted, lastSync) { | |
function clamp(num, low, high) { | |
if (num < low) | |
return low; | |
if (num > high) | |
return high; | |
return num; | |
} | |
var dt = (1 / 60); | |
var damping = 0.5; | |
if (player.lastSync.lx > lastSync.lx) { | |
if (window.showDiff && player.lx !== 0 && predicted.lx !== 0) { | |
console.log(predicted.lx + "\t" + player.lx); | |
} | |
if (window.showSync && player.lx !== 0 && predicted.lx !== 0) { | |
console.log(lastSync.local_lx + "\t" + player.lastSync.lx); | |
} | |
predicted.lx = player.lx; | |
lastSync.lx = player.lastSync.lx; | |
lastSync.local_lx = lastSync.lx; | |
} | |
if (Math.abs(predicted.lx) < player.ms) { | |
if (player.right) { | |
predicted.lx += player.ac; | |
} else if (player.left) { | |
predicted.lx -= player.ac; | |
} | |
// Reduce velocity due to linear damping. | |
predicted.lx *= clamp((1 - dt * damping), 0, 1); | |
} | |
lastSync.local_lx++; | |
if (player.lastSync.ly > lastSync.ly) { | |
if (window.showDiff && player.ly !== 0 && predicted.ly !== 0) { | |
console.log(predicted.ly + "\t" + player.ly); | |
} | |
if (window.showSync && player.ly !== 0 && predicted.ly !== 0) { | |
console.log(lastSync.local_ly + "\t" + player.lastSync.ly); | |
} | |
predicted.ly = player.ly; | |
lastSync.ly = player.lastSync.ly; | |
lastSync.local_ly = lastSync.ly; | |
} | |
if (Math.abs(predicted.ly) < player.ms) { | |
if (player.down) { | |
predicted.ly += player.ac; | |
} else if (player.up) { | |
predicted.ly -= player.ac; | |
} | |
// Reduce velocity due to linear damping. | |
predicted.lx *= clamp((1 - dt * damping), 0, 1); | |
} | |
lastSync.local_ly++; | |
} | |
tagpro.ready(function() { | |
function waitUntilPlayerSprites(callback) { | |
if (!tagpro.players[tagpro.playerId] || !tagpro.players[tagpro.playerId].sprite || !tagpro.players[tagpro.playerId].sprites) { | |
setTimeout(function() { | |
waitUntilPlayerSprites(callback); | |
}, 250); | |
} else { | |
callback(); | |
} | |
} | |
function setup() { | |
var color = 0x00aa00; | |
var drawutils = new DrawUtils(); | |
drawutils.addVector("velocity", color); | |
var self = tagpro.players[tagpro.playerId]; | |
var predicted = { | |
lx: self.lx, | |
ly: self.ly | |
}; | |
var sync = { | |
lx: self.lastSync.lx, | |
ly: self.lastSync.ly, | |
local_lx: self.lastSync.lx, | |
local_ly: self.lastSync.ly | |
}; | |
setInterval(function() { | |
updateVelocity(self, predicted, sync); | |
var velocity = new Point(predicted.lx, predicted.ly); | |
drawutils.updateVector("velocity", velocity.mul(50)); | |
}, 1e3 / 60); | |
} | |
waitUntilPlayerSprites(setup); | |
}); | |
} | |
function inject(source) { | |
source = '(' + source + ')();' | |
// Create a script node holding this source code. | |
var script = document.createElement('script'); | |
script.setAttribute("type", "application/javascript"); | |
script.textContent = source; | |
// Insert the script node into the page, so it will run, and immediately | |
// remove it to clean up. | |
document.body.appendChild(script); | |
document.body.removeChild(script); | |
} | |
inject(scriptContent); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment