Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 4-fix-card10-l0dable-on-crates-io
  • 5-implement-client-c-in-plain-rust
  • api
  • build-from-root
  • master
  • no-str_to_cstr
  • card10-alloc-0.1.0
  • card10-alloc-0.1.1
  • card10-l0dable-0.2.0
  • card10-l0dable-0.3.0
  • card10-sys-1.10.0
  • card10-sys-1.9.0
12 results

Target

Select target project
  • astro/rust-card10
  • rnestler/rust-card10
  • dbrgn/rust-card10
  • toon/rust-card10
  • mwall/rust-card10
  • puzzlewolf/rust-card10
  • rnd/rust-card10
  • lilpep/rust-card10
  • rafael/rust-card10
  • squeed/rust-card10
  • arist/rust-card10
11 results
Select Git revision
  • 4-fix-card10-l0dable-on-crates-io
  • 5-implement-client-c-in-plain-rust
  • build-from-root
  • master
4 results
Show changes
......@@ -5,7 +5,9 @@ version = "0.0.0"
authors = ["Astro <astro@spaceboyz.net>"]
[dependencies]
card10-l0dable = { path = "../l0dable" }
card10-l0dable = { path = "../card10-l0dable" }
card10-alloc = { path = "../card10-alloc" }
embedded-graphics = "0.5"
[build-dependencies]
cc = "1.0"
......
#![no_std]
#![no_main]
extern crate alloc;
use core::fmt::Write;
use card10_l0dable::*;
use card10_l0dable::{*, framebuffer::*};
use embedded_graphics::{
prelude::*,
primitives::Circle,
};
pub const BALL_RADIUS: u16 = 4;
pub const PADDLE_SPACE: u16 = 32;
pub const BLOCK_W: u16 = 16;
pub const BLOCK_H: u16 = 10;
pub const BLOCKS_X: u16 = Display::W / BLOCK_W;
pub const BLOCKS_Y: u16 = (Display::H - PADDLE_SPACE) / BLOCK_H;
pub const BALL_RADIUS: u32 = 4;
pub const PADDLE_SPACE: u32 = 32;
pub const PADDLE_HEIGHT: u32 = 6;
pub const PADDLE_SPEED: u32 = 4;
pub const BLOCK_W: u32 = 16;
pub const BLOCK_H: u32 = 10;
pub const BLOCKS_X: u32 = Display::W as u32 / BLOCK_W;
pub const BLOCKS_Y: u32 = (Display::H as u32 - PADDLE_SPACE) / BLOCK_H;
pub const LED_INTERVAL: u64 = 70;
pub struct Blocks {
blocks: [[Option<Color>; BLOCKS_X as usize]; BLOCKS_Y as usize],
blocks: [[Option<RawColor>; BLOCKS_X as usize]; BLOCKS_Y as usize],
}
impl Blocks {
......@@ -28,7 +36,7 @@ impl Blocks {
let mut buf = [0, 0, 0, 0];
trng::read(&mut buf);
if buf[0] <= rand_max {
*block = Some(Color::rgb8(
*block = Some(RawColor::rgb8(
0x80 | buf[1],
0x80 | buf[2],
0x80 | buf[3],
......@@ -41,18 +49,18 @@ impl Blocks {
result
}
pub fn collides(&mut self, x: u16, y: u16) -> bool {
let col = (x / BLOCK_W) as usize;
let line = (y / BLOCK_H) as usize;
if line >= BLOCKS_Y.into() || col >= BLOCKS_X.into() {
return false;
pub fn collides(&mut self, x: u32, y: u32) -> Option<RawColor> {
let col = x / BLOCK_W;
let line = y / BLOCK_H;
if line >= BLOCKS_Y || col >= BLOCKS_X {
return None;
}
match self.blocks[line][col] {
Some(_) => {
self.blocks[line][col] = None;
true
match self.blocks[line as usize][col as usize] {
Some(color) => {
self.blocks[line as usize][col as usize] = None;
Some(color)
}
None => false,
None => None,
}
}
......@@ -61,9 +69,6 @@ impl Blocks {
}
}
const PADDLE_HEIGHT: u16 = 6;
const PADDLE_SPEED: u16 = 4;
#[derive(Clone, Copy, Debug)]
enum Direction {
/// Up Right
......@@ -77,7 +82,7 @@ enum Direction {
}
impl Direction {
fn motion(&self, x: &mut u16, y: &mut u16) {
fn motion(&self, x: &mut u32, y: &mut u32) {
use Direction::*;
match self {
UR => {
......@@ -164,26 +169,56 @@ enum GameResult {
fn game(level: u16, mut score: u32) -> GameResult {
let start_time = Seconds::time();
let display = Display::open();
let mut display = Display::open();
let mut fb = display.framebuffer();
let accel = BHI160::<Accelerometer>::start().unwrap();
let mut accel_x = 0;
let mut leds = [LEDColor::RGB(0, 0, 0); 6];
let mut last_led_tick = MilliSeconds::time();
let mut paddle = Display::W / 2;
let paddle_size = 18 - (2 * level).min(14);
let mut paddle = Display::W as u32 / 2;
let paddle_size = 18 - (2 * level as u32).min(14);
let mut ball_x = paddle;
let mut ball_y = Display::H - PADDLE_HEIGHT - BALL_RADIUS;
let mut ball_y = Display::H as u32 - PADDLE_HEIGHT - BALL_RADIUS;
let mut ball_direction = Direction::UR;
let mut blocks = Blocks::generate((0x3F + 0x10 * level).min(0xff) as u8);
// Clear screen
draw_rect(&mut fb, 0, 0, Display::W as u16 - 1, Display::H as u16 - 1, RawColor::black());
// Draw Blocks
for (lineno, line) in blocks.blocks.iter_mut().enumerate() {
let lineno = lineno as u32;
for (colno, block) in line.iter_mut().enumerate() {
block.map(|color| {
let colno = colno as u32;
draw_rect(&mut fb, (colno * BLOCK_W) as u16, (lineno * BLOCK_H) as u16,
((colno + 1) * BLOCK_W - 1) as u16, ((lineno + 1) * BLOCK_H - 1) as u16,
color);
// TODO: spacing?
});
}
}
for tick in 0.. {
for data in &accel.read().unwrap() {
accel_x = (17.0 * data.get_x()) as i32;
}
let input = Buttons::read();
let old_paddle = paddle;
if input.left_bottom() {
paddle -= PADDLE_SPEED;
paddle = paddle.max(paddle_size);
paddle = paddle.saturating_sub(PADDLE_SPEED);
}
if input.right_bottom() {
paddle += PADDLE_SPEED;
paddle = paddle.min(Display::W - paddle_size)
}
let paddle_moving = paddle != old_paddle;
if accel_x < 0 {
paddle += -accel_x as u32;
} else if accel_x > 0 {
paddle = paddle.saturating_sub(accel_x as u32);
}
paddle = paddle
.max(paddle_size)
.min(Display::W as u32 - paddle_size);
if input.left_top() {
exit(0);
}
......@@ -195,85 +230,104 @@ fn game(level: u16, mut score: u32) -> GameResult {
ball_direction.motion(&mut ball_x, &mut ball_y);
if (ball_direction.is_left() && ball_x <= BALL_RADIUS) ||
(ball_direction.is_right() && ball_x >= Display::W - BALL_RADIUS) {
(ball_direction.is_right() && ball_x >= Display::W as u32 - BALL_RADIUS) {
// Bounce on left/right border
ball_direction.bounce(Bounce::Vertical);
vibra::vibrate(10);
vibra::vibrate(5);
}
if ball_direction.is_up() && ball_y <= BALL_RADIUS {
// Bounce on top border
ball_direction.bounce(Bounce::Horizontal);
vibra::vibrate(10);
vibra::vibrate(5);
}
if ball_direction.is_down() &&
ball_y >= Display::H - PADDLE_HEIGHT - BALL_RADIUS &&
ball_y >= Display::H as u32 - PADDLE_HEIGHT - BALL_RADIUS &&
ball_x >= paddle - paddle_size &&
ball_x <= paddle + paddle_size {
// Bounce on paddle
if paddle_moving && input.left_bottom() {
if paddle < old_paddle {
ball_direction = Direction::UL;
vibra::vibrate(50);
} else if paddle_moving && input.right_bottom() {
vibra::vibrate(20);
} else if paddle > old_paddle {
ball_direction = Direction::UR;
vibra::vibrate(50);
vibra::vibrate(20);
} else {
ball_direction.bounce(Bounce::Horizontal);
vibra::vibrate(20);
vibra::vibrate(10);
}
}
if ball_y >= Display::H - BALL_RADIUS {
if ball_y >= Display::H as u32 - BALL_RADIUS {
return GameResult::Over(score);
}
if blocks.collides(ball_x - BALL_RADIUS, ball_y) ||
blocks.collides(ball_x + BALL_RADIUS, ball_y) {
let collision_v = blocks.collides(ball_x - BALL_RADIUS, ball_y)
.or_else(|| blocks.collides(ball_x + BALL_RADIUS, ball_y));
if let Some(color) = collision_v {
ball_direction.bounce(Bounce::Vertical);
score += 3;
// paddle_size += 2;
check_finish = true;
vibra::vibrate(60);
vibra::vibrate(15);
leds[0] = LEDColor::RGB(color.r8(), color.g8(), color.b8());
}
if blocks.collides(ball_x, ball_y - BALL_RADIUS) ||
blocks.collides(ball_x, ball_y + BALL_RADIUS) {
let collision_h = blocks.collides(ball_x, ball_y - BALL_RADIUS)
.or_else(|| blocks.collides(ball_x, ball_y + BALL_RADIUS));
if let Some(color) = collision_h {
ball_direction.bounce(Bounce::Horizontal);
score += 2;
// paddle_size += 1;
check_finish = true;
vibra::vibrate(40);
vibra::vibrate(15);
leds[0] = LEDColor::RGB(color.r8(), color.g8(), color.b8());
}
}
if check_finish && blocks.is_finished() {
return GameResult::LevelFinish(score + 100);
}
display.clear(Color::black());
// Paddle
display.rect(
paddle - paddle_size, Display::H - PADDLE_HEIGHT,
paddle + paddle_size, Display::H - 1,
Color::rgb8(0x7f, 0xff, 0x7f), FillStyle::Filled, 1
);
// Ball
display.circ(
ball_x, ball_y, BALL_RADIUS,
Color::rgb8(0x7f, 0x7f, 0xff), FillStyle::Filled, 1
);
// Blocks
// Empty blocks
for (lineno, line) in blocks.blocks.iter_mut().enumerate() {
let lineno = lineno as u16;
let lineno = lineno as u32;
for (colno, block) in line.iter_mut().enumerate() {
block.map(|color| {
let colno = colno as u16;
display.rect(
colno * BLOCK_W,
lineno * BLOCK_H,
(colno + 1) * BLOCK_W - 1,
(lineno + 1) * BLOCK_H - 1,
color, FillStyle::Filled, 1
block.or_else(|| {
let colno = colno as u32;
draw_rect(&mut fb, (colno * BLOCK_W) as u16, (lineno * BLOCK_H) as u16,
((colno + 1) * BLOCK_W - 1) as u16, ((lineno + 1) * BLOCK_H - 1) as u16,
RawColor::black());
None
});
}
}
// Space below blocks
draw_rect(&mut fb, 0, (BLOCK_H * BLOCKS_Y) as u16,
Display::W as u16, Display::H as u16, RawColor::black());
// Paddle
draw_rect(&mut fb,
(paddle - paddle_size) as u16, Display::H as u16 - PADDLE_HEIGHT as u16,
(paddle + paddle_size) as u16, Display::H as u16 - 1,
RawColor::rgb8(0x7f, 0xff, 0x7f));
// Ball
fb.draw(
Circle::new((ball_x, ball_y).into(), BALL_RADIUS)
.fill(Some(RawColor::rgb8(0x7f, 0x7f, 0xff)))
);
fb.send();
update_rgb_leds(|index| {
if index < 6 {
leds[(5 - index) as usize]
} else {
leds[(index - 5) as usize]
}
});
let now = MilliSeconds::time();
if last_led_tick.0 + LED_INTERVAL <= now.0 {
for i in 1..leds.len() {
leds[leds.len() - i] = leds[leds.len() - i - 1];
}
leds[0] = LEDColor::RGB(0, 0, 0);
last_led_tick = now;
}
display.update();
}
unreachable!()
}
......@@ -281,10 +335,10 @@ fn game(level: u16, mut score: u32) -> GameResult {
fn title_screen() {
let display = Display::open();
display.clear(Color::red());
display.print(30, 15, b"Rkanoid\0", Color::white(), Color::red());
display.print(30, 30, b"in Rust\0", Color::white(), Color::red());
display.print(20, 45, b"by Astro\0", Color::white(), Color::red());
display.print(Display::W - 2 * Display::FONT_W, Display::H - Display::FONT_H, b"Go\0", Color::yellow(), Color::blue());
display_adv!(display, Font24, Display::W / 2 - 60, 14, Color::white(), Color::red(), "Rkanoid");
display_adv!(display, Font20, Display::W / 2 - 49, 40, Color::white(), Color::red(), "in Rust");
display_adv!(display, Font16, Display::W / 2 - 44, 64, Color::white(), Color::red(), "by Astro");
display!(display, Display::W - 2 * Display::FONT_W, Display::H - Display::FONT_H + 3, Color::yellow(), Color::blue(), "Go");
display.update();
while !Buttons::read().right_bottom() {}
}
......@@ -292,13 +346,11 @@ fn title_screen() {
fn game_over(score: u32) -> bool {
let display = Display::open();
display.clear(Color::red());
display.print(30, 0, b"Rkanoid\0", Color::white(), Color::red());
display.print(0, 25, b"Game over!\0", Color::white(), Color::red());
let mut score_str = [0u8; 32];
write!(FmtBuffer::new(&mut score_str), "Score {}\0", score).unwrap();
display.print(0, 60, &score_str, Color::white(), Color::red());
display.print(0, 0, b"Q\0", Color::yellow(), Color::blue());
display.print(Display::W - Display::FONT_W, Display::H - 2 * Display::FONT_H, b"S\0", Color::yellow(), Color::blue());
display!(display, 30, 0, Color::white(), Color::red(), "Rkanoid");
display!(display, 0, 25, Color::white(), Color::red(), "Game over!");
display!(display, 0, 60, Color::white(), Color::red(), "Score {}", score);
display!(display, 0, 0, Color::yellow(), Color::blue(), "Q");
display!(display, Display::W - Display::FONT_W, Display::H - 2 * Display::FONT_H, Color::yellow(), Color::blue(), "S");
display.update();
loop {
let buttons = Buttons::read();
......@@ -314,15 +366,11 @@ fn game_over(score: u32) -> bool {
fn level_finish(level: u16, score: u32) -> bool {
let display = Display::open();
display.clear(Color::red());
display.print(30, 0, b"Rkanoid\0", Color::white(), Color::red());
let mut level_str = [0u8; 32];
write!(FmtBuffer::new(&mut level_str), "Lvl {} done!\0", level + 1).unwrap();
display.print(0, 25, &level_str, Color::white(), Color::red());
let mut score_str = [0u8; 32];
write!(FmtBuffer::new(&mut score_str), "Score {}\0", score).unwrap();
display.print(0, 60, &score_str, Color::white(), Color::red());
display.print(0, 0, b"Q\0", Color::yellow(), Color::blue());
display.print(Display::W - Display::FONT_W, Display::H - 2 * Display::FONT_H, b"S\0", Color::yellow(), Color::blue());
display!(display, 30, 0, Color::white(), Color::red(), "Rkanoid");
display!(display, 0, 25, Color::white(), Color::red(), "Lvl {} done!", level + 1);
display!(display, 20, 60, Color::white(), Color::red(), "Score {}", score);
display!(display, 0, 60, Color::yellow(), Color::blue(), "Q");
display!(display, Display::W - Display::FONT_W, Display::H - 2 * Display::FONT_H, Color::yellow(), Color::blue(), "S");
display.update();
loop {
let buttons = Buttons::read();
......@@ -337,13 +385,16 @@ fn level_finish(level: u16, score: u32) -> bool {
main!(main);
fn main() {
card10_alloc::init(128 * 1024);
title_screen();
let mut quit = false;
let mut level = 0;
let mut score = 0;
while !quit {
match game(level, score) {
let game_result = game(level, score);
update_rgb_leds(|_| LEDColor::RGB(0, 0, 0));
match game_result {
GameResult::LevelFinish(new_score) => {
let again = level_finish(level, new_score);
quit = !again;
......@@ -359,3 +410,15 @@ fn main() {
}
}
}
fn draw_rect(fb: &mut FrameBuffer, x1: u16, y1: u16, x2: u16, y2: u16, color: RawColor) {
let x1 = x1.max(0).min(Display::W as u16 - 1);
let x2 = x2.max(0).min(Display::W as u16 - 1);
let y1 = y1.max(0).min(Display::H as u16 - 1);
let y2 = y2.max(0).min(Display::H as u16 - 1);
for y in y1..=y2 {
for x in x1..=x2 {
fb[(x, y)] = color;
}
}
}
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
with import ./default.nix;
with import ./default.nix {};
stdenv.mkDerivation {
name = "env";
......