fix projectiles colliding with dead entities
This commit is contained in:
+34
-19
@@ -217,47 +217,62 @@ export default class Ability {
|
||||
name: 'Shield Throw',
|
||||
castTime: 0.25,
|
||||
cooldown: 5,
|
||||
damage: 90,
|
||||
deceleratePerTick: 90,
|
||||
radius: 110,
|
||||
range: 1025,
|
||||
speed: 2400,
|
||||
effect: function shieldThrowEffect(caster, cursor) {
|
||||
const ability = this
|
||||
const amount = ability.damage
|
||||
let onTheWayBack = false
|
||||
let collided = new Set()
|
||||
|
||||
const accelerateLogic = function accelerateLogic() {
|
||||
const projectile = this
|
||||
projectile.speed += ability.deceleratePerTick
|
||||
const shieldThrowCollision = function shieldThrowCollision(projectile, collidingEntity) {
|
||||
if (collidingEntity == null) { return }
|
||||
if (collidingEntity.id == caster.id) { return }
|
||||
if (caster.team == null || collidingEntity.team == null || collidingEntity.team != caster.team) { return }
|
||||
const entityId = collidingEntity.id
|
||||
|
||||
if (!collided.has(entityId)) {
|
||||
collidingEntity.heal(amount, caster)
|
||||
collided.add(entityId)
|
||||
}
|
||||
}
|
||||
|
||||
const decelerateLogic = function decelerateLogic() {
|
||||
const projectile = this
|
||||
const accelerateLogic = function accelerateLogic(projectile) {
|
||||
if (onTheWayBack) {
|
||||
projectile.speed += ability.deceleratePerTick
|
||||
}
|
||||
else {
|
||||
if (projectile.speed - ability.deceleratePerTick >= ability.deceleratePerTick) {
|
||||
projectile.speed = projectile.speed - ability.deceleratePerTick
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const shieldThrowReturn = function shieldThrowReturn(projectile, homingTarget) {
|
||||
const returnProjectile = new Projectile({
|
||||
homingTarget: caster,
|
||||
logic: accelerateLogic,
|
||||
owner: caster.id,
|
||||
position: projectile.position.clone(),
|
||||
radius: ability.radius,
|
||||
speed: ability.deceleratePerTick,
|
||||
visionRange: ability.radius,
|
||||
})
|
||||
const shieldThrowSecondAfter = function shieldThrowSecondAfter(projectile, homingTarget) {
|
||||
caster.heal(amount, caster)
|
||||
caster.heal(amount, caster) // NOTE: duplicated on purpose
|
||||
}
|
||||
|
||||
caster.game?.spawnProjectile(returnProjectile)
|
||||
const shieldThrowFirstAfter = function shieldThrowFirstAfter(projectile, homingTarget) {
|
||||
projectile.destination = null
|
||||
projectile.homingTarget = caster
|
||||
onTheWayBack = true
|
||||
collided.clear()
|
||||
projectile.after = shieldThrowSecondAfter
|
||||
}
|
||||
|
||||
const projectile = new Projectile({
|
||||
after: shieldThrowReturn,
|
||||
logic: decelerateLogic,
|
||||
after: shieldThrowFirstAfter,
|
||||
logic: accelerateLogic,
|
||||
onCollide: shieldThrowCollision,
|
||||
owner: caster.id,
|
||||
position: caster.position.clone(),
|
||||
radius: ability.radius,
|
||||
speed: ability.speed,
|
||||
visionRange: ability.radius,
|
||||
visionRange: ability.radius * 1.5,
|
||||
})
|
||||
|
||||
projectile.destination = caster.position.clone().add(cursor.clone().sub(caster.position).normalize().multiplyScalar(ability.range + caster.radius))
|
||||
|
||||
+8
-3
@@ -177,6 +177,7 @@ export default class Entity {
|
||||
this.moveAction(cursor, true)
|
||||
}
|
||||
|
||||
// TODO: buffer skill inputs
|
||||
castAction(slot, cursor, halt = false) {
|
||||
if (this.dead) { return }
|
||||
|
||||
@@ -295,10 +296,13 @@ export default class Entity {
|
||||
this.cooldowns[id] = this.game?.currentTick ?? 0
|
||||
}
|
||||
|
||||
closestTargetTo(cursor, range) {
|
||||
closestTargetTo(cursor, range, targetAllies = false) {
|
||||
const entities = this.game?.entities
|
||||
if (entities == null) { return }
|
||||
const targetsInRange = entities.filter((it) => this.team != it.team && it.distanceTo(cursor) <= range + this.radius + it.radius)
|
||||
const targetsInRange = targetAllies
|
||||
? entities.filter((it) => this.team == it.team && it.distanceTo(cursor) <= range + this.radius + it.radius)
|
||||
: entities.filter((it) => this.team != it.team && it.distanceTo(cursor) <= range + this.radius + it.radius)
|
||||
|
||||
if (targetsInRange.length < 1) { return }
|
||||
|
||||
const absoluteClosestTarget = targetsInRange.reduce((e1, e2) => (e1?.distanceTo(cursor) ?? Infinity) < e2.distanceTo(cursor) ? e1 : e2, null)
|
||||
@@ -321,6 +325,7 @@ export default class Entity {
|
||||
return entitiesAndTerrains.filter((it) => !it.dead && it.collision && !((this.ghosting && it.ghostable) || (this.ghostable && it.ghosting)) && SATX.bboxCheck(bbox, it.bbox))
|
||||
}
|
||||
|
||||
// TODO: add shielding logic
|
||||
damage(amount, source = null) {
|
||||
if (this.dead) { return }
|
||||
|
||||
@@ -399,7 +404,7 @@ export default class Entity {
|
||||
return this.buffs.some((it) => it.id == id) && this.game?.buffs.some((it) => it.id == id)
|
||||
}
|
||||
|
||||
heal(amount) {
|
||||
heal(amount, _source) {
|
||||
if (this.dead) { return }
|
||||
|
||||
this.health = Math.min(Math.max(0, this.health + amount), this.maxHealth)
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ export class Dungeon {
|
||||
game.addTerrain(new Terrain([new Vector2(2000, 1500), new Vector2(2500, 1000), new Vector2(2500, 1500)], false))
|
||||
game.spawnEntity(new Entity(Template.player({ id: '6', spawnPosition: new Vector2(2400, 1400), team: enemy, logic: castQ })))
|
||||
|
||||
game.spawnEntity(new Entity(Template.player({ id: '1', spawnPosition: new Vector2(1500, 700), team, dead: true })))
|
||||
game.spawnEntity(new Entity(Template.player({ id: '2', spawnPosition: new Vector2(200, 1300), team, health: 10 })))
|
||||
game.spawnEntity(new Entity(Template.player({ id: '1', spawnPosition: new Vector2(200, 1300), team, health: 10 })))
|
||||
game.spawnEntity(new Entity(Template.player({ id: '2', spawnPosition: new Vector2(1500, 700), team, dead: true })))
|
||||
|
||||
game.spawnEntity(new Entity(Template.basilisk({ id: 'boss', spawnPosition: new Vector2(2200, 750), team: Team.neutral })))
|
||||
|
||||
|
||||
+5
-2
@@ -123,6 +123,9 @@ export default class Projectile {
|
||||
this.#after(this, this.#homingTarget)
|
||||
}
|
||||
|
||||
if (this.destination == null) { return }
|
||||
if (!this.position.equals(this.destination)) { return }
|
||||
|
||||
this.despawn()
|
||||
}
|
||||
|
||||
@@ -131,7 +134,7 @@ export default class Projectile {
|
||||
|
||||
const bbox = this.bbox
|
||||
const entitiesAndTerrains = this.game?.entities ?? []
|
||||
const bboxCheckedObstacles = entitiesAndTerrains.filter((it) => SATX.bboxCheck(bbox, it.bbox))
|
||||
const bboxCheckedObstacles = entitiesAndTerrains.filter((it) => !it.dead && SATX.bboxCheck(bbox, it.bbox))
|
||||
if (bboxCheckedObstacles.length > 0) {
|
||||
const collider = this.collider()
|
||||
const colliding = bboxCheckedObstacles.filter((it) => it.colliders().some((c) => SATX.collideObject(collider, c)))
|
||||
@@ -155,7 +158,7 @@ export default class Projectile {
|
||||
if (this.#onCollide != null) {
|
||||
const bbox = Entity.tunnelBbox(prevPos.x, prevPos.y, this.position.x, this.position.y, this.radius)
|
||||
const entitiesAndTerrains = this.game?.entities ?? []
|
||||
const bboxCheckedObstacles = entitiesAndTerrains.filter((it) => SATX.bboxCheck(bbox, it.bbox))
|
||||
const bboxCheckedObstacles = entitiesAndTerrains.filter((it) => !it.dead && SATX.bboxCheck(bbox, it.bbox))
|
||||
if (bboxCheckedObstacles.length > 0) {
|
||||
const collider = Entity.tunnelCollider(prevPos.x, prevPos.y, this.position.x, this.position.y, this.radius)
|
||||
const colliding = bboxCheckedObstacles.filter((it) => it.colliders().some((c) => SATX.collideObject(collider, c)))
|
||||
|
||||
Reference in New Issue
Block a user