ditch THREE raycasting for SAT again
This commit is contained in:
Generated
+7
@@ -9,6 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"sat": "^0.9.0",
|
||||||
"three": "^0.171.0",
|
"three": "^0.171.0",
|
||||||
"websocket-express": "^3.1.2"
|
"websocket-express": "^3.1.2"
|
||||||
}
|
}
|
||||||
@@ -798,6 +799,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"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": {
|
"node_modules/send": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"sat": "^0.9.0",
|
||||||
"three": "^0.171.0",
|
"three": "^0.171.0",
|
||||||
"websocket-express": "^3.1.2"
|
"websocket-express": "^3.1.2"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -1,5 +1,4 @@
|
|||||||
import * as THREE from 'three'
|
import * as THREE from 'three'
|
||||||
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
|
|
||||||
|
|
||||||
const global = (0,eval)("this")
|
const global = (0,eval)("this")
|
||||||
const scene = new THREE.Scene()
|
const scene = new THREE.Scene()
|
||||||
@@ -23,16 +22,12 @@ directionalLight.position.set(-0.3, 0.1, 1)
|
|||||||
directionalLight.power = 3000
|
directionalLight.power = 3000
|
||||||
scene.add(directionalLight)
|
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.THREE = THREE
|
||||||
global.renderer = renderer
|
global.renderer = renderer
|
||||||
global.camera = camera
|
global.camera = camera
|
||||||
global.scene = scene
|
global.scene = scene
|
||||||
camera.position.set(3, -12, 10)
|
camera.position.set(3, -12, 10)
|
||||||
camera.rotation.set((60 / 180) * Math.PI, 0, 0)
|
camera.rotation.set((60 / 180) * Math.PI, 0, 0)
|
||||||
// camera.lookAt(0, 0, 0)
|
|
||||||
|
|
||||||
function animate() {
|
function animate() {
|
||||||
renderer.render(scene, camera)
|
renderer.render(scene, camera)
|
||||||
@@ -81,7 +76,7 @@ function connectWebSocket() {
|
|||||||
entities[e.id] = entity
|
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)
|
document.getElementById('state').innerHTML = JSON.stringify(state, null, 2)
|
||||||
|
|||||||
+40
-22
@@ -1,32 +1,42 @@
|
|||||||
import * as THREE from 'three'
|
import * as THREE from 'three'
|
||||||
|
import SAT from 'sat'
|
||||||
|
import SATX from './satx.js'
|
||||||
|
|
||||||
export default class Entity {
|
export default class Entity {
|
||||||
id = crypto.randomUUID()
|
id = crypto.randomUUID()
|
||||||
speed = 400
|
speed = 400
|
||||||
|
radius = 0
|
||||||
|
|
||||||
|
#position = new THREE.Vector2(0, 0)
|
||||||
#dest = null
|
#dest = null
|
||||||
#game = null
|
#game = null
|
||||||
#mesh = null
|
|
||||||
|
static collider(x, y, radius) {
|
||||||
|
return new SAT.Circle(new SAT.Vector(x, y), radius)
|
||||||
|
}
|
||||||
|
|
||||||
constructor(...options) {
|
constructor(...options) {
|
||||||
Object.entries(options).forEach((value, key) => this[key] = value)
|
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 game() { return this.#game }
|
||||||
get mesh() { return this.#mesh }
|
get position() { return this.#position }
|
||||||
get pos() { return this.#mesh.position }
|
get x() { return this.position.x }
|
||||||
get radius() { return this.#mesh.userData.radius }
|
get y() { return this.position.y }
|
||||||
get x() { return this.#mesh.position.x }
|
|
||||||
get y() { return this.#mesh.position.y }
|
|
||||||
set game(value) { this.#game = value }
|
set game(value) { this.#game = value }
|
||||||
set x(value) { this.#mesh.position.x = value }
|
set x(value) { this.position.x = value }
|
||||||
set y(value) { this.#mesh.position.y = value }
|
set y(value) { this.position.y = value }
|
||||||
|
|
||||||
set radius(value) {
|
get collidables() {
|
||||||
this.#mesh.geometry = new THREE.CircleGeometry(value)
|
return this.game?.entities.filter((e) => e.id != this.id).map((e) => e.collider)
|
||||||
this.#mesh.userData.radius = value
|
}
|
||||||
|
|
||||||
|
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) {
|
moveAction(x, y) {
|
||||||
@@ -36,30 +46,38 @@ export default class Entity {
|
|||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
...this,
|
...this,
|
||||||
pos: {
|
position: {
|
||||||
x: this.x,
|
x: this.x,
|
||||||
y: this.y,
|
y: this.y,
|
||||||
},
|
},
|
||||||
radius: this.radius,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
teleport(x, y) {
|
teleport(x, y) {
|
||||||
this.#mesh.position.set(x, y, 0)
|
this.position.set(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
takeStep() {
|
takeStep() {
|
||||||
const speed = this.speed / (this.game?.tickBudget ?? 1000)
|
const speed = this.speed / (this.game?.tickBudget ?? 1000)
|
||||||
if (this.#dest != null) {
|
if (this.#dest != null) {
|
||||||
const fixedDest = new THREE.Vector3(
|
const fixedDest = new THREE.Vector2(
|
||||||
Math.min(Math.max(this.radius, this.#dest.x), this.game?.height ?? Infinity),
|
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),
|
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))
|
const distance = this.position.clone().sub(fixedDest).length()
|
||||||
if (this.pos.clone().sub(fixedDest).length() <= speed) {
|
const direction = fixedDest.clone().sub(this.position).normalize()
|
||||||
this.pos.copy(fixedDest)
|
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
|
this.#dest = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ app.listen(port, () => {
|
|||||||
|
|
||||||
const entity2 = new Entity()
|
const entity2 = new Entity()
|
||||||
entity2.id = '2'
|
entity2.id = '2'
|
||||||
entity.teleport(200, 100)
|
entity2.teleport(100, 100)
|
||||||
entity2.radius = 35
|
entity2.radius = 35
|
||||||
game.spawn_entity(entity2)
|
game.spawn_entity(entity2)
|
||||||
|
|
||||||
|
|||||||
+11
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user