Creating game like portable module - javascript

I want to create some game. Is it good, that my view on this game has to be like view on the module? It means, anywhere on the other website I want to run my game, I'll just put my module to it.
So, if we imagine "my view" like class, will it look some like this?
class Mario {
// Whole game module
class Game {
// Game properties
class Player {
}
class Card {
}
}
class Init {
// This take care about gui etc.
class Gui {
show_cards() {
}
}
}
start() {
var init = new Init();
something to init Gui and run method show_cards();
}
}
var mario = new Mario();
mario.start();
Am I right?
But is this syntax right in JavaScript and is this even possible?
Thanks for help!

If you want the extra awesomesauce of an HTML element you can drop into your page to hold your game code, you could make a custom element, but I bet you could get by just fine with a module.
As far as your code structure, this should help you out. It's a Game class template that utilizes separate Player and Resource classes -- and I stuck in a GameHandler class at the top for you (which would be like your Mario class.)
Happy coding!
class GameHandler {
constructor(){
this.handlerSetup();
const gameResources = [ // Array of resource objects for setResources method
{
type: "card",
number: 1,
},
{
type: "card",
number: 2,
options: { category: "A", description:"special" }
}
];
this.game = new Game(4, gameResources); // This can go in a loop to allow sequential games
}
handlerSetup(){ /* Do setup tasks here */ }
}
class Game {
constructor(playerCount, resourcesArray){
this.players = this.setPlayers(playerCount);
this.resources = this.setResources(resourcesArray);
this.winnerIfAny = null;
this.turnNumber = 0;
this.output("Ready to play");
// Main loop
while(this.winnerIfAny === null){
this.winnerIfAny = this.nextTurn(++this.turnNumber);
}
this.output(`Game over -- Player number ${this.winnerIfAny.number} wins`);
}
setPlayers(count){
let i = 0, players = [];
while(i < count){
players.push(new Player(i++));
}
this.output(`${count} players added`)
return players;
}
setResources(resourcesProvided){
let resources = [];
for(let resource of resourcesProvided){
resources.push(new Resource(resource));
}
this.output(`${resources.length} resources added`)
return resources;
}
nextTurn(turnNumber){
this.output("Taking turn...");
let winnerFound = null;
// Turn loop code goes here
// (eg switch to next player, take turn, check for winner
// This demo game is not very interesting -- it randomly assigns a winner
let rand = (Math.floor(Math.random() * (11 - turnNumber * 2)));
if (turnNumber > 1 && rand < 4) { winnerFound = this.players[rand]; }
if(winnerFound){ return winnerFound; }
return null;
}
output(text){ document.querySelector("#outputDiv").innerHTML += `${text}<br/>`; }
}
class Player {
constructor(number){
this.number = number;
//etc...
}
}
class Resource {
constructor(type, number, options){
this.number = number;
//etc...
}
}
new GameHandler();
<div id="outputDiv"></div>

Related

Fabric JS - UNDO & REDO optimization using JSON diff

