Conceptualize Roguelike dungeon crawler components

Hi,

I am working on this program and have been going back and forth between different ways to conceptually structure the components.

Here is where I’ve landed – for now:

MapContainer holds an array of Squares
Square holds either a Creature, Item, Potion, or Landscape
----Each of those keeps track of its stats, in addition to a SquareDisplay
------SquareDisplay renders based on passed props from its parent

Does that make sense? See, I learned C++ back in the day and my objects were permanent things that kept track of their own properties. It is very confusing for me to think of React as rendering things that are more transient, and then re-rendering new ones that are the “same ones”.

If that structure makes sense, do I pretty much have to take the leap into Flux for storing the info? Otherwise it seems like I’d be passing a TON of props down through the chain.

I built this and the other 4 React projects without flux or anything else other than React and ReactDOM. I think that is completely sufficient.

Generally I’d say what you’ve laid out looks pretty good to me. Basically, my Dungeon map was one big array (like you described) in which each array item referred to a square on the map and contained information on what that square was currently in the game.

Whenever an action took place in the game, that array would be modified based on the action, updated in state, and then React would take care of updating the view of that array on the page (re-rendering the map).

The rest was basically just about me properly coding all the possible actions that could occur on the map.

My map was rendered in one child component so basically I just had to pass the map array data as a prop to the map component from the parent.

Thanks! I appreciate you laying out how you did it.

So, your array of components that each represented a square, that’s what I am basically describing. But does that mean that each square handled everything it would need to know whether it was an item, a monster, a sword, a wall, etc? How many props did your square component handle?

So the map array is just an array which is stored in the component’s state. Each item in the array represents a square on the map and the actual array value can represent what the square is, e.g. let’s say our map is only 5 squares:

mapData: [0, 0, 1, 0, 'player']

Here I’m using 0 to represent an empty square, 1 to represent an enemy square, and then player to represent the player’s location. You can use any values in this way.

I then pass this array as a single prop to my child component which is responsible for rendering it to the page. This component simply maps over the array and returns specific HTML for each array element, the HTML can be different based on the value stored in the array.

The size of this array is always the same, it’s values are modified as the player moves around. Whenever it is modified the new array is updated in the state and passed down and re-rendered.

So one array is stored in state, that one array is passed to a single child component responsible for rendering it.

Btw I’m sure there are other ways of solving this, this is just what I came up with and it seemed to work well!

I guess what I don’t understand is how you kept tracks of specifics. Say, a monster’s current health. Or, the name or strength value of a weapon. Rendering based on numbers with a switch statmeent or if/else doesn’t like it would handle that depth.

That was the limitation with my game. I used a simple array with numbers (0 for open space, 1 for wall, 2 for player, 3 for potion, etc.)
In that scenario, picking up a weapon increases your strength by a certain number. (so if you skip the first weapon and pick up the second, you don’t get as much strength as from picking up both) and enemy health is not specific to a particular enemy. Makes no sense, but at the time I didn’t figure out how to do it better without compromising speed. (constantly changing large arrays of objects is not very efficient.)

If I had to redo it, I would try creating a similar array but replacing the enemies and weapons with an object (so something like [0,0,0,1,0,0,2,1,0,{enemy object},0,{weapon object}…] while keeping the rest as numbers.

1 Like

I’ve been putting off this project myself, but I’ve given it some thought. What I would like to do is separate the map and the gamestate, making the map a two-dimensional array indicating whether something is a wall or just floor. I won’t touch this map - it must remain free of mutations. Its only purpose is to build the map on initial render. Items, monsters, and the player will be tracked in a gamestate controller component, and their location property (a tuple representing a coordinate) will be accessed on each render cycle to change the class of the square at that coordinate. I expect this to be much more efficient than having to iterate through an array just to change a few values, and I can be very selective about when the app renders (effectively being the exact opposite of my Game of Life project).

The problem is that I think about doing all of this, groan heavily, and go back to back end programming.

3 Likes

In my implementation of the game, I created a map generator, which generates the map (a grid, like you, with different cell types, extendable to whatever.) and functions to place objects on it. That gave me two arrays to deal with with react : the map and and the objects

It was then easy in react to make to object move on each turn (keypress). The moves where limited by the map array (walkabe, non walkable), and received penalties or bonuses, started a fight when meeting, …

The distinction of the map and the objects made things easier for me. (link to project and to map generator tests)

@PortableStick, that joins your idea.

2 Likes

Wow that’s very impressive!!

@mtancoigne Wow the implementation is amazing, beautiful work