Giter Club home page Giter Club logo

rust-sokoban's People

Contributors

alec-brooks avatar bailey-coding avatar funkill avatar guilhermoreadonly avatar hawk777 avatar iolivia avatar mdssjc avatar mysterycommand avatar ozkriff avatar rojashr avatar telegaovoshey avatar tobiasvl avatar wbprice avatar zubivan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rust-sokoban's Issues

`ggez` related code seems outdated

Hi Olivia! First of all thanks for your time and effort put into preparing this tutorial! I pick up Rust recently and I try to follow your explanation of the code step by step but in Chapter 1.4 Rendering Game the implementation of the run method seems outdated due to changes in ggez::graphics crate, so that some methods can't be found anymore, are deprecated or their signatures have changed.

It would be cool and helpful for everyones, who finds and starts to follow your tutorial if the code is up-to-date, so it works and doesn't confuses.

My Cargo.toml:

[package]
name = "sokoban"
version = "0.1.0"
edition = "2021"

[dependencies]
ggez = "0.8.1"
glam = { version = "0.22.0", features = ["mint"]}
specs = { version = "0.18.0", features = ["specs-derive"] }

I'm trying to fix all places, where code is outdated and compile no longer but it's a quite challenging task for someone, who has absolutely no experience in Rust and libraries used in the project πŸ˜‰. Based on examples from ggezrepository, the code could be refactored as follows:

let (positions, renderables) = data;
        
// Clearing the screen (this gives us the background colour)
let mut canvas = Canvas::from_frame(self.context, graphics::Color::new(0.95, 0.95, 0.95, 1.0));


// Get all the renderables with their positions and sort by the position z
// This will allow us to have entities layered visually.
let mut rendering_data = (&positions, &renderables).join().collect::<Vec<_>>();
rendering_data.sort_by_key(|&k| k.0.z);

// Iterate through all pairs of positions & renderables, load the image
// and draw it at the specified position.
for (position, renderable) in rendering_data.iter() {
    // Load the image
    let image = Image::from_path(self.context, renderable.path.clone()).expect("expected image");
    let x = position.x as f32 * TILE_WIDTH;
    let y = position.y as f32 * TILE_WIDTH;

    // draw
    let draw_params = DrawParam::new().dest(Vec2::new(x, y));
    canvas.draw(&image, draw_params);
}

// Finally, present the context, this will actually display everything
// on the screen.
canvas.finish(self.context).expect("expected to present");

Use compact imports

Example:

use specs::NullStorage;
use specs::WriteStorage;

should be

use specs::{NullStorage, WriteStorage};

Might make sense to do at the same time as #79 to avoid having to change the line numbers twice. Or wait for anchors to be merged (#75 #46)

Deploy with netlify

This is a release task so will probably only be done when the content is ready, but planning to integrate netlify and deploy to https://iolivia.me/rust-sokoban or something very similar and short.

Roadmap ideas

Need to have a think about the book overall structure as it grows.

My thinking so far:

  • Base game
  • poorly named but this is the setup of the game, ECS, basic components and entities and rendering system
  • Gameplay
  • player input, movement, winning/losing states, counting moves
  • Advanced gameplay
  • boxes of different colours, etc. - going deeper into the making a game part
  • UI
  • basic scene transitions and menus
  • Testing
  • add unit and integration tests
  • Save game
  • loading multiple levels from config files and save game to track which levels you've won, etc.
  • Error handling
    Also, I want the first few chapters to be a gentle introduction into Rust gamedev, very accessible to new Rustaceans and/or folks with no Rust/gamedev experience. After that set of chapters we can go deeper into more advanced things.

Ideas for prompts for the user to implement an addition themselves:

  • Centering the game field
  • Preventing more than one box from being pushed by the player
  • Making animation frame duration more easily configurable for myself
  • I also partially implemented differently-coloured boxes and spots before actually reading that section of the book.

Add CI for the code samples

Was thinking it would be cool to have a build task for the code samples in the code folder, it would prevent accidental breaks.

Component traits missing from chapter 3

Hi, really enjoying your tutorial series, however you mention you will be using traits like VecStorage in chapter 3 but don't actually show them in the code and as it stands it won't compile.

Or is it intended that people look at the code in git repo or read the specs docs instead?

