Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an example of using Tetra with an ECS library #45

Closed
17cupsofcoffee opened this issue Dec 18, 2018 · 19 comments
Closed

Add an example of using Tetra with an ECS library #45

17cupsofcoffee opened this issue Dec 18, 2018 · 19 comments
Labels
Area: Documentation Issues related to the crate's documentation. Good First Issue Issues that would be a good starting point for a new contributor. Type: Feature Request Improvements that could be made to the code/documentation.

Comments

@17cupsofcoffee
Copy link
Owner

I'm not sure whether I plan on using anything as heavy duty as Specs for now, but it'd be good to have an example in the repository, both for the sake of documentation and to make sure any API changes we make play nicely.

I ported my rl demo from GGEZ to Tetra and it seems to work well, although it's probably a bit more complicated than what we're looking for here.

@17cupsofcoffee 17cupsofcoffee added Type: Feature Request Improvements that could be made to the code/documentation. Area: Documentation Issues related to the crate's documentation. Good First Issue Issues that would be a good starting point for a new contributor. labels Dec 18, 2018
@17cupsofcoffee
Copy link
Owner Author

Someone has been porting their own Specs code to Tetra as an experiment, and they made a good observation - currently Texture is not Send/Sync, as it contains a Rc. This prevents it from being used in a Specs component/resource.

The solution might be as simple as replacing the Rc with an Arc, but I want to look a little closer at what other frameworks do in that regard before I make the change.

@SymenTimmermans
Copy link

Hi!

First off, thanks for creating Tetra. It really suits the concept of a game I'm creating right now. I especially like how simple working with animations is.

Now for the relevant bit. I am planning to use Specs for this game, and I would really like to use Texture (and Animation) on my components.

Have you looked into implementing Send / Sync yet? I might fork and give it a go, but I'm still a beginner in Rust. Might still be a good learning experience, since this has the 'Good First Issue'-tag.

@17cupsofcoffee
Copy link
Owner Author

First of all, thank you for the kind words :) I'd be interested to hear your experiences with Animation, it's one of the main areas of Tetra I'm not sure about the API for (see #105 for a previous discussion).

Onto the actual question!

It would be possible (and quite easy!) to make Texture implement Send + Sync, by switching the internal handle from Rc<RefCell<GlTexture>> to Arc<Mutex<GlTexture>>. There's a few potential issues with this, however:

  • It would incur runtime overhead for all Texture instances, not just ones that are being used in multi-threaded games.
  • I'm not 100% sure how it'd interact with the cleanup code for GlTexture - you have to run any OpenGL commands on the same thread as the context, and I'm not sure where Drop gets run in multi-threaded code. This is probably something I should investigate regardless of what we do here (Is the OpenGL layer safe? #117).
  • To actually use a Texture, you need access to the Context, which cannot be made Send + Sync, because the window (among other things) has to stay on the main thread.

So I'm currently leaning towards thinking that storing a Texture in a component might not actually be the right approach. What might be better is to either:

  • Handle drawing outside of Specs (which is what I did in my roguelike demo).
  • Store your textures in the system struct instead, and either run it manually or mark it as thread-local in the dispatcher (which is what the developer of Quicksilver, another game framework, recommends - not sure whether it'd work with Tetra, as you'd need to get the Context in there somehow?).

You'd potentially also need to add some kind of identifier component to know which entities should be drawn with which texture, but that'd be a lot cheaper than trying to synchronize access to the texture object itself.

Hopefully that gives you some ideas! The fact I'm having to write a post this long definitely indicates I need to write some example code 😛 If you get stuck with it, I'd definitely like to hear the pain points.

@SymenTimmermans
Copy link

First of all, thank you for the kind words :) I'd be interested to hear your experiences with Animation, it's one of the main areas of Tetra I'm not sure about the API for (see #105 for a previous discussion).

The game I am creating is quite simple and I hope to replicate the feel/responsiveness of an 8-bit Atari game. For instance, the tick rate is at 1/30, and the frame_length of my main character walk animation is 4, so that animation runs at 7.5 fps. It's not performance or predictability I'm specifically after.

I have experience with sprite animation in Unity, and I've looked into approaches in Amethyst. When I saw how simple sprite animation was in Tetra, things clicked. It's about workflow; the minimal info you need for an animation is the location of the frames in a texture, and the speed at which the animation runs. The fact that an animation is considered a Drawable, makes for really elegant code, Textures can be replaced by Animations by changing one line of code. The use of the Rectangle Row and Column classes makes understanding the code a breeze. I can add stuff fast, and that's so nice, considering I'm working on this project in my spare time.

So I'm currently leaning towards thinking that storing a Texture in a component might not actually be the right approach. What might be better is to either:

Handle drawing outside of Specs (which is what I did in my roguelike demo).

That sounds like the best approach. In fact, your roguelike demo gave me the confidence to start with Tetra, as it showed that Specs integration was possible. Though, I thought you were using text output (Console), but I now see that the font is basically a spritesheet, and the Console module an abstraction.

I think I can get away with a custom Component that holds the information needed to know what to draw. It's really only a tag (Spider, Rat, Wasp, Door) and an animation state (Walking, Attacking, Dead, Open, Closed). I think hashmaps will work well for this.

There's just one thing I need to figure out. If the Entity does not hold it's own Animation object, but the Animation object is determined in draw(), I think I need to store each Entity's Animation somewhere, because I need to tick() them in update().

And... If I determine the animation based on some Entity state, I should not determine the animation every game tick; if the Entity was walking, and is now still walking, we should only tick() the animation, and not set the variable again. I think this needs some kind of flag or something, because Animation does not implement Eq or PartialEq.

