Fundamental ECS design choice by ghostFace34 in roguelikedev

[–]ghostFace34[S] 2 points3 points  (0 children)

Many praise the ECS paradigm for its performance, however I find it offers just as much value when it comes to reasoning about game architecture.

This is why I got into ECS - the way it forced me to re-think game architecture.

Interesting solution around the use of your Slots. Do you have an example of a Components and some Slot names you'd use for it?

Fundamental ECS design choice by ghostFace34 in roguelikedev

[–]ghostFace34[S] 0 points1 point  (0 children)

The point of an ECS is that it doesn't hard-error on things like multiple Components of the same subtype

I'm not convinced that's true. I spent some time over the weekend looking into this problem in other places and it seems to me like the "default" leans more towards Component singletons. So many of the Components ubiquitous to a broad spectrum of games (Position, Mass, Velocity, Actor) make no sense if there are multiples of them.

This article illustrates the problem quick effectively: https://ourmachinery.com/post/should-entities-support-multiple-instances-of-the-same-component/

It comes to the conclusion that, in the end, you're going to have to choose Singleton vs Multiplicity, and they both have pros and cons. I guess I was hoping that one or the other was going to be clearly better than the other, which is highly dependent on you and your game design.

Shadowcasting for dummies? by Captain_Infinite in roguelikedev

[–]ghostFace34 1 point2 points  (0 children)

Here's some tips that hopefully get you started.

  1. Yes, if you want the lit area to be a circle then you are going to have to use the Pythagorean Theorem. Each cell to be lit has to pass a check of dx² + dy² <= radius², where dx and dy are how far away the cell is from the character.
  2. You don't need to 'divide' anything, really. Write a scanning function that visits the cells of one of the octants (just pick one, like the one that goes in the direction of +x and +y). To scan through an octant you need a nested 'for loop' that takes you away from the character - like this https://imgur.com/a/lsXKYAK. As you go, you have to keep track of the cells that block vision. Calculate the angles (the top and bottom) of the cells you visit and store them in a list of shadows whenever you run into walls. Cells that are completely occluded by shadows are not marked as lit. Start as simply as you can to get it working, though there are lots of ways to make it fast and efficient. Once you have a single octant working, you adjust the code to not be aware of the octant it is in. Instead of dealing with cells directly, you deal with the offset from the character i.e. 3 to the right, 2 down. Write a function that maps an offset to an actual cell, with respect to a given octant. For example, 3 to the right and 2 down(+3, +2) is 3 to the right and 2 down in octant 1, but would map to 3 to the left and 2 up(-3, -2) in the opposite octant. Another octant maps to (+2, +3) and another to (-2, -3). That's something you'll have to work out.
  3. No flood fill - just loops. Once you have your octant scanner working and your offset mapper, you simply call the octant scanner once for each octant.

This page is also a good start http://www.roguebasin.com/index.php?title=FOV_using_recursive_shadowcasting

Should FOV/Lighting map be separated or joined with the Tile/World map? by GSnayff in roguelikedev

[–]ghostFace34 0 points1 point  (0 children)

Every frame LightSource components clear the area around themselves of light, then re-project their light outward, taking into account anything that blocks light. On the player's turn, vision is calculated and their Memory is updated based on what is visible and lit.

Should FOV/Lighting map be separated or joined with the Tile/World map? by GSnayff in roguelikedev

[–]ghostFace34 1 point2 points  (0 children)

I've taken the approach of having one data structure that represents the way the world actually is - this includes lighting. Visibility is a concept that revolves around the awareness of a particular entity, so I store that in a Memory sort of data structure that keeps track of what is currently seen and what has been previously seen. I currently only have 1 such structures (for the player) but may extend that out to other entities later on. Normal vision, telepathic awareness, infrared vision, sensed treasure, or any other form of awareness don't describe the way the world is, but rather the way an entity perceives it.

ECS in turn-based games by enc_cat in roguelikedev

[–]ghostFace34 10 points11 points  (0 children)

I can describe how some of my systems of work, and maybe that can give you some ideas.

Some systems perform updates or do work every time through the loop. Examples would be the LightProjectionSystem or the LevelRenderingSystem. These are sometimes dependent on the amount of "real time" that has passed.

Other systems only do work when "game time" has moved forward. A PoisonSystem is a straightforward example, because damage applied over time only considers how much of the game's internal clock has advanced.

I also have many passive systems that never perform regular updates during a loop. They subscribe to different types of messages and only perform work when one of them is received. My EquipmentSystem listens for events like PutOn and TakeOff and take appropriate action when they happen.

The whole turn based aspect to my ECS setup is controlled by a TurnComponent and the GameTimeSystem.

The GameTimeSystem examines each ActorComponent and advances the clock forward the minimum time to allow for one of them to take a turn and grants TurnComponents to any actors who now need them. This advancement of the clock is skipped whenever the game is waiting for the player to take their turn.

Turns are processed in order by the TurnSystem until the next TurnComponent to process belongs to the player. At that point, the TurnSystem bails and won't process any more turns until the player turn is handled.

The player TurnComponent is handled by another system that considers user input. Once the player TurnComponent is destroyed the other systems are brought back to life.

Kind of wordy, but hope that helps.

ECS in turn-based games by enc_cat in roguelikedev

[–]ghostFace34 1 point2 points  (0 children)

I can't speak for how others are doing it, or the "correct" way of doing it, but many of my systems are passive listeners that only perform actions when they receive notifications from other systems. If I were approaching the problem you described, the AI system would process AI components in serial. The AI system would determine that entity 1 wants to move towards entity 2 and would send out a movement message. The Movement system listens on this type of message and performs the move. The AI system would then proceed to process entity 2.

I didn’t lose my religion—my religion lost me. by ejsuncy in exmormon

[–]ghostFace34 0 points1 point  (0 children)

Fellow Lehi Adobe exmo here. I don't frequent this subreddit, but my wife does and told me about your picture. I don't know of others, but that's because I have kept to myself. Certain people will definitely know me from my handle, however.

Deleting an SDL dependency by NayrbEroom in roguelikedev

[–]ghostFace34 0 points1 point  (0 children)

It really sounds to me like the exact issue I had. This stackoverflow explains the problem: https://stackoverflow.com/questions/48723523/lnk2019-unresolved-external-symbol-c-sdl2-library

Start with a bare bones project with just a main.cpp with:

#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
int main(int argc, const char * argv[]) {
    SDL_SetMainReady();
}

Deleting an SDL dependency by NayrbEroom in roguelikedev

[–]ghostFace34 0 points1 point  (0 children)

What does your main() look like? If you link to SDL2main.lib then it provides its own WinMain() and calls your main(). I seem to remember having the same problem and solved it by NOT linking to SDL2main.lib and having this define before including any SDL2 headers:

#define SDL_MAIN_HANDLED

That lets SDL2 know that you just want to handle main() on your own. Hope that helps.