marble-machinations/src/marble_engine/board.rs

247 lines
5 KiB
Rust
Raw Normal View History

use crate::Textures;
2024-10-03 22:59:49 +02:00
use super::tile::*;
2024-10-04 22:35:15 +02:00
use raylib::prelude::*;
2024-10-03 22:59:49 +02:00
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct Pos {
pub x: isize,
pub y: isize,
}
2024-10-05 20:22:18 +02:00
impl Pos {
2024-10-06 12:39:36 +02:00
pub const fn to_vec(self) -> Vector2 {
2024-10-05 20:22:18 +02:00
Vector2 {
x: self.x as f32,
y: self.y as f32,
}
}
}
2024-10-03 22:59:49 +02:00
impl From<(usize, usize)> for Pos {
fn from(value: (usize, usize)) -> Self {
Self {
x: value.0 as isize,
y: value.1 as isize,
}
}
}
2024-10-05 15:34:58 +02:00
impl From<Vector2> for Pos {
fn from(vec: Vector2) -> Self {
Self {
x: vec.x as isize,
y: vec.y as isize,
}
}
}
#[derive(Debug, Clone)]
2024-10-03 22:59:49 +02:00
pub struct Board {
rows: Vec<Vec<Tile>>,
width: usize,
height: usize,
offset_x: isize,
offset_y: isize,
2024-10-03 22:59:49 +02:00
}
impl Board {
2024-10-05 19:45:25 +02:00
pub fn parse(source: &str) -> Self {
let mut rows = Vec::new();
let mut width = 0;
for line in source.lines() {
width = width.max(line.len());
let mut tiles = Vec::new();
for char in line.chars() {
tiles.push(Tile::from_char(char));
}
rows.push(tiles);
}
for line in &mut rows {
line.resize(width, Tile::Blank);
}
Board::new(rows)
}
pub fn to_string(&self) -> String {
2024-10-06 16:00:12 +02:00
let mut out = String::new();
for row in &self.rows {
for tile in row {
2024-10-06 16:00:12 +02:00
out.push(tile.to_char())
}
out.push('\n');
}
out
}
2024-10-03 22:59:49 +02:00
pub fn new_empty(width: usize, height: usize) -> Self {
let rows = vec![vec![Tile::Blank; width]; height];
Self {
rows,
width,
height,
offset_x: 0,
offset_y: 0,
2024-10-03 22:59:49 +02:00
}
}
pub fn new(rows: Vec<Vec<Tile>>) -> Self {
Self {
width: rows[0].len(),
height: rows.len(),
rows,
offset_x: 0,
offset_y: 0,
2024-10-03 22:59:49 +02:00
}
}
pub fn count_tiles(&self) -> usize {
let mut sum = 0;
for row in &self.rows {
for tile in row {
match tile {
Tile::Blank | Tile::Block => (),
_ => sum += 1,
}
}
}
sum
}
fn transform(&self, p: Pos) -> Pos {
Pos {
x: p.x + self.offset_x,
y: p.y + self.offset_y,
}
}
pub fn pos_in_bounds(&self, p: Pos) -> bool {
let p = self.transform(p);
self.in_bounds(p)
}
fn in_bounds(&self, p: Pos) -> bool {
2024-10-03 22:59:49 +02:00
p.x >= 0 && p.y >= 0 && p.x < self.width as isize && p.y < self.height as isize
}
pub fn get(&self, p: Pos) -> Option<Tile> {
let p = self.transform(p);
2024-10-03 22:59:49 +02:00
if self.in_bounds(p) {
Some(self.rows[p.y as usize][p.x as usize])
} else {
None
}
}
pub fn get_or_blank(&self, p: Pos) -> Tile {
let p = self.transform(p);
2024-10-03 22:59:49 +02:00
if self.in_bounds(p) {
self.rows[p.y as usize][p.x as usize]
} else {
Tile::default()
}
}
2024-10-05 20:22:18 +02:00
pub fn get_mut(&mut self, p: Pos) -> Option<&mut Tile> {
let p = self.transform(p);
2024-10-05 20:22:18 +02:00
if self.in_bounds(p) {
Some(&mut self.rows[p.y as usize][p.x as usize])
} else {
None
}
}
pub fn get_blank_mut(&mut self, p: Pos) -> Option<&mut Tile> {
let p = self.transform(p);
2024-10-03 22:59:49 +02:00
if self.in_bounds(p) {
let tile = &mut self.rows[p.y as usize][p.x as usize];
if tile == &Tile::Blank {
return Some(tile);
}
2024-10-03 22:59:49 +02:00
}
None
2024-10-03 22:59:49 +02:00
}
pub fn set(&mut self, p: Pos, tile: Tile) {
let p = self.transform(p);
2024-10-03 22:59:49 +02:00
if self.in_bounds(p) {
self.rows[p.y as usize][p.x as usize] = tile;
}
}
pub fn grow_to_include(&mut self, p: Pos) {
let p = self.transform(p);
if p.x < 0 {
2024-10-06 23:37:21 +02:00
let len = p.x.unsigned_abs();
for row in &mut self.rows {
let mut new_row = vec![Tile::Blank; len];
new_row.append(row);
*row = new_row;
}
self.offset_x += len as isize;
self.width += len;
} else if p.x as usize >= self.width {
let new_width = p.x as usize + 1;
for row in &mut self.rows {
row.resize(new_width, Tile::Blank);
}
self.width = new_width;
}
if p.y < 0 {
2024-10-06 23:37:21 +02:00
let len = p.y.unsigned_abs();
let mut new_rows = vec![vec![Tile::Blank; self.width]; len];
new_rows.append(&mut self.rows);
self.rows = new_rows;
self.offset_y += len as isize;
self.height += len;
} else if p.y as usize > self.height {
let new_height = p.y as usize + 1;
self.rows.resize(new_height, vec![Tile::Blank; self.width]);
self.height = new_height;
}
}
2024-10-03 22:59:49 +02:00
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn draw(&self, d: &mut RaylibDrawHandle, textures: &Textures, offset: Vector2, zoom: i32) {
let tile_size = 16 << zoom;
let start_x = (-offset.x as i32) / tile_size + self.offset_x as i32 - 1;
let tile_width = d.get_screen_width() / tile_size + 2;
let start_y = (-offset.y as i32) / tile_size + self.offset_y as i32 - 1;
let tile_height = d.get_screen_height() / tile_size + 2;
for x in start_x..(start_x + tile_width) {
for y in start_y..(start_y + tile_height) {
if self.in_bounds(Pos {
x: x as isize,
y: y as isize,
}) {
let tx = x as usize;
let ty = y as usize;
let tile = self.rows[ty][tx];
let px = (x - self.offset_x as i32) * tile_size + offset.x as i32;
let py = (y - self.offset_y as i32) * tile_size + offset.y as i32;
let texture = textures.get(&tile.texture());
d.draw_texture_ex(
texture,
Vector2::new(px as f32, py as f32),
0.0,
(1 << zoom) as f32,
Color::WHITE,
);
}
}
}
}
2024-10-03 22:59:49 +02:00
}