I am confident enough to try it. Maybe my experiences can help designing a bare-bones Tetra/Specs example, considering that's what this issue's actually about 😄

@17cupsofcoffee
Copy link
Owner Author

That's really helpful feedback, thank you! I To focus on a few bits in particular:

The fact that an animation is considered a Drawable, makes for really elegant code, Textures can be replaced by Animations by changing one line of code.

I'm actually currently looking at potentially changing the Drawable trait a bit (see #94), and I hadn't considered 'change the type without changing the draw calls' as a positive of the current design. I'll have to give that some thought when working on those changes!

There's just one thing I need to figure out. If the Entity does not hold it's own Animation object, but the Animation object is determined in draw(), I think I need to store each Entity's Animation somewhere, because I need to tick() them in update().

And... If I determine the animation based on some Entity state, I should not determine the animation every game tick; if the Entity was walking, and is now still walking, we should only tick() the animation, and not set the variable again. I think this needs some kind of flag or something, because Animation does not implement Eq or PartialEq.

This is a really good point, and I hadn't considered this use case until now!

One potential solution I can think of off the top of my head - maybe Tetra could offer a AnimationState type, that contains everything but the texture? Then you could store that in a component, update it in your Specs systems, and then recombine it with the Texture in draw() to actually render it?

The Animation type could then just be a convienence type that bundles an AnimationState with a Texture, for scenarios where you don't need that level of complexity.

There's nothing about Animation that relies on Tetra's internals, so I might have a go at mocking something like that up in an external file later on...

I am confident enough to try it. Maybe my experiences can help designing a bare-bones Tetra/Specs example, considering that's what this issue's actually about 😄

I'd definitely love to take a look at your code, if you do come up with anything 😄

@17cupsofcoffee
Copy link
Owner Author

17cupsofcoffee commented Sep 17, 2019

@SymenTimmermans: Here's some minimal example code for how AnimationState might work - note that there's nothing in the struct that's tied to the graphics context, so it should work fine as a Specs component.

Feel free to copy it into your codebase and use it as a starting point if you want 😄

https://gist.github.com/17cupsofcoffee/1eb6b061a9c4b5f9237d25de49c1dc52

Also check out the animation controller example if you haven't already - it shows how you could wrap an animation in a state machine to handle transitioning between states. Should apply equally to AnimationState.

@SymenTimmermans
Copy link

That's amazing! Thanks. I recognize the implementation of Animation, now without the graphics context, it's quite nice to look at its simplicity.
I also like the AnimationController as a starting point. I decided I needed a state machine already, I have been writing down use cases, like timed transitions (Dying -> Dead). I will share my work in progress once it's working. Thanks again for your efforts!

@17cupsofcoffee 17cupsofcoffee changed the title Add an example of using Tetra with Specs Add an example of using Tetra with an ECS library Nov 19, 2020
@rghartmann
Copy link
Contributor

I see this is marked as a good first issue. I don't know if @SymenTimmermans intends to contribute an example here, but I'll take a shot at converting examples/bunnymark.rs to use Legion ECS.

Also - thanks for the cool engine, @17cupsofcoffee !

@17cupsofcoffee
Copy link
Owner Author

@rghartmann I would rather keep the existing bunnymark minimal, as it's what I usually use to benchmark changes to the renderer, but if you'd like to create a seperate version of it (or a new example entirely) that uses Legion/Hecs/whatever, I'd definitely be interested in that!

@rghartmann
Copy link
Contributor

rghartmann commented May 30, 2021 via email

@rghartmann
Copy link
Contributor

I've got the example working - how best to contribute it? I also couldn't find where you keep documentation so I could add the ECS example to the list; Let me know how to proceed.

@17cupsofcoffee
Copy link
Owner Author

If you could submit it as a PR, that'd be ideal - if it's just one file you can do that pretty easily through the GitHub UI:

image

Documentation is in a seperate repo, I can update that myself later.

@rghartmann
Copy link
Contributor

rghartmann commented May 31, 2021 via email

@rghartmann
Copy link
Contributor

rghartmann commented Jun 7, 2021 via email

@17cupsofcoffee
Copy link
Owner Author

Sorry for the delay, this week's been a bit hectic. I think to push multiple files you'd need to make a fork and then PR from that - if that's too much hassle though, just submit the example file as a PR on it's own and I'll add the Legion dependency 👍

@rghartmann
Copy link
Contributor

rghartmann commented Jun 9, 2021 via email

@17cupsofcoffee
Copy link
Owner Author

Sounds good, no rush and hope your kid feels better soon!

@SymenTimmermans
Copy link

I see this is marked as a good first issue. I don't know if @SymenTimmermans intends to contribute an example here, but I'll take a shot at converting examples/bunnymark.rs to use Legion ECS.

Also - thanks for the cool engine, @17cupsofcoffee !

Thanks for mentioning me! However, I have basically abandoned Rust game-development for now, in favor of using the Godot engine, since learning bindings with Rust (and ECS libraries) are possible.
Most of my projects are suited well for mobile devices, and most Rust game engines/libraries do not really support Android as a build target.

I still think Tetra is a really nice project and encourage it's further development!

@17cupsofcoffee
Copy link
Owner Author

Done by @rghartmann in #268, finally! 🚀 🚀 🚀

And no problem @SymenTimmermans, glad you've found tools that work well for you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Documentation Issues related to the crate's documentation. Good First Issue Issues that would be a good starting point for a new contributor. Type: Feature Request Improvements that could be made to the code/documentation.
Projects
None yet
Development

No branches or pull requests

3 participants