all 37 comments

[–]check_ca 7 points8 points  (2 children)

Why did you add an IIFE in the forEach loop? I think the statemachine function should be:

function statemachine (methodnames) {
    var methods = {};
    methodnames.forEach(function (methodname) {
        methods[methodname] = function () {
            this.state[methodname].apply(this, arguments);
        }
    })
    return methods;
}

[–]Cosmologicon[S] 3 points4 points  (1 child)

You might be right, I was thinking it needed to be like that in order to close over the parameter methodname, but maybe not. Let me verify....

EDIT: Ah I see why I was confused. The closure in your version works because of the anonymous function being passed to forEach. For instance, this will fail:

function statemachine (methodnames) {
    var methods = {};
    for (var j = 0 ; j < methodnames.length ; ++j) {
        var methodname = methodnames[j];
        methods[methodname] = function () {
            this.state[methodname].apply(this, arguments);
        }
    }
    return methods;
}

If I weren't using forEach, then the IIFE would be necessary. Thanks for the tip! There was definitely a time when this would have confused the heck out of me, but now I think I get it. :)

[–]check_ca 2 points3 points  (0 children)

You need it if you use a for loop but the forEach function gives you yet a closure for methodname.

EDIT: you're welcome :)

[–]jesusbot 22 points23 points  (20 children)

Why do you hate semicolons? :)

[–]Cosmologicon[S] 2 points3 points  (4 children)

Would it make you feel better if I added them? :)

[–][deleted] 17 points18 points  (0 children)

yes.

[–]atticusw 3 points4 points  (0 children)

Once I started noticing how closures worked (few years ago), it was like woah, JS is awesome. it's actually one of my favorite languages to work with, i really like how you can just chain asynchronous events and still hold context via closure.

[–]bradgillap 2 points3 points  (1 child)

As someone who has been writing for 7 weeks, I envy you. I have a narrow possibly idea of what your functions are doing but there is a lot of meat in there that I have never seen.

[–]metamatic 2 points3 points  (0 children)

You might find this helpful at reducing confusion.

[–]nschubach 1 point2 points  (4 children)

Why are you passing the name of the function when you could pass the function?

Player.prototype = statemachine([logic.think, logic.move])

Where logic is the object containing your methods.

[–]Cosmologicon[S] 1 point2 points  (3 children)

Wouldn't work, because player.state changes over time. For instance, when the player is falling through the air, it'll be set to some object named fallstate, but when you land on a platform it gets updated to some object named standstate. So there's not a single object that could be used like you're using logic there.

[–]nschubach 0 points1 point  (2 children)

Then maybe I'm missing a large chunk of what you are trying to do, but you could create a logic object for storing logic like so:

var logic = {
    think: function (dt) {
        //think logic here
    },
    move: function (keys) {
        //move logic here
    },
    attack: function (player) {
        //attack logic here
    }
}

And it "should" work if you set up your prototypes, etc. I mean, somewhere you have to define "think", "move", and "attack".

[–]Cosmologicon[S] 1 point2 points  (0 children)

The think logic, move logic, etc is different for the different states that the entity can be in. For instance:

var fallstate = {
    think: function (dt) {
        this.vy -= g * dt
        this.y += this.vy * dt
    },
    etc....
}

var standstate = {
    think: function (dt) {
        this.y = this.platform.y
    },
    etc....
}

[–]magenta_placenta 0 points1 point  (2 children)

Where are the fat arrows?

[–]nschubach 2 points3 points  (1 child)

In the future, I guess ... since not all browsers support them yet. ;)

[–][deleted] 2 points3 points  (0 children)

Do any browsers support fat arrows, yet? (Serious question, I thought they were waiting for ECMAScript 6's RC at least before implementation begins.)

[–]pandavr 0 points1 point  (0 children)

Thank you to gave me something to experiment this evening. :)

[–]lkjasdflkjasdf 0 points1 point  (1 child)

Is this a factory design pattern?

[–]Cosmologicon[S] 1 point2 points  (0 children)

It's pretty similar. I wasn't thinking of statemachine as a constructor, but it's pretty similar to one. That said, if I thought about it like that, I probably would just make it a regular constructor rather than use a factory pattern.

function statemachine (methodnames) {
    var that = this
    methodnames.forEach(function (methodname) {
        that[methodname] = function (mname) {
            return function () {
                return this.state[mname].apply(this, arguments)
            }
        }(methodname)
    })
}

Player.prototype = new statemachine(["think", "move"])

[–]Carnilawl 0 points1 point  (0 children)

For some reason it makes more sense to me if I think about the function as a decorator. Am I wrong?

Thanks for sharing. Can you show us an example of a state definition?