@box2d/core
Version:
A TypeScript port of Box2D
208 lines (207 loc) • 8.36 kB
JavaScript
"use strict";
// MIT License
Object.defineProperty(exports, "__esModule", { value: true });
exports.b2ChainShape = void 0;
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// DEBUG: import { b2Assert, b2_linearSlop } from "../common/b2_common";
const b2_common_1 = require("../common/b2_common");
const b2_math_1 = require("../common/b2_math");
const b2_shape_1 = require("./b2_shape");
const b2_edge_shape_1 = require("./b2_edge_shape");
/**
* A chain shape is a free form sequence of line segments.
* The chain has one-sided collision, with the surface normal pointing to the right of the edge.
* This provides a counter-clockwise winding like the polygon shape.
* Connectivity information is used to create smooth collisions.
*
* @warning the chain will not collide properly if there are self-intersections.
*/
class b2ChainShape extends b2_shape_1.b2Shape {
constructor() {
super(b2_shape_1.b2ShapeType.e_chain, b2_common_1.b2_polygonRadius);
this.m_vertices = [];
this.m_prevVertex = new b2_math_1.b2Vec2();
this.m_nextVertex = new b2_math_1.b2Vec2();
}
/**
* Create a loop. This automatically adjusts connectivity.
*
* @param vertices An array of vertices, these are copied
* @param count The vertex count
*/
CreateLoop(vertices, count = vertices.length) {
// DEBUG: b2Assert(count >= 3);
if (count < 3) {
return this;
}
// DEBUG: for (let i = 1; i < count; ++i) {
// DEBUG: const v1 = vertices[i - 1];
// DEBUG: const v2 = vertices[i];
// DEBUG: // If the code crashes here, it means your vertices are too close together.
// DEBUG: b2Assert(b2Vec2.DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
// DEBUG: }
this.m_vertices.length = count + 1;
for (let i = 0; i < count; ++i) {
const { x, y } = vertices[i];
this.m_vertices[i] = new b2_math_1.b2Vec2(x, y);
}
this.m_vertices[count] = this.m_vertices[0].Clone();
this.m_prevVertex.Copy(this.m_vertices[this.m_vertices.length - 2]);
this.m_nextVertex.Copy(this.m_vertices[1]);
return this;
}
/**
* Create a chain with ghost vertices to connect multiple chains together.
*
* @param vertices An array of vertices, these are copied
* @param count The vertex count
* @param prevVertex Previous vertex from chain that connects to the start
* @param nextVertex Next vertex from chain that connects to the end
*/
CreateChain(vertices, count, prevVertex, nextVertex) {
// DEBUG: b2Assert(count >= 2);
// DEBUG: for (let i = 1; i < count; ++i) {
// DEBUG: // If the code crashes here, it means your vertices are too close together.
// DEBUG: b2Assert(b2Vec2.DistanceSquared(vertices[i-1], vertices[i]) > b2_linearSlop * b2_linearSlop);
// DEBUG: }
this.m_vertices.length = count;
for (let i = 0; i < count; ++i) {
const { x, y } = vertices[i];
this.m_vertices[i] = new b2_math_1.b2Vec2(x, y);
}
this.m_prevVertex.Copy(prevVertex);
this.m_nextVertex.Copy(nextVertex);
return this;
}
/**
* Implement b2Shape. Vertices are cloned using b2Alloc.
*/
Clone() {
return new b2ChainShape().Copy(this);
}
Copy(other) {
super.Copy(other);
// DEBUG: b2Assert(other instanceof b2ChainShape);
return this.CreateChain(other.m_vertices, other.m_vertices.length, other.m_prevVertex, other.m_nextVertex);
}
/**
* @see b2Shape::GetChildCount
*/
GetChildCount() {
// edge count = vertex count - 1
return this.m_vertices.length - 1;
}
/**
* Get a child edge.
*/
GetChildEdge(edge, index) {
// DEBUG: b2Assert(0 <= index && index < this.m_vertices.length - 1);
edge.m_radius = this.m_radius;
edge.m_vertex1.Copy(this.m_vertices[index]);
edge.m_vertex2.Copy(this.m_vertices[index + 1]);
edge.m_oneSided = true;
if (index > 0) {
edge.m_vertex0.Copy(this.m_vertices[index - 1]);
}
else {
edge.m_vertex0.Copy(this.m_prevVertex);
}
if (index < this.m_vertices.length - 2) {
edge.m_vertex3.Copy(this.m_vertices[index + 2]);
}
else {
edge.m_vertex3.Copy(this.m_nextVertex);
}
}
/**
* This always return false.
*
* @see b2Shape::TestPoint
*/
TestPoint(_xf, _p) {
return false;
}
/**
* Implement b2Shape.
*/
RayCast(output, input, xf, childIndex) {
// DEBUG: b2Assert(childIndex < this.m_vertices.length);
const edgeShape = b2ChainShape.RayCast_s_edgeShape;
const i1 = childIndex;
let i2 = childIndex + 1;
if (i2 === this.m_vertices.length) {
i2 = 0;
}
edgeShape.m_vertex1.Copy(this.m_vertices[i1]);
edgeShape.m_vertex2.Copy(this.m_vertices[i2]);
return edgeShape.RayCast(output, input, xf, 0);
}
/**
* @see b2Shape::ComputeAABB
*/
ComputeAABB(aabb, xf, childIndex) {
// DEBUG: b2Assert(childIndex < this.m_vertices.length);
const i1 = childIndex;
let i2 = childIndex + 1;
if (i2 === this.m_vertices.length) {
i2 = 0;
}
const v1 = b2_math_1.b2Transform.MultiplyVec2(xf, this.m_vertices[i1], b2ChainShape.ComputeAABB_s_v1);
const v2 = b2_math_1.b2Transform.MultiplyVec2(xf, this.m_vertices[i2], b2ChainShape.ComputeAABB_s_v2);
const lower = b2_math_1.b2Vec2.Min(v1, v2, b2ChainShape.ComputeAABB_s_lower);
const upper = b2_math_1.b2Vec2.Max(v1, v2, b2ChainShape.ComputeAABB_s_upper);
aabb.lowerBound.x = lower.x - this.m_radius;
aabb.lowerBound.y = lower.y - this.m_radius;
aabb.upperBound.x = upper.x + this.m_radius;
aabb.upperBound.y = upper.y + this.m_radius;
}
/**
* Chains have zero mass.
*
* @see b2Shape::ComputeMass
*/
ComputeMass(massData, _density) {
massData.mass = 0;
massData.center.SetZero();
massData.I = 0;
}
SetupDistanceProxy(proxy, index) {
// DEBUG: b2Assert(0 <= index && index < this.m_vertices.length);
proxy.m_vertices = proxy.m_buffer;
proxy.m_vertices[0] = this.m_vertices[index];
const secondIndex = index + 1 < this.m_vertices.length ? index + 1 : 0;
proxy.m_vertices[1] = this.m_vertices[secondIndex];
proxy.m_count = 2;
proxy.m_radius = this.m_radius;
}
Draw(draw, color) {
const vertices = this.m_vertices;
let v1 = vertices[0];
for (let i = 1; i < vertices.length; ++i) {
const v2 = vertices[i];
draw.DrawSegment(v1, v2, color);
v1 = v2;
}
}
}
exports.b2ChainShape = b2ChainShape;
b2ChainShape.RayCast_s_edgeShape = new b2_edge_shape_1.b2EdgeShape();
b2ChainShape.ComputeAABB_s_v1 = new b2_math_1.b2Vec2();
b2ChainShape.ComputeAABB_s_v2 = new b2_math_1.b2Vec2();
b2ChainShape.ComputeAABB_s_lower = new b2_math_1.b2Vec2();
b2ChainShape.ComputeAABB_s_upper = new b2_math_1.b2Vec2();