// modules mod tile; // namespacing use crate::{util::*, MainState, Result}; use ggez::{ graphics::{self, DrawParam}, Context, }; use mint::{Point2, Vector2, Vector3}; use std::{collections::HashMap, path::PathBuf}; use tile::*; /// represent a whole rendered world pub struct World { width: isize, depth: isize, height: isize, data: HashMap, Tile>, builder: TileBuilder, offset: Point2, zoom: Vector2, } impl World { /// create a new world instance pub fn new( ctx: &mut Context, tile_config: PathBuf, width: isize, depth: isize, height: isize, ) -> Result { let builder = TileBuilder::new(ctx, tile_config)?; let mut data: HashMap, Tile> = HashMap::new(); let offset: Point2 = [350.0f32, 100.0f32].into(); let zoom: Vector2 = [1.0f32, 1.0f32].into(); for x in 0..width { for y in 0..depth { for z in 0..height { data.insert([x, y, z].into(), builder.build("nothing".to_owned())?); } } } Ok(World { width, height, depth, data, builder: builder, offset, zoom, }) } /// renders the world to the window pub fn render(&self, ctx: &mut Context) -> Result<()> { for x in 0..self.width { for y in 0..self.depth { for z in 0..self.height { let tile = self.data.get(&[x, y, z].into()).unwrap(); let iso_coord: IsometricVector2 = Point2::from([x as f32, y as f32]).into(); let scale = [self.zoom.x, self.zoom.y]; let dest = [ iso_coord.x() * (self.builder.tile_width() / 2.0) * scale[0] + self.offset.x, iso_coord.y() * (self.builder.tile_height() / 2.0) * scale[1] + self.offset.y, ]; let param = DrawParam::default() .dest(Point2::from_slice(&dest)) .scale(Point2::from_slice(&scale)); graphics::draw(ctx, tile.texture(), param)?; } } } Ok(()) } } /// action struct for wrapping offsetting input #[derive(Debug)] pub struct OffsetAction(Vector2); impl OffsetAction { /// construct a new offset action pub fn new(offset: Vector2) -> OffsetAction { OffsetAction(offset) } } impl crate::Action for OffsetAction { fn execute(&self, _ctx: &mut Context, state: &mut MainState) -> Result<()> { state.world.offset.x = self.0.x * (state.world.builder.tile_width() / 2.0) + state.world.offset.x; state.world.offset.y = self.0.y * (state.world.builder.tile_height() / 2.0) + state.world.offset.y; Ok(()) } fn undo(&self, _ctx: &mut Context, state: &mut MainState) -> Result<()> { state.world.offset.x = state.world.offset.x - self.0.x; state.world.offset.y = state.world.offset.y - self.0.y; Ok(()) } } /// action struct for wrapping zoom input #[derive(Debug)] pub struct ZoomAction(Vector2); impl ZoomAction { /// construct a new scale action pub fn new(scale: Vector2) -> ZoomAction { ZoomAction(scale) } } impl crate::Action for ZoomAction { fn execute(&self, _ctx: &mut Context, state: &mut MainState) -> Result<()> { state.world.zoom.x = self.0.x + state.world.zoom.x; state.world.zoom.y = self.0.y + state.world.zoom.y; Ok(()) } fn undo(&self, _ctx: &mut Context, state: &mut MainState) -> Result<()> { state.world.zoom.x = state.world.zoom.x - self.0.x; state.world.zoom.y = state.world.zoom.y - self.0.y; Ok(()) } }