fix auto-attack targeting

This commit is contained in:
2025-01-13 11:45:26 +09:00
parent 49a4d3e924
commit 03bbea4862
8 changed files with 32 additions and 134 deletions
-7
View File
@@ -10,7 +10,6 @@
"license": "UNLICENSED",
"dependencies": {
"@tweenjs/tween.js": "^25.0.0",
"quickhull": "^1.0.3",
"sat": "^0.9.0",
"three": "^0.171.0",
"websocket-express": "^3.1.2"
@@ -753,12 +752,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/quickhull": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/quickhull/-/quickhull-1.0.3.tgz",
"integrity": "sha512-AQbLaXdzGDJdO9Mu3qY/NY5JWlDqIutCLW8vJbsQTq+/bydIZeltnMVRKCElp81Y5/uRm4Yw/RsMdcltFYsS6w==",
"license": "MIT"
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-1
View File
@@ -11,7 +11,6 @@
"description": "",
"dependencies": {
"@tweenjs/tween.js": "^25.0.0",
"quickhull": "^1.0.3",
"sat": "^0.9.0",
"three": "^0.171.0",
"websocket-express": "^3.1.2"
-9
View File
@@ -184,8 +184,6 @@ function connectWebSocket() {
entity.position.set(e.position.x / 100, e.position.y / 100, e.height / 100)
scene.add(entity)
// TODO: player model out of basic geometries
const hpMargin = 0.4
const maxHp = new THREE.Sprite(new THREE.SpriteMaterial({ color: 0xd03333 }))
maxHp.position.set(0, (e.height / 100) + hpMargin, 0)
@@ -386,13 +384,6 @@ window.addEventListener('load', () => {
if (event.code == 'KeyE') {
websocket.send(JSON.stringify({ action: 'cast', slot: 3, id: playerId, x, y }))
}
if (event.code == 'KeyD') {
websocket.send(JSON.stringify({ action: 'teleport', id: playerId, x, y }))
}
if (event.code == 'KeyF') {
websocket.send(JSON.stringify({ action: 'teleport', id: playerId, x, y }))
}
}
})
+1 -1
View File
@@ -68,7 +68,7 @@ export default class Ability {
let closest = null
let distance = Infinity
caster.game?.entities.filter((e) => e.team != caster.team && e.position.clone().sub(caster.position).length() < ability.range).forEach((e) => {
const newDistance = e.position.clone().sub(cursor).length() < distance
const newDistance = e.position.clone().sub(cursor).length()
if (newDistance < distance) {
closest = e
distance = newDistance
+13 -18
View File
@@ -27,6 +27,7 @@ export default class Entity {
#dest = null
#game = null
#logic = null
#move = false
#path = []
#position = new Vector2()
#scheduledPathfinding = null
@@ -87,7 +88,7 @@ export default class Entity {
this.moveAction(x, y, true)
}
castAction(slot, x, y, clearDestination = true) {
castAction(slot, x, y, halt = true) {
const ability = this.abilities[slot]
if (this.casting != null) {
@@ -99,8 +100,8 @@ export default class Entity {
return false
}
if (clearDestination) {
this.#dest = null
if (halt) {
this.#move = false
}
const cursor = new Vector2(x, y)
@@ -117,21 +118,22 @@ export default class Entity {
}
haltAction() {
this.#dest = null
this.#move = false
}
moveAction(x, y, attack = false) {
this.#attack = attack
if (this.casting != null && (!this.#attack || this.casting.ability.id != this.abilities[0].id)) {
this.casting = null
}
this.#attack = attack
this.#move = true
this.#dest = SATX.fixCollisions(new Vector2(x, y), this.collidables(), this.radius, this.game?.width, this.game?.height)
}
stopAction() {
this.casting = null
this.#dest = null
this.#move = true
this.#attack = false
}
@@ -160,14 +162,6 @@ export default class Entity {
return entityColliders.concat(terrainColliders)
}
// DEPRECATED: hulls were a failed concept for position fixing
collidableHulls() {
const entityColliders = (this.game?.entities ?? []).filter((e) => e.id != this.id).map((e) => e.collider)
const terrainColliders = (this.game?.terrains ?? []).map((t) => t.hull)
return entityColliders.concat(terrainColliders)
}
cooldown(id) {
this.cooldowns[id] = this.game?.currentTick ?? 0
}
@@ -207,7 +201,7 @@ export default class Entity {
this.fixPosition()
}
takeStep(distanceTraveled = 0) {
move(distanceTraveled = 0) {
if (this.casting != null) { return false }
if (this.#attack && this.game?.entities.some((e) => e.team != this.team && e.position.clone().sub(this.position).length() < this.abilities[0].range)) {
@@ -221,7 +215,7 @@ export default class Entity {
return true
}
if (this.#dest == null) { return false }
if (!this.#move || this.#dest == null) { return false }
const collidables = this.collidables()
const fixedDest = SATX.clamp(SATX.fixCollisions(this.#dest, collidables, this.radius), this.game?.width, this.game?.height, this.radius)
@@ -268,10 +262,11 @@ export default class Entity {
if (this.position.equals(destination)) {
this.#path = this.#path.slice(1)
if (this.#path.length > 0) {
this.takeStep(distance)
this.move(distance)
}
else {
this.#dest = null
this.#move = false
}
}
}
@@ -279,7 +274,7 @@ export default class Entity {
update() {
this.cast()
this.takeStep()
this.move()
this.fixPosition()
if (this.#logic != null) {
this.#logic()
+3 -78
View File
@@ -35,11 +35,6 @@ app.ws('/ws', async (req, res) => {
}
console.log(message)
// DEPRECATED: teleporting is now directly possible via Ability...
if (message.action == 'teleport') {
entity.teleport(new Vector2(message.x, message.y))
}
if (message.action == 'attack') {
entity.attackAction(message.x, message.y)
}
@@ -62,79 +57,6 @@ app.ws('/ws', async (req, res) => {
})
})
// function testScenario() {
// const entity1 = new Entity()
// entity1.id = '1'
// entity1.teleport(new Vector2(200, 500))
// entity1.radius = 50
// entity1.maxHealth = 100
// entity1.health = 80
// game.spawnEntity(entity1)
// const entity2 = new Entity()
// entity2.id = '2'
// entity2.teleport(new Vector2(110, 110))
// entity2.radius = 50
// entity2.maxHealth = 50
// entity2.health = 50
// game.spawnEntity(entity2)
// const horseshoe = new Terrain([
// { x: 400, y: 200 },
// { x: 600, y: 200 },
// { x: 700, y: 300 },
// { x: 650, y: 600 },
// { x: 400, y: 600 },
// { x: 400, y: 450 },
// { x: 600, y: 500 },
// { x: 600, y: 300 },
// { x: 400, y: 300 },
// ])
// horseshoe.id = 'horseshoe'
// game.addTerrain(horseshoe)
// const stopsign = new Terrain([
// { x: 800, y: 800 },
// { x: 900, y: 900 },
// { x: 900, y: 1000 },
// { x: 800, y: 1100 },
// { x: 800, y: 1100 },
// { x: 700, y: 1100 },
// { x: 600, y: 1000 },
// { x: 600, y: 900 },
// { x: 700, y: 800 },
// ])
// stopsign.id = 'stopsign'
// game.addTerrain(stopsign)
// const box = new Terrain([
// { x: 1200, y: 700 },
// { x: 1200, y: 800 },
// { x: 1300, y: 800 },
// { x: 1300, y: 700 },
// ])
// box.id = 'box'
// game.addTerrain(box)
// const diamond = new Terrain([
// { x: 1000, y: 300 },
// { x: 1100, y: 400 },
// { x: 1000, y: 500 },
// { x: 900, y: 400 },
// ])
// diamond.id = 'diamond'
// game.addTerrain(diamond)
// const pole = new Terrain([
// { x: 400, y: 1000 },
// { x: 410, y: 1000 },
// { x: 410, y: 1010 },
// { x: 400, y: 1010 },
// ])
// pole.id = 'pole'
// game.addTerrain(pole)
// }
function laneScenario() {
const entity1 = new Entity({
id: '1',
@@ -197,6 +119,9 @@ function laneScenario() {
if (entity.id == '2') {
entity.teleport(new Vector2(1600, 1800))
}
if (entity.id == '3') {
entity.teleport(new Vector2(1800, 1600))
}
}
}
}
+14 -7
View File
@@ -4,19 +4,26 @@ import PriorityQueue from './priority-queue.js'
import SATX from './satx.js'
export default class Pathfind {
static precision = 0.001
static multiplier = 1000 // (1 / this.precision)
static precision = 0.01
static multiplier = 1000000 // (1 / this.precision) * 10^expected_digit_count / 10
static key2(a, b) {
return `${a},${b}`
}
// TODO: Value exceeds safe integer limit: collisions cause waypointing anomalies
// Fowler-Noll-Vo hash prime and offset basis for small keyspaces
static floatKey4(a, b, c, d) {
return Math.floor(a * Pathfind.multiplier) +
Math.floor(b * Pathfind.multiplier) * Pathfind.multiplier +
Math.floor(c * Pathfind.multiplier) * Pathfind.multiplier ** 2 +
Math.floor(d * Pathfind.multiplier) * Pathfind.multiplier ** 3
const prime = 16777619
let result = 2166136261
result ^= Math.floor(a * Pathfind.multiplier)
result *= prime
result ^= Math.floor(b * Pathfind.multiplier)
result *= prime
result ^= Math.floor(c * Pathfind.multiplier)
result *= prime
result ^= Math.floor(d * Pathfind.multiplier)
result *= prime
return result
}
static uniqueWaypoints(waypoints) {
-12
View File
@@ -1,4 +1,3 @@
import QuickHull from 'quickhull' // DEPRECATED: hulls were a failed concept for position fixing
import SAT from 'sat'
import { Shape, ShapeUtils, Vector2 } from 'three'
@@ -26,7 +25,6 @@ export default class Terrain {
}
get colliders() { return this.#colliders }
get hull() { return this.#hull } // DEPRECATED: hulls were a failed concept for position fixing
get unadjustedWaypoints() { return this.#unadjustedWaypoints }
get vertices() { return this.#vertices }
@@ -76,16 +74,6 @@ export default class Terrain {
}
this.#colliders = ShapeUtils.triangulateShape(points.shape, points.holes).map(indicesToPolygon)
this.#calculateHull()
}
// DEPRECATED: hulls were a failed concept for position fixing
#calculateHull() {
const vertices = QuickHull(this.#vertices.map((v) => ({ x: v.x, y: v.y }))).map((v) => new Vector2(v.x, v.y))
const first = vertices.at(0)
const satPoints = [new SAT.Vector(...first.toArray()), ...vertices.slice(1).map((v) => new SAT.Vector(...v.clone(first).sub(first).toArray()))]
this.#hull = new SAT.Polygon(satPoints[0], [new SAT.Vector(), ...satPoints.slice(1)])
}
#calculatePosition() {