Box can move in situation where it shouldn't move

Steps to reproduce:

    N N W W W W W W
    W W W . . . . W
    W . P W B . . W
    W . . . . . . W 
    W . . . . . . W
    W . . . . . . W
    W . . S . . . W
    W . . . . . . W
    W W W W W W W W

I was able to stop the behaviour by changing the match expression on line 173 to

                            match immov.get(&pos) {
                                Some(id) => {
                                    to_move.clear();
                                    break
                                },
                                None => break,
                            }

I haven't tested rigorously to see whether or not this introduces any new unwanted behaviour, but it seems to not do so.

InputSystem doesn't use input in correct order

InputSystem uses input_queue.keys_pressed.pop() and is commented as // Get the first key pressed but pop() removes the last item.

If you input keys fast enough (very easy when not using release mode and batch rendering) this can be seen because of erratic movement of the player character.

Not working with GNOME 3.38 + Wayland 1.19

The GGEZ engine cannot create a window in said environment, returning [wayland-client error] Attempted to dispatch unknown opcode 0 for wl_shm, aborting. error. This is tied to a compatibility issue with glutin library, which is resolved in version 0.25.

You can circumvent the issue by upgrading to ggez version 0.16.0-rc0, which has all the necessary fixes. With one quirk though: on Wayland it produces a window that has no styling. On XOrg everything works, resulting in a normal GNOME-styled window.

I'm not sure this bug needs any fixes on your side per se. Just leaving this here for anyone who stumbles upon a similar issue.

First round of feedback

Thanks a lot everyone who offered to be an early beta tester!

Here are some questions to help structure your feedback:

  1. Structure - did the structure make sense? Anything you would change, add, remove?
  2. Form - was the text useful? was the formatting OK, etc? was the text clear and was it easy to understand?
  3. Rust level - some of your are just getting started in Rust and some of you are more experienced, did the book make sense at your level, could you follow?
  4. Something to add - if you could add one thing, what would it be?
  5. Something to remove - if you could remove one thing, what would it be?
  6. Learning - do you feel like you learned enough about making a simple 2D game in Rust? is there anything you would've hoped to learn with this that wasn't covered?
  7. Graphics - would it help having nicer game graphics or would it distract from the content?

I'll edit this issue if I can think of more stuff, but it would be awesome once you've gone through the book if you could write a sentence or two on each of the topics above. You can reply here on the issue or if you are not comfortable with that please DM me on Twitter πŸ˜„


EDIT: feedback summary

πŸ‘positives

  1. ECS + ggez is a good intro!
  2. section on splitting into modules

πŸ€”to work on/think about

  1. delay on input queue #22 (2)
  2. deep dive into ECS and storage
  3. derive macros #23 (2)
  4. title screens and transitions #25
  5. lifetimes #24 (2)
  6. use tree for printing directories
  7. use prettier for the md files
  8. more intuitive code sampler folder naming
  9. procedurally generated maps
  10. audio
  11. better explanation of &mut stuff
  12. &'static syntax explanation
  13. where to put the input function

❓questions/more vague

  1. jumping into ECS to start with?
  2. more complex graphics
  3. resolution independence
  4. had to look up #[storage(VecStorage)]

Chapter 2 Section 5 Missing code

Attempting to just follow along, there are two missing code pieces in the book for the Gameplay section:

Incrementing the move count in the input system:

        // We've just moved, so let's increase the number of moves
        if to_move.len() > 0 {
            gameplay.moves_count += 1;
        }

And running the new system:

        // Run gameplay state system
        {
            let mut gss = GameplayStateSystem {};
            gss.run_now(&self.world);
        }

It took me a while to track down the changes in the full code.

Unused and too big readme.gif file

File books/en_US/src/images/readme.gif is quite big (55.65 MB) and is not used in the book. The only place where it seems to be referenced is the README.md file but using an incorrect path:
<img src="src/images/readme.gif" width="80%">

As the file is in books/en_US, it is duplicated with every translation, increasing disk usage. Github shows a warning message when pushing this file because of its size:

