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

Should Game::load receive &mut Window? (not a duplicate of #130) #137

Open
DomtronVox opened this issue Aug 3, 2020 · 1 comment
Open

Comments

@DomtronVox
Copy link

So this may be a dumb question as it is very similar to #130 (I copied the title and tweaked it slightly even).

I'm having some trouble understanding Tasks, so this may just be stemming from that.
I have this code that does not work because Game::load receives an immutable window ref.

    fn load(_window: &Window) -> Task<MyGame> {
        let player = Image::load("assets/sara-atlas.png")
                      .map(|image| SpriteSheet::new(image, 5, 5))
                      .run(_window.gpu())
                      .expect("Error loading image.");

        let world = World::new();


        Task::succeed(|| MyGame { 
             player, 
             world,
        })
    }

The issue is, I want to load this image now then pass it into the MyGame object at the end of the load function. But Task::run function needs gpu and the Window::gpu function wants a mutable Window which load doesn't get.

In #103 you said it is by design that Game::update doesn't get a mutable window because only game logic should happen there and you don't want it to be changing the window itself, but I assume the same doesn't apply to Game::load, or am I wrong?

This is likely me just being confused about Tasks. When do Tasks actually get run? From the looks of it, it seems whatever calls Game::load runs the task(s), but if I have 100 images to load and I'm only supposed to return a Task<Game> from load how am I supposed to load all those images?
Also, down the road I want to have an AssetDatabase struct that holds lookup tables for all loaded assets (sprite sheets, dialogue trees, etc). And I want to load those assets after the main menu when the player selects one of the campaigns to play. That means it won't be happening in Game::load. But I also don't want some 'if' statement stuck in my Game::draw function being checked every tick. Should it go in Game::interact? (i've yet to mess with interact and input so I'm not sure)

Finally, thanks for making and maintaining this project. It's been very nice to work with so far.

@DomtronVox
Copy link
Author

DomtronVox commented Aug 3, 2020

Here is a quick example of something I want to do that needs Game::load to have a mutable window.

I'm adding in ECS, specifically Specs. My rendering system needs a value put into the ECS world object that the render function can draw to. That value should be initialised in the load function. I was going to use Batch. To create a batch you need an image and to create an image you need a gpu.

fn load(_window: &Window) -> Task<MyGame> {
        let player = ... //same as above

        let world = World::new();

        //insert data into the world
        let bg_img = Image::from_image(_window.gpu(), 
                                                             DynamicImage::new_rgba8(_window.width(), _window.height()))
                             .expect("Error creating batch image.");
        world.insert(Batch::new(bg_img)); 

        Task::succeed(|| MyGame { 
             player, 
             world,
        })
    }

//....

    fn draw(&mut self, frame: &mut Frame, _timer: &Timer) {
        // Clear the current frame
        frame.clear(Color::BLACK);

        let mut screen_batch = self.world.write_resource::<Batch>();
        screen_batch.clear();
        
        //run render system which uses the batch object to draw to

       //something like this to draw to screen.
       screen_batch.draw(&mut frame.as_target());
    }

EDIT

Ok, I seemed to have figured out how to do this. It still feels kinda hacky to me though and would be simplified by Game::load getting a mut window. This is my new Game::load function:

    fn load(_window: &Window) -> Task<MyGame> {

        (
            Image::load("assets/sara-atlas.png"),
            Task::using_gpu(|gpu| {
                Ok(Batch::new(
                    Image::from_colors(gpu, &[Color::BLACK])
                      .expect("Failed to creat batch image.")
                ))
            })
        ).join()
         .map(|(player_atlas, render_system_batch)| {
              
              let player = SpriteSheet::new(player_atlas, 5, 5);

              let mut world = World::new();
              ecs::register_components(&mut world);

              //insert data into the world
              world.insert(render_system_batch); 

              MyGame { player, world }
         })

    }

Is this an abuse of the task system or more or less the intended use?

EDIT 2
I realize now I'm misusing Batch. I thought it was something to draw images to. I now realize it is for drawing the same image/image segment multiple times. However, I also cannot use Canvas for this as it needs a gpu for the as_target() and I cannot seem to get the gpu into my system. But this is getting off topic from the original ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant