Commit 01c17f8c authored by Florian Blasius's avatar Florian Blasius 🤘
Browse files

Working on architecture, stage, tile map and game.

parent 8b0ff67c
......@@ -23,7 +23,7 @@ opt-level = 1
[dependencies]
orbclient = "0.3.11"
orbtk = "0.2.26"
orbtk = { git = "https://github.com/redox-os/orbtk.git" }
orbimage = "0.1.15"
serde = "1.0"
serde_derive = "1.0"
......
extern crate orbgame;
extern crate orbimage;
extern crate orbtk;
use orbtk::{Color, Label, Point, Rect, Text, Window};
use orbtk::traits::Place;
use orbimage::Image;
use orbgame::*;
use std::env;
fn main() {
let mut window = Window::new(Rect::new(100, 100, 800, 600), "OrbAdventure");
let level = Level::from_path("res/adventure_level.toml");
let sheet = Image::from_path(&level.sheet());
let player_image = Image::from_path("res/adventure_character.png");
let map = level.map().clone();
let main_scene = Scene::new();
main_scene.size(window.width(), window.height());
if let Ok(sheet) = sheet {
// todo: use correct width and height. Maybe need a extra animation file .toml
let player = Entity::new(Rect::new(32, 32, 14, 21), 256.0);
use orbgame::Game;
if let Ok(player_image) = player_image {
main_scene
.camera(Camera::new(
Rect::new(0, 0, window.width(), window.height()),
Point::new(
map.column_count() as i32 * map.tile_size() as i32 - window.width() as i32,
map.row_count() as i32 * map.tile_size() as i32 - window.height() as i32,
),
))
.level(level)
.level_sheet(sheet)
.player(player)
.player_image(player_image);
}
}
window.add(&main_scene);
let fps_counter = Label::new();
fps_counter.position(10, 10).size(16, 16);
fps_counter.bg.set(Color::rgba(0, 0, 0, 0));
fps_counter.fg.set(Color::rgb(255, 255, 255));
window.add(&fps_counter);
let mut game = Game::new(window);
game.fps_label(&fps_counter);
game.add(&main_scene);
game.exec();
fn main() {
Game::from_toml("res/adventure/game.toml").exec();
}
title = "OrbAdventure"
stage = "res/adventure/stage.toml"
stage = "examples/adventure/stage.toml"
target_fps = 60
ui_css = "examples/adventure/ui.css"
width = 800
height = 600
\ No newline at end of file
sheet = "examples/adventure/player.png"
layer = 1
width = 32
heigh = 32
\ No newline at end of file
......@@ -2,7 +2,7 @@ x = 0
y = 0
[map]
tile_set = "res/adventure/tile_set.toml"
tile_set = "examples/adventure/tile_set.toml"
layer_count = 3
row_count = 49
column_count = 60
......
sheet = "res/adventure/tile_sheet.png"
sheet = "examples/adventure/tile_sheet.png"
tile_size = 16
blocked_tiles = [1, 86, 87, 88, 89, 90, 126, 127, 128, 129, 130, 166, 167, 169, 170, 521, 522, 523, 561, 563, 601, 602, 603, 685, 686]
fn main() {
}
\ No newline at end of file
sheet = "res/adventure/player.png"
layer = 1
width = 32
heigh = 32
\ No newline at end of file
use std::cell::Cell;
use orbtk::{Point, Rect};
use Entity;
pub struct Camera {
rect: Cell<Rect>,
......@@ -47,44 +47,44 @@ impl Camera {
self.rect().set(rect);
}
pub fn follow(&mut self, entity: &mut Entity) {
let mut screen_position = entity.screen_position().get();
let entity_rect = entity.rect().get();
let mut rect = self.rect.get();
let maximum = self.maximum.get();
screen_position.x = rect.width as i32 / 2;
screen_position.y = rect.height as i32 / 2;
// make the camera follow the sprite
rect.x = entity_rect.x - rect.width as i32 / 2;
rect.y = entity_rect.y - rect.height as i32 / 2;
let zero: i32 = 0;
// clamp values
rect.x = zero.max(rect.x.min(maximum.x));
rect.y = zero.max(rect.y.min(maximum.y));
// in map corners, the sprite cannot be placed in the center of the screen
// and we have to change its screen coordinates
// left and right sides
if entity_rect.x < rect.width as i32 / 2
|| entity_rect.x > maximum.x + rect.width as i32 / 2
{
let new_x = entity_rect.x - rect.x;
screen_position.x = new_x;
}
// top and bottom sides
if entity_rect.y < rect.height as i32 / 2
|| entity_rect.y > maximum.y + rect.height as i32 / 2
{
let new_y = entity_rect.y - rect.y;
screen_position.y = new_y;
}
entity.screen_position().set(screen_position);
self.rect.set(rect);
}
// pub fn follow(&mut self, entity: &mut Entity) {
// let mut screen_position = entity.screen_position().get();
// let entity_rect = entity.rect().get();
// let mut rect = self.rect.get();
// let maximum = self.maximum.get();
// screen_position.x = rect.width as i32 / 2;
// screen_position.y = rect.height as i32 / 2;
// // make the camera follow the sprite
// rect.x = entity_rect.x - rect.width as i32 / 2;
// rect.y = entity_rect.y - rect.height as i32 / 2;
// let zero: i32 = 0;
// // clamp values
// rect.x = zero.max(rect.x.min(maximum.x));
// rect.y = zero.max(rect.y.min(maximum.y));
// // in map corners, the sprite cannot be placed in the center of the screen
// // and we have to change its screen coordinates
// // left and right sides
// if entity_rect.x < rect.width as i32 / 2
// || entity_rect.x > maximum.x + rect.width as i32 / 2
// {
// let new_x = entity_rect.x - rect.x;
// screen_position.x = new_x;
// }
// // top and bottom sides
// if entity_rect.y < rect.height as i32 / 2
// || entity_rect.y > maximum.y + rect.height as i32 / 2
// {
// let new_y = entity_rect.y - rect.y;
// screen_position.y = new_y;
// }
// entity.screen_position().set(screen_position);
// self.rect.set(rect);
// }
}
// use std::sync::Arc;
// use std::cell::RefCell;
// use std::time;
use std::io::Read;
use std::fs::File;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use toml;
use toml::Value;
use std::io::Read;
use std::fs::File;
use orbtk::{Label, Rect, Text, Widget, Window};
use orbclient::Renderer;
use orbtk::{Event, Label, Place, Point, Rect, Text, Widget, Window};
use orbtk::theme::Theme;
use fps_counter::FPSCounter;
use Map;
use super::{TileMap, Stage};
pub trait UpdatableWidget: Widget {
fn update(&self);
}
pub struct Stage {
}
impl Stage {
pub fn from_toml(path: &str) -> Self {
println!("{}", path);
let mut file = File::open(path).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let value = contents.parse::<Value>().unwrap();
println!("{:?}", value);
Stage {
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Config {
title: String,
......@@ -48,6 +27,7 @@ pub struct Config {
target_fps: u32,
width: u32,
height: u32,
ui_css: String,
}
impl Config {
......@@ -55,7 +35,6 @@ impl Config {
let config = {
// todo: handel result
let mut file = File::open(path).unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
toml::from_slice(&buf).unwrap()
......@@ -67,7 +46,7 @@ impl Config {
pub struct Game {
config: Config,
stage: Stage,
stage: Arc<Stage>,
// window: Window,
// updateable_widgets: RefCell<Vec<Arc<UpdatableWidget>>>,
// last_tick_time: time::Instant,
......@@ -82,8 +61,8 @@ impl Game {
}
pub fn from_config(config: Config) -> Self {
let stage = Stage::from_toml(&config.stage[..]);
stage.size(config.width, config.height);
Game { config, stage }
}
......@@ -96,6 +75,8 @@ impl Game {
&self.config.title[..],
);
window.add(&self.stage);
'event: while window.running.get() {
window.drain_events();
self.update();
......
......@@ -9,18 +9,29 @@ extern crate orbtk;
extern crate chrono;
extern crate fps_counter;
use toml::Value;
use std::io::Read;
use std::fs::File;
pub use self::camera::*;
pub use self::entity::*;
// pub use self::entity::*;
pub use self::game::*;
pub use self::level::*;
pub use self::map::*;
pub use self::scene::*;
// pub use self::level::*;
pub use self::tile_map::*;
// pub use self::scene::*;
pub use self::stage::*;
mod camera;
mod entity;
// mod entity;
mod game;
mod level;
mod map;
mod scene;
mod stage;
\ No newline at end of file
// mod level;
mod tile_map;
// mod scene;
mod stage;
pub fn load_toml_value(path: &str) -> Value {
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")
}
extern crate orbgame;
use std::env;
use orbgame::Game;
// static CHAR: &'static [u8; 1290] = include_bytes!("../res/adventure_character.png");
// static LEVEL: &'static [u8; 32877] = include_bytes!("../res/adventure_level.toml");
// static LEVEL_SHEET: &'static [u8; 100846] = include_bytes!("../res/adventure_sheet.png");
fn main() {
Game::from_toml("res/adventure/game.toml").exec();
// let config = Config::from_toml("res/adventure/game.toml");
// println!("{:?}", config);
// let mut window = Window::new(Rect::new(100, 100, 800, 600), "OrbAdventure");
// let level = Level::from_data(LEVEL);
// let map = level.map().clone();
// let main_scene = Scene::new();
// main_scene.size(window.width(), window.height());
// if let Ok(sheet) = orbimage::parse_png(LEVEL_SHEET) {
// // todo: use correct width and height. Maybe need a extra animation file .toml
// let player = Entity::new(Rect::new(32, 32, 14, 21), 256.0);
// if let Ok(player_image) = orbimage::parse_png(CHAR) {
// main_scene
// .camera(Camera::new(
// Rect::new(0, 0, window.width(), window.height()),
// Point::new(
// map.column_count() as i32 * map.tile_size() as i32 - window.width() as i32,
// map.row_count() as i32 * map.tile_size() as i32 - window.height() as i32,
// ),
// ))
// .level(level)
// .level_sheet(sheet)
// .player(player)
// .player_image(player_image);
// }
// }
// window.add(&main_scene);
// let fps_counter = Label::new();
// fps_counter.position(10, 10).size(16, 16);
// fps_counter.bg.set(Color::rgba(0, 0, 0, 0));
// fps_counter.fg.set(Color::rgb(255, 255, 255));
// window.add(&fps_counter);
// let mut game = Game::new(window);
// game.fps_label(&fps_counter);
// game.add(&main_scene);
// game.exec();
let args: Vec<String> = env::args().collect();
Game::from_toml(&args[1][..]).exec();
}
......@@ -5,6 +5,7 @@ use std::cmp;
use orbclient::{Color, Renderer};
use orbtk::{Event, Place, Point, Rect, Widget, Label};
use orbimage::Image;
use orbclient;
use Camera;
use Level;
......@@ -13,6 +14,8 @@ use Direction;
use Map;
use UpdatableWidget;
use orbtk::theme::Theme;
pub struct Scene {
rect: Cell<Rect>,
camera: RefCell<Option<Camera>>,
......@@ -337,7 +340,11 @@ impl Widget for Scene {
&self.rect
}
fn draw(&self, renderer: &mut Renderer, _focused: bool) {
fn name(&self) -> &str {
"scene"
}
fn draw(&self, renderer: &mut Renderer, _focused: bool, theme: &Theme) {
if let Some(ref camera) = *self.camera.borrow() {
if let Some(ref level) = *self.level.borrow() {
self.draw_layer_by_camera(0, &camera, &level.map(), renderer);
......@@ -365,33 +372,43 @@ impl Widget for Scene {
fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
let mut direction = self.direction.get();
match event {
Event::LeftArrow => {
direction.x = -1;
// match event {
// Event::KeyPressed(key_event) {
// match key_event {
// orbclient::K_LEFT => {
*redraw = true;
}
Event::UpArrow => {
direction.y = -1;
// },
// orbclient::K_UP => {
*redraw = true;
}
Event::RightArrow => {
direction.x = 1;
// }
// }
// }
// Event::LeftArrow => {
// direction.x = -1;
*redraw = true;
}
Event::DownArrow => {
direction.y = 1;
// *redraw = true;
// }
// Event::UpArrow => {
// direction.y = -1;
*redraw = true;
}
_ => (),
}
// *redraw = true;
// }
// Event::RightArrow => {
// direction.x = 1;
// *redraw = true;
// }
// Event::DownArrow => {
// direction.y = 1;
// *redraw = true;
// }
// _ => (),
// }
self.direction.set(direction);
// self.direction.set(direction);
focused
// focused
}
}
......
// use std::sync::Arc;
// use std::cell::RefCell;
// use std::time;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use std::cmp;
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 orbimage::{Image, ImageRoi};
use fps_counter::FPSCounter;
use Camera;
use TileMap;
static MAP_KEY: &str = "map";
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Stage {
x: i32,
y: i32,
}
\ No newline at end of file
rect: Cell<Rect>,
tile_map: RefCell<Option<TileMap>>,
camera: RefCell<Camera>,
}
impl Stage {
pub fn from_toml(path: &str) -> Arc<Self> {
let value = super::load_toml_value(path);
// todo handle Result of tilemap and use None for error (not found)
Arc::new(Stage {
tile_map: RefCell::new(Some(TileMap::from_toml_value(&value[MAP_KEY]))),
rect: Cell::new(Rect::new(0, 0, 0, 0)),
camera: RefCell::new(Camera::new(Rect::new(0, 0, 800, 600), Point::new(1000, 1000))),
})
}
pub fn camera(&self, camera: Camera) -> &Self {
(*self.camera.borrow_mut()) = camera;
self
}
pub fn draw_all_layers(&self, renderer: &mut Renderer) {
let rect = self.rect.get();
let camera_rect = self.camera.borrow().rect().get();
// draw the tile map
let mut tile_size = 0;
let mut start_column = 0;
let mut end_column = 0;
let mut start_row = 0;
let mut end_row = 0;
let mut offset_x = 0.;
let mut offset_y = 0.;
let tile_map = self.tile_map.borrow();
if let Some(ref tile_map) = *tile_map {
tile_size = tile_map.tile_size();
start_column = (camera_rect.x as f32 / tile_size as f32).floor() as usize;
end_column =
start_column + (camera_rect.width as f32 / tile_size as f32).ceil() as usize;
start_row = (camera_rect.y as f32 / tile_size as f32).floor() as usize;
end_row = start_row + (camera_rect.height as f32 / tile_size as f32).ceil() as usize;
offset_x =
rect.x as f32 + -camera_rect.x as f32 + start_column as f32 * tile_size as f32;
offset_y = rect.y as f32 + -camera_rect.y as f32 + start_row as f32 * tile_size as f32;
}
for i in 0..3 {
if let Some(ref tile_map) = *tile_map {
self.draw_tile_map_layer(
i,
tile_map,
start_column,
end_column,
start_row,
end_row,
offset_x,
offset_y,
renderer,
);
}
}
}
fn draw_tile_map_layer(
&self,
layer: usize,
tile_map: &TileMap,
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) = *tile_map.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 > tile_map.column_count() {
end_column = tile_map.column_count();
}
if end_row > tile_map.row_count() {
end_row = tile_map.row_count();
}
for r in start_row..end_row {
for c in start_column..end_column {
let tile = tile_map.get_tile(layer, r, c);