make projectiles use bounding boxes too
This commit is contained in:
+4
-2
@@ -38,7 +38,8 @@ export default class Ability {
|
|||||||
const ability = this
|
const ability = this
|
||||||
const straightShotCollision = function straightShotCollision(projectile, collidingEntity) {
|
const straightShotCollision = function straightShotCollision(projectile, collidingEntity) {
|
||||||
if (collidingEntity == null) { return }
|
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)
|
collidingEntity.damage(ability.damage, caster)
|
||||||
projectile.despawn()
|
projectile.despawn()
|
||||||
@@ -181,7 +182,8 @@ export default class Ability {
|
|||||||
const ability = this
|
const ability = this
|
||||||
const exposeCollision = function exposeCollision(projectile, collidingEntity) {
|
const exposeCollision = function exposeCollision(projectile, collidingEntity) {
|
||||||
if (collidingEntity == null) { return }
|
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)
|
collidingEntity.applyBuff(Buff.exposed.id, caster.id)
|
||||||
projectile.despawn()
|
projectile.despawn()
|
||||||
|
|||||||
+22
-9
@@ -25,6 +25,7 @@ export default class Entity {
|
|||||||
visualRadius = null
|
visualRadius = null
|
||||||
|
|
||||||
#attacking = false
|
#attacking = false
|
||||||
|
#colliders = []
|
||||||
#dest = null
|
#dest = null
|
||||||
#game = null
|
#game = null
|
||||||
#logic = null
|
#logic = null
|
||||||
@@ -123,6 +124,8 @@ export default class Entity {
|
|||||||
if (this.visualRadius == null) {
|
if (this.visualRadius == null) {
|
||||||
this.visualRadius = this.radius
|
this.visualRadius = this.radius
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.#calculateCollider()
|
||||||
}
|
}
|
||||||
|
|
||||||
get attacking() { return this.#attacking }
|
get attacking() { return this.#attacking }
|
||||||
@@ -256,11 +259,11 @@ export default class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
collider() {
|
collider() {
|
||||||
return Entity.collider(this.position.x, this.position.y, this.radius)
|
return this.#colliders.at(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
colliders() {
|
colliders() {
|
||||||
return [this.collider()]
|
return this.#colliders
|
||||||
}
|
}
|
||||||
|
|
||||||
cooldown(id) {
|
cooldown(id) {
|
||||||
@@ -329,7 +332,10 @@ export default class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fixPosition() {
|
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) {
|
fixFuturePosition(futurePosition) {
|
||||||
@@ -400,14 +406,18 @@ export default class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
respawn() {
|
respawn() {
|
||||||
this.position = this.#spawnPosition.clone()
|
this.setPosition(this.#spawnPosition)
|
||||||
this.health = this.maxHealth
|
this.health = this.maxHealth
|
||||||
this.dead = false
|
this.dead = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPosition(vector) {
|
||||||
|
this.position.copy(vector)
|
||||||
|
this.#calculateCollider()
|
||||||
|
}
|
||||||
|
|
||||||
teleport(cursor) {
|
teleport(cursor) {
|
||||||
this.position = cursor.clone()
|
this.setPosition(this.fixFuturePosition(cursor))
|
||||||
this.fixPosition()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
@@ -425,8 +435,6 @@ export default class Entity {
|
|||||||
if (this.#logic != null) {
|
if (this.#logic != null) {
|
||||||
this.#logic()
|
this.#logic()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#calculateBbox()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
waypoints() {
|
waypoints() {
|
||||||
@@ -456,6 +464,11 @@ export default class Entity {
|
|||||||
this.bbox[3] = this.position.x - this.radius
|
this.bbox[3] = this.position.x - this.radius
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#calculateCollider() {
|
||||||
|
this.#calculateBbox()
|
||||||
|
this.#colliders = [Entity.collider(this.position.x, this.position.y, this.radius)]
|
||||||
|
}
|
||||||
|
|
||||||
#cast() {
|
#cast() {
|
||||||
if (this.casting == null) {
|
if (this.casting == null) {
|
||||||
return false
|
return false
|
||||||
@@ -574,7 +587,7 @@ export default class Entity {
|
|||||||
this.rotation = rotation
|
this.rotation = rotation
|
||||||
|
|
||||||
if (!this.willCollide(position)) {
|
if (!this.willCollide(position)) {
|
||||||
this.position.copy(position)
|
this.setPosition(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.position.equals(destination)) {
|
if (this.position.equals(destination)) {
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ export default class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (after - before > tickBudget) {
|
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}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-16
@@ -125,25 +125,28 @@ function laneScenario() {
|
|||||||
new Vector2(9136, 8248),
|
new Vector2(9136, 8248),
|
||||||
].map((p) => p.multiplyScalar(1.6))
|
].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) {
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: topRoute })))
|
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: midRoute })))
|
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: topRoute })))
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: botRoute })))
|
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: midRoute })))
|
||||||
|
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: botRoute })))
|
||||||
|
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: topRoute.toReversed() })))
|
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: topRoute.toReversed() })))
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: midRoute.toReversed() })))
|
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: midRoute.toReversed() })))
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: botRoute.toReversed() })))
|
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 % (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 })))
|
||||||
|
|
||||||
|
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: topRoute.toReversed() })))
|
||||||
|
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: midRoute.toReversed() })))
|
||||||
|
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: botRoute.toReversed() })))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([(3 * game.tickRate), (4 * game.tickRate), (5 * game.tickRate)].includes(game.currentTick % (30 * 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 })))
|
|
||||||
|
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: topRoute.toReversed() })))
|
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: midRoute.toReversed() })))
|
|
||||||
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: botRoute.toReversed() })))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
game.logic = gameLogic
|
game.logic = gameLogic
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-17
@@ -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() {
|
collider() {
|
||||||
return new SAT.Circle(new SAT.Vector(this.position.x, this.position.y), this.radius)
|
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)
|
this.game?.despawn(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPosition(vector) {
|
||||||
|
this.position.copy(vector)
|
||||||
|
this.#calculateBbox()
|
||||||
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
this.#move()
|
this.#move()
|
||||||
this.#calculateBbox()
|
this.#checkStationaryCollisions()
|
||||||
if (this.onCollide != null) { this.checkCollisions(this.collider()) }
|
|
||||||
this.#checkIfArrived()
|
this.#checkIfArrived()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,21 +73,41 @@ export default class Projectile {
|
|||||||
this.despawn()
|
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() {
|
#move() {
|
||||||
if (this.destination == null) { return }
|
if (this.destination == null) { return }
|
||||||
|
|
||||||
const speed = (this.speed / (this.game?.tickBudget ?? 1000))
|
const speed = (this.speed / (this.game?.tickBudget ?? 1000))
|
||||||
const prevPos = this.position.clone()
|
const prevPos = this.position.clone()
|
||||||
if (this.position.distanceTo(this.destination) < speed) {
|
if (this.position.distanceTo(this.destination) < speed) {
|
||||||
this.position.copy(this.destination)
|
this.setPosition(this.destination)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const step = this.destination.clone().sub(this.position).normalize().multiplyScalar(speed)
|
const step = this.destination.clone().sub(this.position).normalize().multiplyScalar(speed)
|
||||||
this.position.add(step)
|
this.position.add(step)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: decouple from entity's tunnel collider
|
if (this.onCollide != null) {
|
||||||
const tunnel = Entity.tunnelCollider(prevPos.x, prevPos.y, this.position.x, this.position.y, this.radius)
|
const bbox = Entity.tunnelBbox(position.x, position.y, destination.x, destination.y, this.radius)
|
||||||
if (this.onCollide != null) { this.checkCollisions(tunnel) }
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user