ditch THREE raycasting for SAT again

This commit is contained in:
2024-12-23 09:46:26 +09:00
parent 054d22d01a
commit e23978ea90
6 changed files with 61 additions and 29 deletions
+7
View File
@@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "UNLICENSED",
"dependencies": {
"sat": "^0.9.0",
"three": "^0.171.0",
"websocket-express": "^3.1.2"
}
@@ -798,6 +799,12 @@
"license": "MIT",
"peer": true
},
"node_modules/sat": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/sat/-/sat-0.9.0.tgz",
"integrity": "sha512-mxdv5RZJO4tdMnUURGU3gAMcnDUEwcNJwE+lPO0/V+rBeDvFLH3wEZEOR0fH7cTN0zQaNxBEbHnyQL9DzupwQQ==",
"license": "MIT"
},
"node_modules/send": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+1
View File
@@ -10,6 +10,7 @@
"license": "UNLICENSED",
"description": "",
"dependencies": {
"sat": "^0.9.0",
"three": "^0.171.0",
"websocket-express": "^3.1.2"
}
+1 -6
View File
@@ -1,5 +1,4 @@
import * as THREE from 'three'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
const global = (0,eval)("this")
const scene = new THREE.Scene()
@@ -23,16 +22,12 @@ directionalLight.position.set(-0.3, 0.1, 1)
directionalLight.power = 3000
scene.add(directionalLight)
// const loader = new GLTFLoader()
// loader.load('player.gltf', (gltf) => scene.add(gltf.scene), undefined, (err) => console.log(err))
global.THREE = THREE
global.renderer = renderer
global.camera = camera
global.scene = scene
camera.position.set(3, -12, 10)
camera.rotation.set((60 / 180) * Math.PI, 0, 0)
// camera.lookAt(0, 0, 0)
function animate() {
renderer.render(scene, camera)
@@ -81,7 +76,7 @@ function connectWebSocket() {
entities[e.id] = entity
}
entity.position.set(e.pos.x / 100, e.pos.y / 100, e.radius / 100)
entity.position.set(e.position.x / 100, e.position.y / 100, e.radius / 100)
}
document.getElementById('state').innerHTML = JSON.stringify(state, null, 2)
+40 -22
View File
@@ -1,32 +1,42 @@
import * as THREE from 'three'
import SAT from 'sat'
import SATX from './satx.js'
export default class Entity {
id = crypto.randomUUID()
speed = 400
radius = 0
#position = new THREE.Vector2(0, 0)
#dest = null
#game = null
#mesh = null
static collider(x, y, radius) {
return new SAT.Circle(new SAT.Vector(x, y), radius)
}
constructor(...options) {
Object.entries(options).forEach((value, key) => this[key] = value)
const geometry = new THREE.CircleGeometry(options.radius ?? 0)
this.#mesh = new THREE.Mesh(geometry)
}
get game() { return this.#game }
get mesh() { return this.#mesh }
get pos() { return this.#mesh.position }
get radius() { return this.#mesh.userData.radius }
get x() { return this.#mesh.position.x }
get y() { return this.#mesh.position.y }
get position() { return this.#position }
get x() { return this.position.x }
get y() { return this.position.y }
set game(value) { this.#game = value }
set x(value) { this.#mesh.position.x = value }
set y(value) { this.#mesh.position.y = value }
set x(value) { this.position.x = value }
set y(value) { this.position.y = value }
set radius(value) {
this.#mesh.geometry = new THREE.CircleGeometry(value)
this.#mesh.userData.radius = value
get collidables() {
return this.game?.entities.filter((e) => e.id != this.id).map((e) => e.collider)
}
get collider() {
return new SAT.Circle(new SAT.Vector(this.x, this.y), this.radius)
}
isColliding(collider) {
return SATX.colliding(this.collider, collider)
}
moveAction(x, y) {
@@ -36,30 +46,38 @@ export default class Entity {
state() {
return {
...this,
pos: {
position: {
x: this.x,
y: this.y,
},
radius: this.radius,
}
}
teleport(x, y) {
this.#mesh.position.set(x, y, 0)
this.position.set(x, y)
}
takeStep() {
const speed = this.speed / (this.game?.tickBudget ?? 1000)
if (this.#dest != null) {
const fixedDest = new THREE.Vector3(
Math.min(Math.max(this.radius, this.#dest.x), this.game?.height ?? Infinity),
const fixedDest = new THREE.Vector2(
Math.min(Math.max(this.radius, this.#dest.x), this.game?.width ?? Infinity),
Math.min(Math.max(this.radius, this.#dest.y), this.game?.height ?? Infinity),
0,
)
this.pos.add(fixedDest.clone().sub(this.pos).normalize().multiplyScalar(speed))
if (this.pos.clone().sub(fixedDest).length() <= speed) {
this.pos.copy(fixedDest)
const distance = this.position.clone().sub(fixedDest).length()
const direction = fixedDest.clone().sub(this.position).normalize()
const stepTaken = this.position.clone().add(direction.multiplyScalar(speed))
const position = distance <= speed ? fixedDest : stepTaken
const collider = Entity.collider(position.x, position.y, this.radius)
const isColliding = this.collidables.some((c) => SATX.colliding(collider, c))
if (!isColliding) {
this.position.copy(position)
}
if (this.x == this.#dest?.x && this.y == this.#dest?.y) {
this.#dest = null
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ app.listen(port, () => {
const entity2 = new Entity()
entity2.id = '2'
entity.teleport(200, 100)
entity2.teleport(100, 100)
entity2.radius = 35
game.spawn_entity(entity2)
+11
View File
@@ -0,0 +1,11 @@
import SAT from 'sat'
export default class SATX {
static colliding(collider1, collider2) {
if (collider1 instanceof SAT.Circle && collider2 instanceof SAT.Circle) {
return SAT.testCircleCircle(collider1, collider2)
}
return false
}
}