box 重载 collidesWith

This commit is contained in:
yhh
2020-07-07 12:18:51 +08:00
parent 8be65fa685
commit ace8fb685d
12 changed files with 204 additions and 6 deletions

View File

@@ -743,6 +743,7 @@ declare class Rectangle {
height: number; height: number;
private _tempMat; private _tempMat;
private _transformMat; private _transformMat;
readonly max: Vector2;
readonly left: number; readonly left: number;
readonly right: number; readonly right: number;
readonly top: number; readonly top: number;
@@ -760,6 +761,7 @@ declare class Rectangle {
res: Vector2; res: Vector2;
edgeNormal: Vector2; edgeNormal: Vector2;
}; };
getClosestPointOnBoundsToOrigin(): Vector2;
calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, rotation: number, width: number, height: number): void; calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, rotation: number, width: number, height: number): void;
static rectEncompassingPoints(points: Vector2[]): Rectangle; static rectEncompassingPoints(points: Vector2[]): Rectangle;
} }
@@ -883,6 +885,7 @@ declare class Box extends Polygon {
height: number; height: number;
constructor(width: number, height: number); constructor(width: number, height: number);
private static buildBox; private static buildBox;
collidesWithShape(other: Shape): any;
updateBox(width: number, height: number): void; updateBox(width: number, height: number): void;
containsPoint(point: Vector2): boolean; containsPoint(point: Vector2): boolean;
} }
@@ -915,6 +918,8 @@ declare class ShapeCollisions {
static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2): Vector2; static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2): Vector2;
static pointToPoly(point: Vector2, poly: Polygon): CollisionResult; static pointToPoly(point: Vector2, poly: Polygon): CollisionResult;
static circleToCircle(first: Circle, second: Circle): CollisionResult; static circleToCircle(first: Circle, second: Circle): CollisionResult;
static boxToBox(first: Box, second: Box): false | CollisionResult;
private static minkowskiDifference;
} }
declare class SpatialHash { declare class SpatialHash {
gridBounds: Rectangle; gridBounds: Rectangle;

View File

@@ -3343,6 +3343,13 @@ var Rectangle = (function () {
this.width = width ? width : 0; this.width = width ? width : 0;
this.height = height ? height : 0; this.height = height ? height : 0;
} }
Object.defineProperty(Rectangle.prototype, "max", {
get: function () {
return new Vector2(this.right, this.bottom);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "left", { Object.defineProperty(Rectangle.prototype, "left", {
get: function () { get: function () {
return this.x; return this.x;
@@ -3466,6 +3473,27 @@ var Rectangle = (function () {
} }
return { res: res, edgeNormal: edgeNormal }; return { res: res, edgeNormal: edgeNormal };
}; };
Rectangle.prototype.getClosestPointOnBoundsToOrigin = function () {
var max = this.max;
var minDist = Math.abs(this.location.x);
var boundsPoint = new Vector2(this.location.x, 0);
if (Math.abs(max.x) < minDist) {
minDist = Math.abs(max.x);
boundsPoint.x = max.x;
boundsPoint.y = 0;
}
if (Math.abs(max.y) < minDist) {
minDist = Math.abs(max.y);
boundsPoint.x = 0;
boundsPoint.y = max.y;
}
if (Math.abs(this.location.y) < minDist) {
minDist = Math.abs(this.location.y);
boundsPoint.x = 0;
boundsPoint.y = this.location.y;
}
return boundsPoint;
};
Rectangle.prototype.calculateBounds = function (parentPosition, position, origin, scale, rotation, width, height) { Rectangle.prototype.calculateBounds = function (parentPosition, position, origin, scale, rotation, width, height) {
if (rotation == 0) { if (rotation == 0) {
this.x = parentPosition.x + position.x - origin.x * scale.x; this.x = parentPosition.x + position.x - origin.x * scale.x;
@@ -4076,6 +4104,12 @@ var Box = (function (_super) {
verts[3] = new Vector2(-halfWidth, halfHeight); verts[3] = new Vector2(-halfWidth, halfHeight);
return verts; return verts;
}; };
Box.prototype.collidesWithShape = function (other) {
if (this.isUnrotated && other instanceof Box && other.isUnrotated) {
return ShapeCollisions.boxToBox(this, other);
}
return _super.prototype.collidesWithShape.call(this, other);
};
Box.prototype.updateBox = function (width, height) { Box.prototype.updateBox = function (width, height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
@@ -4147,6 +4181,9 @@ var Circle = (function (_super) {
}(Shape)); }(Shape));
var CollisionResult = (function () { var CollisionResult = (function () {
function CollisionResult() { function CollisionResult() {
this.minimumTranslationVector = Vector2.zero;
this.normal = Vector2.zero;
this.point = Vector2.zero;
} }
CollisionResult.prototype.invertResult = function () { CollisionResult.prototype.invertResult = function () {
this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector); this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector);
@@ -4321,6 +4358,24 @@ var ShapeCollisions = (function () {
} }
return null; return null;
}; };
ShapeCollisions.boxToBox = function (first, second) {
var result = new CollisionResult();
var minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(new Vector2(0, 0))) {
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector == Vector2.zero)
return false;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
}
return result;
};
ShapeCollisions.minkowskiDifference = function (first, second) {
var positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, Vector2.divide(first.bounds.size, new Vector2(2))));
var topLeft = Vector2.subtract(Vector2.add(first.bounds.location, positionOffset), second.bounds.max);
var fullSize = Vector2.add(first.bounds.size, second.bounds.size);
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y);
};
return ShapeCollisions; return ShapeCollisions;
}()); }());
var SpatialHash = (function () { var SpatialHash = (function () {

File diff suppressed because one or more lines are too long

View File

@@ -14,7 +14,7 @@ class MainScene extends Scene {
bg.addComponent(new SpriteRenderer()).setSprite(sprite).setColor(0xff0000); bg.addComponent(new SpriteRenderer()).setSprite(sprite).setColor(0xff0000);
bg.addComponent(new PlayerController()); bg.addComponent(new PlayerController());
bg.addComponent(new Mover()); bg.addComponent(new Mover());
// bg.addComponent(new BoxCollider()); bg.addComponent(new BoxCollider());
bg.position = new Vector2(Math.random() * 200, Math.random() * 200); bg.position = new Vector2(Math.random() * 200, Math.random() * 200);
for (let i = 0; i < 100; i++) { for (let i = 0; i < 100; i++) {

View File

@@ -743,6 +743,7 @@ declare class Rectangle {
height: number; height: number;
private _tempMat; private _tempMat;
private _transformMat; private _transformMat;
readonly max: Vector2;
readonly left: number; readonly left: number;
readonly right: number; readonly right: number;
readonly top: number; readonly top: number;
@@ -760,6 +761,7 @@ declare class Rectangle {
res: Vector2; res: Vector2;
edgeNormal: Vector2; edgeNormal: Vector2;
}; };
getClosestPointOnBoundsToOrigin(): Vector2;
calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, rotation: number, width: number, height: number): void; calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, rotation: number, width: number, height: number): void;
static rectEncompassingPoints(points: Vector2[]): Rectangle; static rectEncompassingPoints(points: Vector2[]): Rectangle;
} }
@@ -883,6 +885,7 @@ declare class Box extends Polygon {
height: number; height: number;
constructor(width: number, height: number); constructor(width: number, height: number);
private static buildBox; private static buildBox;
collidesWithShape(other: Shape): any;
updateBox(width: number, height: number): void; updateBox(width: number, height: number): void;
containsPoint(point: Vector2): boolean; containsPoint(point: Vector2): boolean;
} }
@@ -915,6 +918,8 @@ declare class ShapeCollisions {
static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2): Vector2; static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2): Vector2;
static pointToPoly(point: Vector2, poly: Polygon): CollisionResult; static pointToPoly(point: Vector2, poly: Polygon): CollisionResult;
static circleToCircle(first: Circle, second: Circle): CollisionResult; static circleToCircle(first: Circle, second: Circle): CollisionResult;
static boxToBox(first: Box, second: Box): false | CollisionResult;
private static minkowskiDifference;
} }
declare class SpatialHash { declare class SpatialHash {
gridBounds: Rectangle; gridBounds: Rectangle;

View File

@@ -3343,6 +3343,13 @@ var Rectangle = (function () {
this.width = width ? width : 0; this.width = width ? width : 0;
this.height = height ? height : 0; this.height = height ? height : 0;
} }
Object.defineProperty(Rectangle.prototype, "max", {
get: function () {
return new Vector2(this.right, this.bottom);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "left", { Object.defineProperty(Rectangle.prototype, "left", {
get: function () { get: function () {
return this.x; return this.x;
@@ -3466,6 +3473,27 @@ var Rectangle = (function () {
} }
return { res: res, edgeNormal: edgeNormal }; return { res: res, edgeNormal: edgeNormal };
}; };
Rectangle.prototype.getClosestPointOnBoundsToOrigin = function () {
var max = this.max;
var minDist = Math.abs(this.location.x);
var boundsPoint = new Vector2(this.location.x, 0);
if (Math.abs(max.x) < minDist) {
minDist = Math.abs(max.x);
boundsPoint.x = max.x;
boundsPoint.y = 0;
}
if (Math.abs(max.y) < minDist) {
minDist = Math.abs(max.y);
boundsPoint.x = 0;
boundsPoint.y = max.y;
}
if (Math.abs(this.location.y) < minDist) {
minDist = Math.abs(this.location.y);
boundsPoint.x = 0;
boundsPoint.y = this.location.y;
}
return boundsPoint;
};
Rectangle.prototype.calculateBounds = function (parentPosition, position, origin, scale, rotation, width, height) { Rectangle.prototype.calculateBounds = function (parentPosition, position, origin, scale, rotation, width, height) {
if (rotation == 0) { if (rotation == 0) {
this.x = parentPosition.x + position.x - origin.x * scale.x; this.x = parentPosition.x + position.x - origin.x * scale.x;
@@ -4076,6 +4104,12 @@ var Box = (function (_super) {
verts[3] = new Vector2(-halfWidth, halfHeight); verts[3] = new Vector2(-halfWidth, halfHeight);
return verts; return verts;
}; };
Box.prototype.collidesWithShape = function (other) {
if (this.isUnrotated && other instanceof Box && other.isUnrotated) {
return ShapeCollisions.boxToBox(this, other);
}
return _super.prototype.collidesWithShape.call(this, other);
};
Box.prototype.updateBox = function (width, height) { Box.prototype.updateBox = function (width, height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
@@ -4147,6 +4181,9 @@ var Circle = (function (_super) {
}(Shape)); }(Shape));
var CollisionResult = (function () { var CollisionResult = (function () {
function CollisionResult() { function CollisionResult() {
this.minimumTranslationVector = Vector2.zero;
this.normal = Vector2.zero;
this.point = Vector2.zero;
} }
CollisionResult.prototype.invertResult = function () { CollisionResult.prototype.invertResult = function () {
this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector); this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector);
@@ -4321,6 +4358,24 @@ var ShapeCollisions = (function () {
} }
return null; return null;
}; };
ShapeCollisions.boxToBox = function (first, second) {
var result = new CollisionResult();
var minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(new Vector2(0, 0))) {
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector == Vector2.zero)
return false;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
}
return result;
};
ShapeCollisions.minkowskiDifference = function (first, second) {
var positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, Vector2.divide(first.bounds.size, new Vector2(2))));
var topLeft = Vector2.subtract(Vector2.add(first.bounds.location, positionOffset), second.bounds.max);
var fullSize = Vector2.add(first.bounds.size, second.bounds.size);
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y);
};
return ShapeCollisions; return ShapeCollisions;
}()); }());
var SpatialHash = (function () { var SpatialHash = (function () {

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,13 @@ class Rectangle {
private _tempMat: Matrix2D; private _tempMat: Matrix2D;
private _transformMat: Matrix2D; private _transformMat: Matrix2D;
/**
* 获取矩形的最大点,即右下角
*/
public get max(){
return new Vector2(this.right, this.bottom);
}
public get left() { public get left() {
return this.x; return this.x;
} }
@@ -124,6 +131,32 @@ class Rectangle {
return { res: res, edgeNormal: edgeNormal }; return { res: res, edgeNormal: edgeNormal };
} }
public getClosestPointOnBoundsToOrigin(){
let max = this.max;
let minDist = Math.abs(this.location.x);
let boundsPoint = new Vector2(this.location.x, 0);
if (Math.abs(max.x) < minDist){
minDist = Math.abs(max.x);
boundsPoint.x = max.x;
boundsPoint.y = 0;
}
if (Math.abs(max.y) < minDist){
minDist = Math.abs(max.y);
boundsPoint.x = 0;
boundsPoint.y = max.y;
}
if (Math.abs(this.location.y) < minDist){
minDist = Math.abs(this.location.y);
boundsPoint.x = 0;
boundsPoint.y = this.location.y;
}
return boundsPoint;
}
public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2,
rotation: number, width: number, height: number) { rotation: number, width: number, height: number) {
if (rotation == 0) { if (rotation == 0) {

View File

@@ -21,6 +21,20 @@ class Box extends Polygon {
return verts; return verts;
} }
/**
*
* @param other
*/
public collidesWithShape(other: Shape){
if (this.isUnrotated && other instanceof Box && other.isUnrotated){
return ShapeCollisions.boxToBox(this, other);
}
// TODO: 让 minkowski 运行于 cricleToBox
return super.collidesWithShape(other);
}
public updateBox(width: number, height: number){ public updateBox(width: number, height: number){
this.width = width; this.width = width;
this.height = height; this.height = height;

View File

@@ -1,8 +1,8 @@
class CollisionResult { class CollisionResult {
public collider: Collider; public collider: Collider;
public minimumTranslationVector: Vector2; public minimumTranslationVector: Vector2 = Vector2.zero;
public normal: Vector2; public normal: Vector2 = Vector2.zero;
public point: Vector2; public point: Vector2 = Vector2.zero;
public invertResult(){ public invertResult(){
this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector); this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector);

View File

@@ -252,4 +252,34 @@ class ShapeCollisions {
return null; return null;
} }
/**
*
* @param first
* @param second
*/
public static boxToBox(first: Box, second: Box){
let result = new CollisionResult();
let minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(new Vector2(0, 0))){
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector == Vector2.zero)
return false;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
}
return result;
}
private static minkowskiDifference(first: Box, second: Box){
let positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, Vector2.divide(first.bounds.size, new Vector2(2))));
let topLeft = Vector2.subtract(Vector2.add(first.bounds.location, positionOffset), second.bounds.max);
let fullSize = Vector2.add(first.bounds.size, second.bounds.size);
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y)
}
} }

View File

@@ -1,5 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"experimentalDecorators": true,
"module": "system", "module": "system",
"target": "es5", "target": "es5",
"declaration": true, "declaration": true,