1

我正在尝试创建一个 requestAnimationFrame 循环,它将调用game.render()每一帧。我正在关注本教程 - https://rustwasm.github.io/wasm-bindgen/examples/request-animation-frame.html


struct Game {
    state: GameState,
    ctx: web_sys::CanvasRenderingContext2d
}

impl Game {
    fn render(self: Game) {
        self.ctx.begin_path();
        self.ctx.arc(self.state.x, 50.0, 40.0, 0.0, 2.0 * std::f64::consts::PI);
        self.ctx.stroke();
    }
}

#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {

    let game = init();

    let f = Rc::new(RefCell::new(None));
    let g = f.clone();


    *g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
        game.render();
        request_animation_frame(f.borrow().as_ref().unwrap());
    }) as Box<dyn FnMut()>));

    request_animation_frame(g.borrow().as_ref().unwrap());
    Ok(())
}


fn init() -> Game {
    let doc = document();
    let canvas = doc.create_element("canvas").unwrap();
    canvas.set_attribute("width", "800px").unwrap();
    canvas.set_attribute("height", "800px").unwrap();
    canvas.set_id("fp-canvas");
    body().append_child(&canvas).expect("Could not attach canvas");

    Game {
        ctx: context(),
        state: GameState {
            x: 3.0
        }
    }
}

但它给出了以下错误 -


error[E0277]: expected a `std::ops::FnMut<()>` closure, found `[closure@src/lib.rs:89:51: 92:6 game:Game, f:std::rc::Rc<std::cell::RefCell<std::option::Option<wasm_bindgen::closure::Closure<dyn std::ops::FnMut()>>>>]`
  --> src/lib.rs:89:42
   |
89 |       *g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
   |  __________________________________________^
90 | |         game.render();
91 | |         request_animation_frame(f.borrow().as_ref().unwrap());
92 | |     }) as Box<dyn FnMut()>));
   | |______^ expected an `FnMut<()>` closure, found `[closure@src/lib.rs:89:51: 92:6 game:Game, f:std::rc::Rc<std::cell::RefCell<std::option::Option<wasm_bindgen::closure::Closure<dyn std::ops::FnMut()>>>>]`
   |
   = help: the trait `std::ops::FnMut<()>` is not implemented for `[closure@src/lib.rs:89:51: 92:6 game:Game, f:std::rc::Rc<std::cell::RefCell<std::option::Option<wasm_bindgen::closure::Closure<dyn std::ops::FnMut()>>>>]`
   = note: wrap the `[closure@src/lib.rs:89:51: 92:6 game:Game, f:std::rc::Rc<std::cell::RefCell<std::option::Option<wasm_bindgen::closure::Closure<dyn std::ops::FnMut()>>>>]` in a closure with no arguments: `|| { /* code */ }
   = note: required for the cast to the object type `dyn std::ops::FnMut()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `fighting-pixel`.

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

如果我注释掉game.render()它会编译。但我想保持一个将被更新以创建动画的状态。我做错了什么?为什么闭包不允许调用结构方法?

在此先感谢您的帮助。

4

2 回答 2

2

我发现了这个问题。游戏结构就像 -

impl Game {
    fn render(self: &Game) {
        self.ctx.begin_path();
        self.ctx.arc(self.state.x, 50.0, 40.0, 0.0, 2.0 * std::f64::consts::PI);
        self.ctx.stroke();
    }
}

忘记放&符号了self。感谢 Discord 频道#wg-wasm 的 Pauan#6666 指出这一点。

于 2019-10-28T06:38:47.647 回答
0

Shimul评论对我有用。我在这里分享我的游戏 start_loop 阻塞功能。

有趣的线在最后:

draw_scene(&self.state, &self.gl_context).unwrap();
impl GameGl { pub fn start_loop(mut self) -> Result<(), JsValue> {
    // Render loop
    // Dont ask me
    let f = Rc::new(RefCell::new(None));
    let g = f.clone();
    const FPS_THROTTLE: f64 = 1000.0 / 60.0; // milliseconds / frames
    let mut previous: f64 = js_sys::Date::now();
    *g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
        request_animation_frame(f.borrow().as_ref().unwrap());

        // Get time (miliseconds)
        let now = js_sys::Date::now();

        // Clause: must work or sleeep ?
        // The current rotation angle 1 rad/sec
        if now < previous + FPS_THROTTLE {
           return ();
        }

        // Update time
        let delta_time = now - previous;
        previous = now;

        // Update game
        self.state.cube_rotation += delta_time as f32 * 0.001;

        // Draw
        draw_scene(&self.state, &self.gl_context).unwrap();
            //&self.gl, &self.program_info, &self.texture, &buffers, &state).unwrap();

    }) as Box<dyn FnMut()>));

    console::log_1(&"Requesting animation frame".into());
    request_animation_frame(g.borrow().as_ref().unwrap());
    //let program_info = 
    Ok(())
}}
于 2021-02-26T12:59:52.727 回答