Total 69 (delta 8), reused 54 (delta 7), pack-reused 0
remote: Resolving deltas: 100% (8/8), completed with 1 local object.
remote: warning: See http://git.io/iEPt8g for more information.
remote: warning: File 23acb375f216b5989782ed46e8ce1a50cbd12bea is 55.65 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB
remote: warning: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
remote: 

I think of two options:

  1. Reduce readme.gif size and move it to the same level as the README.md file so that it could be easily referenced.
  2. Replace it with another smaller file, I think animations.gif is a good candidate.

I'm working on option 1, you can have a look at https://github.com/mexchip/rust-sokoban/tree/reduce-readme-gif-size, let me know if itΒ΄d be an acceptable change for you.

Performance Issues due to Debug Mode

Section 3.4 states that the game is running slowly due to unbatched draw calls, but the reality is that rust's debug mode is very slow. Compiling in release mode or turning on optimizations when compiling in debug mode will make the game much faster. I added the following to make rust optimize in debug mode:

[profile.dev]
opt-level = 2

Here's a table with the performance I got with the various techniques:

Optimizations Spritebatching FPS
No No 7 fps
No Yes 47 fps
Yes No 144 fps
Yes Yes 144 fps

I know of this technique from following (and occasionally contributing to) veloren, which is a good example of how specs can be used to make a larger game.

First Chapter Code Sample Doesn't Compile

The example on the first chapter fails to compile:

use ggez;
use ggez::{conf, event, Context, GameResult};

// This struct will hold all our game state
// For now there is nothing to be held, but we'll add
// things shortly.
struct Game {}

// This is the main event loop. ggez tells us to implement
// two things:
// - updating
// - rendering
impl event::EventHandler for Game {
    fn update(&mut self, _context: &mut Context) -> GameResult {
        // TODO: update game logic here
        Ok(())
    }

    fn draw(&mut self, _context: &mut Context) -> GameResult {
        // TODO: update draw here
        Ok(())
    }
}

pub fn main() -> GameResult {
    // Create a game context and event loop
    let context_builder = ggez::ContextBuilder::new("rust_sokoban", "sokoban")
        .window_setup(conf::WindowSetup::default().title("Rust Sokoban!"))
        .window_mode(conf::WindowMode::default().dimensions(800.0, 600.0))
        .add_resource_path(path::PathBuf::from("./resources"));

    let (context, event_loop) = &mut context_builder.build()?;
    // Create the game state
    let game = &mut Game {};
    // Run the main event loop
    event::run(context, event_loop, game)
}

➜  rust-sokoban git:(master) βœ— cargo run
   Compiling rust-sokoban v0.1.0 (/Users/wbprice/Documents/rust-sokoban)
error[E0433]: failed to resolve: use of undeclared type or module `path`
  --> src/main.rs:30:28
   |
