semeion 0.9.1

A generic 2D environment simulator
Documentation
//! Zoom and pan transformations driven by user inputs.
//!
//! Zoom with keys Up and Down.
//! Pan with A, W, D, and S.

use ggez::input::keyboard::*;
use ggez::*;
use semeion::*;

use entity::*;

mod entity;
mod env;

struct GameState<'a> {
    // the environment where the simulation takes place
    env: Environment<'a, Kind, Context>,
    // the global transformation matrix
    transform: Transform,
}

impl<'a> GameState<'a> {
    /// Constructs the game state by populating the environment with the initial
    /// entities.
    fn new(ctx: &mut Context) -> Result<Self, GameError> {
        let mut env = Environment::new(env::dimension());
        debug_assert!(env.is_empty());
        // a grid as a static entity used only for drawing purposes in order to
        // show the white grid cells borders
        env.insert(Grid::new(grid::mesh(ctx)?));
        env.insert(Rect::new(env::dimension().center(), rect::mesh(ctx)?));

        Ok(Self {
            env,
            transform: Transform::scale_around(
                [0.9, 0.9],
                env::size().center(),
            ),
        })
    }
}

impl<'a> event::EventHandler<GameError> for GameState<'a> {
    fn update(&mut self, ctx: &mut Context) -> GameResult {
        while timer::check_update_time(ctx, 10) {
            self.env
                .nextgen()
                .expect("Cannot move to the next generation");
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        graphics::clear(ctx, [0.9, 0.9, 0.9, 1.0].into());
        self.env
            .draw(ctx, self.transform)
            .expect("Cannot draw the environment");
        graphics::present(ctx)?;
        timer::yield_now();
        Ok(())
    }

    fn key_down_event(
        &mut self,
        _ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        // compute the translation matrix
        let t = match keycode {
            KeyCode::A => Transform::translate([10.0, 0.0]),
            KeyCode::D => Transform::translate([-10.0, 0.0]),
            KeyCode::W => Transform::translate([0.0, 10.0]),
            KeyCode::S => Transform::translate([0.0, -10.0]),
            _ => Transform::identity(),
        };

        // compute the scaling matrix around the center of the window
        let center = env::size().center();
        let s = match keycode {
            KeyCode::Up => Transform::scale_around([1.1, 1.1], center),
            KeyCode::Down => Transform::scale_around([0.9, 0.9], center),
            _ => Transform::identity(),
        };

        self.transform *= t * s;
    }
}

fn main() -> GameResult {
    use conf::{WindowMode, WindowSetup};

    let (mut ctx, events_loop) = ContextBuilder::new("camera", "Marco Conte")
        .window_setup(WindowSetup::default().title("Camera!"))
        .window_mode(WindowMode::default().dimensions(env::WIDTH, env::HEIGHT))
        .build()?;

    let state = GameState::new(&mut ctx)?;
    event::run(ctx, events_loop, state)
}