1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Anima Engine. The quirky game engine
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;

use time::Duration;

use mrusty::*;

use super::game::Game;
use super::super::scripting;


/// A `struct` used to run games from mruby directly.
///
/// Make sure you point to an mruby file with a `Game` `Class` defined which implements a method
/// `update(dt)`, where `dt` is a `Float` representing the time since the last frame.
///
/// # Examples
///
/// ```no-run
/// let game = MrubyGame::new(Path::new("game.rb"));
///
/// GameLoop::new(game).run();
/// ```
pub struct MrubyGame {
    pub mruby: MrubyType,
    pub game: Value
}

impl MrubyGame {
    /// Creates a new `MrubyGame` from an mruby script.
    ///
    /// Make sure you point to an mruby file with a `Game` `Class` defined which implements a
    /// method `update(dt)`, where `dt` is a `Float` representing the time since the last frame.
    ///
    /// # Examples
    ///
    /// ```no-run
    /// let game = MrubyGame::new(Path::new("game.rb"));
    ///
    /// GameLoop::new(game).run();
    /// ```
    pub fn new(script: &Path) -> MrubyGame {
        let mruby = scripting::get_mruby();

        mruby.execute(script).unwrap();

        let game = mruby.run("Game.new")
                        .unwrap_or_else(|_| { panic!("Game class must be defined in mruby") });

        MrubyGame {
            mruby: mruby,
            game: game
        }
    }
}

impl Game for MrubyGame {
    fn update(&self, dt: Duration) -> bool {
        let seconds = dt.num_seconds() as f64;
        let nanoseconds = match dt.num_nanoseconds() {
            Some(nanoseconds) => nanoseconds as f64 / 1.0e+9,
            None              => 0f64
        };

        let dt = self.mruby.float(seconds + nanoseconds);

        self.game.call("update", vec![dt]).unwrap().to_bool().unwrap()
    }
}