How to switch states from interaction (input) with game object

I’m working on a little project using Phaser 3 and I’ve run into a problem. I have two sprites that are interactable, and I want it to change the player state depending on which is pressed. The items don’t move, I think of them as button that are set in another scene that is being launched.

So far my attempts have yielded only more questions about the logic.

export let ToolSelectScene = new Phaser.Class({
    Extends: Phaser.Scene,
    initialize: function (config) {
        Phaser.Scene.call(this, { key: "ToolSelectScene" })
    },
    init: () => {
        console.log("tool select scene initialized")  
    },
    preload: function () {
    this.load.multiatlas('items', 'assets/items.json', 'assets');
    },
    create: function () {
        this.gameScene = this.scene.get("GameScene")
        this.player = this.gameScene.players.getChildren()[0]

        this.weaponSlot1 = this.add.sprite(120,37,"items", "swordsprite.png").setInteractive()
        this.weaponSlot2 = this.add.sprite(150,37,"items", "firesprite.png").setInteractive()

        this.input.on("gameobjectdown", (pointer, object) => {
            console.log(object.frame.name)
            if(object.frame.name == "swordsprite.png") {
                this.player.playerStateMachine.transition("useSword", object)
            }
            if (object.frame.name == "firesprite.png") {
                console.log("use fire")
                this.player.playerStateMachine.transition("useFire", object)
            }
        })
    },
    update: function () {
    }
})

So when I run the code, the state changes but then something funny happens, the first state continues to be active while the second state has started. I’ve implemented a state machine, originally had written it like this but all in state code, and using the rexUI plugins.

I have state machines for each entity, which handles all the animation and input.

How can I get this work properly?

I wrote this post on stackoverflow, but I thought I’d post it here as well.

If anyone has any advice on how to do this or any critiques and hints, I’d very much appreciate it. :slight_smile:

I don’t know how your state machine works, but my guess is that it doesn’t play nicely with scenes. The state has probably changed (it’s pretty useless if it can be in 2 states at once), but whatever that previous state has started won’t stop.

Oh I got it work. I wasn’t turning off the gameobjectdown event, or at least I think thats why its working. Thanks anyway though! I did it in the state machine and it worked.

    this.toolSelectScene = scene.scene.get("ToolSelectScene")
    this.toolSelectScene.input.on("gameobjectdown", (pointer, object) => {
      if (object.frame.name == "swordsprite.png") {
        scene.input.off("gameobjectdown")
        this.stateMachine.transition("useSword")
      }
      if (object.frame.name == "firesprite.png") {
        scene.input.off("gameobjectdown")
        this.stateMachine.transition("useFire")
      }
    })

That’s pretty much exactly what I said :slight_smile:

I may have misunderstood what you were referring to. I apologize about that, learning these things have been quite confusing.

Even though I have seem to my have found a solution, I feel I have gaps in my understanding with phaser and javascript in general, especially with events and listeners.

Why and how should I be using events, and the on and off functions and when to use them? Should I be emitting events and would that help the situation if I learn to properly use them? Why is it when I use the scene.get(“ToolSelectScene”), some variables work and others comeback as undefined? Just thought i’d get some questions out there to help with the progress, I hope its not a hassle. :slight_smile: I appreciate the help!

This should be easy. If you don’t understand scope, stop everything until you do :slight_smile: In this case, the scene doesn’t know these variables.

Combining a state machine with event driven logic is a nightmare. Each state should be pretty much atomic, and not be influenced by outside events. So the safest solution would be to have only 1 scene running per state.

I like having a global EventEmitter, just because it’s easy. Not sure how it’s relevant for your situation (though maybe you could use it to signal running scenes when there is a state transition) . There’s a difference between event-listeners for input and using an emitter for event-driven logic.

1 Like