make projectiles use bounding boxes too

This commit is contained in:
2025-01-19 16:11:51 +09:00
parent e75c0d2944
commit 04cc3f951e
5 changed files with 76 additions and 45 deletions
+4 -2
View File
@@ -38,7 +38,8 @@ export default class Ability {
const ability = this
const straightShotCollision = function straightShotCollision(projectile, collidingEntity) {
if (collidingEntity == null) { return }
if (collidingEntity.team == (projectile.owner?.team ?? 'unknown')) { return }
if (collidingEntity.id == caster.id) { return }
if (collidingEntity.team == (caster.team ?? 'unknown')) { return }
collidingEntity.damage(ability.damage, caster)
projectile.despawn()
@@ -181,7 +182,8 @@ export default class Ability {
const ability = this
const exposeCollision = function exposeCollision(projectile, collidingEntity) {
if (collidingEntity == null) { return }
if (collidingEntity.team == (projectile.owner?.team ?? 'unknown')) { return }
if (collidingEntity.team == caster.id) { return }
if (collidingEntity.team == (caster.team ?? 'unknown')) { return }
collidingEntity.applyBuff(Buff.exposed.id, caster.id)
projectile.despawn()
+22 -9
View File
@@ -25,6 +25,7 @@ export default class Entity {
visualRadius = null
#attacking = false
#colliders = []
#dest = null
#game = null
#logic = null
@@ -123,6 +124,8 @@ export default class Entity {
if (this.visualRadius == null) {
this.visualRadius = this.radius
}
this.#calculateCollider()
}
get attacking() { return this.#attacking }
@@ -256,11 +259,11 @@ export default class Entity {
}
collider() {
return Entity.collider(this.position.x, this.position.y, this.radius)
return this.#colliders.at(0)
}
colliders() {
return [this.collider()]
return this.#colliders
}
cooldown(id) {
@@ -329,7 +332,10 @@ export default class Entity {
}
fixPosition() {
this.position = this.fixFuturePosition(this.position.clone()).clone()
const fixedPosition = this.fixFuturePosition(this.position)
if (this.position.equals(fixedPosition)) { return }
this.setPosition(fixedPosition)
}
fixFuturePosition(futurePosition) {
@@ -400,14 +406,18 @@ export default class Entity {
}
respawn() {
this.position = this.#spawnPosition.clone()
this.setPosition(this.#spawnPosition)
this.health = this.maxHealth
this.dead = false
}
setPosition(vector) {
this.position.copy(vector)
this.#calculateCollider()
}
teleport(cursor) {
this.position = cursor.clone()
this.fixPosition()
this.setPosition(this.fixFuturePosition(cursor))
}
update() {
@@ -425,8 +435,6 @@ export default class Entity {
if (this.#logic != null) {
this.#logic()
}
this.#calculateBbox()
}
waypoints() {
@@ -456,6 +464,11 @@ export default class Entity {
this.bbox[3] = this.position.x - this.radius
}
#calculateCollider() {
this.#calculateBbox()
this.#colliders = [Entity.collider(this.position.x, this.position.y, this.radius)]
}
#cast() {
if (this.casting == null) {
return false
@@ -574,7 +587,7 @@ export default class Entity {
this.rotation = rotation
if (!this.willCollide(position)) {
this.position.copy(position)
this.setPosition(position)
}
if (this.position.equals(destination)) {
+1 -1
View File
@@ -124,7 +124,7 @@ export default class Game {
}
if (after - before > tickBudget) {
console.warn(`Can't keep up! A tick took ${taken.toFixed(1)} ms (Budget: ${tickBudget.toFixed(1)} ms)`)
console.warn(`Can't keep up! A tick took ${taken.toFixed(1)} ms. Entity count: ${this.entities.length}`)
}
}
}
+5 -2
View File
@@ -125,7 +125,8 @@ function laneScenario() {
new Vector2(9136, 8248),
].map((p) => p.multiplyScalar(1.6))
if ([(0 * game.tickRate), (1 * game.tickRate), (2 * game.tickRate)].includes(game.currentTick % (30 * game.tickRate))) {
if (game.entities.length < 100) {
if ([(0 * game.tickRate), (1 * game.tickRate), (2 * game.tickRate)].includes(game.currentTick % (6 * game.tickRate))) {
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: topRoute })))
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: midRoute })))
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: botRoute })))
@@ -135,7 +136,7 @@ function laneScenario() {
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: botRoute.toReversed() })))
}
if ([(3 * game.tickRate), (4 * game.tickRate), (5 * game.tickRate)].includes(game.currentTick % (30 * game.tickRate))) {
if ([(3 * game.tickRate), (4 * game.tickRate), (5 * game.tickRate)].includes(game.currentTick % (6 * game.tickRate))) {
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: topRoute })))
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: midRoute })))
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: botRoute })))
@@ -145,6 +146,8 @@ function laneScenario() {
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: botRoute.toReversed() })))
}
}
}
game.logic = gameLogic
}
+30 -17
View File
@@ -36,17 +36,6 @@ export default class Projectile {
}
}
checkCollisions(collider) {
(this.game?.entities ?? []).filter((e) => e.id != this.id).forEach((e) => {
if (this.game == null) { return }
if (e.id == this.owner?.id) { return }
if (SATX.collideObject(collider, e.collider())) {
if (this.onCollide != null) { this.onCollide(this, e) }
}
})
}
collider() {
return new SAT.Circle(new SAT.Vector(this.position.x, this.position.y), this.radius)
}
@@ -55,10 +44,14 @@ export default class Projectile {
this.game?.despawn(this)
}
setPosition(vector) {
this.position.copy(vector)
this.#calculateBbox()
}
update() {
this.#move()
this.#calculateBbox()
if (this.onCollide != null) { this.checkCollisions(this.collider()) }
this.#checkStationaryCollisions()
this.#checkIfArrived()
}
@@ -80,21 +73,41 @@ export default class Projectile {
this.despawn()
}
#checkStationaryCollisions() {
if (this.onCollide == null) { return }
const bbox = this.bbox
const entitiesAndTerrains = this.game?.entities ?? []
const bboxCheckedObstacles = entitiesAndTerrains.filter((it) => SATX.bboxCheck(bbox, it.bbox))
if (bboxCheckedObstacles.length > 0) {
const colliders = bboxCheckedObstacles.map((it) => it.colliders()).flat()
const collider = this.collider()
colliders.filter((it) => SATX.collideObject(collider, it)).forEach((it) => this.onCollide(this, it))
}
}
#move() {
if (this.destination == null) { return }
const speed = (this.speed / (this.game?.tickBudget ?? 1000))
const prevPos = this.position.clone()
if (this.position.distanceTo(this.destination) < speed) {
this.position.copy(this.destination)
this.setPosition(this.destination)
}
else {
const step = this.destination.clone().sub(this.position).normalize().multiplyScalar(speed)
this.position.add(step)
}
// TODO: decouple from entity's tunnel collider
const tunnel = Entity.tunnelCollider(prevPos.x, prevPos.y, this.position.x, this.position.y, this.radius)
if (this.onCollide != null) { this.checkCollisions(tunnel) }
if (this.onCollide != null) {
const bbox = Entity.tunnelBbox(position.x, position.y, destination.x, destination.y, this.radius)
const entitiesAndTerrains = this.game?.entities ?? []
const bboxCheckedObstacles = entitiesAndTerrains.filter((it) => SATX.bboxCheck(bbox, it.bbox))
if (bboxCheckedObstacles.length > 0) {
const colliders = bboxCheckedObstacles.map((it) => it.colliders()).flat()
const collider = Entity.tunnelCollider(prevPos.x, prevPos.y, this.position.x, this.position.y, this.radius)
colliders.filter((it) => SATX.collideObject(collider, it)).forEach((it) => this.onCollide(this, it))
}
}
}
}