新增raycast射线

This commit is contained in:
yhh
2020-07-31 17:17:44 +08:00
parent 514572f291
commit 40fe7a57db
13 changed files with 1182 additions and 813 deletions

View File

@@ -130,7 +130,7 @@ declare module es {
divide(value: Vector2): Vector2;
multiply(value: Vector2): Vector2;
subtract(value: Vector2): this;
normalize(): void;
normalize(): this;
length(): number;
round(): Vector2;
equals(other: Vector2): boolean;
@@ -1206,6 +1206,7 @@ declare module es {
static rectEncompassingPoints(points: Vector2[]): Rectangle;
intersects(value: egret.Rectangle): boolean;
containsRect(value: Rectangle): boolean;
contains(x: number, y: number): boolean;
getHalfSize(): Vector2;
getClosestPointOnRectangleBorderToPoint(point: Vector2, edgeNormal: Vector2): Vector2;
getClosestPointOnBoundsToOrigin(): Vector2;
@@ -1273,6 +1274,20 @@ declare module es {
static debugDraw(secondsToDisplay: any): void;
}
}
declare module es {
class RaycastHit {
collider: Collider;
fraction: number;
distance: number;
point: Vector2;
normal: Vector2;
centroid: Vector2;
constructor(collider: Collider, fraction: number, distance: number, point: Vector2, normal: Vector2);
setValues(collider: Collider, fraction: number, distance: number, point: Vector2): void;
reset(): void;
toString(): string;
}
}
declare module es {
abstract class Shape {
position: Vector2;
@@ -1296,13 +1311,15 @@ declare module es {
constructor(points: Vector2[], isBox?: boolean);
_edgeNormals: Vector2[];
readonly edgeNormals: Vector2[];
static buildSymmetricalPolygon(vertCount: number, radius: number): any[];
static recenterPolygonVerts(points: Vector2[]): void;
static findPolygonCenter(points: Vector2[]): Vector2;
static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2, distanceSquared: number, edgeNormal: Vector2): Vector2;
setPoints(points: Vector2[]): void;
recalculateCenterAndEdgeNormals(): void;
buildEdgeNormals(): void;
static buildSymmetricalPolygon(vertCount: number, radius: number): any[];
static recenterPolygonVerts(points: Vector2[]): void;
static findPolygonCenter(points: Vector2[]): Vector2;
static getFarthestPointInDirection(points: Vector2[], direction: Vector2): Vector2;
static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2, distanceSquared: number, edgeNormal: Vector2): Vector2;
static rotatePolygonVerts(radians: number, originalPoints: Vector2[], rotatedPoints: any): void;
recalculateBounds(collider: Collider): void;
overlaps(other: Shape): any;
collidesWithShape(other: Shape, result: CollisionResult): boolean;
@@ -1320,6 +1337,7 @@ declare module es {
overlaps(other: Shape): any;
collidesWithShape(other: Shape, result: CollisionResult): boolean;
containsPoint(point: Vector2): boolean;
pointCollidesWithShape(point: es.Vector2, result: es.CollisionResult): boolean;
}
}
declare module es {
@@ -1336,10 +1354,12 @@ declare module es {
declare module es {
class CollisionResult {
collider: Collider;
minimumTranslationVector: Vector2;
normal: Vector2;
minimumTranslationVector: Vector2;
point: Vector2;
invertResult(): void;
removeHorizontal(deltaMovement: Vector2): void;
invertResult(): this;
toString(): string;
}
}
declare module es {
@@ -1353,6 +1373,7 @@ declare module es {
static circleToPolygon(circle: Circle, polygon: Polygon, result: CollisionResult): boolean;
static circleToBox(circle: Circle, box: Box, result: CollisionResult): boolean;
static pointToCircle(point: Vector2, circle: Circle, result: CollisionResult): boolean;
static pointToBox(point: Vector2, box: Box, result: CollisionResult): boolean;
static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2): Vector2;
static pointToPoly(point: Vector2, poly: Polygon, result: CollisionResult): boolean;
static circleToCircle(first: Circle, second: Circle, result: CollisionResult): boolean;

View File

@@ -744,6 +744,7 @@ var es;
var val = 1 / Math.sqrt((this.x * this.x) + (this.y * this.y));
this.x *= val;
this.y *= val;
return this;
};
Vector2.prototype.length = function () {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
@@ -5639,6 +5640,9 @@ var es;
(this.y <= value.y)) &&
(value.y < (this.y + this.height)));
};
Rectangle.prototype.contains = function (x, y) {
return ((((this.x <= x) && (x < (this.x + this.width))) && (this.y <= y)) && (y < (this.y + this.height)));
};
Rectangle.prototype.getHalfSize = function () {
return new es.Vector2(this.width * 0.5, this.height * 0.5);
};
@@ -6024,6 +6028,37 @@ var es;
es.Physics = Physics;
})(es || (es = {}));
var es;
(function (es) {
var RaycastHit = (function () {
function RaycastHit(collider, fraction, distance, point, normal) {
this.fraction = 0;
this.distance = 0;
this.point = es.Vector2.zero;
this.normal = es.Vector2.zero;
this.collider = collider;
this.fraction = fraction;
this.distance = distance;
this.point = point;
this.centroid = es.Vector2.zero;
}
RaycastHit.prototype.setValues = function (collider, fraction, distance, point) {
this.collider = collider;
this.fraction = fraction;
this.distance = distance;
this.point = point;
};
RaycastHit.prototype.reset = function () {
this.collider = null;
this.fraction = this.distance = 0;
};
RaycastHit.prototype.toString = function () {
return "[RaycastHit] fraction: " + this.fraction + ", distance: " + this.distance + ", normal: " + this.normal + ", centroid: " + this.centroid + ", point: " + this.point;
};
return RaycastHit;
}());
es.RaycastHit = RaycastHit;
})(es || (es = {}));
var es;
(function (es) {
var Shape = (function () {
function Shape() {
@@ -6056,48 +6091,6 @@ var es;
enumerable: true,
configurable: true
});
Polygon.buildSymmetricalPolygon = function (vertCount, radius) {
var verts = new Array(vertCount);
for (var i = 0; i < vertCount; i++) {
var a = 2 * Math.PI * (i / vertCount);
verts[i] = new es.Vector2(Math.cos(a), Math.sin(a) * radius);
}
return verts;
};
Polygon.recenterPolygonVerts = function (points) {
var center = this.findPolygonCenter(points);
for (var i = 0; i < points.length; i++)
points[i] = es.Vector2.subtract(points[i], center);
};
Polygon.findPolygonCenter = function (points) {
var x = 0, y = 0;
for (var i = 0; i < points.length; i++) {
x += points[i].x;
y += points[i].y;
}
return new es.Vector2(x / points.length, y / points.length);
};
Polygon.getClosestPointOnPolygonToPoint = function (points, point, distanceSquared, edgeNormal) {
distanceSquared = Number.MAX_VALUE;
edgeNormal = new es.Vector2(0, 0);
var closestPoint = new es.Vector2(0, 0);
var tempDistanceSquared;
for (var i = 0; i < points.length; i++) {
var j = i + 1;
if (j == points.length)
j = 0;
var closest = es.ShapeCollisions.closestPointOnLine(points[i], points[j], point);
tempDistanceSquared = es.Vector2.distanceSquared(point, closest);
if (tempDistanceSquared < distanceSquared) {
distanceSquared = tempDistanceSquared;
closestPoint = closest;
var line = es.Vector2.subtract(points[j], points[i]);
edgeNormal = new es.Vector2(-line.y, line.x);
}
}
edgeNormal = es.Vector2Ext.normalize(edgeNormal);
return closestPoint;
};
Polygon.prototype.setPoints = function (points) {
this.points = points;
this.recalculateCenterAndEdgeNormals();
@@ -6126,6 +6119,68 @@ var es;
this._edgeNormals[i] = perp;
}
};
Polygon.buildSymmetricalPolygon = function (vertCount, radius) {
var verts = new Array(vertCount);
for (var i = 0; i < vertCount; i++) {
var a = 2 * Math.PI * (i / vertCount);
verts[i] = es.Vector2.multiply(new es.Vector2(Math.cos(a), Math.sin(a)), new es.Vector2(radius));
}
return verts;
};
Polygon.recenterPolygonVerts = function (points) {
var center = this.findPolygonCenter(points);
for (var i = 0; i < points.length; i++)
points[i] = es.Vector2.subtract(points[i], center);
};
Polygon.findPolygonCenter = function (points) {
var x = 0, y = 0;
for (var i = 0; i < points.length; i++) {
x += points[i].x;
y += points[i].y;
}
return new es.Vector2(x / points.length, y / points.length);
};
Polygon.getFarthestPointInDirection = function (points, direction) {
var index = 0;
var maxDot = es.Vector2.dot(points[index], direction);
for (var i = 1; i < points.length; i++) {
var dot = es.Vector2.dot(points[i], direction);
if (dot > maxDot) {
maxDot = dot;
index = i;
}
}
return points[index];
};
Polygon.getClosestPointOnPolygonToPoint = function (points, point, distanceSquared, edgeNormal) {
distanceSquared = Number.MAX_VALUE;
edgeNormal = new es.Vector2(0, 0);
var closestPoint = new es.Vector2(0, 0);
var tempDistanceSquared;
for (var i = 0; i < points.length; i++) {
var j = i + 1;
if (j == points.length)
j = 0;
var closest = es.ShapeCollisions.closestPointOnLine(points[i], points[j], point);
tempDistanceSquared = es.Vector2.distanceSquared(point, closest);
if (tempDistanceSquared < distanceSquared) {
distanceSquared = tempDistanceSquared;
closestPoint = closest;
var line = es.Vector2.subtract(points[j], points[i]);
edgeNormal = new es.Vector2(-line.y, line.x);
}
}
es.Vector2Ext.normalize(edgeNormal);
return closestPoint;
};
Polygon.rotatePolygonVerts = function (radians, originalPoints, rotatedPoints) {
var cos = Math.cos(radians);
var sin = Math.sign(radians);
for (var i = 0; i < originalPoints.length; i++) {
var position = originalPoints[i];
rotatedPoints[i] = new es.Vector2(position.x * cos + position.y * -sin, position.x * sin + position.y * cos);
}
};
Polygon.prototype.recalculateBounds = function (collider) {
this.center = collider.localOffset;
if (collider.shouldColliderScaleAndRotateWithTransform) {
@@ -6236,7 +6291,7 @@ var es;
};
Box.prototype.overlaps = function (other) {
if (this.isUnrotated) {
if (other instanceof Box)
if (other instanceof Box && other.isUnrotated)
return this.bounds.intersects(other.bounds);
if (other instanceof es.Circle)
return es.Collisions.isRectToCircle(this.bounds, other.position, other.radius);
@@ -6254,6 +6309,11 @@ var es;
return this.bounds.contains(point.x, point.y);
return _super.prototype.containsPoint.call(this, point);
};
Box.prototype.pointCollidesWithShape = function (point, result) {
if (this.isUnrotated)
return es.ShapeCollisions.pointToBox(point, this, result);
return _super.prototype.pointCollidesWithShape.call(this, point, result);
};
return Box;
}(es.Polygon));
es.Box = Box;
@@ -6317,13 +6377,26 @@ var es;
(function (es) {
var CollisionResult = (function () {
function CollisionResult() {
this.minimumTranslationVector = es.Vector2.zero;
this.normal = es.Vector2.zero;
this.minimumTranslationVector = es.Vector2.zero;
this.point = es.Vector2.zero;
}
CollisionResult.prototype.removeHorizontal = function (deltaMovement) {
if (Math.sign(this.normal.x) != Math.sign(deltaMovement.x) || (deltaMovement.x == 0 && this.normal.x != 0)) {
var responseDistance = this.minimumTranslationVector.length();
var fix = responseDistance / this.normal.y;
if (Math.abs(this.normal.x) != 1 && Math.abs(fix) < Math.abs(deltaMovement.y * 3)) {
this.minimumTranslationVector = new es.Vector2(0, -fix);
}
}
};
CollisionResult.prototype.invertResult = function () {
this.minimumTranslationVector = es.Vector2.negate(this.minimumTranslationVector);
this.normal = es.Vector2.negate(this.normal);
return this;
};
CollisionResult.prototype.toString = function () {
return "[CollisionResult] normal: " + this.normal + ", minimumTranslationVector: " + this.minimumTranslationVector;
};
return CollisionResult;
}());
@@ -6458,6 +6531,14 @@ var es;
}
return false;
};
ShapeCollisions.pointToBox = function (point, box, result) {
if (box.containsPoint(point)) {
result.point = box.bounds.getClosestPointOnRectangleBorderToPoint(point, result.normal);
result.minimumTranslationVector = es.Vector2.subtract(point, result.point);
return true;
}
return false;
};
ShapeCollisions.closestPointOnLine = function (lineA, lineB, closestTo) {
var v = es.Vector2.subtract(lineB, lineA);
var w = es.Vector2.subtract(closestTo, lineA);
@@ -6495,7 +6576,7 @@ var es;
if (result.minimumTranslationVector.equals(es.Vector2.zero))
return false;
result.normal = new es.Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
result.normal = result.normal.normalize();
return true;
}
return false;

File diff suppressed because one or more lines are too long

View File

@@ -71,7 +71,7 @@ module es {
}
/**
* 是否与另一个矩形相交
* 如果其他相交矩形返回true
* @param value
*/
public intersects(value: egret.Rectangle) {
@@ -91,6 +91,10 @@ module es {
(value.y < (this.y + this.height)));
}
public contains(x: number, y: number): boolean{
return ((((this.x <= x) && (x < (this.x + this.width))) && (this.y <= y)) && (y < (this.y + this.height)));
}
public getHalfSize() {
return new Vector2(this.width * 0.5, this.height * 0.5);
}

View File

@@ -211,6 +211,7 @@ module es {
let val = 1 / Math.sqrt((this.x * this.x) + (this.y * this.y));
this.x *= val;
this.y *= val;
return this;
}
/** 返回它的长度 */

View File

@@ -0,0 +1,57 @@
module es {
export class RaycastHit {
/**
* 对撞机被射线击中
*/
public collider: Collider;
/**
* 撞击发生时沿射线的距离。
*/
public fraction: number = 0;
/**
* 从射线原点到碰撞点的距离
*/
public distance: number = 0;
/**
* 世界空间中光线击中对撞机表面的点
*/
public point: Vector2 = Vector2.zero;
/**
* 被射线击中的表面的法向量
*/
public normal: Vector2 = Vector2.zero;
/**
* 用于执行转换的质心。使其接触的形状的位置。
*/
public centroid: Vector2;
constructor(collider: Collider, fraction: number, distance: number, point: Vector2, normal: Vector2){
this.collider = collider;
this.fraction = fraction;
this.distance = distance;
this.point = point;
this.centroid = Vector2.zero;
}
public setValues(collider: Collider, fraction: number, distance: number, point: Vector2){
this.collider = collider;
this.fraction = fraction;
this.distance = distance;
this.point = point;
}
public reset(){
this.collider = null;
this.fraction = this.distance = 0;
}
public toString(){
return `[RaycastHit] fraction: ${this.fraction}, distance: ${this.distance}, normal: ${this.normal}, centroid: ${this.centroid}, point: ${this.point}`;
}
}
}

View File

@@ -56,7 +56,7 @@ module es {
public overlaps(other: Shape) {
// 特殊情况这一个高性能方式实现其他情况则使用polygon方法检测
if (this.isUnrotated) {
if (other instanceof Box)
if (other instanceof Box && other.isUnrotated)
return this.bounds.intersects(other.bounds);
if (other instanceof Circle)
@@ -83,5 +83,12 @@ module es {
return super.containsPoint(point);
}
public pointCollidesWithShape(point: es.Vector2, result: es.CollisionResult): boolean {
if (this.isUnrotated)
return ShapeCollisions.pointToBox(point, this, result);
return super.pointCollidesWithShape(point, result);
}
}
}

View File

@@ -1,13 +1,47 @@
module es {
export class CollisionResult {
/**
* 与之相撞的对撞机
*/
public collider: Collider;
public minimumTranslationVector: Vector2 = Vector2.zero;
/**
* 被形状击中的表面的法向量
*/
public normal: Vector2 = Vector2.zero;
/**
* 应用于第一个形状以推入形状的转换
*/
public minimumTranslationVector: Vector2 = Vector2.zero;
/**
* 不是所有冲突类型都使用!在依赖这个字段之前请检查ShapeCollisions切割类!
*/
public point: Vector2 = Vector2.zero;
/**
* 改变最小平移向量如果没有相同方向上的运动它将移除平移的x分量。
* @param deltaMovement
*/
public removeHorizontal(deltaMovement: Vector2){
// 检查是否需要横向移动,如果需要,移除并固定响应
if (Math.sign(this.normal.x) != Math.sign(deltaMovement.x) || (deltaMovement.x == 0 && this.normal.x != 0)){
let responseDistance = this.minimumTranslationVector.length();
let fix = responseDistance / this.normal.y;
// 检查一些边界情况。因为我们除以法线 使得x == 1和一个非常小的y这将导致一个巨大的固定值
if (Math.abs(this.normal.x) != 1 && Math.abs(fix) < Math.abs(deltaMovement.y * 3)){
this.minimumTranslationVector = new Vector2(0, -fix);
}
}
}
public invertResult() {
this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector);
this.normal = Vector2.negate(this.normal);
return this;
}
public toString(){
return `[CollisionResult] normal: ${this.normal}, minimumTranslationVector: ${this.minimumTranslationVector}`;
}
}
}

View File

@@ -46,85 +46,6 @@ module es {
return this._edgeNormals;
}
/**
* 建立一个对称的多边形(六边形八角形n角形)并返回点
* @param vertCount
* @param radius
*/
public static buildSymmetricalPolygon(vertCount: number, radius: number) {
let verts = new Array(vertCount);
for (let i = 0; i < vertCount; i++) {
let a = 2 * Math.PI * (i / vertCount);
verts[i] = new Vector2(Math.cos(a), Math.sin(a) * radius);
}
return verts;
}
/**
* 重定位多边形的点
* @param points
*/
public static recenterPolygonVerts(points: Vector2[]) {
let center = this.findPolygonCenter(points);
for (let i = 0; i < points.length; i++)
points[i] = Vector2.subtract(points[i], center);
}
/**
* 找到多边形的中心。注意,这对于正则多边形是准确的。不规则多边形没有中心。
* @param points
*/
public static findPolygonCenter(points: Vector2[]) {
let x = 0, y = 0;
for (let i = 0; i < points.length; i++) {
x += points[i].x;
y += points[i].y;
}
return new Vector2(x / points.length, y / points.length);
}
/**
* 迭代多边形的所有边,并得到任意边上离点最近的点。
* 通过最近点的平方距离和它所在的边的法线返回。
* 点应该在多边形的空间中(点-多边形.位置)
* @param points
* @param point
* @param distanceSquared
* @param edgeNormal
*/
public static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2, distanceSquared: number, edgeNormal: Vector2): Vector2 {
distanceSquared = Number.MAX_VALUE;
edgeNormal = new Vector2(0, 0);
let closestPoint = new Vector2(0, 0);
let tempDistanceSquared;
for (let i = 0; i < points.length; i++) {
let j = i + 1;
if (j == points.length)
j = 0;
let closest = ShapeCollisions.closestPointOnLine(points[i], points[j], point);
tempDistanceSquared = Vector2.distanceSquared(point, closest);
if (tempDistanceSquared < distanceSquared) {
distanceSquared = tempDistanceSquared;
closestPoint = closest;
// 求直线的法线
let line = Vector2.subtract(points[j], points[i]);
edgeNormal = new Vector2(-line.y, line.x);
}
}
edgeNormal = Vector2Ext.normalize(edgeNormal);
return closestPoint;
}
/**
* 重置点并重新计算中心和边缘法线
* @param points
@@ -172,6 +93,121 @@ module es {
}
}
/**
* 建立一个对称的多边形(六边形八角形n角形)并返回点
* @param vertCount
* @param radius
*/
public static buildSymmetricalPolygon(vertCount: number, radius: number) {
let verts = new Array(vertCount);
for (let i = 0; i < vertCount; i++) {
let a = 2 * Math.PI * (i / vertCount);
verts[i] = Vector2.multiply(new Vector2(Math.cos(a), Math.sin(a)), new Vector2(radius));
}
return verts;
}
/**
* 重定位多边形的点
* @param points
*/
public static recenterPolygonVerts(points: Vector2[]) {
let center = this.findPolygonCenter(points);
for (let i = 0; i < points.length; i++)
points[i] = Vector2.subtract(points[i], center);
}
/**
* 找到多边形的中心。注意,这对于正则多边形是准确的。不规则多边形没有中心。
* @param points
*/
public static findPolygonCenter(points: Vector2[]) {
let x = 0, y = 0;
for (let i = 0; i < points.length; i++) {
x += points[i].x;
y += points[i].y;
}
return new Vector2(x / points.length, y / points.length);
}
/**
* 不知道辅助顶点所以取每个顶点如果你知道辅助顶点执行climbing算法
* @param points
* @param direction
*/
public static getFarthestPointInDirection(points: Vector2[], direction: Vector2): Vector2{
let index = 0;
let maxDot = Vector2.dot(points[index], direction);
for (let i = 1; i < points.length; i ++){
let dot = Vector2.dot(points[i], direction);
if (dot > maxDot){
maxDot = dot;
index = i;
}
}
return points[index];
}
/**
* 迭代多边形的所有边,并得到任意边上离点最近的点。
* 通过最近点的平方距离和它所在的边的法线返回。
* 点应该在多边形的空间中(点-多边形.位置)
* @param points
* @param point
* @param distanceSquared
* @param edgeNormal
*/
public static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2, distanceSquared: number, edgeNormal: Vector2): Vector2 {
distanceSquared = Number.MAX_VALUE;
edgeNormal = new Vector2(0, 0);
let closestPoint = new Vector2(0, 0);
let tempDistanceSquared;
for (let i = 0; i < points.length; i++) {
let j = i + 1;
if (j == points.length)
j = 0;
let closest = ShapeCollisions.closestPointOnLine(points[i], points[j], point);
tempDistanceSquared = Vector2.distanceSquared(point, closest);
if (tempDistanceSquared < distanceSquared) {
distanceSquared = tempDistanceSquared;
closestPoint = closest;
// 求直线的法线
let line = Vector2.subtract(points[j], points[i]);
edgeNormal = new Vector2(-line.y, line.x);
}
}
Vector2Ext.normalize(edgeNormal);
return closestPoint;
}
/**
* 旋转原始点并复制旋转的值到旋转的点
* @param radians
* @param originalPoints
* @param rotatedPoints
*/
public static rotatePolygonVerts(radians: number, originalPoints: Vector2[], rotatedPoints){
let cos = Math.cos(radians);
let sin = Math.sign(radians);
for (let i = 0; i < originalPoints.length; i ++){
let position = originalPoints[i];
rotatedPoints[i] = new Vector2(position.x * cos + position.y * -sin, position.x * sin + position.y * cos);
}
}
public recalculateBounds(collider: Collider) {
// 如果我们没有旋转或不关心TRS我们使用localOffset作为中心我们会从那开始
this.center = collider.localOffset;

View File

@@ -205,6 +205,18 @@ module es {
return false;
}
public static pointToBox(point: Vector2, box: Box, result: CollisionResult){
if (box.containsPoint(point)){
// 在方框的空间里找到点
result.point = box.bounds.getClosestPointOnRectangleBorderToPoint(point, result.normal);
result.minimumTranslationVector = Vector2.subtract(point, result.point);
return true;
}
return false;
}
/**
*
* @param lineA
@@ -277,7 +289,7 @@ module es {
return false;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
result.normal = result.normal.normalize();
return true;
}
@@ -285,7 +297,7 @@ module es {
return false;
}
private static minkowskiDifference(first: Box, second: Box) {
private static minkowskiDifference(first: Box, second: Box): Rectangle {
// 我们需要第一个框的左上角
// 碰撞器只会修改运动的位置所以我们需要用位置来计算出运动是什么。
let positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, Vector2.divide(first.bounds.size, new Vector2(2))));