collapse Effect into Ability
This commit is contained in:
+98
-33
@@ -1,48 +1,113 @@
|
|||||||
import Effect from './effect.js'
|
import Projectile from './projectile.js'
|
||||||
|
|
||||||
|
// Q: damage -> self sustain / crowd control
|
||||||
|
// W: control -> mobility
|
||||||
|
// E: support -> vision / selfless support / creative
|
||||||
|
|
||||||
export default class Ability {
|
export default class Ability {
|
||||||
id = crypto.randomUUID()
|
id = crypto.randomUUID()
|
||||||
name = 'Ability'
|
name = 'Ability'
|
||||||
cooldown = 0
|
|
||||||
castTime = 0
|
castTime = 0
|
||||||
|
cooldown = 0
|
||||||
|
damage = 0
|
||||||
|
radius = 1
|
||||||
|
range = 0
|
||||||
|
speed = 1000
|
||||||
|
|
||||||
#effect = () => {}
|
#effect = () => {}
|
||||||
|
|
||||||
get effect() { return this.#effect }
|
get effect() { return this.#effect }
|
||||||
set effect(value) { this.#effect = value }
|
set effect(value) { this.#effect = value }
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options = {}) {
|
||||||
if (options.name != null) { this.name = options.name }
|
Object.entries(options).forEach(([key, value]) => this[key] = value)
|
||||||
if (options.effect != null) { this.#effect = options.effect }
|
|
||||||
if (options.cooldown != null) { this.cooldown = options.cooldown }
|
|
||||||
if (options.castTime != null) { this.castTime = options.castTime }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static basicAttack(range, radius, speed) {
|
static straightShot = new Ability({
|
||||||
return new this({
|
id: 'straight_shot',
|
||||||
name: 'Basic Attack',
|
name: 'Straight Shot',
|
||||||
castTime: 0.25,
|
castTime: 0.1,
|
||||||
cooldown: 1.25,
|
cooldown: 7,
|
||||||
effect: Effect.homingProjectile({
|
damage: 10,
|
||||||
range,
|
radius: 7,
|
||||||
radius,
|
range: 800,
|
||||||
speed,
|
speed: 3000,
|
||||||
after: Effect.damage({ despawn: true }).bind(this),
|
effect: function straightShotEffect(caster, cursor) {
|
||||||
}),
|
const ability = this
|
||||||
})
|
const straightShotCollision = function straightShotCollision(projectile, collidingEntity) {
|
||||||
}
|
collidingEntity.damage(ability.damage)
|
||||||
|
projectile.despawn()
|
||||||
|
}
|
||||||
|
|
||||||
static straightShot(range, radius, speed) {
|
const projectile = new Projectile({
|
||||||
return new this({
|
onCollide: straightShotCollision,
|
||||||
name: 'Straight Shot',
|
owner: caster,
|
||||||
castTime: 0.1,
|
position: caster.position.clone(),
|
||||||
cooldown: 7,
|
radius: ability.radius,
|
||||||
effect: Effect.skillshot({
|
speed: ability.speed,
|
||||||
range,
|
})
|
||||||
radius,
|
|
||||||
speed,
|
projectile.destination = caster.position.clone().add(cursor.clone().sub(caster.position).normalize().multiplyScalar(ability.range))
|
||||||
onCollide: Effect.damage({ despawn: true }).bind(this)
|
caster.game?.spawnProjectile(projectile)
|
||||||
}),
|
caster.cooldown(ability.id)
|
||||||
})
|
},
|
||||||
}
|
})
|
||||||
|
|
||||||
|
static basicAttack = new Ability({
|
||||||
|
id: 'basic_attack',
|
||||||
|
name: 'Basic Attack',
|
||||||
|
castTime: 0.25,
|
||||||
|
cooldown: 1.25,
|
||||||
|
damage: 5,
|
||||||
|
radius: 5,
|
||||||
|
range: 600,
|
||||||
|
speed: 600,
|
||||||
|
effect: function basicAttackEffect(caster, cursor) {
|
||||||
|
const ability = this
|
||||||
|
let closest = null
|
||||||
|
let distance = Infinity
|
||||||
|
caster.game?.entities.filter((e) => e.id != caster.id && e.position.clone().sub(caster.position).length() < ability.range).forEach((e) => {
|
||||||
|
const newDistance = e.position.clone().sub(cursor).length() < distance
|
||||||
|
if (newDistance < distance) {
|
||||||
|
closest = e
|
||||||
|
distance = newDistance
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (closest == null) { return }
|
||||||
|
|
||||||
|
const basicAttackAfter = function basicAttackAfter() {
|
||||||
|
closest.damage(ability.damage)
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectile = new Projectile({
|
||||||
|
after: basicAttackAfter,
|
||||||
|
homingTarget: closest,
|
||||||
|
owner: caster,
|
||||||
|
position: caster.position.clone(),
|
||||||
|
radius: ability.radius,
|
||||||
|
speed: ability.speed,
|
||||||
|
})
|
||||||
|
|
||||||
|
caster.game?.spawnProjectile(projectile)
|
||||||
|
caster.cooldown(ability.id)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
static control = new Ability({
|
||||||
|
id: 'control',
|
||||||
|
name: 'Control',
|
||||||
|
castTime: 1,
|
||||||
|
cooldown: 5,
|
||||||
|
effect: function controlEffect() { console.log('Control is still work in progress.') },
|
||||||
|
})
|
||||||
|
|
||||||
|
static shieldThrow = new Ability({
|
||||||
|
id: 'shield_throw',
|
||||||
|
name: 'Shield Throw',
|
||||||
|
castTime: 0.1,
|
||||||
|
cooldown: 7,
|
||||||
|
effect: function shieldThrowEffect() { console.log('Shield throw is still work in progress.') },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import { Vector2 } from 'three'
|
|
||||||
import Projectile from './projectile.js'
|
|
||||||
|
|
||||||
export default class Effect {
|
|
||||||
static damage({ despawn }) {
|
|
||||||
return function(projectile, entity) {
|
|
||||||
entity.damage(10, this)
|
|
||||||
if (despawn) {
|
|
||||||
projectile.despawn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static skillshot({ range, radius, speed, onCollide, after }) {
|
|
||||||
return function(cursor) {
|
|
||||||
const projectile = new Projectile()
|
|
||||||
const destination = this.position.clone().add(cursor.clone().sub(this.position).normalize().multiplyScalar(range))
|
|
||||||
projectile.owner = this.id
|
|
||||||
projectile.position.copy(this.position)
|
|
||||||
projectile.destination = destination
|
|
||||||
projectile.radius = radius
|
|
||||||
projectile.speed = speed
|
|
||||||
projectile.after = after
|
|
||||||
projectile.onCollide = onCollide
|
|
||||||
this.game?.spawnProjectile(projectile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static homingProjectile({ range, radius, speed, onCollide, after }) {
|
|
||||||
return function(cursor) {
|
|
||||||
let closest = null
|
|
||||||
let distance = Infinity
|
|
||||||
this.game?.entities.filter((e) => e.id != this.id && e.position.clone().sub(this.position).length() < range).forEach((e) => {
|
|
||||||
const newDistance = e.position.clone().sub(cursor).length() < distance
|
|
||||||
if (newDistance < distance) {
|
|
||||||
closest = e
|
|
||||||
distance = newDistance
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (closest == null) { return } // TODO: refund
|
|
||||||
|
|
||||||
const projectile = new Projectile()
|
|
||||||
projectile.owner = this.id
|
|
||||||
projectile.position.copy(this.position)
|
|
||||||
projectile.homingTarget = closest
|
|
||||||
projectile.radius = radius
|
|
||||||
projectile.speed = speed
|
|
||||||
projectile.after = after
|
|
||||||
projectile.onCollide = onCollide
|
|
||||||
this.game?.spawnProjectile(projectile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+22
-11
@@ -11,10 +11,10 @@ export default class Entity {
|
|||||||
health = 1 // TODO: health can go into negatives and can go over maxHealth
|
health = 1 // TODO: health can go into negatives and can go over maxHealth
|
||||||
maxHealth = 1
|
maxHealth = 1
|
||||||
abilities = [
|
abilities = [
|
||||||
Ability.basicAttack(600, 5, 600),
|
Ability.basicAttack,
|
||||||
Ability.straightShot(800, 7, 3000),
|
Ability.straightShot,
|
||||||
() => {},
|
Ability.control,
|
||||||
() => {},
|
Ability.shieldThrow,
|
||||||
]
|
]
|
||||||
casting = null
|
casting = null
|
||||||
// TODO: teams
|
// TODO: teams
|
||||||
@@ -30,8 +30,8 @@ export default class Entity {
|
|||||||
return new SAT.Circle(new SAT.Vector(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(([key, value]) => this[key] = value)
|
||||||
}
|
}
|
||||||
|
|
||||||
get game() { return this.#game }
|
get game() { return this.#game }
|
||||||
@@ -82,11 +82,7 @@ export default class Entity {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.casting.ability.effect.bind(this)(this.casting.cursor)
|
this.casting.ability.effect(this, this.casting.cursor)
|
||||||
|
|
||||||
if (this.casting.ability.cooldown != null) {
|
|
||||||
this.cooldowns[this.casting.ability.id] = timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
this.casting = null
|
this.casting = null
|
||||||
return true
|
return true
|
||||||
@@ -123,6 +119,10 @@ export default class Entity {
|
|||||||
return entityColliders.concat(terrainColliders)
|
return entityColliders.concat(terrainColliders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cooldown(id) {
|
||||||
|
this.cooldowns[id] = this.game?.currentTick ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
damage(amount, source = null) {
|
damage(amount, source = null) {
|
||||||
this.health = Math.min(Math.max(0, this.health - amount), this.maxHealth)
|
this.health = Math.min(Math.max(0, this.health - amount), this.maxHealth)
|
||||||
}
|
}
|
||||||
@@ -213,6 +213,17 @@ export default class Entity {
|
|||||||
this.cast()
|
this.cast()
|
||||||
this.takeStep()
|
this.takeStep()
|
||||||
this.fixPosition()
|
this.fixPosition()
|
||||||
|
if (this.health <= 0) {
|
||||||
|
if (this.id == '1' || this.id == '2') {
|
||||||
|
this.health = this.maxHealth
|
||||||
|
if (this.id == '1') {
|
||||||
|
this.teleport(200, 200)
|
||||||
|
}
|
||||||
|
if (this.id == '2') {
|
||||||
|
this.teleport(1800, 1800)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waypoints() {
|
waypoints() {
|
||||||
|
|||||||
+4
-3
@@ -32,8 +32,8 @@ export default class Projectile {
|
|||||||
this.#homingTarget = value
|
this.#homingTarget = value
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(...options) {
|
constructor(options = {}) {
|
||||||
Object.entries(options).forEach((value, key) => this[key] = value)
|
Object.entries(options).forEach(([key, value]) => this[key] = value)
|
||||||
}
|
}
|
||||||
|
|
||||||
get game() { return this.#game }
|
get game() { return this.#game }
|
||||||
@@ -44,10 +44,11 @@ export default class Projectile {
|
|||||||
set x(value) { this.position.x = value }
|
set x(value) { this.position.x = value }
|
||||||
set y(value) { this.position.y = value }
|
set y(value) { this.position.y = value }
|
||||||
set destination(value) { this.#dest = value }
|
set destination(value) { this.#dest = value }
|
||||||
|
set position(value) { this.#position = value }
|
||||||
|
|
||||||
checkCollisions() {
|
checkCollisions() {
|
||||||
(this.game?.entities ?? []).filter((e) => e.id != this.id).forEach((e) => {
|
(this.game?.entities ?? []).filter((e) => e.id != this.id).forEach((e) => {
|
||||||
if (e.id == this.owner) { return }
|
if (e.id == this.owner?.id) { return }
|
||||||
|
|
||||||
if (SATX.collideObject(this.collider, e.collider)) {
|
if (SATX.collideObject(this.collider, e.collider)) {
|
||||||
this.onCollide(this, e)
|
this.onCollide(this, e)
|
||||||
|
|||||||
Reference in New Issue
Block a user