Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trouble with Swap #32

Closed
majonathany opened this issue Sep 29, 2019 · 5 comments
Closed

Trouble with Swap #32

majonathany opened this issue Sep 29, 2019 · 5 comments

Comments

@majonathany
Copy link

majonathany commented Sep 29, 2019

Hi,

I am trying to build a game that has entities. Upon changing the level, there is a new main character, a new maze, and a new goal. I presume that to change entities for the Game Engine component I have to use swap(), but I can't seem to find the object that possesses this method. I've looked through some of the other posts and I tried to place refs inside the component and then to call it, but it doesn't seem to update my components, or it produces a can't find swap from undefined object error.

How do I use the swap() method, or any other method to switch out the entities?

This is my GameEngine component:

<GameEngine
         systems={[this.physics, this.updateGame]}
         entities={this._getEntities()}
         style={{paddingLeft: widthWindow * .05}}
         running={this.state.running}
         ref="engine"
         onEvent={this.handleEvent}
>
                </GameEngine>

And this is my swap use case at the bottom:

updateGame = (entities, {touches}) => {
        let move = touches.find(x => x.type === 'move');

        if (move) {
            // if (move.delta.pageX + move.delta.pageY > 3) {
            //     return entities;
            // }

            let newX = this.state.currentBall.position.x + move.delta.pageX;
            let newY = this.state.currentBall.position.y + move.delta.pageY;

            const newPosition = {x: newX, y: newY};
            Matter.Body.setPosition(this.state.currentBall, newPosition);

        }

        if (this.state.notTransitioning) {
            var collision = Matter.SAT.collides(
                this.state.currentBall,
                this.state.currentGoal);
            if (collision.collided) {

                this._addObjectsToWorld();
                let engine = Matter.Engine.create({enableSleeping: false});
                let world = engine.world;

                this.setState({
                    engine: engine,
                    world: world,
                });

                Matter.World.add(this.state.world, [
                    this.state.currentMaze,
                    this.state.currentBall,
                    this.state.currentGoal])

                this.refs.engine.swap(this._getEntities())

                this.setState({  // -- GameEngine 'running' property gets this state
                    running: true
                });

            }
        }
        return entities;
    };

Thanks!!!

@bberak
Copy link
Owner

bberak commented Sep 29, 2019

Hi @majonathany,

Hmm, that's interesting. I've never really tried to call swap from within a system to be honest, that's not where my head was going when I designed the component (not saying it's wrong or anything).

The swap method is on the GameEngine component itself. Perhaps I should also make it an argument that gets passed into the systems - I'll have a think about it. In any case, here's how it was designed to be used:

const updatePhysics = (entities) => {
	/* DO PHYSICS STUFF */
	
	return entities;
}

const updateGame = (entities, { touches, dispatch }) => {

	if ( /* SOME CONDITION */ ) {
		dispatch({ type: "game-over"});
	}

	return entities;
}

const getEntities = () => {
	return { /* SOME ENTITIES */ };
};

export default class App extends React.Component {

	handleEvent = (ev) => {
		if (ev.type === "game-over")
			this.refs.engine.swap(getEntities());
	};

	render() {
		return (
			<GameEngine
				systems={[updatePhysics, updateGame]}
				entities={getEntities()}
				style={{ paddingLeft: widthWindow * 0.05 }}
				running={this.state.running}
				ref="engine"
				onEvent={this.handleEvent}
			/>
		);
	}
}

Let me know if that helps!

@majonathany
Copy link
Author

Wow, this worked!!! I was just missing the dispatch() method. Thanks for the prompt response! This is helpful information. I am new to all the libraries and JavaScript.

So, just a few questions - the methods that you have outside the class definition are systems, right? Can they go inside the class or do they have to defined outside the class? I know these are functions that you describe in the systems prop.

Also, for their parameters (entities, {touches, dispatch}), what function is passing these parameters? Where is entities, touches and dispatch coming from? Is it correct to say that they are keys that are essentially passed in as dictionaries that the GameEngine automatically provides? How do I know what other parameters these systems can support?

@bberak
Copy link
Owner

bberak commented Oct 1, 2019

Glad it helped @majonathany!

I personally define the systems outside of the class definition because eventually, when your game becomes more complex, the number of systems will increase to the point where you will bloat your class.

I also find that keeping the systems outside of the class will stop the temptation to access class variables or properties. Systems should be treated almost as pure functions, and should only act on the provided entities and read/use the supplied args. The library provides ways to facilitate communication between your class and your systems (using the dispatch method as an example).

Finally, keeping your systems separate from your class will allow you to re-use your systems in other projects (via an npm module perhaps) and platforms (I've recently released a similar game engine for the web.

And yep, you are correct, the GameEngine supplies the entities and other args for the systems. This is what the second parameter (args) into the system calls contains:

let args = {
      touches,
      screen,
      events,
      dispatch,
      time
    };

Hope that helps!

@majonathany
Copy link
Author

This is immensely helpful. Where can I find an exhaustive list of the types of parameters that systems can take, besides entities and the five args? Is there anything else that a system can accept?

Finally, does the React Native Game Engine supply these programming interfaces, or did someone else pick those 5 arguments and determine what the inputs to those arguments would be?

@bberak
Copy link
Owner

bberak commented Oct 8, 2019

Hi @majonathany,

These two parameters (entities, args) are supplied by the React Native Game Engine because I felt that they are general enough to be used in a lot of cases. I will expand them as required - but no immediate plans.

A useful pattern that I've used in my recent games is to write a system that injects other properties and functions into the args that I know will be useful by the subsequent systems. This can be things like a controller interface or whatever might be useful for your games. See this system for an example.

Hope that helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants