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))
}