Currently, I have implemented quite standard UNDO and REDO by using listeners to trigger canvas.getObjects() whose JSON output I store in a stack.
// Canvas modified listeners
canvas?.on('object:modified', onCanvasModifiedHandler)
canvas?.on('object:removed', onCanvasModifiedHandler)
canvas?.on('object:changed', onCanvasModifiedHandler)
When the user clicks undo and redo, we fetch JSON representation of the canvas from the stack and loads it using canvas?.loadFromJSON(json, () => { ... })
My problem is that it is quite inefficient to store the entire JSON representation of the canvas when the actual change is quite small. As a result, this approach causes my application to freeze for 500 milliseconds when the user clicks UNDO and REDO.
My proposed solution is to store only the JSON diff by using for example this package, although it is quite an undertaking. https://www.npmjs.com/package/jsondiffpatch
My question is if anyone has had this problem before, and how did you solve it in that case? Or if someone has any other ideas.
Inspired by this thread: https://bountify.co/undo-redo-with-2-canvases-in-fabric-js
I think you need to use the command pattern for this. It will be more efficient than using all JSON data. For that, you need to implement the next approach:
Create a class for storing History. It maybe looks like this
class CommandHistory {
commands = [];
index = 0;
getIndex() {
return this.index;
}
back() {
if (this.index > 0) {
let command = this.commands[--this.index];
command.undo();
}
return this;
}
forward() {
if (this.index < this.commands.length) {
let command = this.commands[this.index++];
command.execute();
}
return this;
}
add(command) {
if (this.commands.length) {
this.commands.splice(this.index, this.commands.length - this.index);
}
this.commands.push(command);
this.index++;
return this;
}
clear() {
this.commands.length = 0;
this.index = 0;
return this;
}
}
// use when you init your Canvas, like this.history = new CommandHistory();
Then you must implement the command classes for your commands.
For adding object
class AddCommand {
constructor(receiver, controller) {
this.receiver = receiver;
this.controller = controller;
}
execute() {
this.controller.addObject(this.receiver);
}
undo() {
this.controller.removeObject(this.receiver);
}
}
// When you will add object on your canvas invoke also this.history.add(new AddCommand(object, controller))
For removing object
class RemoveCommand {
constructor(receiver, controller) {
this.receiver = receiver;
this.controller = controller;
}
execute() {
this.controller.removeObject(this.receiver);
}
undo() {
this.controller.addObject(this.receiver);
}
}
The fabric.js has the saveState method for every object http://fabricjs.com/docs/fabric.Object.html#saveState. And you can use it for implementing the transform command, which will be added to the history object when you will modify your fabric object on the canvas.
class TransformCommand {
constructor(receiver, options = {}) {
this.receiver = receiver;
this._initStateProperties(options);
this.state = {};
this.prevState = {};
this._saveState();
this._savePrevState();
}
execute() {
this._restoreState();
this.receiver.setCoords();
}
undo() {
this._restorePrevState();
this.receiver.setCoords();
}
// private
_initStateProperties(options) {
this.stateProperties = this.receiver.stateProperties;
if (options.stateProperties && options.stateProperties.length) {
this.stateProperties.push(...options.stateProperties);
}
}
_restoreState() {
this._restore(this.state);
}
_restorePrevState() {
this._restore(this.prevState);
}
_restore(state) {
this.stateProperties.forEach((prop) => {
this.receiver.set(prop, state[prop]);
});
}
_saveState() {
this.stateProperties.forEach((prop) => {
this.state[prop] = this.receiver.get(prop);
});
}
_savePrevState() {
if (this.receiver._stateProperties) {
this.stateProperties.forEach((prop) => {
this.prevState[prop] = this.receiver._stateProperties[prop];
});
}
}
}
Now you can add your commands to your history and execute or undo them.

Passing arguments through multiple functions in Javascript

I'm currently writing a tic tac toe game in javascript, and I've written the following class to represents the "Computer".
I've included the entire class below, but the method I'm struggling with is atRiskSquare(). Here's how it's supposed to work: the method move() should get called with a board object, and then it should pass that board object into atRiskSquare() which checks whether any of the squares are at risk (in which case the computer would play a defensive move).
When I console.log the "board" inside of the move() method I get an array that represents the board. however, when I console.log the board inside of the atRiskSquare() method I get undefined. I'm not sure if I'm missing something simple, but I can't seem to figure out why this is happening.
Any help would be greatly appreciated
class Computer extends Player {
constructor() {
super();
}
static COMPUTER_MOVE = 'O';
move(board) {
console.log(board); // **Logs the board**
if (this.atRiskSquare(board)) {
this.defensiveMove(this.atRiskSquare(board));
} else {
this.randomMove(board, this.atRiskSquare());
}
}
atRiskSquare(board) {
console.log(board); // **logs undefined**
let humanMoves = board.findSpaces('X'); // Throws an error. Can't iterate over undefined
for (let winningCombo of Game.WINNING_COMBOS) {
let atRiskSquare;
let count;
for (let square of winningCombo) {
if (humanMoves.includes(square)) {
count += 1;
} else {
atRiskSquare = square;
}
}
if (count === 2) {
return atRiskSquare;
}
}
return null;
}
defensiveMove(board, square) {
board.addMove(square, Computer.COMPUTER_MOVE);
this.moves.push(square);
}
randomMove(board) {
let openSpaces = board.findSpaces(' ');
let randomSpace = Math.floor(Math.random() * openSpaces.length);
let move = openSpaces[randomSpace].toString();
board.addMove(move, Computer.COMPUTER_MOVE);
this.moves.push(move);
}
}

Can an instance of a type class object inherit a value of instance of a parent given in js?

I'm trying to make a program that allows you to calculate, how much a person on a students apartment, should pay for a invoice given.
At first I had created a Invoice and a Roomie classes and all worked just fine.
Continuing whit this, I had implemented the Apartment class, that has some property in it but a really important one for the logic of the program, the number of rooms.
The thing that I want to happen, is that you can create a instance of an Apartment (myHouse) and every time you add a Invoice gets the values of it.
class Apartment {
constructor(id, adress, numberOfRooms) {
this.id = id;
this.adress = adress;
this.numberOfRooms = numberOfRooms;
this.roomies = [];
this.invoices = [];
}
addRoomie(roomie) {
this.roomies.push(roomie);
}
addInvoice(invoice) {
this.invoices.push(invoice);
}
}
class Invoice {
constructor(total, type, begin, end) {
//Ask for this!
this.total = total;
this.type = type;
this.begin = begin;
this.end = end;
this.payed = false;
this.totalFractionated = this.totalPerPerson();
this.debtors = {};
}
totalPerPerson() {
const { begin, end, total, numberOfRooms } = this;
const difference = end.getTime() - begin.getTime();
const daysOfInterval = difference / (1000 * 60 * 60 * 24);
const totalPerDay = total / daysOfInterval;
return totalPerDay / 5; // This 5 I wanted to be numberOfRooms specify on the Aparment class
}
Of course that I can put the super method and everything, but I have to specify the values of the invoice (numberOfRooms) every time this way.
So, first thing, you shouldn't use inheritance here cause an Invoice isn't a specialized case of Apartment.
Said that, there are couple ways you can do this:
When you create an Invoice you pass the Apartment instance to the constructor so you can save it an refer it later as this.apartment.numberOfRooms
You can move the totalPerPerson method to the Apartment class and call it passing the index of the invoice you want as parameter, since seems like you're saving the invoices there
You can make a function that isn't part of any of those 2 classes and have it receive an instance of an Invoice and an instance of an Apartment as parameters
From experience, you might be missing some critical objects. Roomies have no relationship with an apartment whatsoever. You might be missing the Tenant class. Tenants occupy a room. Each tenant has a room instance, so you are also missing the room class. We can also make a room extend an apartment so that it can get its properties of the apartment which includes an address e.t.c. Each tenant in a room can have an invoice property if the monthly invoice will be splitted or each room can have an invoice property if the tenants decided together how to pay the rent every month. This will enable us have the following. Since pure JS does not have an abstract class, we will make an apartment a normal class.
class Apartment {
this.address = "1234 HackerWay, linux ln, 000000";
this.numberOfRooms = 20;
}
class Room extends Apartment {
constructor() {
super();
this.isOccupied = false;
this.tenants = [];
this.maximumTenantsAllowed = 2;
this._invoice = new Invoice();
}
addTenant(tenant) {
if(this.isFull) throw "Room at maximum capacity";
this.tenants.push(tenant);
}
get isFull() {
return this.tenants.length === this.maximumTenantsAllowed;
}
/// Returns the invoice object
get invoice() {
return this._invoice;
}
get numberOfTenants() {
return this.tenants.length;
}
}
class Tenant {
constructor(tenantName) {
this.name = tenantName;
this._invoice = new Invoice();
}
get Invoice() {
return this._invoice;
}
}
class Invoice {
generateInvoice(invoiceObject) {
if(invoiceObject instanceof Room) // write logic for Room
if(invoiceObject instanceof Tenant) // write logic for tenant
}
}
If there is a logic need to know if the apartment is full, create a RealEstateAgent class that keeps track of the apartment and modify the Room code as needed.
I didn't test the code. I only presented you a general idea.
I had earlier provided a OOP based answer that you can build on but it has limitations. Below is an algorithmic approach. This is just a framework that you can build on.
class Apartment {
constructor(name = "Apartment",address = "1234 HackerWay, linux ln, 000000") {
this.address = address;
this.name = name;
// This can also be a doubly linked list but for the sake of
// learning, we just use an array. A doubly linkedlist will allow
// us know which room is next to which within O(1) complexity.
// Keeping it in an array will cause at least O(n)
this.rooms = [
new Room(1),
new Room(2),
new Room(3),
new Room(4),
new Room(5),
];
}
// returns the first available room that is not filled
// to maximum capacity
get firstAvailableVacancy() {
return this.rooms.find((e) => !e.isFull);
}
// returns first empty room
get firstEmpty() {
return this.rooms.find((e) => e.isVacant);
}
findRoomByNumber(number) {
return this.rooms.find((e) => e.id === number);
}
get numberOfRooms() {
return this.rooms.length;
}
get hasVacancy() {
return Boolean(this.firstAvailableVacancy) || Boolean(this.firstEmpty);
}
get hasEmptyRoom() {
return Boolean(this.firstEmpty);
}
/// Or whatever algorithm for calculating cost
generateCostOfRoom(room) {
// algorithm to generate cost of room
}
// Adds tenant to room based on if they wish to have a
// co-tenant or not
addTenant(tenant) {
if (!this.hasVacancy) throw "No vacancy, check back again";
if (tenant.acceptsCoTenant) {
let vacantRoom = this.firstAvailableVacancy;
if (vacantRoom.hasTenant && vacantRoom.tenants[0].acceptsCoTenant) {
vacantRoom.addTenant(tenant);
this.generateCostOfRoom(vacantRoom);
tenant.room = vacantRoom;
return vacantRoom;
}
} else {
let vacantRoom = this.firstEmpty;
if (!vacantRoom)
throw "No vacancy, check back again or consider haviing a co-tenant";
vacantRoom.addTenant(tenant);
this.generateCostOfRoom(vacantRoom);
tenant.room = vacantRoom;
return vacantRoom;
}
}
}
class Room {
constructor(roomNumber) {
this.id = roomNumber;
this.tenants = [];
this.maximumTenantsAllowed = 2;
this._invoice = new Invoice();
this.cost = 0;
}
addTenant(tenant) {
if (this.isFull) throw "Room at maximum capacity";
this.tenants.push(tenant);
}
get isVacant() {
return this.tenants.length == 0;
}
get hasTenant() {
return this.tenants.length > 0;
}
get isFull() {
return this.tenants.length === this.maximumTenantsAllowed;
}
/// Returns the invoice object
get invoice() {
return this._invoice;
}
get numberOfTenants() {
return this.tenants.length;
}
}
class Tenant {
constructor(tenantName, acceptsCoTenant) {
this.name = tenantName;
this.acceptsCoTenant = acceptsCoTenant;
this.room = null;
this._invoice = new Invoice();
}
get Invoice() {
return this._invoice;
}
}
class Invoice {
generate(entity) {
if (entity instanceof Room) {
// Write logic. You can share the cost between tenants
}
if (entity instanceof Tenant) {
// Write logic. Divide tenant room cost by number of tenants in the room
}
}
}
let apartment = new Apartment();
apartment.addTenant(new Tenant("Michael", false));
apartment.addTenant(new Tenant("Joe", false));
apartment.addTenant(new Tenant("Mary", true));
apartment.addTenant(new Tenant("Turtle", true));
let room2 = apartment.findRoomByNumber(2);
console.log(room2.tenants);
if(room2.hasTenant) {
let tenant1 = room2.tenants[0];
console.log(tenant1.Invoice);
}

Creating x amount of new objects in Class Constructor with for loop and later modifying them in JavaScript

I am trying to create x amount of new Kitten() in the class constructor House and storing them in an object of objects this.kittens. But when I later try to modify this object of objects nothing happens or I get undefined. I am however able to modify another property/object of House, or more specifically the child class Playroom without any problems (this.exampleKitten) which was "created normally".
I do understand that the House constructor creates a new kittens object everytime it is called, however I would like for it to behave the same as exampleKitten, that is once it has been created I would like to be able to modify its contents. How can I achieve this? Is it bad practice to create and store x amount of new objects in a constructor the way I do?
I hope you understand my question! Thanks in advance!
class House {
constructor (numberOfKittens) {
this.numberOfKittens = numberOfKittens
this.kittens = function () {
const kitts = {}
for (let i = 0; i < this.numberOfKittens; i++) {
kitts[i] = new Kitten(`Kitten ${i}`)
}
return kitts
}
this.exampleKitten = {7: {name: "Jenny", favoriteToy: "dog"}}
}
}
class Playroom extends House {
constructor (numberOfKittens, kittens, exampleKitten) {
super(numberOfKittens, kittens, exampleKitten)
}
}
class Kitten {
constructor (name, favoriteToy) {
this.name = name
this.favoriteToy = favoriteToy
}
}
let p = new Playroom(15)
p.kittens()[0].name = "Does not work"
p.exampleKitten[7].name = "This does work"
I think you may be getting a little confused on how/when your kittens get generated vs how you interact with them.
The easier way to set this up is to create a function that will generate your kittens. Additionally, add another property that holds the kittens.
Given the below setup, once you 'new up' the Playroom, it will generate that amount of kittens and set your kittens property to the dataset.
You can then interact with the kittens by index by accessing your kittens property. ie Playroom.kittens[<index>].<property>
class House {
constructor(numberOfKittens) {
this.numberOfKittens = numberOfKittens
this.kittens = this.makeKittens(); // <-- Set a property for your kittens to live
this.exampleKitten = {
7: {
name: "Jenny",
favoriteToy: "dog"
}
}
}
makeKittens() { // Make a function that generates your kittens
const kitts = {};
for (let i = 0; i < this.numberOfKittens; i++) {
kitts[i] = new Kitten(`Kitten ${i}`);
}
return kitts;
}
}
class Playroom extends House {
constructor(numberOfKittens, kittens, exampleKitten) {
super(numberOfKittens, kittens, exampleKitten)
}
}
class Kitten {
constructor(name, favoriteToy) {
this.name = name
this.favoriteToy = favoriteToy
}
}
let p = new Playroom(15)
// p.makeKittens()[0].name = "Does not work"
// p.exampleKitten[7].name = "This does work"
console.log('Kitten Playroom', p);
console.log('First Kitten Name', p.kittens[0].name);
console.log('Updating First Kitten Name to "Frank"');
p.kittens[0].name = 'Frank';
console.log('First Kitten Name', p.kittens[0].name);
I would also suggest that updating any kittens by index as it's not readible and prone to error (index out of range, being off by one, etc...)
I would suggest adding a function similar to this:
updateKitten(idx, name) { // Or whatever you're wanting to update
const kitten = this.kittens[idx];
if (kitten) {
kitten.name = name;
return kitten;
}
throw new Error(`No kitten at index ${idx}`); // or return null or however you want to handle it
}
So the kittens() method is actually returning an object, but it is not assigning that object as the new value of kittens. What you have there is a factory, and you can use it to create separate instances if you want.
const house = new House()
const kittens1 = house.kittens()
const kittens2 = house.kittens()
kittens1[0] = oldKitten
kittens2[0] = newKitten
kittens1[0] // still oldKitten
If you want to manage only one instance at a time on the house object, I would rename your method addKittens() or something, and have the result assigned to this.kittens. Furthermore, I would use a native array instead of an object with indexes as keys. This will allow you to take advantage of all the powerful array methods js has to offer.
class House {
constructor() {
this.kittens = []
}
addKittens(numOfKittens) {
for (let i = 0; i < numOfKittens; i++) {
const newKitten = new Kitten(`Kitten ${i}`)
this.kittens.push(newKitten)
}
}
}

Javascript Object Composition with assign & Object.create

trying to wrap my head around javascript composition using assign. The property on my base object is unexpectedly being shared between instances. What am I doing wrong? I have...
Stat.js:
import assign from 'object-assign';
var Stat = assign({}, {
_value: undefined,
get: function() {
return this._value;
},
set: function(n) {
var max = this.getMax();
if(n > max) {
this._value = max;
} else {
this._value = n;
}
},
getMax: function() {
return 1;
}
});
module.exports = Stat;
HitPoints.js:
import assign from 'object-assign'
import Stat from './Stat.js';
var HitPoints = assign({}, Stat, {
getMax: function() {
return 100;
}
});
module.exports = HitPoints;
Unit.js:
import assign from 'object-assign';
import HitPoints from 'HitPoints.js';
var Unit = assign({}, {
hp: Object.create(HitPoints)
}
);
module.exports = Unit;
Usage:
import Unit from 'Unit.js';
var u1 = Object.create(Unit);
console.log( u1.hp.get() ); // undefined - ok
u1.hp.set(11);
console.log( u1.hp.get() ); // 11 - ok
var u2 = Object.create(Unit);
console.log( u2.hp.get() ); // 11 - ???
u2.hp.set(22);
console.log( u1.hp.get() ); // 22 - ???
console.log( u2.hp.get() ); // 22
Thanks for your help...
For starters, a quick example of why people don't want you using class.
I don't necessarily hate class, but 90% of the reason to use class is to get inheritance, and while it's occasionally helpful, it can frequently be very painful.
class Person { }
class ArmedPerson extends Person {
constructor (details) {
super(details);
const gun = new Gun();
this.equipment = { gun };
}
attack (target) {
this.equipment.gun.fireAt(target);
}
}
class Civilian extends Person { }
class ArmedCivilian extends ArmedPerson {
/* ... shouldn't it be extending Civilian?
Maybe all Civilians should be armed?
Is this why most games take place in the US?
*/
}
class Soldier extends ArmedPerson {
constructor (personDetails) {
super(personDetails);
}
}
class UnarmedSoldier extends Soldier {
/* HOW DO I TAKE HIS GUN AWAY? */
constructor (personDetails) {
super(personDetails);
}
attack () {
/* I know he has a gun, and anybody hacking the game can use it, but what do I do here? */
}
}
class inheritance has shown itself to be one of those things that people have misused terribly, for the past 30+ years (just like every other useful tool out there).
Rather than inheritance, we can look at composition (via Dependency Inversion).
class Soldier {
constructor (personDetails, gun) {
/*...setup...*/
this.equipment = { gun };
this.selectedWeapon = gun;
}
attack (target) {
this.selectedWeapon.fireAt(target);
}
}
const soldier = new Soldier({ /*...details... */ }, new Gun());
Not a lot has changed, in terms of the end-result we wanted... we've been able to simplify really a lot, and now we can even give him a method to swap guns if we want, all because rather than bolting the gun into something that he inherits from, we're handing him a gun when we first meet him.
It could be any type of gun we want, as long as it can still be fired in a similar fashion.
The question arises:
are there better ways of making things reusable, then, if inheritance is completely off the table?
To that I say: inheritance shouldn't be completely off the table... ...it should just be so far off to the side that it should be an "aha" moment, when you discover that it really is the best and cleanest way to accomplish something (rather than attempting to inherit from .......something, anything, right now!).
Various languages have a concept referred to as Traits or Mix-Ins.
In something like Java, a close-ish approximation is Interfaces.
I'm not a huge fan of Interfaces (the structure, not the concept - love the concept).
In Java, Interfaces make you do more work, because they have you define the function, what the function takes, what it returns...
...but you can't give it any default behaviour (traditionally), so if you have 14 objects which implement the same interface, that's the same method you write out 14 times (plus the signature for the interface). Sometimes, those methods are going to be completely different in the specifics of the implementation; that's fine... ...sometimes, they'll be the exact same as what you intended when you wrote the interface to begin with.
That's less okay. Queue Traits; these are things which you define the interface of, define the behaviour for, and then copy onto your object.
In JS, we can even have some closure safety around them, by injecting context that they get to work from, rather than letting them assume they get to mess around with the entirety of this.
const Movable = (pos) => ({
up (distance) { pos.y += distance; },
down (distance) { pos.y -= distance; },
left (distance) { pos.x -= distance; },
right (distance) { pos.x += distance; }
});
class Point {
constructor (x, y) {
Object.assign(this, { x, y });
}
}
class Person {
constructor (position) {
Object.assign(this, { position }, Movable(position));
}
}
const person = new Person( new Point(0, 0) );
person.up( 20 );
person.position.y; // 20
If you'll note, Movable is returning a new instance of an object, with methods which change values on position. That object is having its methods copied onto the instance of person.
I can now create as many of these Traits as I'd like, and copy them onto as many objects as I'd like, and get reuse that way.
Well, this worked...
Stat.js:
var Stat = {
get: function() {
return this._value;
},
set: function(n) {
var max = this.getMax();
if(n > max) {
this._value = max;
} else {
this._value = n;
}
},
getMax: function() {
return 1;
}
}
HitPoints.js:
var HitPoints = function() {
return assign(Object.create(Stat), {
getMax: function() {
return 100;
}
});
}
Unit.js:
var Unit = function() {
return assign({},
Object.create(XYPiece),
Object.create(TeamMember),
{
hp: HitPoints()
}
);
}
Usage:
var u1 = Unit();
console.log( u1.hp.get() ); // undefined
u1.hp.set(11);
console.log( u1.hp.get() ); // 11
var u2 = Unit();
console.log( u2.hp.get() ); // undefined
u2.hp.set(22);
console.log( u1.hp.get() ); // 11
console.log( u2.hp.get() ); // 22
This article helped. Hooray!!!
Still, tho, if this is fundamentally an idiotic way to go about it, tell me...

Categories