30 |         .add_resource_path(path::PathBuf::from("./resources"));
   |                            ^^^^ use of undeclared type or module `path`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0433`.
error: could not compile `rust-sokoban`.

To learn more, run the command again with --verbose.

Probably just needs a use path; at the top.

Procedural Macros are missing in book

I'm just reading the book and I noticed that the procedural macros in Chapter 1, Section 3 are missing, because they are treated as comments due to the leading #.

This makes following this specific section a little hard as the text explains procedural macros, yet there are none in the code of the whole section. So it may be a good idea to either explain the macro annotations outside the snippet or alter the snippet (which may be not that easy as it is imported from the source file itself)?

Anyway, it's been a fun book so far, even for a long-time Rustacean, so thanks!

Fix inconsistencies and small text tweaks

Will fill this in with the first round feedback nitpicks + text tweaks.

  • add a link to this video for a good explanation on delta times https://www.youtube.com/watch?v=pctGOMDW-HQ&list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT&index=37
  • explain first usage of #[storage(VecStorage)]
  • better explanation for &mut usage
  • &'static syntax explanation
  • explain where to put the input function
  • 1.3 Components and entities - Assets section. We are told to add the Resources folder but not the images folder shown in the hierarchy, just a minor inconsistency.
  • 1.2 - being explicit about the requirements
  • Annotating code sections with their corresponding file path would be really nice.
  • {:?} syntax in the prinln! function.
  • better links to sounds (or explain how to download them)

Add contributors to book front page

Add everyone who contributed with at least one PR to the front page of the book and also add a section with thanks to folks who beta tested and provided feedback!

Should be impl RenderingSystem<'_> { instead of pub struct RenderingSystem<'a> {

Hi,
It should be impl Rendering system instead of pub struct when trying to do the animation.

I am talking about this function in the book:

// rendering_system.rs
pub struct RenderingSystem<'a> {
    //...
    pub fn get_image(&mut self, renderable: &Renderable, delta: Duration) -> Image {
        let path_index = match renderable.kind() {
            RenderableKind::Static => {
                // We only have one image, so we just return that
                0
            }
            RenderableKind::Animated => {
                // If we have multiple, we want to select the right one based on the delta time.
                // First we get the delta in milliseconds, we % by 1000 to get the seconds only
                // and finally we divide by 250 to get a number between 0 and 4. If it's 4
                // we technically are on the next iteration of the loop (or on 0), but we will let
                // the renderable handle this logic of wrapping frames.
                ((delta.as_millis() % 1000) / 250) as usize
            }
        };

        let image_path = renderable.path(path_index);

        Image::new(self.context, image_path).expect("expected image")
    }
}

Further performace improvements for rendering (image caching)

First of all, thank you for the awesome book! I just started learning Rust and it was fun and helpful to build the game.

I had the issue that even after implementing batch rendering the FPS were somewhere between 40 and 50, but never 60. After finishing the book I continued playing around with the code trying to reach 60 FPS. I managed by introducing a cache for the images. Now the game reaches 60 FPS after a few seconds. Would this be an addition to the book you would be interested in?

I am not sure if my implementation is well done (really new to rust), but if you are interested:
The biggest change is https://github.com/NiklasEi/sokoban-rust/blob/master/src/systems/rendering_system.rs#L56-L63

Translations

Opening this as the master tracker issue for translations.

There are three main things to be tackled:

  1. adding infrastructure to support translations - this is very dependent on mdbook and currently complicated - see rust-lang/mdBook#5
  2. writing translations - once the infrastructure is in place we can start working on actual translations, which languages and how much depends on interest and contributors who speak different languages
  3. coming up with a process for managing changes across languages - if we add new chapters, what does that mean for translations? do we say that english is the base, and translations might be a few diffs off?

Also, if you come to this issue interested in a specific translation or would like to contribute by translating, leave a comment below including the language so we can keep track of interest, etc.

Feedback: Confusing imports at interim stages of project

I'm coming into this with a few months of Rust experience, but nearly no experience with making games or using an ECS.

While working through this project I found some of the presentation of imports confusing. For example, when going from chapter 01-01 to chapter 01-03 a whole bunch of new imports are added all at once. Not all of them are actually used at the chapter 01-03 stage of the project, so I was confused by why the unused ones were added. I'm using chapter 01-03 as one example, but it seems there are unused imports at most stages of the book.

I also found the structure of the import statements unclear, e.g. importing ggez, then importing ggez::graphics, then ggez::graphics::DrawParam, expecially when some lines later the more compact curly brace notation is used. The imports feel unexplained to me in general---I would like to know things such as: whether the imported elements are modules, functions, traits, structs, or enums, a brief summary of the imported elements, and finally why they are imported at the current stage of the project. The first two questions are answered to an extent by the documentation on the crates themselves, so I feel that answering the third question here is most important.

Speaking more generally about the book itself, it is pretty good. I found it a useful exercise to go off the book's track at various places and implement my own additions to the sokoban game---the book provides enough detail to enable this. I'd like to know more about why games use ECS so often, as I do not know what kinds of problems come up that ECS is introduced to solve.

Investigate input queue delay

Moving the player is a bit slow, I remember a bug in ggez related with the event input queue, but it also might be my dodgy implementation, maybe what we are doing is a bit too expensive. Would be good to investigate if just getting input is slow or the movement system itself is slow, that should narrow it down between us and ggez.

Testing

Would be great to add a chapter about testing - some basic stuff like:

  • pressing right actually moves the player right
  • pressing right next to a wall doesn't move the player right
  • pressing right when there is a box to the right actually moves the player right and pushes the box

I am thinking this would be an ideal end to the Advanced gameplay chapter.

Remove unused imports

The only tricky bit here is to ensure all code references are changed correctly since the line numbers will be different.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.