Skip to content

Instantly share code, notes, and snippets.

@Larkenx
Last active December 27, 2018 05:18
Show Gist options
  • Save Larkenx/139b4215089deeff38d2599686be72a1 to your computer and use it in GitHub Desktop.
Save Larkenx/139b4215089deeff38d2599686be72a1 to your computer and use it in GitHub Desktop.
JavaScript multiple inheritance / mixins for game development (entity component systems inspired) - mixin implementation from http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/
import { Entity } from '#/entities/Entity.js'
import { itemTypes, equipmentSlots, ammoTypes } from '#/utils/Constants';
import { mix } from '#/utils/Mixins'
import { Stackable, Equippable, AmmunitionTyped, Fireable } from './ItemMixins';
export default class Item extends Entity {
constructor(options) {
super(options)
this.category = options.category || itemTypes.MISCELLANEOUS
this.description = options.description || []
}
}
export class Arrow extends mix(Item).with(Stackable, Equippable, AmmunitionTyped) {
constructor(configuration) {
super({
equipmentSlot: equipmentSlots.AMMO,
ammoType: ammoTypes.ARROW,
...configuration
})
}
}
export class Bow extends mix(Item).with(Equippable, AmmunitionTyped, Fireable) {
constructor(configuration) {
super({
equipmentSlot: equipmentSlots.WEAPON,
ammoType: ammoTypes.ARROW,
...configuration
})
}
}
import { ammoTypes } from "#/utils/Constants";
export const Stackable = superclass => class extends superclass {
constructor(configuration) {
super(configuration)
if (!configuration.equipmentSlot) console.warn(`Defaulting to stackable quantity of 1 for stackable item: ${this}!`)
this.quantity = configuration.quantity || 1
}
}
export const Equippable = superclass => class extends superclass {
constructor(configuration) {
super(configuration)
if (!configuration.equipmentSlot) throw `Unable to create equippable item without equipment slot: ${this}!`
this.equipmentSlot = configuration.equipmentSlot
}
}
export const Consumable = superclass => class extends superclass {
constructor(configuration) {
super(configuration)
if (!configuration.use) throw `Unable to create consumable item without "use" function: ${this}!`
this.use = configuration.use
}
}
export const Fireable = superclass => class extends superclass {
constructor(configuration) {
super(configuration)
if (!configuration.range) console.warn(`No maximum firable range set for this item: ${this}`)
this.cb.range = configuration.range || null
this.cb.ranged = true
}
}
export const AmmunitionTyped = superclass => class extends superclass {
constructor(configuration) {
super(configuration)
if (!configuration.ammoType) console.warn(`No ammunition type specified for this item, assuming it can be fired with anything: ${this}`)
this.ammoType = configuration.ammoType || ammoTypes.ANY
}
}
export const mix = superclass => new MixinBuilder(superclass)
class MixinBuilder {
constructor(superclass) {
this.superclass = superclass
}
with(...mixins) {
return mixins.reduce((c, mixin) => mixin(c), this.superclass)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment