Commit 85686cb0 authored by Florian Blasius's avatar Florian Blasius 🤘
Browse files

Remove old code. Start implementation of sprite and entity. Expand example files.

parent 01c17f8c
......@@ -5,5 +5,5 @@ use std::env;
use orbgame::Game;
fn main() {
Game::from_toml("res/adventure/game.toml").exec();
Game::from_toml("examples/adventure/game.toml").exec();
}
sheet = "examples/adventure/player.png"
layer = 1
width = 32
heigh = 32
\ No newline at end of file
x = 16
y = 16
width = 14
height = 21
[sprite]
sheet = "examples/adventure/player.png"
animations = [[0, 0, 14, 21], [14, 0, 14, 21], [28, 0, 14, 21], [42, 0, 14, 21],
[0, 21, 14, 21], [14, 21, 14, 21], [28, 21, 14, 21], [42, 21, 14, 21],
[0, 42, 14, 21], [14, 42, 14, 21], [28, 42, 14, 21], [42, 42, 14, 21],
[0, 63, 14, 21], [14, 63, 14, 21], [28, 63, 14, 21], [42, 63, 14, 21]]
\ No newline at end of file
x = 0
y = 0
entities = [
"examples/adventure/player.toml"
]
[map]
tile_set = "examples/adventure/tile_set.toml"
layer_count = 3
......
use std::cell::Cell;
use orbtk::Rect;
use orbtk::{Point, Rect};
use sprite::Sprite;
use Map;
pub enum Direction {
Left,
Up,
Right,
Down,
}
static LAYER_KEY: &str = "layer";
static X_KEY: &str = "x";
static Y_KEY: &str = "y";
static WIDTH_KEY: &str = "width";
static HEIGHT_KEY: &str = "height";
static SPRITE_KEY: &str = "sprite";
pub struct Entity {
layer: i32,
rect: Cell<Rect>,
speed: f32,
direction: Direction,
animation_step: f32,
total_animation_steps: f32,
animation_speed: f32,
screen_position: Cell<Point>,
sprite: Cell<Option<Sprite>>,
}
impl Entity {
pub fn new(rect: Rect, speed: f32) -> Self {
Entity {
rect: Cell::new(rect),
speed,
animation_step: 0.0,
total_animation_steps: 4.0,
animation_speed: 10.0,
direction: Direction::Down,
screen_position: Cell::new(Point::new(rect.x, rect.y)),
}
}
pub fn mov(&mut self, delta: f32, dir_x: f32, dir_y: f32, map: &Map) {
let mut rect = self.rect.get();
pub fn from_toml(path: &str) -> Self {
let value = super::load_toml_value(path).unwrap();
if dir_y > 0.0 {
self.direction = Direction::Down;
self.animation_step += self.animation_speed * delta;
} else if dir_y < 0.0 {
self.direction = Direction::Up;
self.animation_step += self.animation_speed * delta;
} else if dir_x > 0.0 {
self.direction = Direction::Right;
self.animation_step += self.animation_speed * delta;
} else if dir_x < 0.0 {
self.direction = Direction::Left;
self.animation_step += self.animation_speed * delta;
}
println!("{:?}", value);
if self.animation_step > self.total_animation_steps {
self.animation_step = 0.0;
Entity {
layer: value[LAYER_KEY]
.as_integer()
.expect("property layer not found") as i32,
rect: Cell::new(Rect::new(
value[X_KEY]
.as_integer()
.expect("property x not found") as i32,
value[Y_KEY]
.as_integer()
.expect("property y not found") as i32,
value[WIDTH_KEY]
.as_integer()
.expect("property width not found") as u32,
value[HEIGHT_KEY]
.as_integer()
.expect("property height not found") as u32,
)),
sprite: Cell::new(Some(Sprite::from_toml_value(&value[SPRITE_KEY]))),
}
rect.x += (dir_x * self.speed * delta) as i32;
self.check_tile_collison(&mut rect, dir_x, 0.0, map);
rect.y += (dir_y * self.speed * delta) as i32;
self.check_tile_collison(&mut rect, 0.0, dir_y, map);
let max_x = map.column_count() * map.tile_size() as usize - rect.width as usize;
let max_y = map.row_count() * map.tile_size() as usize - rect.height as usize;
let zero_x: i32 = 0 + rect.width as i32;
let zero_y: i32 = 0 + rect.height as i32;
// adjust to respect the render_bounds
rect.x = zero_x.max(rect.x.min(max_x as i32));
rect.y = zero_y.max(rect.y.min(max_y as i32));
self.rect.set(rect);
}
fn check_tile_collison(&mut self, rect: &mut Rect, dir_x: f32, dir_y: f32, map: &Map) {
let left = rect.x as f32 + 1.0;
let right = rect.x as f32 + rect.width as f32 - 1.0;
let top = rect.y as f32 + 1.0;
let bottom = rect.y as f32 + rect.height as f32 - 1.0;
// check for collisions on sprite sides
let collision = map.is_tile_blocked(left, top) || map.is_tile_blocked(right, top)
|| map.is_tile_blocked(right, bottom)
|| map.is_tile_blocked(left, bottom);
if !collision {
return;
}
if dir_y > 0.0 {
rect.y = map.get_y(map.get_row(bottom)) as i32 - rect.height as i32;
} else if dir_y < 0.0 {
rect.y = map.get_y(map.get_row(top) + 1.0) as i32;
} else if dir_x > 0.0 {
rect.x = map.get_x(map.get_column(right)) as i32 - rect.width as i32;
} else if dir_x < 0.0 {
rect.x = map.get_x(map.get_column(left) + 1.0) as i32;
}
pub fn layer(&self) -> i32 {
self.layer
}
pub fn rect(&self) -> &Cell<Rect> {
&self.rect
}
pub fn direction(&self) -> &Direction {
&self.direction
}
pub fn animation_step(&self) -> f32 {
self.animation_step
}
pub fn screen_position(&self) -> &Cell<Point> {
&self.screen_position
pub fn sprite(&self) -> &Cell<Option<Sprite>> {
&self.sprite
}
}
// use std::sync::Arc;
// use std::cell::RefCell;
// use std::time;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use toml;
use std::io::Read;
use std::fs::File;
use orbclient::Renderer;
use orbtk::{Event, Label, Place, Point, Rect, Text, Widget, Window};
use orbtk::theme::Theme;
use fps_counter::FPSCounter;
use super::{TileMap, Stage};
use orbtk::{Place, Rect, Window};
pub trait UpdatableWidget: Widget {
fn update(&self);
}
use super::Stage;
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Config {
......@@ -47,12 +35,6 @@ impl Config {
pub struct Game {
config: Config,
stage: Arc<Stage>,
// window: Window,
// updateable_widgets: RefCell<Vec<Arc<UpdatableWidget>>>,
// last_tick_time: time::Instant,
// fps_in_nanos: f32,
// fps_counter: FPSCounter,
// fps_label: RefCell<Option<Arc<Label>>>,
}
impl Game {
......@@ -82,69 +64,6 @@ impl Game {
self.update();
window.draw();
window.drain_orbital_events();
// if let Some(ref label) = *self.fps_label.borrow() {
// label.text(format!("{}", self.fps_counter.tick()));
// }
}
}
// pub fn new(window: Window) -> Self {
// Game {
// window,
// updateable_widgets: RefCell::new(Vec::new()),
// last_tick_time: time::Instant::now(),
// fps_in_nanos: (1. / 60.) * 1_000_000_000.,
// fps_counter: FPSCounter::new(),
// fps_label: RefCell::new(None),
// }
// }
// pub fn elapsed(&self) -> f32 {
// let time = self.last_tick_time.elapsed();
// let total_nanos = time.as_secs() * 1_000_000_000 + time.subsec_nanos() as u64;
// self.fps_in_nanos - (total_nanos as f32)
// }
// pub fn update(&mut self) {
// if self.elapsed() > 0. {
// return
// }
// self.last_tick_time = time::Instant::now();
// for i in 0..self.updateable_widgets.borrow().len() {
// if let Some(widget) = self.updateable_widgets.borrow().get(i) {
// widget.update();
// }
// }
// }
// pub fn add<T: UpdatableWidget>(&self, widget: &Arc<T>) -> usize {
// let mut widgets = self.updateable_widgets.borrow_mut();
// let id = widgets.len();
// widgets.push(widget.clone());
// id
// }
// pub fn fps_label(&self, fps_label: &Arc<Label>) -> &Self {
// (*self.fps_label.borrow_mut()) = Some(fps_label.clone());
// self
// }
// pub fn exec(&mut self) {
// 'event: while self.window.running.get() {
// self.window.drain_events();
// self.update();
// self.window.draw();
// self.window.drain_orbital_events();
// if let Some(ref label) = *self.fps_label.borrow() {
// label.text(format!("{}", self.fps_counter.tick()));
// }
// }
// }
}
......@@ -9,29 +9,32 @@ extern crate orbtk;
extern crate chrono;
extern crate fps_counter;
use toml::Value;
use std::io::Read;
use std::fs::File;
use toml::Value;
pub use self::camera::*;
// pub use self::entity::*;
pub use self::entity::*;
pub use self::game::*;
// pub use self::level::*;
pub use self::tile_map::*;
// pub use self::scene::*;
pub use self::sprite::Sprite;
pub use self::stage::*;
mod camera;
// mod entity;
mod entity;
mod game;
// mod level;
mod tile_map;
// mod scene;
mod sprite;
mod stage;
pub fn load_toml_value(path: &str) -> Value {
pub fn load_toml_value(path: &str) -> Result<Value, String> {
let mut file = File::open(path).expect("file not found");
let mut contents = String::new();
file.read_to_string(&mut contents).expect("cannot read file");
contents.parse::<Value>().expect("toml value not found")
if let Ok(value) = contents.parse::<toml::Value>() {
return Result::Ok(value)
}
Result::Err(String::from(format!("Could not parse file; {}", path)))
}
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use std::cmp;
use orbclient::{Color, Renderer};
use orbtk::{Event, Place, Point, Rect, Widget, Label};
use orbimage::Image;
use orbclient;
use Camera;
use Level;
use Entity;
use Direction;
use Map;
use UpdatableWidget;
use orbtk::theme::Theme;
pub struct Scene {
rect: Cell<Rect>,
camera: RefCell<Option<Camera>>,
level: RefCell<Option<Arc<Level>>>,
level_sheet: RefCell<Option<Image>>,
direction: Cell<Point>,
player: RefCell<Option<Entity>>,
player_image: RefCell<Option<Image>>,
debug: Cell<bool>,
}
impl Scene {
pub fn new() -> Arc<Self> {
Arc::new(Scene {
rect: Cell::new(Rect::default()),
camera: RefCell::new(None),
level: RefCell::new(None),
level_sheet: RefCell::new(None),
direction: Cell::new(Point::new(0, 0)),
player: RefCell::new(None),
player_image: RefCell::new(None),
debug: Cell::new(true),
})
}
pub fn camera(&self, camera: Camera) -> &Self {
*self.camera.borrow_mut() = Some(camera);
self
}
pub fn player(&self, player: Entity) -> &Self {
*self.player.borrow_mut() = Some(player);
self
}
pub fn player_image(&self, player_image: Image) -> &Self {
*self.player_image.borrow_mut() = Some(player_image);
self
}
pub fn level(&self, level: Arc<Level>) -> &Self {
*self.level.borrow_mut() = Some(level);
self
}
pub fn level_sheet(&self, level_sheet: Image) -> &Self {
*self.level_sheet.borrow_mut() = Some(level_sheet);
self
}
pub fn debug(&self) -> &Cell<bool> {
&self.debug
}
fn draw_layer_by_camera(
&self,
layer: usize,
camera: &Camera,
map: &Map,
renderer: &mut Renderer,
) {
let camera_rect = camera.rect().get();
let rect = self.rect().get();
let start_column = (camera_rect.x as f32 / map.tile_size() as f32).floor() as usize;
let end_column =
start_column + (camera_rect.width as f32 / map.tile_size() as f32).ceil() as usize;
let start_row = (camera_rect.y as f32 / map.tile_size() as f32).floor() as usize;
let end_row =
start_row + (camera_rect.height as f32 / map.tile_size() as f32).ceil() as usize;
let offset_x =
rect.x as f32 + -camera_rect.x as f32 + start_column as f32 * map.tile_size() as f32;
let offset_y =
rect.y as f32 + -camera_rect.y as f32 + start_row as f32 * map.tile_size() as f32;
self.draw_layer(
layer,
map,
start_column,
end_column,
start_row,
end_row,
offset_x,
offset_y,
renderer,
);
}
fn draw_layer(
&self,
layer: usize,
map: &Map,
start_column: usize,
end_column: usize,
start_row: usize,
end_row: usize,
offset_x: f32,
offset_y: f32,
renderer: &mut Renderer,
) {
if let Some(ref image) = *self.level_sheet.borrow() {
// add 1 to prevent missing tiles at the borders
let mut end_column = end_column + 1;
let mut end_row = end_row + 1;
if end_column > map.column_count() {
end_column = map.column_count();
}
if end_row > map.row_count() {
end_row = map.row_count();
}
for r in start_row..end_row {
for c in start_column..end_column {
let tile = map.get_tile(layer, r, c);
if tile == -1 {
continue;
}
let tile_column_count = image.width() / map.tile_size();
let tile_c = tile as f32 % tile_column_count as f32;
let tile_r = (tile as f32 / tile_column_count as f32).floor();
Scene::draw_image_part(
renderer,
image,
(((c - start_column) as f32) * map.tile_size() as f32 + offset_x as f32)
as i32,
(((r - start_row) as f32) * map.tile_size() as f32 + offset_y as f32)
as i32,
tile_c as u32 * map.tile_size(),
tile_r as u32 * map.tile_size(),
map.tile_size(),
map.tile_size(),
);
}
}
}
}
// tmp solution
fn draw_image_part(
renderer: &mut Renderer,
image: &Image,
x: i32,
y: i32,
part_x: u32,
part_y: u32,
w: u32,
h: u32,
) {
let stride = image.width();
let mut offset = (part_y * stride + part_x) as usize;
let last_offset = cmp::min(
((part_y + h) * stride + part_x) as usize,
image.data().len(),
);
let mut y = y;
while offset < last_offset {
let next_offset = offset + stride as usize;
renderer.image(x, y, w, 1, &image.data()[offset..]);
offset = next_offset;
y += 1;
}
}
fn draw_entity(&self, entity: &Entity, image: &Image, renderer: &mut Renderer) {
let position = entity.screen_position().get();
let rect = entity.rect().get();
let tile_r: u32;
let tile_c = entity.animation_step().floor() as u32;
match *entity.direction() {
Direction::Up => tile_r = 2,
Direction::Left => tile_r = 3,
Direction::Right => tile_r = 1,
_ => tile_r = 0,
}
Scene::draw_image_part(
renderer,
image,
position.x,
position.y,
tile_c * rect.width,
tile_r * rect.height,
rect.width,
rect.height,
);
}
fn draw_debugging_grid(&self, level: &Level, camera: &Camera, renderer: &mut Renderer) {
let rect = self.rect.get();
let camera_rect = camera.rect().get();
let tile_size = level.map().tile_size();
let start_column = (camera.rect().get().x as f32 / tile_size as f32).floor() as i32;
let end_column =
1 + start_column + (camera.rect().get().width as f32 / tile_size as f32).ceil() as i32;
let start_row = (camera_rect.y as f32 / tile_size as f32).floor() as i32;
let end_row = 1 + start_row + (camera_rect.height as f32 / tile_size as f32).ceil() as i32;
let offset_x = -camera_rect.x + start_column * tile_size as i32;
let offset_y = -camera_rect.y + start_row * tile_size as i32;
for i in start_column..end_column {
renderer.rect(
((i - start_column)) * tile_size as i32 + offset_x,
0,
1,
rect.height,
Color::rgb(0, 0, 0),
);
}
for i in start_row..end_row {
renderer.rect(
0,
((i - start_row)) * tile_size as i32 + offset_y,
rect.width,
1,
Color::rgb(0, 0, 0),
);
}
}
fn draw_debugging_collision(
&self,
level: &Level,
camera: &Camera,
entity: &Entity,
renderer: &mut Renderer,
) {
let camera_rect = camera.rect().get();
let map = level.map();
let entity_rect = entity.rect().get();
let left = entity_rect.x as f32 + 1.0;
let right = entity_rect.x as f32 + entity_rect.width as f32 - 1.0;
let top = entity_rect.y as f32 + 1.0;
let bottom = entity_rect.y as f32 + entity_rect.height as f32 - 1.0;
let start_column = (left / map.tile_size() as f32).floor() as i32 - 2;
let end_column = (right / map.tile_size() as f32).floor() as i32 + 2;
let start_row = (top / map.tile_size() as f32).floor() as i32 - 2;
let end_row = (bottom / map.tile_size() as f32).floor() as i32 + 2;
// check map render_bounds
let start_column = {
if start_column < 0 {
0