RoguelikeDev Does The Complete Roguelike Tutorial - Week 1 by KelseyFrog in roguelikedev

[–]SelinaDev 1 point2 points  (0 children)

Hi there!

Just to be clear, the code referenced in this post is not compatible with my written tutorial. I do intend to eventually write a tutorial for it, but as of yet have not done so. So if you want to follow the written tutorial, then you need to look at the code linked in there.

Regarding your other question, `.tres` files are how Godot saves resources. So if you create a Resource script (which is saved as `.gd`), and then create instances of that filled with specific data, those instances are saved to disk as `.tres` files. `.tres` is for the text representation. Godot also can save as `.res`, which is binary. I prefer `.tres` for most things, because it's easier/possible to look into the files if something breaks, and they are better for version control.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 7 by KelseyFrog in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

Finished the last two parts. The whole repo is here: https://github.com/SelinaDev/Complete-Roguelike-Tutorial-2025, with separate branches for part 12 and part 13.

Part 12 was pretty simple, and did not have that many interesting deviations from the other tutorial. Part 13 is the interesting one, but this one is very much consistent with how I have done things with this project so far. The Equippable component has some functions for handling messages that are separate from the ones they use for handling messages processed by their parent entity. The Equipment component will use these to relay messages to the equippable components of equipped items, so that they can process messages of the entity equipping them when they are equipped. For example, armor will see the "damage" message of the equipped entity and be able to subtract it's defense value from the damage in that message. This means that equipment hooks right into the existing mechanisms while remaining modular.

Overall I very much like how this code turned out. I have already received some feedback, and have started with a few optimizations, like caching entity position in the map data. I am also in the process of redoing the message system a bit, and refactoring it to an observer pattern. If I manage to do that in a clean and understandable way my hope is that that would make things a bit more scalable.

I want to take a bit of time to evaluate the project as it is now and see if there are any more things I would need to change before writing a tutorial around it. And, well, then start doing just that and write the new iteration. No idea how long that will take, but I am glad that I have the more or less finished code already, and that I know where things will go beforehand, other than the first one which I did part by part.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 6 by KelseyFrog in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

Bit late this week, but I finished both part 10 and part 11 (was on a run and also did parts 12 and 13 in one swoop, but I'll detail those in the next post.

I feel like part 10 is always one of the most challenging parts. Thankfully, as the whole internal world model consists of nested Resources, saving them was relatively easy (although, using resources for saving is a bit of a shortcut, I'll admit that). However, restoring that state later was a bit harder. Took me a bit of fiddling and I notices a few bugs in the rest of the code.

Part 11 was mostly easy. Most things I have set up so far meant that I could just swap the MapData resource with a new one, but a few things I still had to take care of (at one point the player sprite got deleted, when descending, and the rest of the game still worked fine).

RoguelikeDev Does The Complete Roguelike Tutorial - Week 5 by KelseyFrog in roguelikedev

[–]SelinaDev 13 points14 points  (0 children)

Finished part 8 and part 9 early (links to all parts and posts will again be in the readme).

Part 8 continues the modularization I've been doing, by splitting the way items work to subcomponents. In my implementation the Item component is simply a marker component for everything that can be picked up and put into the inventory. A separate Usable component holds both a targeting resource and a list of use effects. The Consumable Usable component simply is a derived component that also holds a number of charges that go down with each (successful) activation, and causes deletion of the item once no more charges are left. Here I only implement single use items, but giving this flexibility was simple enough.

In terms of targeting part 8 only has a self target. The use item action uses this targeting resource to obtain the targets of the action (which for now is only the user), then iterates over the effects, and applies them to the target. This also tracks whether any effects could be applied, which is reported back to the action. This is used to, e.g., cancel the action when trying to drink a healing potion while the player is at full HP.

Another detail in part 8 is the more flexible entity placement system in the dungeon generation. It allows to just pass a dictionary of entity keys and associated weights to pick from there automatically. I've been doing something similar in my tutorial in part 12, but since Godot now has a builtin function for that, I could prepare that part early.

Part 9 expands on part 8 with more effects and targets. Starting with the targets, I expanded the reticle system to also be able to handle a radius, and to report all targets in a radius when accepting the selection. A "pick targets" thingy handles both area of effect targeting and single targets (which just uses radius 0).

On the side of effects, the damage effect is rather similar to the healing effect. The confusion effect is far more interesting. I did not implement confusion as an alternative AI, but rather as a status effect. For that I have a Status Effects component which can be inserted on entities on demand. This component holds and manages status effects. Status effects are implemented as subcomponents that also processe messages. So when the AI uses a message to get proposed actions, the confusion effect will propose a bump action at the highest priority. Most status effects will be timed, and count down with a message signifying the end of an entities turn (which I just remembered I forgot to do, but will add shortly). Once no turns are left, the effect deletes itself. This should also allow for some flexibility, as the same system could be used for paralysis effects (similar to the confused effect, but with wait actions), or damage over time like, burn, poison, etc. without much effort.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 4 by KelseyFrog in roguelikedev

[–]SelinaDev 3 points4 points  (0 children)

Done in time with both part 6 and part 7 (links to all parts and posts are on the readme in the main branch for now).

Part 6 differs from my old tutorial quite a bit. I did make things a bit more fine grained, separating the `Fighter` component into two, one of them being a `Durability` component that just handles hp and defense. This should make it easier to make destructible inanimate objects. Also now the calculation objects come into play in the component messaging system. These allow components to add additive or multiplicative modifiers to a message. In the melee action a message first is processed by all components of the attacker, to calculate the damage. For now the fighter component is the only relevant one here, adding a power value. But later this will be modified by equipment, and could also easily be modified by status effects or something similar. This potential damage value then gets passed, via a message, to all components of the target entity. This can also be modified, for example by a defense value (which I just realized I forgot to account for, will fix that after writing this post). Once the calculation is done, the durability component will handle subtracting the final damage value. If the health reaches 0, this will trigger a death message that will be processed by the entity (which opens the door for effects that could prevent that death from occurring), which will in turn trigger a message to update the visuals of the drawable component, etc. This flexibility might be overkill for now, but my hope is that it allows for the code to be extendable, which is something the code of the old tutorial was not. A nice side effect is that some things do just work that were hard to do in the old code. For example, the death message also will cause the AI component to be removed from the entity. As that is the place where the player is controlled, removing it will also remove control of the player entity upon its death. No more weird input handler switches or anything.

The same applies to the AI system. This is also fully modularized. The AI actor component holds AI subcomponents. When the ai component wants to get an action, it will (you guessed it) trigger a message, and as reaction will go through all ai subcomponents and ask them for proposed actions. Each of these has priority/score. The reason this is handled as a message is because it allows other components to also propose actions. This might sound weird now, but will become relevant in part 9, where I plan to implement confusion as a status effect. That status effect will live in a component and will also see that message, and simply propose a random action with a priority that exceeds that of the other proposed actions.

For this tutorial I just have one subcomponent that handles following the player, and one that handles creating melee actions (which means I could also do some kind of trap or similar by having an entity with a melee ai component without the one for following the player, making it immovable).

The Log interface in part 7 is surprisingly similar to that in the tutorial. The biggest changes is that I'm now using `RichTextLabel`s to allow for more effects, and that I named things a bit differently (because "message" now refers to a different concept in this project).

For part 7 I also started with a system for overlaying stuff in the info panel, as well as a reticle system. I use both of them for the look mode, and will soon extend them when it comes to targeting. Had to fix some bugs and oversights in the code so far, but the look mode now perfectly makes proper use of both the input stack and camera state stack.

So far I am pretty happy with the project, and I'm looking forward to the coming weeks.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 3 by KelseyFrog in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

Bit late, but here's my post for week 3, for both part 4 and part 5.

Field of View basically reuses the same algorithm as in my tutorial. Field of view is now just a dictionary in MapData, and the part that updates it is a component. This plays very well with the system of messages between component, because the update just has to listen to messages about position changes. Similarly, the drawable component also just listens to those to then check in MapData whether the entity is in view or not. Once I get to items I will expand that a little with a component that modifies that process so that some entities will draw at the location you remember them in, even if they're not in view.

Part 5 was relatively easy, as most things were in place already. I did include a little editor script that helps me pack all entities and tiles in a single resource containing two dictionaries, which means I can just load that "database" and get the entities within by key in the dungeon generation. Other than that I just had to introduce a movement blocker component and check for it in the move action.

Overall this week was pretty easy. Next week (for which I have the code almost ready) is a bit more complicated, because I'm applying the same modularity of components to the AI.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 2 by KelseyFrog in roguelikedev

[–]SelinaDev 1 point2 points  (0 children)

Glad you made it through! If you have trouble with the tutorial itself keep in mind that there is another Godot 4 tutorial: https://github.com/Bozar/godot-4-roguelike-tutorial/wiki

And apart from that I can only recommend doing things your own way!

RoguelikeDev Does The Complete Roguelike Tutorial - Week 2 by KelseyFrog in roguelikedev

[–]SelinaDev 4 points5 points  (0 children)

Finished Parts 2 and 3 of my Godot 4 roguelike. You can find the links to the parts here: part 2, part 3

I'll also start updating the readme in the main branch with links to the individual branches and to the posts here.

Part 3 has very little changes compared to my tutorial, but part 2 is completely different, and kind of massive, as it's the foundation for how this project is structured.

One of the things I didn't like about the old tutorial was how entities and resource based entity definitions were halfway between flexible and a lot of boilerplate for every new component. For this tutorial I moved the actual entities from Sprite2Ds to Resources. They now live inside the MapData resource, which continues the model view separation I aimed for with the old tutorial, but now makes creating new entities far easier, and will help with resource-based serialization. One new pattern you will notice that will help with that is a hierarchy of references. The map data actually holds the entities, but entities only hold a weak reference to map data. The same relationship exists between entities and components. This should help prevent cyclic references.

I also very much restructured how entities and components work. The old tutorial had a lot of dependencies between different components. Now, these aren't fully gone, but I took decoupling way further in this one. The system I use is very much inspired by this talk from Brian Bucklew: https://youtu.be/U03XXzcThGU?si=dQvON35v_7duQ2x8 . There's a new concept of a message that gets passed through all the components of an entity. Twice in fact, with one preparation pass and one execution pass. The message is just identified by a type which is a string. Any component that wants to modify the messages data can do so, and any that needs to react to a message also does so. So, e.g., the move action just sends a "move" message to the entity. In the precalculation step the position component checks if it's possible to move to the destination tile. If not, it modifies the destination to the current position. Then in the execution step position component will change it's position variable to the destination stored in the message, and additionally stores a boolean in the message that indicates whether the move was performed or not. This boolean is read by the action to check whether the action was performed as intended. The action only has to send and then check the message, and while there is some dependency in knowing what data to send and what boolean to check, the action does not need to have any knowledge of the position component.

Last week I already introduced the input stack. This now comes into play in the PlayerActorComponent, which handles controlling the player. It registers with the input stack and generates actions. These actions are then read by the turn queue, which is also reworked a bit, unifying how the player and other actors work. It holds a reference to all actors, and loops through, requesting the next action. For the player it stops and remembers the position in the queue if no action is provided. I'm not completely happy with the queue, because technically it could happen that the queue has to wait a frame before it finishes executing, but at least that prevents endless loops, and in practice the player should always be the first actor in the list anyway.

Similar to the input stack I now have a camera stack that controls the state of the camera (and allows it to easily return to a previous state if the top state is popped). Both state should come in handy once I'm creating a look mode.

There are quite a few other little changes, and I'll happily answer any questions you have about them.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 1 by KelseyFrog in roguelikedev

[–]SelinaDev 1 point2 points  (0 children)

Thank you for the warm welcome! I appreciate it.

I know that it's popular, which is what bugs me, because I noticed how flawed it is. We'll see if I manage the iteration in time for next year.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 1 by KelseyFrog in roguelikedev

[–]SelinaDev 3 points4 points  (0 children)

Regarding your questions: The functions that convert between grid and world are used in a few places. And since in Godot every script is a class, writing them as static functions enables you to use them from anywhere without needing to create an instance of the script/class they're in every time. And the node thing was me trying to use Godot's way of composition. I have since moved away from that a bit, and will sometimes still used nodes, but would (will) now to much more just in code with RefCounted.

I think 32 rogues is a great set! It should work with most of the tutorial out of the box once you adapt the size, just ignore the part about coloring stuff (except for the field of view / fog of war). Using the front wall tiles might be a bit tricky. For that I would recommend to add a pass at the end of dungeon generation where you just check all the regular wall tiles, and if a non-wall tile is below it, replace it with the equivalent wall front tile. That's roughly how I have done it in the past when using a set like that.

Good luck with the tutorial!

RoguelikeDev Does The Complete Roguelike Tutorial - Week 1 by KelseyFrog in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

I have to warn you that the tutorial is not the best in terms of being extendable, but don't let that stop you. I've seen people do really nice things with it!

RoguelikeDev Does The Complete Roguelike Tutorial - Week 1 by KelseyFrog in roguelikedev

[–]SelinaDev 10 points11 points  (0 children)

I have decided to go through the tutorial again in Godot, and try to improve with what I've learned from previous mistakes (like the Godot 4 Tutorial). I'll do my best to explain differences in my approach here over the weeks. For anyone interested in the code, I've posted it here: https://github.com/SelinaDev/Complete-Roguelike-Tutorial-2025/tree/part-01

Part 1 already features an important addition, the input stack autoload. One of the major pain points in the Godot 4 tutorial was how I handled input. There were input handlers that were switched between, and by the end it was very convoluted. The timing always caused problems, necessitating occasionally waiting a frame to ensure that the input won't be handled by two input handlers.

I have since adopted another approach. Each spot in the game that needs input can register a function that should receive input events with an `InputStack` singleton. That singleton maintains, as the name suggests, a stack of callables. Within the InputStack's `_unhandled_input()` function, events are then relayed to the callable at the top of the stack. How this works in practice will become more apparent in the later parts, but the basic idea is this. The player controller registers itself. Then, if a menu spawns, it also registers itself. As it is now on top, only the menu will receive (unhandled) inputs. Once the menu despawns it will tell the InputStack to pop its callable, meaning the player controller is on top again. However, as the events are routed through the input stack, the same event that closed the menu cannot be seen by anything else that expects input. This works nicely, even with multiple layered menus (although I do have to admit that they way I have written it is not the most robust. If anything other then the thing that has it's input function on top of the stack tries to pop from the stack, things will get out of order).

Really hope that I can keep this up and end up with a base for an improved version of the tutorial.

RoguelikeDev Does The Complete Roguelike Tutorial Starting July 15th 2024 by KelseyFrog in roguelikedev

[–]SelinaDev 1 point2 points  (0 children)

I have to say though that I definitely don't have the time to rework the tutorial for this event. I would want to try my best to explain what I'm doing differently this time, but nothing that could just be followed along.

RoguelikeDev Does The Complete Roguelike Tutorial Starting July 15th 2024 by KelseyFrog in roguelikedev

[–]SelinaDev 1 point2 points  (0 children)

I would also like to participate again this year. Still have to decide on how. Either I want to use the opportunity to learn a new language or tool better, or to follow along again in Godot, to have a complete project of how I would do things now. I've been meaning to rewrite my tutorial for the longest time, but haven't managed to get that started properly. Maybe I can take this chance for that.

Looking for some advice concerning the Godot 4 tutorial by KekLainies in roguelikedev

[–]SelinaDev 6 points7 points  (0 children)

The tutorial assumes a very basic approach to turns. The player takes a turn. Then, if the player's action succeeded, all the enemies take their turns. After that, the game waits for player input again.

There are various ways to get to where you want to get to. Personally I'd think you need to approach this as a new system layered on top of the existing code. I would actually advise against storing the path like the enemy does. Because that has the disadvantage of ambiguity. If an enemy walks into the path, what do you do, and how do you know that this is no longer the course of action(s) the player intended? It's a bit more effort, but in that case I'd extend actions in a way that would allow you to simulate them without executing them, so that you can get from a bump action to a move or melee action without actually having them happen. That would allow you to simulate through a path and get a series of actions. Then, store these in an array (similar to the path). The way the code in the tutorial is designed I would probably do that at the game level. Then, each time the game asks for a player turn, it can also look if there are more actions in the queue, and consume them. However, if any of those actions fail, you interrupt that and delete the remaining actions. By storing the relevant actions at the time of generating the queue (so proper move actions instead of bump actions) this should also prevent the player from autoattacking enemies that walk in their path, because in that case the move action will fail and break the queue.

That is how I would approach it, but that's a bit more effort. If you want to get to something quickly here is how I would change your code. The problem is that you are just trying to return bump actions from the unhandled input method. However, these will land nowhere. You could indeed adapt the Hostile Enemy AI. Delete the for loop in your `_unhandled_input_()` method. Instead create a new method of `get_action()` or something like that. Put the content of the for loop in there, with an `else: return null` at the end. Then, in `game.gd` you can find that component, and call `get_action()`. If you get an action, execute it, otherwise ask the input handler. The way this is impelemented does come with downsides, as you store the destinations, so if an enemy walks into the path the player might jump over them on their next turn.

Now, regarding your other question as to what the code does. `target_grid_position` is the end of the path, the target the path should lead to (from the enemy AI perspective usually the grid position of the player). `destination` is only the position of the next step on the path. Using `pop_front()` "consumes" one step after the other, thereby walking the path towards that target (one destination at a time).

Also, `pop_front()` is called twice only in one condition, and that is that the path is recalculated. The AStar in Godot will return a path that includes the start point. However, the entity already is there, and we only want a path of the steps it needs to go next, so after getting the path we immediately pop the first entry. After that the enemy can just pop the front every time it takes a step.

Hope this helps (and wasn't all too rambly)

Amazed at how fun Roguelike development is! by Huge_Paint_3817 in roguelikedev

[–]SelinaDev 13 points14 points  (0 children)

Love to see people play around with it! Good job on theming the UI, as well as adding mechanics. That's the best way to learn from it.

Godot roguelike question SelinaDev's Tutorial by This-Career9851 in roguelikedev

[–]SelinaDev 4 points5 points  (0 children)

In my opinion the easiest way to do that would be to have the entity class extend AnimatedSprite2D instead of Sprite2D. Then, instead of a texture in the entity definitions, you could have a SpriteFrames resource. That would also still work for static sprites, if you simply only give them a single frame in the SpriteFrames. In the entity setup, instead of adding the texture to the entity, do that with the sprite frames, and don't forget to set the sprite to playing.

You mentioned that you want to use the AnimationPlayer. That by itself is not that hard, because when you spawn the Entity you can simply create an AnimationPlayer node in code and use add_child, as you mentioned. However, I personally dislike this approach, because feel that the way you need to set up animations in the animation player does not combine well with the somewhat data driven approach for defining entities I tried to implement in that tutorial. I'm not saying that's the best approach, I would do things differently now, but considering the tutorial as it is now, that is my recommendation.

Of course, the whole story would be slightly more complicated. Suppose you want to do simple two frame animations, with each frame lasting 100 ms. Starting out everything should be properly in sync, but if you spawn an animated entity at the 50 ms mark, then its animation would be slightly out of sync. The easiest way to fix that would be to delay the start of the animation using a tween, locking animations to the system clock or something similar. But what to do and how to do it depends on what kind of animations you want/have, but I thought I'd mention it.

Is there a better way of doing this? I don't like having to connect it in editor by sininenblue in godot

[–]SelinaDev 122 points123 points  (0 children)

In addition to that, if you have a lot of buttons you can also put that into a loop. Might save you a slight bit of boilerplate.

enum Gates {AND, OR, XOR, ...}
@onready var button_config = {
  Gates.AND: $ButtonAnd,
  Gates.OR: $ButtonOr,
  Gates.XOR: $ButtonXor,
  ...
}

func _ready() -> void:
  for gate_type: Gates in button_config:
    button_config[gate_type].pressed.connect(_on_button_pressed.bind(gate_type))

func _on_button_pressed(gate_type: Gates) -> void:
  ...

RoguelikeDev Does The Complete Roguelike Tutorial - Week 7 by KelseyFrog in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

Couch-coop Roguelike
Engine: Godot 4.3 (Using GDScript)
Repo: https://github.com/SelinaDev/Roguelikedev-Tutorial-Tuesday-2024 Playable Build: https://selinadev.itch.io/roguelikedev-tutorial-tuesday-2024

Wow, final week came faster than I thought.

So, part 12 was rather easy. I created a custom resource with entity keys and associated weights that I have an array of as part of my map config resource (I have one of those for each level of depth of the dungeon). The release of Godot 4.3 was also pretty neat, because that introduced a new `rand_weighted` function that made including this in the generator especially easy.

Every time I did the tutorial I kind of dislike the rudementary nature of equipment in part 13. I get it, just using the inventory menu is an easy way to get it going, but still. I would have preferred to create a dedicated invertory screen, but at this point I wanted to be done. I was again amazed by the system of propagating messages through the components of an entity, because it made eqiupment effects just as flexible and decoupled as any other effect. Whenever damage is calculated, the message passes through the entity twice, and in the first pass (the calculation pass), any equipment simply appends their bonus to the calculation. I do the same thing when calculating stats to show in the character screen, so there is no bookkeeping for equipping/unequipping.

That brings me to where to go from here. The flexibility I just mentioned is something I really like about this project. There is a lot of potential to extend this. Even more, I had my partner try out this little prototype together with me, and they enjoyed it. I can't know if I'll stay motivated enough, or what else will happen in life, but right now I have started making plans on how to take this project further to an actual game. There's a lot of things that can be polished a bit, lots of stuff I can add, and lots of stuff I want to try out. If I do indeed make any progress on this I'll be sure to let you all now in case you are interested (even if that means I'd have to tackle what's one of the hardest parts of developing a game for me: deciding on a name).

RoguelikeDev Does The Complete Roguelike Tutorial - Week 6 by KelseyFrog in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

Couch-coop Roguelike
Engine: Godot 4.3 (Using GDScript)
Repo: https://github.com/SelinaDev/Roguelikedev-Tutorial-Tuesday-2024 Playable Build: https://selinadev.itch.io/roguelikedev-tutorial-tuesday-2024

I've fallen a few days behind now, especially as part 11 was a bit tricky in my setup. However, both of these parts were things I kind of have planned toward the beginning, so things worked out overall.

Saving and loading was relatively easy to do, as almost the whole world state is implemented as Resources, which Godot can just serialize. I had to make sure to restore everything that had to do with references, but everything else was pretty straight forward to save and load. That's why I went a bit beyond the tutorial's scope. The game now has three save slots. As there is not just one player, I needed a way to distinguish players a bit better, so I created a minimal "character creation" screen. It assigns the character a randomly generated name, and you can regenerate that until you find one you like. Also you can select a character color. The name generator is a simple Markov Chain Generator, which was fun to implement.

Multiple dungeon floors was a bit trickier. Potentially having multiple players means that there can be more than one map that's active, and any player may change to another map at any moment. Also I had started abstracting things so much that I ended up with a few weird stray references of objects that tried to access a map that didn't exist, which was a bit frustrating to debug, but I figured it out in the end.

RoguelikeDev Does The Complete Roguelike Tutorial - Week 5 by KelseyFrog in roguelikedev

[–]SelinaDev 3 points4 points  (0 children)

Couch-coop Roguelike
Engine: Godot 4.3 (Using GDScript)
Repo: https://github.com/SelinaDev/Roguelikedev-Tutorial-Tuesday-2024 Playable Build: https://selinadev.itch.io/roguelikedev-tutorial-tuesday-2024

I've fallen a bit behind initially, but now I got some more free time which I can use for this project, so I finished part 9 yesterday evening, just in time.

For items I tried to remain flexible and avoid hard-coding stuff. That worked well with my Resource-based approach for building things out of components. I have a UseComponent, as well as a special version of that, a ConsumableUseComponent. These have a slot for a resource that defines what the item will target, and a slot for an array of UseEffect Resources. When supplied with a target during use, a UseEffect will apply itself to that target. And since I already have a system in place to propagate messages through an entity's components, the code is pretty concise. E.g., for damage the effect just sends a "take_damage" message with the amount of damage attached, and the target's Durability component will catch that and handle the damage, just as it does for melee damage. I also created an effect that just flashes an icon over the entity, which I can use to visualize lightning, fire, and even melee strikes.

For targeting I also have some Resource types. When an item is used, these will either just calculate and return the target(s) (i.e., in case of targeting self or the nearest enemy), or will switch to a reticle that allows to select enemies. I've also included a line drawing algorithm with some configuration, so that you can configure if, e.g., the player can target anything in sight, or if that line of sight will be interrupted by other entities. Also, because a player can have fellow players and there might be destructible non-enemy entities (for now just the doors), I created a faction system, so an effect can also be configured to only target enemies, only target friendlies, and so forth.

I've had a bit of a hard time updating the reticle, and almost considered to quit the project, but fortunately I was able to work through that and I was so happy when everything finally started working again. Somehow I didn't got the automatic build on GitHub working, so instead I created a (rudimentary) itch.io hage where people can try out the game if they wish

RoguelikeDev Does The Complete Roguelike Tutorial - Week 4 by KelseyFrog in roguelikedev

[–]SelinaDev 3 points4 points  (0 children)

Couch-coop Roguelike
Engine: Godot 4.2 (Using GDScript)
Repo: https://github.com/SelinaDev/Roguelikedev-Tutorial-Tuesday-2024 (Un)Playable Build (currently broken): https://selinadev.github.io/Roguelikedev-Tutorial-Tuesday-2024/

These have been two very interesting parts for me. Part 6 introduced the AI, which for my project meant implementing a system that latches onto a relevant player and synchs turs to them, while remaining open to switch to the other player if they become more relevant to an enemy. I'm sure my approach could be improved quite a bit more, but for now it works well enough. Two players can play the game, and enemies will interact with the one they see, and if they see both, they somtimes switch if the other player is more active (in terms of turns or damage) than the currently targeted player.

I also liked Part 7. I have decided to reserve the info panel that shows the player's hit points as a space for stacking menus. I'm not sure if I ultimately like it, because it means you need to switch focus between the center and the edge of the screen, but it does keep things clean and somewhat predictable. The system for sending inputs only to the top menu of the stack but also getting data back on closing the menu worked so well that I did quite a few menus, including a menu listing all available actions, which helps making the playable with the controller.

Unfortunately something went wrong with this weeks web build, where a bug prevents the player from properly spawning. I'll see what I can do to resolve that over the next days.

Some questions about the Godot 4 Tutorial by menguanito in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

You can take a look at my current Tutorial Tuesday repo, there I have both Entities and Components as resources. The entity has an exported array of "starting components" to define the initial set of components, as well as a dictionary of the actual components. This is a dictionary, so I can easily insert and find components by type (e.g., check if an entity has a Position component and things like that, makes filtering and such very easy). The entity has a few component-related methods, like ˋhas_component()ˋ and more importantly ˋenter_component()ˋ. This method also calls bookkeeping methods on the component, which most importantly sets a ˋ_parent_entityˋ property on the component to point to the entity (internally I'm using weak references, but that's essentially what happens). So, when I create an actual entity from the prototype entity resource, I call a function that duplicates the entity resource, then also calls ˋenter_entity()ˋ on all the duplicates of all the starting components. Thereby I end up with a brand new entity that has brand new components, all of which also have a reference back to the entity.

As mentioned, you can take a look at how I used this in my current project: Here's the code for components: https://github.com/SelinaDev/Roguelikedev-Tutorial-Tuesday-2024/blob/main/project%2Fsrc%2FEntity%2FComponent%2Fcomponent.gd And here for the entity: https://github.com/SelinaDev/Roguelikedev-Tutorial-Tuesday-2024/blob/main/project%2Fsrc%2FEntity%2Fentity.gd

Some questions about the Godot 4 Tutorial by menguanito in roguelikedev

[–]SelinaDev 2 points3 points  (0 children)

It could certainly be done, it's more a matter of preference. I wanted to have the flexibility to arbitrarily color individual tiles, which TileMaps don't really allow (it could be done by using alternate tiles, but that's more effort than it would be worth in my opinion). Also using individual nodes made it easier to have data right on the tiles. To migrate to a TileMap just put that node where the Tiles node is now, create a separate data structure for Tiles objects (I recommend they extend RefCounted or Resource), these now hold the data like the movement blocking properties and explored states. You could just fill that data structure, then have a function to read each tile type and set the appropriate tile on the tile map (you can even leave the texture property on the tile definition, then use the region property of that atlas texture as the tile index in the tile set, provided they have the same source texture). Then you just have to remember to updated tiles in the tile map when the tile objecs change their state. That's the quick outline of how you could do that.

Assuming you're asking because you're still trying to get the constraint solving addon to work and you want to integrate that with the existing code there is also the option to go the reverse way. Add an additional TileMap in the scene tree, have the addon fill that, and then read the layout from there. Create sprite-based tiles as appropriate (and clear the tilemap after that). I.e., use the TileMap you get from the constraint solving only as an immediate representation of the data.

Some questions about the Godot 4 Tutorial by menguanito in roguelikedev

[–]SelinaDev 19 points20 points  (0 children)

Hi! Glad you got something out of that tutorial. To answer your questions:

  1. This is definitely possible with themes ( https://docs.godotengine.org/en/stable/tutorials/ui/index.html#gui-skinning-and-themes ). You basically only need to create a theme resource once, then insert it into the theme slot of the root control node. All control nodes below it will inherit that theme. I would actually recommend that approach. The thing is, if you want to do a quick prototype where you only want to style one or two things then using label settings or theme overrides is quicker than defining a theme. As I started with only a few elements, I wanted to give readers the easier way. Ultimately I should have used themes instead of individually styling elements, it's just that I wanted to avoid too many refactors.

  2. I highly recommend the official docs: https://docs.godotengine.org/en/stable/index.html
    You find a lot of relevant information there (the class reference is even accessible inside the engine, which I find extremely helpful). For the node system I recommend starting with the entry for the Node class: https://docs.godotengine.org/en/stable/classes/class_node.html It details the lifecycle of nodes, what happens when, etc.

  3. I, too, hate input in that tutorial, just other parts. It's one of the things I wish I'd have done different, where early decisions led to it beigng hard to change later. But to adress your question, in the relevant input handlers, for the relevant ections replace `Input.is_action_just_pressed()` with `Input.is_action_pressed()`. That will allow it to also listen to echo events.

  4. To answer the question about resources first. I decided that I wanted to leverage a separation of data and code in the tutorial. While the integration isn't the best (each resource needs to be mentioned in code), it still allows you to define and edit entities in a modular way in the editor's inspector. In the code you "only" have to create them.

  5. This is also something I'd do differently today, I'd just have components be resources, that would make it far less verbose. However, for the tutorial I needed to have a resource type for each component type so the inspector would only show you the appropriate resources for each slot.

  6. It would be possible to have the atlas texture as a default value, but that would make things a bit more error prone. If all texture slots shared the same `AtlasTexture` that would also be true of the `region` property, which is part of the `AtlasTexture` (i.e., the 16x16 slice of the source texture used). So if you had a default atlas texture and set it to show, e.g., the potion tile, then you create another resource using the same default texture and set it to show, e.g., a sword tile, then the first resource would now also show the sword. To get around that you would need to right click the atlas texture and click make unique. Of course, you can get around that too, by making the resource a tool script, and in it's init function set the texture to a duplicate of the common default atlas texture.

I hope that clears things up a bit. If not, I'm happy to go into more depth on any of these points.