bberak / react-native-game-engine

A lightweight Game Engine for React Native 🕹⚡🎮
MIT License
2.87k stars 172 forks source link

How to Pass parameters into a Renderer #33

Closed majonathany closed 4 years ago

majonathany commented 4 years ago

Hi,

Thanks for the help with my previous question! I have a simpler question this time around. I am trying to do the following where I pass parameters to a renderer in order to change what images appears:

_getEntities = () => {
    if (this.state.currentLevel === 1) {
        return {
            physics: {engine: this.state.engine, world: this.state.world},
            currentItem: {
                body: this.state.currentItem,
                renderer: Character({body: this.state.currentItem, typeName: "currentItem"})},
            recycleBin: {
                body: this.state.bins.recycleBin,
                renderer: Character({body: this.state.bins.recycleBin, typeName: "recycleBin"})},
            trashCan: {
                body: this.state.bins.trashCan,
                renderer: Character({body: this.state.bins.trashCan, typeName: "trashCan"})}
        };
    }
};

The above code doesn't work. It seems that we pass the class instead of instances of the class. The following is a copy of the renderer file. What do you think I should do to pass options into the renderer class?

const Character = ({ body, typeName }) => {
  const {position} = body;

  const x = position.x;
  const y = position.y;

  if (typeName === "item") {
    return <Image
        source={paperBall}
        style={[styles.head, {left: x, top: y,}]}
    />;
  }
  else if (typeName === "trashCan")
  {
    return <Image
        source={trashCan}
        style={[styles.head, {left: x, top: y,}]}
    />;
  }
  else if (typeName === "recycleBin")
  {
      return <Image
          source={recycleBin}
          style={[styles.head, {left: x, top: y,}]}
      />;
  }

};
bberak commented 4 years ago

Hi @majonathany,

The renderer for each entity should be instantiated properly, and passed all the properties of its parent entity via the props object.

I think you're close/on the right track:

_getEntities = () => {
    if (this.state.currentLevel === 1) {
        return {
            physics: {engine: this.state.engine, world: this.state.world},
            currentItem: {
                body: this.state.currentItem,
                typeName: "currentItem",
                renderer: Character,
            recycleBin: {
                body: this.state.bins.recycleBin,
                typeName: "recycleBin",
                renderer: Character,
            trashCan: {
                body: this.state.bins.trashCan,
                typeName: "trashCan",
                renderer: Character
        };
    }
};

Your Character code should not require any change. That said, it's worth noting that your Character functional component will be re-rendered on each frame because functional components are harder to optimize than classes (I believe this shortcoming can be alleviated in the recent versions fo React). React classes give you the ability to inherit from PureComponent or provide an additional shouldComponentUpdate lifecycle method that allows you to help React determine whether a component should be re-renderered or not. Might not be worth worying about now, but just keep it in mind if you need to optimize for performance in the future..

Let me kow if that helps!

majonathany commented 4 years ago

Thank you so much @bberak. I'm working on a project for a client that involves three games and has a bunch of database backend stuff. This library has saved my life and was pretty much the only option. This issue is resolved. Do you think I should keep it open if I have more questions or close this issue?

bberak commented 4 years ago

Awesome @majonathany, I'm glad it has helped! Would love to hear more about your project when it is completed or has been released.. All the best with the rest of the development, and don't hesitate to open another issue if required (I'm going to close this one out to keep things organised).