Skip to content

Instantly share code, notes, and snippets.

@Cazra
Last active August 29, 2015 14:13
Show Gist options
  • Save Cazra/348653571dffc16e87b9 to your computer and use it in GitHub Desktop.
Save Cazra/348653571dffc16e87b9 to your computer and use it in GitHub Desktop.
Roll20 Token Collisions
/**
* A small library for testing collisions between moving tokens in Roll20.
*
* Requires:
* Vector Math https://gist.github.com/Cazra/348653571dffc16e87b9
*/
var TokenCollisions = (function() {
/**
* Returns the first token, from some list of tokens, that a token has
* collided with during its last movement.
* @param {Graphic} token The token that moved
* @param {Graphic[]} otherTokens The list of tokens we are testing collisions with.
* @return {Graphic || false} If the token collided with another token, the first token that
* it would collide with during its movement is returned. Otherwise it returns false.
*/
var getFirstCollision = function(token, otherTokens) {
// Get all the points for the movement.
var movePts = _getAllPointsDuringMovement(token);
// Check each segment of movement to see if we triggered a trap.
for(var i = 0; i < movePts.length-1; i++) {
var p1 = movePts[i];
var p2 = movePts[i+1];
// If we encountered a trap, we're done.
var collidedToken = _getFirstCollisionInWaypoint(token, otherTokens, p1, p2);
if(collidedToken) {
return collidedToken;
}
}
return false
};
/**
* Returns the list of tokens, from some list of tokens, that a token has
* collided with during its last movement.
* @param {Graphic} token The token that moved
* @param {Graphic[]} otherTokens The tokens we're checking collisions with.
* @return {Graphic[]}
*/
var getCollisions = function(token, otherTokens) {
// Get all the points for the movement.
var movePts = _getAllPointsDuringMovement(token);
var collisions = [];
// Check each segment of movement to see if we triggered a trap.
for(var i = 0; i < movePts.length-1; i++) {
var p1 = movePts[i];
var p2 = movePts[i+1];
// If we encountered a trap, we're done.
var newCollisions = _getCollisionsInWaypoint(token, otherTokens, p1, p2);
collisions = collisions.concat(newCollisions);
}
return collisions
};
/**
* @private
* Gets the list of all points traversed during a token's movement, including
* its current position at the end of the movement.
* @param {Graphic} token
* @return {vec2[]}
*/
var _getAllPointsDuringMovement = function(token) {
var results = [];
var moveCoords = token.get("lastmove").split(",");
for(var i=0; i < moveCoords.length; i++) {
moveCoords[i] = parseInt(moveCoords[i]);
}
moveCoords.push(parseInt(token.get("left")));
moveCoords.push(parseInt(token.get("top")));
for(var i=0; i <= moveCoords.length - 2; i+=2) {
var x = moveCoords[i];
var y = moveCoords[i+1];
results.push([x, y]);
}
return results;
};
/**
* @private
* Checks if a token collided with another token during its movement between two points.
* @param {Graphic} token
* @param {vec2} startPt
* @param {vec2} endPt
* @return {Graphic || false} The first other token that token collided with in its movement. If there was no collision, return false.
*/
var _getFirstCollisionInWaypoint = function(token, otherTokens, startPt, endPt) {
var collisions = _getCollisionsInWaypoint(token, otherTokens, startPt, endPt);
if(collisions.length > 0) {
return _getNearestTokenToPoint(startPt, collisions);
}
else {
return false;
}
};
/**
* @private
* For some token, this gets the list of tokens it collided with during its
* movement between two points, from some list of other tokens.
* @param {Graphic} token
* @param {Graphic[]} otherTokens
* @param {vec2} startPt
* @param {vec2} endPt
* @return {Graphic[]}
*/
var _getCollisionsInWaypoint = function(token, otherTokens, startPt, endPt) {
var result = [];
for(var i in otherTokens) {
var other = otherTokens[i];
if(_checkCollisionInWaypoint(token, other, startPt, endPt)) {
result.push(other);
}
}
return result;
};
/**
* @private
* Checks if a token collides with the other token during its movement between
* two points.
* @param {Graphic} token The moving token
* @param {Graphic} other
* @param {vec2} startPt
* @param {vec2} endPt
* @return {Boolean} true iff there was a collision.
*/
var _checkCollisionInWaypoint = function(token, other, startPt, endPt) {
var otherPt = _getTokenPt(other);
// We assume that all tokens are circular, therefore width = diameter.
var thresholdDist = (parseInt(other.get("width")) + parseInt(token.get("width")))/2;
// Don't count the other token if our movement already started in it.
if(Math.round(vecLength(vec(startPt, otherPt))) >= thresholdDist) {
// Figure out the closest distance we came to the other token during
// the movement.
var dist = Math.round(ptSegDist(otherPt, startPt, endPt));
if(dist < thresholdDist) {
return true;
}
}
return false;
};
/**
* @private
* Returns the token nearest to the specified point
* out of some list of tokens.
* @param {vec2} pt
* @param {Graphic[]} tokens
* @return {Graphic}
*/
var _getNearestTokenToPoint = function(pt, tokens) {
var result = null;
var bestDist = -1;
for(var i in tokens) {
var token = tokens[i];
var tokenPt = _getTokenPt(token);
var dist = vecLength(vec(pt, tokenPt));
if(bestDist === -1 || dist < bestDist) {
result = token;
bestDist = dist;
}
}
return result;
};
/**
* @private
* Gets the position of a token.
* @param {Graphic} token
* @return {vec2}
*/
var _getTokenPt = function(token) {
var x = token.get("left");
var y = token.get("top");
return [x, y];
};
return {
getFirstCollision: getFirstCollision,
getCollisions: getCollisions
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment