Replies: 6 comments 7 replies
-
|
I'm going to experiment to see if I can test out something in this direction to see if anything glaring comes up to make it not possible/reasonable. |
Beta Was this translation helpful? Give feedback.
-
Which scale is this game expected to reach? Beat 'em ups should be very lightweight, so I think performance shouldn't be a concern. If it comes for free, sure 😄 |
Beta Was this translation helpful? Give feedback.
-
He. Interesting; I didn't think that the states could be extended 😅 I think I understand the architecture described. |
Beta Was this translation helpful? Give feedback.
-
|
I'm not sure the sparse set thing will matter for us based on the amount of components/entities I expect we will end up with, unsure about that as your starting point for basing the design off/if it's premature optimization I'm not yet 100% sold yet and haven't quite pieced together implications for scripting/extensibility. Using components as state is really nice because you can just directly query for the components, and have a system/systems responsible for behavior. I think it would end up with systems that are very readable/maintainable. I really like the input priority handling stuff, this would be something similar to what that the parsing system in an input buffer would usually require to decide priority of actions based on sets of inputs over a certain window #148, so it's something that I was already imagining to be in future design. What I was going to implement for the event buffer sounds very similar to what you are suggesting for the player input event component, only extended over a multi frame window so as to account for actions triggered by sequential inputs. (and maybe would not drain?) I'm going to keep chewing it over. I look forward to looking at code if you want to put up a draft PR. |
Beta Was this translation helpful? Give feedback.
-
|
I'm working on a real PR, but here's what the player state looks like so far. I got flopping ( animation-only ) and idling working in the actual game with the new design, but I've commented out most of the game just to get it compiling, since I've removed the https://gist.github.com/zicklag/b9ada0123580d0bfb8c54b71d2837394 I would have avoided stages and just used I could have made 3 new stages, instead, but it seems like we may as well allow the collector and transition systems to run at the same time as any other PreUpdate systems, and we might as well allow the state handler systems to run at the same time as other Update systems. We can use
I did make a change ( we may want to make more ) that just replaces the animation states with the animation |
Beta Was this translation helpful? Give feedback.
-
|
In #203 I now have pretty much everything other than items and attack collision detection working, which I can hopefully finish tomorrow. I think the design is turning out very clean and easy to read. I also removed the need to clamp the player movements in multiple places. Now all movement is controlled by modifying the Before the Here's the list of files that are just about where I want them:
Also, I'm sorry if I changed some stuff I didn't need to change for the sake of the player state effort! It just helps my brain to fix the stuff that is bugging me about design while I work on it, but I know it makes it so hard to review when everything is changing at the same time. If we want to merge this at all we can do whichever of these you feel is easiest:
I know I could have tried to change one thing at a time, but for me it it'd be easier just to break it into pieces later because so much is changing that it's heard to make standalone commits. Again, sorry this is so difficult to review! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
A reply to #195 (comment).
OK, I had another idea which I'm going to brain-dump here. Forgive the length and ambition and anything that I might have missed that might make this all pointless. 😜
SparseSetComponents Instead of EventsWe can use components with
SparseSetstorage to trigger actions on the player in other systems, instead of using events.SparseSetstorage is important because we an add and remove components withSparseSetstorage more efficiently without causing archetype table moves.For instance, when we want the player to flop, would add a
ShouldFlopcomponent to the player entity that we want to flop. Then the system that makes the player flop would iterate through all players with theShouldFlopcomponent. That way we let Bevy handle efficiently iterating through all the entities that we need to worry about flopping or moving, etc.I feel like this could be a good idea regardless of the rest of this comment which is far more ambitious and possibly overreaching for what we should do right now.
Extensible Player Actions/Effects
This got me thinking about the bigger scheme of things and how we would manage scriptable actions and even things like player effects later.
What if we structured it so that each player state would be governed by a system responsible for controlling the player while they are in that state. The state of the player would be represented by a component on the player.
For instance, let's consider the following state systems and their components:
idle, Component:Idlingflop, Component:Floppingmove, Component:Moving { velocity: Vec2 }fall, Component:Falling { from_super_move: bool }( handles when the player is getting hit )If the player is flopping, they will have a
Floppingcomponent and theflopstate will operate on that player and be responsible for modifications to the player such as animation frames, movement, etc.Additionally, whatever state the player is in is responsible for triggering transitions to other states. For instance, if the player is flopping, they won't stop flopping until the
flopsystem willingly removes theFloppingcomponent and adds another state component.Inputs and Attempted State Transitions
Finally, we have to manage input both from the player gamepad/keyboard and from other player influencing factors such as attacks that are hitting them, etc. For instance we could have the following systems that will want to try and control the player:
player_input: This system grabs input from theActionStatethat is generated from our controller bindings and will want to cause the player to move or start flopping, etc. when buttons are pressed.enemy_attacks: This system will want to trigger the playerFallingwhen the player gets hit by an attack.Each player will have a
PlayerStateEventscomponent added to it that will simply be a vector containing all the events that are sent by systems that are attempting to control the player. We use this instead of normal Bevy events because each event should only be handled once, and only by the system for the players currently active state.For instance, if we are currently
Flopping, theflopsystem will run on the player anddrain(..)all of events out of the player'sPlayerStateEventscomponent and handle them as it deems fit. Each event will be aPlayerStateEventdefined like so:This is where things get interesting. Because we could end up with any number of player states eventually, and ones that have been added by scripts, for that matter, we can't have an enum that lists all of the possible states we might need to transition the player to. Therefore we must have our
PlayerStateEventcontain the information needed to transition to the new state, even though the current state may not know what actual component type to add at compile time.That is where the power of
ReflectComponentandBox<dyn Reflect>come into play.We will implement a
DynamicCommandssystem parameter that acts just likeCommands, but that has an additional method for inserting components not known at compile time from it'sReflectComponentandBox<dyn Reflect>.Flopping Example
Let's consider a hypothetical flop system. It could be implemented like this:
With this design, we can add new attacks and fighter moves in Rust and in scripts without having to know them all upfront, and each state can intelligently decide when to transition out of the state.
Summary
At this point you can probably imagine how you might implement the other states:
idlewould be very low priority and would transition to whatever the highest priority event it gets in a given frame without asking questions.movewould transition back to idle every frame, so that you would stop moving as soon as the player released the buttonfallwould work similar toflopThere could be things I'm missing, and I wouldn't really know if this would work well without trying it, but there's the idea!
Beta Was this translation helpful? Give feedback.
All reactions