1
0
Fork 0
spacetac/src/game/Target.ts

105 lines
3.8 KiB
TypeScript

/// <reference path="Serializable.ts"/>
module TS.SpaceTac.Game {
// Find the nearest intersection between a line and a circle
// Circle is supposed to be centered at (0,0)
// Nearest intersection to (x1,y1) is returned
function intersectLineCircle(x1: number, y1: number, x2: number, y2: number, r: number): [number, number] {
// See http://mathworld.wolfram.com/Circle-LineIntersection.html
var dx = x2 - x1;
var dy = y2 - y1;
var dr = Math.sqrt(dx * dx + dy * dy);
var d = x1 * y2 - x2 * y1;
var delta = r * r * dr * dr - d * d;
var rx = (d * dy - dx * Math.sqrt(delta)) / (dr * dr);
var ry = (-d * dx - dy * Math.sqrt(delta)) / (dr * dr);
return [rx, ry];
}
// Target for a capability
// This could be a location in space, or a ship
export class Target extends Serializable {
// Coordinates of the target
x: number;
y: number;
// If the target is a ship, this attribute will be set
ship: Ship;
// Standard constructor
constructor(x: number, y: number, ship: Ship) {
super();
this.x = x;
this.y = y;
this.ship = ship;
}
// Constructor to target a single ship
static newFromShip(ship: Ship): Target {
return new Target(ship.arena_x, ship.arena_y, ship);
}
// Constructor to target a location in space
static newFromLocation(x: number, y: number): Target {
return new Target(x, y, null);
}
// Get distance to another target
getDistanceTo(other: Target): number {
var dx = other.x - this.x;
var dy = other.y - this.y;
return Math.sqrt(dx * dx + dy * dy);
}
// Get the normalized angle, in radians, to another target
getAngleTo(other: Target): number {
var dx = other.x - this.x;
var dy = other.y - this.y;
return Math.atan2(dy, dx);
}
// Check if a target is in range from a specific point
isInRange(x: number, y: number, radius: number): boolean {
var dx = this.x - x;
var dy = this.y - y;
var length = Math.sqrt(dx * dx + dy * dy);
return (length <= radius);
}
// Constraint a target, to be in a given range from a specific point
// May return the original target if it's already in radius
constraintInRange(x: number, y: number, radius: number): Target {
var dx = this.x - x;
var dy = this.y - y;
var length = Math.sqrt(dx * dx + dy * dy);
if (length <= radius) {
return this;
} else {
var factor = radius / length;
return Target.newFromLocation(x + dx * factor, y + dy * factor);
}
}
// Force a target to stay out of a given circle
// If the target is in the circle, it will be moved to the nearest intersection between targetting line
// and the circle
// May return the original target if it's already out of the circle
moveOutOfCircle(circlex: number, circley: number, radius: number, sourcex: number, sourcey: number): Target {
var dx = this.x - circlex;
var dy = this.y - circley;
var length = Math.sqrt(dx * dx + dy * dy);
if (length >= radius) {
// Already out of circle
return this;
} else {
// Find nearest intersection with circle
var res = intersectLineCircle(sourcex - circlex, sourcey - circley,
this.x - circlex, this.y - circley, radius);
return Target.newFromLocation(res[0] + circlex, res[1] + circley);
}
}
}
}