onyx 0.2.0

A simple engine for simple minds
Documentation
extern crate onyx;

use std::collections::HashMap;
use onyx::Vec2;

struct Scene {
    left_plank: Rect,
    right_plank: Rect,
    left_score: u32,
    right_score: u32,
    ball: Rect,
    keys: HashMap<onyx::Key, (Direction, Plank)>,
}

#[derive(Copy, Clone, PartialEq)]
enum Kind {
    Start,
    Stop,
}

#[derive(Copy, Clone, PartialEq)]
enum Direction {
    Up,
    Down,
}

#[derive(Copy, Clone, PartialEq)]
enum Plank {
    Left,
    Right,
}

struct Action {
    plank: Plank,
    direction: Direction,
    kind: Kind,
}

struct Rect {
    center: Vec2,
    size: Vec2,
    velocity: Vec2,
    transform: onyx::Transform,
}

impl Rect {
    fn new(state: &mut onyx::State<Action>, center: Vec2, size: Vec2, velocity: Vec2) -> Rect {
        let transform = state.graph().add(center, Vec2::new(1.0, 1.0));
        let child = state.graph().add_child(transform, -0.5 * size, size);
        state.renderer().add(child);
        Self { center, size, velocity, transform }
    }

    fn min(&self) -> Vec2 {
        self.center - 0.5 * self.size
    }

    fn max(&self) -> Vec2 {
        self.center + 0.5 * self.size
    }
}

impl onyx::Scene for Scene {
    type Action = Action;

    fn new(state: &mut onyx::State<Action>) -> Self {
        let size = state.context().size();
        let plank_size = Vec2::new(10.0, 100.0);
        let left_plank = Rect::new(state, 0.5 * Vec2::new(plank_size.x, size.y), plank_size, Vec2::zero());
        let right_plank = Rect::new(state, Vec2::new(size.x - 0.5 * plank_size.x, 0.5 * size.y), plank_size, Vec2::zero());
        let ball_size = Vec2::new(20.0, 20.0);
        let ball = Rect::new(state, 0.5 * size, ball_size, Vec2::new(100.0, 100.0));
        state.ui().build(onyx::ui::panel()
            .layout(onyx::ui::Layout::Horizontal)
            .alignment(onyx::ui::Alignment::Center, onyx::ui::Alignment::Min)
            .child(onyx::ui::label("0").id("left"))
            .child(onyx::ui::label(":"))
            .child(onyx::ui::label("0").id("right"))
        );
        let mut keys = HashMap::new();
        keys.insert(onyx::Key::W, (Direction::Up, Plank::Left));
        keys.insert(onyx::Key::S, (Direction::Down, Plank::Left));
        keys.insert(onyx::Key::Up, (Direction::Up, Plank::Right));
        keys.insert(onyx::Key::Down, (Direction::Down, Plank::Right));
        Scene { 
            left_plank,
            right_plank,
            ball,
            left_score: 0,
            right_score: 0,
            keys,
        }
    }

    fn event(&mut self, event: onyx::Event) -> Option<Action> {
        match event {
            onyx::Event::KeyPressed(key) => {
                if let Some(&(direction, plank)) = self.keys.get(&key) {
                    Some(Action { direction, plank, kind: Kind::Start })
                } else {
                    None
                }
            },
            onyx::Event::KeyReleased(key) => {
                if let Some(&(direction, plank)) = self.keys.get(&key) {
                    Some(Action { direction, plank, kind: Kind::Stop })
                } else {
                    None
                }
            },
            _ => None,
        }
    }

    fn action(&mut self, action: Self::Action, state: &mut onyx::State<Action>) -> onyx::Transition {
        let plank = match action.plank {
            Plank::Left => &mut self.left_plank,
            Plank::Right => &mut self.right_plank,
        };
        let velocity = match action.direction {
            Direction::Down => Vec2::new(0.0, 100.0),
            Direction::Up => Vec2::new(0.0, -100.0),
        };
        match action.kind {
            Kind::Start => plank.velocity += velocity,
            Kind::Stop => plank.velocity -= velocity,
        }
        state.none()
    }

    fn update(&mut self, state: &mut onyx::State<Action>) -> onyx::Transition {
        let min = Vec2::zero();
        let max = state.context().size();
        self.ball.center += self.ball.velocity * state.context().dt();
        self.left_plank.center += self.left_plank.velocity * state.context().dt();
        self.right_plank.center += self.right_plank.velocity * state.context().dt();
        if self.ball.max().x > max.x - self.right_plank.size.x && self.ball.max().x < max.x {
            if self.ball.min().y < self.right_plank.max().y && self.ball.max().y > self.right_plank.min().y {
                self.ball.center.x = max.x - self.right_plank.size.x - 0.5 * self.ball.size.x;
                self.ball.velocity.x = -self.ball.velocity.x;
            }
        }
        if self.ball.min().x > max.x {
            self.ball.center.x = 0.5 * (max.x - min.x);
            self.left_score += 1;
            state.ui().set_text("left", &self.left_score.to_string());
        }
        if self.ball.min().x < min.x + self.left_plank.size.x && self.ball.max().x > min.x {
            if self.ball.min().y < self.left_plank.max().y && self.ball.max().y > self.left_plank.min().y {
                self.ball.center.x = min.x + self.left_plank.size.x + 0.5 * self.ball.size.x;
                self.ball.velocity.x = -self.ball.velocity.x;
            }
        }
        if self.ball.max().x < min.x {
            self.ball.center.x = 0.5 * (max.x - min.x);
            self.right_score += 1;
            state.ui().set_text("right", &self.right_score.to_string());
        }
        if self.ball.min().y < min.y {
            self.ball.center.y = min.y + 0.5 * self.ball.size.y;
            self.ball.velocity.y = -self.ball.velocity.y;
        }
        if self.ball.max().y > max.y {
            self.ball.center.y = max.y - 0.5 * self.ball.size.y;
            self.ball.velocity.y = -self.ball.velocity.y;
        }
        state.graph().set_position(self.ball.transform, self.ball.center);
        state.graph().set_position(self.left_plank.transform, self.left_plank.center);
        state.graph().set_position(self.right_plank.transform, self.right_plank.center);
        state.none()
    }
}

fn main() {
    onyx::run::<Scene>("Pong", (800, 600))
}