What are folks doing to integrate some OOP design into their Screeps code?
Background: I'm an experienced systems programmer but I'm brand new to Javascript, and it's not immediately clear to me how to integrate JS classes efficiently with the existing Screeps classes. I've been playing around in the console a bit and it seems like we can't just write class MyCreep extends Creep { ... } sadly, which is exactly what I want to do.
I've been thinking about this in the back of my mind for a few days and I think a good construct would be class MyCreep { constructor(creep_id) { ... } } where all the properties are just setters/getters to/from the creep's memory, then wherever I deal with MyCreep objects if I want to invoke a true Creep method (moveTo, etc...) I'll just have to go through a special method/property like MyCreep.creep which would return the true Creep. Kind of like this:
class MyCreep {
creep;
constructor(creep_id) { this.creep = Game.getObjectById(creep_id); }
get memory() { return this.creep.memory; }
get target() { return Game.getObjectById(this.memory.target_id); }
set target(target_object) { this.memory.target_id = target_object.id; }
myMoveTo(target_object) {
this.target = target_object;
// other state adjustments...
}
Then I could use them like this:
var john = new MyCreep(Game.creeps['John Galt'].id);
john.myMoveTo(john.creep.room.controller);
My biggest concern with this method is that MyCreep objects require the apparently superfluous creep member, and I have to actually allocate them with new - I would have to resort to _.forEach(Game.creeps, (creep) => {new MyCreep(creep.id)}) each tick. The systems side of me is triggered by the dynamic allocations incurred by the calls to new MyCreep(). At a high level there is no real extra state I need to capture that isn't already in the Creep object itself to which I already have a reference. I find myself inclined to find a way to run MyCreep methods directly on true Creep objects, where this can refer to the Creep itself. I'd want to use something like in the following pseudocode in-place of new:
new_MyCreep(creep_id) {
var creep = Game.getObjectById(creep_id);
return (MyCreep) creep; // indicates my desire for a "conversion" from Creep to MyCreep
}
In my naiivete, I see this as avoiding the extra allocation of a dedicated MyCreep object, which now can just operate directly on the API-allocated Creep object. I would then like to use _.forEach(Game.creeps, new_MyCreep) (instead of new MyCreep()) and then use instances of MyCreep to invoke true Creep methods as well as MyCreep methods, like:
var john = new_MyCreep(Game.creeps['John Galt'].id);
john.myMoveTo(john.room.controller);
I've seen various people mess with .prototype but I am unable refer to Creep.prototype in the Screeps console and creep_instance.prototype is undefined, so I've given up on pursuing that lead.
I'm not well-versed enough in JS to know how dumb this all sounds, so please share your thoughts. Is my first method fine, and I'm just overestimating how expensive the extra new calls are? Is the second method even possible? What do you do?
Cheers!
Fritz