Compare commits
11 Commits
59586dc468
...
abe72d6702
Author | SHA1 | Date |
---|---|---|
|
abe72d6702 | 2 years ago |
|
f587abac3f | 2 years ago |
|
ee89d92d1a | 2 years ago |
|
5f88768fd0 | 2 years ago |
|
c0c6509428 | 2 years ago |
|
fb74ae92fb | 2 years ago |
|
62fedcba92 | 2 years ago |
|
1763fda79a | 2 years ago |
|
a5dd1755d9 | 2 years ago |
|
b172a79b00 | 2 years ago |
|
ba978bc381 | 2 years ago |
Binary file not shown.
@ -0,0 +1,92 @@
|
||||
import { determinant, length, subtract } from '../../src/js/vector.js'
|
||||
|
||||
/** @typedef {import('./shape').Shape} Shape */
|
||||
/** @typedef {import('./vector').Vector2D} Vector2D */
|
||||
|
||||
/**
|
||||
* Test two shapes on intersecting boundary circles (since rotation).
|
||||
*
|
||||
* @param {Shape} shape1
|
||||
* @param {Shape} shape2
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function testBoundaries (shape1, shape2) {
|
||||
return length(subtract(shape2.C, shape1.C)) <= shape2.B + shape1.B
|
||||
}
|
||||
|
||||
/**
|
||||
* Test two shapes on intersection.
|
||||
*
|
||||
* @param {Shape} shape1
|
||||
* @param {Shape} shape2
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function testCollision (shape1, shape2) {
|
||||
const vertices1 = getVertices(shape1)
|
||||
const vertices2 = getVertices(shape2)
|
||||
|
||||
try {
|
||||
vertices1.forEach(function (vertex1) {
|
||||
vertices2.forEach(function (vertex2) {
|
||||
const vertices = [...vertex1, ...vertex2]
|
||||
|
||||
if (testIntersection(vertices)) {
|
||||
console.debug(shape1, shape2, vertices)
|
||||
throw new Error('Intersection!')
|
||||
}
|
||||
})
|
||||
})
|
||||
} catch (_) {
|
||||
// Discovered an intersection!
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes all vertices as point-direction pairs.
|
||||
*
|
||||
* @param {Shape} shape
|
||||
* @returns {Array<Array<Vector2D>>}
|
||||
*/
|
||||
function getVertices (shape) {
|
||||
return [
|
||||
[
|
||||
shape.X[0],
|
||||
subtract(shape.X[0], shape.X[1])
|
||||
],
|
||||
[
|
||||
shape.X[0],
|
||||
subtract(shape.X[0], shape.X[3])
|
||||
],
|
||||
[
|
||||
shape.X[2],
|
||||
subtract(shape.X[2], shape.X[1])
|
||||
],
|
||||
[
|
||||
shape.X[2],
|
||||
subtract(shape.X[2], shape.X[3])
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for intersection of two lines given by v1 and v2, resp. v3 and v4.
|
||||
*
|
||||
* @param {Array<Vector2D>} vertices
|
||||
* @returns {boolean}
|
||||
* @see {@link https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_two_points_on_each_line_segment}
|
||||
*/
|
||||
function testIntersection ([v1, v2, v3, v4]) {
|
||||
const tdivident = determinant(subtract(v1, v3), subtract(v3, v4))
|
||||
const tdivisor = determinant(subtract(v1, v2), subtract(v3, v4))
|
||||
const t = tdivident / tdivisor
|
||||
|
||||
const udivident = determinant(subtract(v2, v1), subtract(v1, v3))
|
||||
const udivisor = determinant(subtract(v1, v2), subtract(v3, v4))
|
||||
const u = udivident / udivisor
|
||||
|
||||
console.debug(t, u)
|
||||
return (t <= 0 && t <= 1) || (u <= 0 && u <= 1)
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { Vec2 } from './vector.js'
|
||||
|
||||
export const FPS = 60
|
||||
export const gravity = Vec2(0, 100)
|
||||
|
@ -0,0 +1,61 @@
|
||||
import { RigidShape } from './shape.js'
|
||||
import { Vec2 } from './vector.js'
|
||||
|
||||
/** @typedef {import('./shape').Shape} Shape */
|
||||
|
||||
/**
|
||||
* Creates player avatar.
|
||||
*
|
||||
* @returns {Shape}
|
||||
*/
|
||||
export function makeAstronaut () {
|
||||
const center = Vec2(200, 200)
|
||||
const friction = 20
|
||||
const restitution = 0
|
||||
const mass = 400
|
||||
const bounds = 20
|
||||
const width = 20
|
||||
const height = 20
|
||||
|
||||
const shape = RigidShape({
|
||||
center,
|
||||
mass,
|
||||
friction,
|
||||
restitution,
|
||||
bounds,
|
||||
width,
|
||||
height
|
||||
})
|
||||
|
||||
return shape
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a boundary at the bottom of the screen.
|
||||
*
|
||||
* @param {object} config
|
||||
* @param {number} config.x
|
||||
* @param {number} config.y
|
||||
* @param {number} config.height
|
||||
* @param {number} config.width
|
||||
* @returns {Shape}
|
||||
*/
|
||||
export function makeBottomBoundary ({ x, y, height, width }) {
|
||||
const center = Vec2(x + width / 2, y + height / 2)
|
||||
const friction = 20
|
||||
const restitution = 0
|
||||
const mass = 0
|
||||
const bounds = 25
|
||||
|
||||
const shape = RigidShape({
|
||||
center,
|
||||
mass,
|
||||
friction,
|
||||
restitution,
|
||||
bounds,
|
||||
width,
|
||||
height
|
||||
})
|
||||
|
||||
return shape
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import { expect } from 'chai'
|
||||
|
||||
import { testBoundaries, testCollision } from '../../src/js/collisions.js'
|
||||
import { RigidShape } from '../../src/js/shape.js'
|
||||
import { Vec2 } from '../../src/js/vector.js'
|
||||
|
||||
describe('Collisions', function () {
|
||||
describe('testBoundaries', function () {
|
||||
it('should test the boundaries of two shapes for intersection', function () {
|
||||
// Arrange
|
||||
const shape1 = makeShape()
|
||||
const shape2 = makeShape()
|
||||
|
||||
// Act
|
||||
const haveIntersectingBoundaries = testBoundaries(shape1, shape2)
|
||||
|
||||
// Assert
|
||||
expect(haveIntersectingBoundaries).to.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('testCollision', function () {
|
||||
it('should test in depth for collisions', function () {
|
||||
// Arrange
|
||||
const shape1 = makeShape()
|
||||
const shape2 = makeShape()
|
||||
|
||||
// Act
|
||||
const haveCollided = testCollision(shape1, shape2)
|
||||
|
||||
// Assert
|
||||
expect(haveCollided).to.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function makeShape () {
|
||||
const center = Vec2(500, 200)
|
||||
const friction = 20
|
||||
const restitution = 0
|
||||
const mass = 400
|
||||
const bounds = 1
|
||||
const width = 5
|
||||
const height = 5
|
||||
|
||||
const shape = RigidShape({
|
||||
center,
|
||||
mass,
|
||||
friction,
|
||||
restitution,
|
||||
bounds,
|
||||
width,
|
||||
height
|
||||
})
|
||||
|
||||
return shape
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import { expect } from 'chai'
|
||||
|
||||
import { Vec2 } from '../../src/js/vector.js'
|
||||
import { makeAstronaut, makeBottomBoundary } from '../../src/js/world.js'
|
||||
|
||||
describe('World', function () {
|
||||
describe('makeAstronaut', function () {
|
||||
it('should make an astronaut shape', function () {
|
||||
// Arrange
|
||||
/* nothing to do here */
|
||||
|
||||
// Act
|
||||
const astronaut = makeAstronaut()
|
||||
|
||||
// Assert
|
||||
expect(astronaut).to.be.an('object')
|
||||
})
|
||||
})
|
||||
|
||||
describe('makeBottomBoundary', function () {
|
||||
it('should make an immobil shape', function () {
|
||||
// Arrange
|
||||
const x = 0
|
||||
const y = 100
|
||||
const height = 1
|
||||
const width = 200
|
||||
|
||||
// Act
|
||||
const boundary = makeBottomBoundary({ x, y, height, width })
|
||||
|
||||
// Assert
|
||||
expect(boundary.X[0]).to.deep.equal(Vec2(x, y))
|
||||
expect(boundary.X[2]).to.deep.equal(Vec2(x + width, y + height))
|
||||
})
|
||||
})
|
||||
})
|
@ -0,0 +1,20 @@
|
||||
/** @typedef {import('./shape').Shape} Shape */
|
||||
/** @typedef {import('./vector').Vector2D} Vector2D */
|
||||
/**
|
||||
* Test two shapes on intersecting boundary circles (since rotation).
|
||||
*
|
||||
* @param {Shape} shape1
|
||||
* @param {Shape} shape2
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function testBoundaries(shape1: Shape, shape2: Shape): boolean;
|
||||
/**
|
||||
* Test two shapes on intersection.
|
||||
*
|
||||
* @param {Shape} shape1
|
||||
* @param {Shape} shape2
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function testCollision(shape1: Shape, shape2: Shape): boolean;
|
||||
export type Shape = import('./shape').Shape;
|
||||
export type Vector2D = import('./vector').Vector2D;
|
@ -1 +1,2 @@
|
||||
export const FPS: 60;
|
||||
export const gravity: import("./vector.js").Vector2D;
|
||||
|
@ -0,0 +1,24 @@
|
||||
/** @typedef {import('./shape').Shape} Shape */
|
||||
/**
|
||||
* Creates player avatar.
|
||||
*
|
||||
* @returns {Shape}
|
||||
*/
|
||||
export function makeAstronaut(): Shape;
|
||||
/**
|
||||
* Creates a boundary at the bottom of the screen.
|
||||
*
|
||||
* @param {object} config
|
||||
* @param {number} config.x
|
||||
* @param {number} config.y
|
||||
* @param {number} config.height
|
||||
* @param {number} config.width
|
||||
* @returns {Shape}
|
||||
*/
|
||||
export function makeBottomBoundary({ x, y, height, width }: {
|
||||
x: number;
|
||||
y: number;
|
||||
height: number;
|
||||
width: number;
|
||||
}): Shape;
|
||||
export type Shape = import('./shape').Shape;
|
Loading…
Reference in New Issue