From 23057dac837b2cb3c0901165e8139796e4dfd97a Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Fri, 1 Apr 2022 23:39:20 -0400 Subject: [PATCH 1/9] working on obj description format --- game/game_logic/Cargo.toml | 2 +- game/game_logic/src/model/mod.rs | 3 ++- game/game_logic/src/model/world_object.rs | 26 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 game/game_logic/src/model/world_object.rs diff --git a/game/game_logic/Cargo.toml b/game/game_logic/Cargo.toml index be0d2754..e6fb3ce5 100644 --- a/game/game_logic/Cargo.toml +++ b/game/game_logic/Cargo.toml @@ -25,4 +25,4 @@ thiserror = "1.0.30" approx = "0.5.1" poll-promise = { version = "0.1.0", features = ["tokio"] } tempfile = "3.3.0" -nalgebra = "0.30.1" \ No newline at end of file +nalgebra = { version = "0.30.1", features=["serde-serialize"]} \ No newline at end of file diff --git a/game/game_logic/src/model/mod.rs b/game/game_logic/src/model/mod.rs index d44230b1..f576cdb7 100644 --- a/game/game_logic/src/model/mod.rs +++ b/game/game_logic/src/model/mod.rs @@ -1 +1,2 @@ -pub mod player; \ No newline at end of file +pub mod player; +pub mod world_object; \ No newline at end of file diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs new file mode 100644 index 00000000..44ef9a46 --- /dev/null +++ b/game/game_logic/src/model/world_object.rs @@ -0,0 +1,26 @@ +use nalgebra as na; +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +pub struct PossiblyAnimatedTexture { + /// Signal if the texture is animated or static + pub animated: bool, + /// Relative file path from `dist` to the texture + pub rel_file_path: String, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct WorldObject { + /// Object name. Must match the name of the texture + pub name: String, + /// Object variant name. Must match the name of the texture, or None if there is only one variant + pub variant_name: Option, + /// Object position. 1,1 being up and to the right + pub position: na::Vector2, + /// Object rotation, positive is clockwise + pub rotation_radians: f32, + /// The object's bottom texture + pub bottom_texture: PossiblyAnimatedTexture, + /// The object's top texture + pub top_texture: Option, +} From e1eccd2f9e0991ea23bc75384b9987ce0eec5e66 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 00:07:03 -0400 Subject: [PATCH 2/9] json backings --- game/game_logic/src/model/world_object.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index 44ef9a46..ceb0fe9c 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -9,6 +9,17 @@ pub struct PossiblyAnimatedTexture { pub rel_file_path: String, } + +#[derive(Debug, Clone, Deserialize)] +pub struct ObjectCollider { + /// Position, relative to the object's center (north east is 1,1 south west is -1,-1) + pub position: na::Vector2, + /// Possible sizing + pub size: Option>, + /// Possible radius + pub radius: Option, +} + #[derive(Debug, Clone, Deserialize)] pub struct WorldObject { /// Object name. Must match the name of the texture @@ -23,4 +34,10 @@ pub struct WorldObject { pub bottom_texture: PossiblyAnimatedTexture, /// The object's top texture pub top_texture: Option, + /// colliders describing the object's footprint + pub footprint: Vec, + /// Colliders for physics + pub physics_colliders: Vec, + /// Temperature + pub temperature: Option, } From f5c63a5c559578827bea54f218185b90a8bb8815 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 15:07:22 -0400 Subject: [PATCH 3/9] Defining a test object --- .../env_testObject/env_testObject.xcf | Bin 0 -> 10666 bytes .../env/env_testObject/env_testObject.json | 31 ++++++++++++++++++ .../env_testObject/env_testObjectBottom.png | Bin 0 -> 1225 bytes .../env/env_testObject/env_testObjectTop.png | Bin 0 -> 1537 bytes game/dist/map_gameMap.objects.json | 8 +++++ game/game_logic/src/model/world_object.rs | 2 +- 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 assets/ewpratten/env_testObject/env_testObject.xcf create mode 100644 game/dist/assets/env/env_testObject/env_testObject.json create mode 100644 game/dist/assets/env/env_testObject/env_testObjectBottom.png create mode 100644 game/dist/assets/env/env_testObject/env_testObjectTop.png create mode 100644 game/dist/map_gameMap.objects.json diff --git a/assets/ewpratten/env_testObject/env_testObject.xcf b/assets/ewpratten/env_testObject/env_testObject.xcf new file mode 100644 index 0000000000000000000000000000000000000000..23a451738397b3f1320f095c979d2be401bfd443 GIT binary patch literal 10666 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 literal 0 HcmV?d00001 diff --git a/game/dist/assets/env/env_testObject/env_testObject.json b/game/dist/assets/env/env_testObject/env_testObject.json new file mode 100644 index 00000000..1e1cbfa6 --- /dev/null +++ b/game/dist/assets/env/env_testObject/env_testObject.json @@ -0,0 +1,31 @@ +{ + "name": "env_testObject", + "bottom_texture": { + "file_path": "assets/env/env_testObject/env_testObjectBottom.png" + }, + "top_texture": { + "file_path": "assets/env/env_testObject/env_testObjectTop.png" + }, + "footprint": [ + { + "position": [ + 0, + 0 + ], + "radius": 256.0 + } + ], + "physics_colliders": [ + { + "position": [ + -118, + -60 + ], + "size": [ + 230, + 127 + ] + } + ], + "temperature": 5.0 +} \ No newline at end of file diff --git a/game/dist/assets/env/env_testObject/env_testObjectBottom.png b/game/dist/assets/env/env_testObject/env_testObjectBottom.png new file mode 100644 index 0000000000000000000000000000000000000000..a38050380d7b01f9f278cfee737206db2445dba6 GIT binary patch literal 1225 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$5xX)7d$|)7e>}peR2rGbfdS zL1SX=L|c!;4l+mMFMGLa$-Yr|G-07t2Wz09`&uVKt(K^Tq3n~r_b=#F^eikCiQ(p} z(+QJ}nNwO?Aj)!(U%*{m-Bn!kW4-4>*BG|H1cpYaboiF zaRvsa&7LlfAr-gY-fav#Y{27ivFr3d?QTYm@|TH8o^|<+({BAL_2OC&R7oaqKNZU_ z6IVU^+&&HS4~h)Wr&@E_saL1npVh)(v1qOq*ZO#y9~FuWY;)#UoALjOWIf>USVe__ zOgTe~DWM4fkAsMk literal 0 HcmV?d00001 diff --git a/game/dist/assets/env/env_testObject/env_testObjectTop.png b/game/dist/assets/env/env_testObject/env_testObjectTop.png new file mode 100644 index 0000000000000000000000000000000000000000..47f071186a97bd07957f26565848ad9fbe202601 GIT binary patch literal 1537 zcmaJ=3rtg282<0=EiFZ8QI>XCr1%H}9JJY#=y()Lg=$o0hFF7CWko9j1DoC zWtnxgI5gl1Z@9*^vV!`)Z=yNgH?(}SDTP+I=0am-kR&h9FU`xRcfA0AEKw~44_|7n_mkjT zBC00@M7g>&vp=uH81SVQCmKq_&OaU43D$-ax9)Cs&?|B%>|5Du`zYaR(itpTE>C6j z`c;Vsrwtt;%;)`h^r`e*v+hU?NFRmjC|oXnamjb-6I!);N3QFr;>AnK0(SoXhK+m< z`YfKxB6C%C-&ZbHXYH^tMli#G-eh+sLOwg=jMv z0=tc+AXKv2Y@!^ld*cwWFXQ^bzA5 zuryRU5RbnvX;NGZ^lSr55s(1#X6-pPC^5i+4mGwI5=bv#fe=W;ON@Xtx5iEJ{>89J z9g~qb_5Ve)Pd#s-Pc}m?`(#AomnGenln2Q4g=3GY048G@IfHt+U+jW)ZJ{ zHu1CNpJ9(47+q4{AU?ay-&6mdV^%Bwp_!#3Hxy=>w~S8R7on-6xgAafBZdlYh=5eo zEXk^uKeUcS+FQ_IlZu#@BCKYQvmGqd@grfd>%yyc;AtE;akN7R_`!Fc2hv22EL$=GBVJTeSWq4fAb0oID{ z=nzV+dfx8t!|+}q3TMhtEqi+)7Uf|%e7r;o3DC{$NCf%+F9d%9ga?ew8xoDlD^eGgt0I~OccbEH@pyj{t)3gu~D#)96CTl(e`oFzdmpQ z_*%vY~r{>0~?f*h(tm|xh1_*F)PO$Z0^mBiqPKr`tnTeiCUZCKLJoUB;? r>~Yk%QLr?j-}k literal 0 HcmV?d00001 diff --git a/game/dist/map_gameMap.objects.json b/game/dist/map_gameMap.objects.json new file mode 100644 index 00000000..e5bb13c2 --- /dev/null +++ b/game/dist/map_gameMap.objects.json @@ -0,0 +1,8 @@ +[ + { + "type":"env", + "name":"env_testObject", + "position": [0,0], + "rotation_radians": 0.5 + } +] \ No newline at end of file diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index ceb0fe9c..59fb0094 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -6,7 +6,7 @@ pub struct PossiblyAnimatedTexture { /// Signal if the texture is animated or static pub animated: bool, /// Relative file path from `dist` to the texture - pub rel_file_path: String, + pub file_path: String, } From 74066c01895bfca90e893a1f8f38a20bf47bc7cf Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 15:27:26 -0400 Subject: [PATCH 4/9] wip objects --- game/game_logic/src/model/world_object.rs | 80 ++++++++++++++++++++--- game/game_logic/src/scenes/test_fox.rs | 6 +- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index 59fb0094..44a14d15 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -1,15 +1,19 @@ +use std::collections::HashMap; + use nalgebra as na; use serde::Deserialize; +use crate::asset_manager::{load_json_structure, InternalJsonLoadError}; + #[derive(Debug, Clone, Deserialize)] pub struct PossiblyAnimatedTexture { /// Signal if the texture is animated or static - pub animated: bool, + pub animated: Option, /// Relative file path from `dist` to the texture pub file_path: String, } - +/// Defines a collider in object space. #[derive(Debug, Clone, Deserialize)] pub struct ObjectCollider { /// Position, relative to the object's center (north east is 1,1 south west is -1,-1) @@ -20,16 +24,11 @@ pub struct ObjectCollider { pub radius: Option, } +/// Definition of an object. Only one of these should exist *per object*, and they will be GPU instanced. #[derive(Debug, Clone, Deserialize)] pub struct WorldObject { /// Object name. Must match the name of the texture pub name: String, - /// Object variant name. Must match the name of the texture, or None if there is only one variant - pub variant_name: Option, - /// Object position. 1,1 being up and to the right - pub position: na::Vector2, - /// Object rotation, positive is clockwise - pub rotation_radians: f32, /// The object's bottom texture pub bottom_texture: PossiblyAnimatedTexture, /// The object's top texture @@ -41,3 +40,68 @@ pub struct WorldObject { /// Temperature pub temperature: Option, } + +/// Used to reference an object in the world definition +#[derive(Debug, Clone, Deserialize)] +pub struct WorldObjectRef { + /// Object type + #[serde(rename = "type")] + pub kind: String, + /// Object name + pub name: String, + /// Object position. 1,1 being up and to the right + pub position: na::Vector2, + /// Object rotation, positive is clockwise + pub rotation_radians: f32, +} + +/// A simply interface for the madness +#[derive(Debug, Clone)] +pub struct WorldObjectPackage { + /// The object definitions + pub object_definitions: HashMap, + /// The object references + pub object_references: Vec, + /// Bottom static textures + pub bottom_static_textures: HashMap, + /// Top static textures + pub top_static_textures: HashMap, + /// Bottom animated textures + pub bottom_animated_textures: HashMap, + /// Top animated textures + pub top_animated_textures: HashMap, +} + +impl WorldObjectPackage { + pub fn load(map_objects_file_path: &str) -> Result { + // Attempt to load the object reference list + let object_references: Vec = load_json_structure(map_objects_file_path)?; + + // We also need to load the object definitions + let mut object_definitions = HashMap::new(); + for reference in &object_references { + // If this is a new object, load it. + let object_key = format!("{}:{}", reference.kind, reference.name); + if !object_definitions.contains_key(object_key.as_str()) { + // Construct the file path from the data we know about the reference + let path = format!( + "assets/{}/{}/{}.json", + reference.kind, reference.name, reference.name + ); + + // Attempt to load the object definition + let object_definition: WorldObject = load_json_structure(&path)?; + + // Store the object definition + object_definitions.insert(object_key.to_string(), object_definition); + } + } + + Ok(Self { + object_definitions, + object_references, + }) + } + + +} diff --git a/game/game_logic/src/scenes/test_fox.rs b/game/game_logic/src/scenes/test_fox.rs index d9d1973e..34625b67 100644 --- a/game/game_logic/src/scenes/test_fox.rs +++ b/game/game_logic/src/scenes/test_fox.rs @@ -7,7 +7,7 @@ use raylib::prelude::*; use crate::{ discord::DiscordChannel, global_resource_package::GlobalResources, - rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, + rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, model::world_object::WorldObjectPackage, }; #[derive(Debug)] @@ -15,6 +15,7 @@ pub struct TestFoxScene { fox_animation: AnimatedTexture, world_map: MapRenderer, camera: Camera2D, + objects: WorldObjectPackage } impl TestFoxScene { @@ -25,6 +26,7 @@ impl TestFoxScene { // Load the map let map_renderer = MapRenderer::new("map_gameMap.tmx", raylib_handle, thread).unwrap(); + let objects = WorldObjectPackage::load("map_gameMap.objects.json").unwrap(); // Create a camera let camera = Camera2D { @@ -37,10 +39,12 @@ impl TestFoxScene { zoom: 1.0, }; + Self { fox_animation: fox, world_map: map_renderer, camera, + objects } } From 2d944dc2f32b3746ad536ec75e1e675ca71c00d9 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 15:43:42 -0400 Subject: [PATCH 5/9] World object loading --- game/game_logic/src/model/mod.rs | 3 +- game/game_logic/src/model/world_object.rs | 54 +-------- .../src/model/world_object_package.rs | 111 ++++++++++++++++++ game/game_logic/src/scenes/test_fox.rs | 11 +- 4 files changed, 123 insertions(+), 56 deletions(-) create mode 100644 game/game_logic/src/model/world_object_package.rs diff --git a/game/game_logic/src/model/mod.rs b/game/game_logic/src/model/mod.rs index f576cdb7..dbd3fca7 100644 --- a/game/game_logic/src/model/mod.rs +++ b/game/game_logic/src/model/mod.rs @@ -1,2 +1,3 @@ pub mod player; -pub mod world_object; \ No newline at end of file +pub mod world_object; +pub mod world_object_package; \ No newline at end of file diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index 44a14d15..15f14555 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -3,7 +3,10 @@ use std::collections::HashMap; use nalgebra as na; use serde::Deserialize; -use crate::asset_manager::{load_json_structure, InternalJsonLoadError}; +use crate::{ + asset_manager::{load_json_structure, InternalJsonLoadError}, + rendering::utilities::anim_texture::AnimatedTexture, +}; #[derive(Debug, Clone, Deserialize)] pub struct PossiblyAnimatedTexture { @@ -55,53 +58,4 @@ pub struct WorldObjectRef { pub rotation_radians: f32, } -/// A simply interface for the madness -#[derive(Debug, Clone)] -pub struct WorldObjectPackage { - /// The object definitions - pub object_definitions: HashMap, - /// The object references - pub object_references: Vec, - /// Bottom static textures - pub bottom_static_textures: HashMap, - /// Top static textures - pub top_static_textures: HashMap, - /// Bottom animated textures - pub bottom_animated_textures: HashMap, - /// Top animated textures - pub top_animated_textures: HashMap, -} -impl WorldObjectPackage { - pub fn load(map_objects_file_path: &str) -> Result { - // Attempt to load the object reference list - let object_references: Vec = load_json_structure(map_objects_file_path)?; - - // We also need to load the object definitions - let mut object_definitions = HashMap::new(); - for reference in &object_references { - // If this is a new object, load it. - let object_key = format!("{}:{}", reference.kind, reference.name); - if !object_definitions.contains_key(object_key.as_str()) { - // Construct the file path from the data we know about the reference - let path = format!( - "assets/{}/{}/{}.json", - reference.kind, reference.name, reference.name - ); - - // Attempt to load the object definition - let object_definition: WorldObject = load_json_structure(&path)?; - - // Store the object definition - object_definitions.insert(object_key.to_string(), object_definition); - } - } - - Ok(Self { - object_definitions, - object_references, - }) - } - - -} diff --git a/game/game_logic/src/model/world_object_package.rs b/game/game_logic/src/model/world_object_package.rs new file mode 100644 index 00000000..8f8cd245 --- /dev/null +++ b/game/game_logic/src/model/world_object_package.rs @@ -0,0 +1,111 @@ +use std::collections::HashMap; + +use raylib::{texture::Texture2D, RaylibHandle, RaylibThread}; + +use crate::{ + asset_manager::{load_json_structure, load_texture_from_internal_data}, + rendering::utilities::anim_texture::AnimatedTexture, +}; + +use super::world_object::{WorldObject, WorldObjectRef}; + +#[derive(Debug, thiserror::Error)] +pub enum WorldObjectPackageLoadError { + #[error(transparent)] + JsonError(#[from] crate::asset_manager::InternalJsonLoadError), + #[error(transparent)] + ResourceError(#[from] crate::asset_manager::ResourceLoadError), +} + +/// A simply interface for the madness +#[derive(Debug)] +pub struct WorldObjectPackage { + /// The object definitions + pub object_definitions: HashMap, + /// The object references + pub object_references: Vec, + /// Bottom static textures + pub bottom_static_textures: HashMap, + /// Top static textures + pub top_static_textures: HashMap, + /// Bottom animated textures + pub bottom_animated_textures: HashMap, + /// Top animated textures + pub top_animated_textures: HashMap, +} + +impl WorldObjectPackage { + pub fn load( + raylib_handle: &mut RaylibHandle, + thread: &RaylibThread, + map_objects_file_path: &str, + ) -> Result { + // Attempt to load the object reference list + let object_references: Vec = load_json_structure(map_objects_file_path)?; + + // We also need to load the object definitions + let mut object_definitions = HashMap::new(); + let mut bottom_static_textures = HashMap::new(); + let mut top_static_textures = HashMap::new(); + let mut bottom_animated_textures = HashMap::new(); + let mut top_animated_textures = HashMap::new(); + for reference in &object_references { + // If this is a new object, load it. + let object_key = format!("{}:{}", reference.kind, reference.name); + if !object_definitions.contains_key(object_key.as_str()) { + // Construct the file path from the data we know about the reference + let path = format!( + "assets/{}/{}/{}.json", + reference.kind, reference.name, reference.name + ); + + // Attempt to load the object definition + let object_definition: WorldObject = load_json_structure(&path)?; + + // If this object has a static bottom texture, load it + if object_definition.bottom_texture.animated.unwrap_or(false) { + panic!("Animated bottom textures are not supported yet") + } else { + // Load the bottom texture and save it + bottom_static_textures.insert( + object_key.to_string(), + load_texture_from_internal_data( + raylib_handle, + thread, + &object_definition.bottom_texture.file_path, + )?, + ); + } + + // If there is a top texture, load it + if let Some(top_texture) = &object_definition.top_texture { + if top_texture.animated.unwrap_or(false) { + panic!("Animated top textures are not supported yet") + } else { + // Load the top texture and save it + top_static_textures.insert( + object_key.to_string(), + load_texture_from_internal_data( + raylib_handle, + thread, + &top_texture.file_path, + )?, + ); + } + } + + // Store the object definition + object_definitions.insert(object_key.to_string(), object_definition); + } + } + + Ok(Self { + object_definitions, + object_references, + bottom_static_textures, + top_static_textures, + bottom_animated_textures, + top_animated_textures, + }) + } +} diff --git a/game/game_logic/src/scenes/test_fox.rs b/game/game_logic/src/scenes/test_fox.rs index 34625b67..23a7f257 100644 --- a/game/game_logic/src/scenes/test_fox.rs +++ b/game/game_logic/src/scenes/test_fox.rs @@ -7,7 +7,8 @@ use raylib::prelude::*; use crate::{ discord::DiscordChannel, global_resource_package::GlobalResources, - rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, model::world_object::WorldObjectPackage, + model::world_object_package::WorldObjectPackage, + rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, }; #[derive(Debug)] @@ -15,7 +16,7 @@ pub struct TestFoxScene { fox_animation: AnimatedTexture, world_map: MapRenderer, camera: Camera2D, - objects: WorldObjectPackage + objects: WorldObjectPackage, } impl TestFoxScene { @@ -26,7 +27,8 @@ impl TestFoxScene { // Load the map let map_renderer = MapRenderer::new("map_gameMap.tmx", raylib_handle, thread).unwrap(); - let objects = WorldObjectPackage::load("map_gameMap.objects.json").unwrap(); + let objects = + WorldObjectPackage::load(raylib_handle, thread, "map_gameMap.objects.json").unwrap(); // Create a camera let camera = Camera2D { @@ -39,12 +41,11 @@ impl TestFoxScene { zoom: 1.0, }; - Self { fox_animation: fox, world_map: map_renderer, camera, - objects + objects, } } From 133e71a78f4b989254afc6547f3cefb17f6e71b6 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 15:51:45 -0400 Subject: [PATCH 6/9] Time to begin rendering --- game/game_logic/src/model/world_object.rs | 2 ++ .../src/rendering/utilities/map_render.rs | 27 +++++++++++++++---- game/game_logic/src/scenes/test_fox.rs | 13 ++++----- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index 15f14555..ffad27a3 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -42,6 +42,8 @@ pub struct WorldObject { pub physics_colliders: Vec, /// Temperature pub temperature: Option, + /// Friction + pub friction: Option, } /// Used to reference an object in the world definition diff --git a/game/game_logic/src/rendering/utilities/map_render.rs b/game/game_logic/src/rendering/utilities/map_render.rs index b9822917..c89c70e4 100644 --- a/game/game_logic/src/rendering/utilities/map_render.rs +++ b/game/game_logic/src/rendering/utilities/map_render.rs @@ -1,6 +1,9 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc}; -use crate::asset_manager::{load_texture_from_internal_data, InternalData}; +use crate::{ + asset_manager::{load_texture_from_internal_data, InternalData}, + model::world_object_package::WorldObjectPackage, +}; use nalgebra as na; use raylib::{ camera::Camera2D, @@ -75,12 +78,14 @@ impl ResourceCache for ProgramDataTileCache { pub struct MapRenderer { map: Map, tile_textures: HashMap, + world_objects: WorldObjectPackage, } impl MapRenderer { /// Construct a new MapRenderer. pub fn new( tmx_path: &str, + objects_path: &str, raylib: &mut RaylibHandle, raylib_thread: &RaylibThread, ) -> Result { @@ -116,7 +121,14 @@ impl MapRenderer { } } - Ok(Self { map, tile_textures }) + // Load the world objects + let world_objects = WorldObjectPackage::load(raylib, raylib_thread, objects_path).unwrap(); + + Ok(Self { + map, + tile_textures, + world_objects, + }) } pub fn sample_friction_at(&self, position: na::Vector2) -> f32 { @@ -127,7 +139,12 @@ impl MapRenderer { todo!() } - pub fn render_map(&self, draw_handle: &mut RaylibMode2D, camera: &Camera2D, show_debug_grid:bool) { + pub fn render_map( + &self, + draw_handle: &mut RaylibMode2D, + camera: &Camera2D, + show_debug_grid: bool, + ) { // Get the window corners in world space let screen_width = draw_handle.get_screen_width(); let screen_height = draw_handle.get_screen_height(); @@ -187,8 +204,8 @@ impl MapRenderer { tile_y * tile_height as i32, Color::WHITE, ); - } - + } + if show_debug_grid { draw_handle.draw_rectangle_lines( tile_x * tile_width as i32, diff --git a/game/game_logic/src/scenes/test_fox.rs b/game/game_logic/src/scenes/test_fox.rs index 23a7f257..38bfdb06 100644 --- a/game/game_logic/src/scenes/test_fox.rs +++ b/game/game_logic/src/scenes/test_fox.rs @@ -7,7 +7,6 @@ use raylib::prelude::*; use crate::{ discord::DiscordChannel, global_resource_package::GlobalResources, - model::world_object_package::WorldObjectPackage, rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, }; @@ -16,7 +15,6 @@ pub struct TestFoxScene { fox_animation: AnimatedTexture, world_map: MapRenderer, camera: Camera2D, - objects: WorldObjectPackage, } impl TestFoxScene { @@ -26,9 +24,13 @@ impl TestFoxScene { let fox = AnimatedTexture::new(raylib_handle, thread, "chr", "testFox").unwrap(); // Load the map - let map_renderer = MapRenderer::new("map_gameMap.tmx", raylib_handle, thread).unwrap(); - let objects = - WorldObjectPackage::load(raylib_handle, thread, "map_gameMap.objects.json").unwrap(); + let map_renderer = MapRenderer::new( + "map_gameMap.tmx", + "map_gameMap.objects.json", + raylib_handle, + thread, + ) + .unwrap(); // Create a camera let camera = Camera2D { @@ -45,7 +47,6 @@ impl TestFoxScene { fox_animation: fox, world_map: map_renderer, camera, - objects, } } From 10fbc842526550ae168f06dad5e6fac8310b3d96 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 16:33:40 -0400 Subject: [PATCH 7/9] Allow players to take shade --- .../env/env_testObject/env_testObject.json | 10 +- game/game_logic/src/model/world_object.rs | 5 +- .../src/rendering/utilities/anim_texture.rs | 13 +- .../src/rendering/utilities/map_render.rs | 119 +++++++++++++++++- game/game_logic/src/scenes/test_fox.rs | 36 ++++-- 5 files changed, 154 insertions(+), 29 deletions(-) diff --git a/game/dist/assets/env/env_testObject/env_testObject.json b/game/dist/assets/env/env_testObject/env_testObject.json index 1e1cbfa6..0655307a 100644 --- a/game/dist/assets/env/env_testObject/env_testObject.json +++ b/game/dist/assets/env/env_testObject/env_testObject.json @@ -6,15 +6,7 @@ "top_texture": { "file_path": "assets/env/env_testObject/env_testObjectTop.png" }, - "footprint": [ - { - "position": [ - 0, - 0 - ], - "radius": 256.0 - } - ], + "footprint_radius": 128.0, "physics_colliders": [ { "position": [ diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index ffad27a3..2a540451 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -37,7 +37,8 @@ pub struct WorldObject { /// The object's top texture pub top_texture: Option, /// colliders describing the object's footprint - pub footprint: Vec, + // pub footprint: Vec, + pub footprint_radius: Option, /// Colliders for physics pub physics_colliders: Vec, /// Temperature @@ -54,7 +55,7 @@ pub struct WorldObjectRef { pub kind: String, /// Object name pub name: String, - /// Object position. 1,1 being up and to the right + /// Object position (tile-space *not* pixel-space). 1,1 being up and to the right pub position: na::Vector2, /// Object rotation, positive is clockwise pub rotation_radians: f32, diff --git a/game/game_logic/src/rendering/utilities/anim_texture.rs b/game/game_logic/src/rendering/utilities/anim_texture.rs index bbe593de..42bc7dc7 100644 --- a/game/game_logic/src/rendering/utilities/anim_texture.rs +++ b/game/game_logic/src/rendering/utilities/anim_texture.rs @@ -5,7 +5,7 @@ use nalgebra::Vector2; use raylib::{ color::Color, math::Rectangle, - prelude::{RaylibDraw, RaylibDrawHandle}, + prelude::{RaylibDraw, RaylibDrawHandle, RaylibMode2D}, texture::Texture2D, RaylibHandle, RaylibThread, }; @@ -127,7 +127,7 @@ impl AnimatedTexture { #[profiling::function] pub fn render_frame_by_index( &self, - draw_handle: &mut RaylibDrawHandle, + draw_handle: &mut RaylibMode2D, index: usize, position: Vector2, percent_scale: Option>, @@ -186,7 +186,7 @@ impl AnimatedTexture { /// Render the animation based on timestamp pub fn render_automatic( &mut self, - draw_handle: &mut RaylibDrawHandle, + draw_handle: &mut RaylibMode2D, position: Vector2, percent_scale: Option>, origin: Option>, @@ -216,4 +216,11 @@ impl AnimatedTexture { warn!("We somehow got a frame index of None"); } } + + pub fn size(&self) -> Vector2{ + Vector2::new( + self.texture.width as f32, + self.texture.height as f32, + ) + } } diff --git a/game/game_logic/src/rendering/utilities/map_render.rs b/game/game_logic/src/rendering/utilities/map_render.rs index c89c70e4..858571bd 100644 --- a/game/game_logic/src/rendering/utilities/map_render.rs +++ b/game/game_logic/src/rendering/utilities/map_render.rs @@ -131,19 +131,30 @@ impl MapRenderer { }) } - pub fn sample_friction_at(&self, position: na::Vector2) -> f32 { + pub fn sample_friction_at(&self, world_position: na::Vector2) -> f32 { + // Convert to a tile position + let tile_position = na::Vector2::new( + (world_position.x / 128.0).floor() as i32, + (world_position.y / 128.0).floor() as i32, + ); todo!() } - pub fn sample_temperature_at(&self, position: na::Vector2) -> f32 { + pub fn sample_temperature_at(&self, world_position: na::Vector2) -> f32 { + // Convert to a tile position + let tile_position = na::Vector2::new( + (world_position.x / 128.0).floor() as i32, + (world_position.y / 128.0).floor() as i32, + ); todo!() } pub fn render_map( - &self, + &mut self, draw_handle: &mut RaylibMode2D, camera: &Camera2D, show_debug_grid: bool, + player_position: na::Vector2, ) { // Get the window corners in world space let screen_width = draw_handle.get_screen_width(); @@ -206,6 +217,108 @@ impl MapRenderer { ); } + // Check if there is an object at this tile + for obj_ref in &self.world_objects.object_references { + if obj_ref.position.x == sampler_x as f32 + && obj_ref.position.y == sampler_y as f32 + { + // Get access to the actual object definition + let object_key = + format!("{}:{}", obj_ref.kind, obj_ref.name); + let obj_def = self + .world_objects + .object_definitions + .get(&object_key) + .unwrap(); + + // We need to render the base layer of the object + if obj_def.bottom_texture.animated.unwrap_or(false) { + let tex = self + .world_objects + .bottom_animated_textures + .get_mut(&object_key) + .unwrap(); + tex.render_automatic( + draw_handle, + obj_ref.position - (tex.size() / 2.0), + None, + None, + Some(obj_ref.rotation_radians), + None, + ); + } else { + let tex = self + .world_objects + .bottom_static_textures + .get_mut(&object_key) + .unwrap(); + let p: Vector2 = obj_ref.position.into(); + draw_handle.draw_texture_ex( + &tex, + p - Vector2::new( + tex.width as f32 / 2.0, + tex.height as f32 / 2.0, + ), + obj_ref.rotation_radians, + 1.0, + Color::WHITE, + ); + } + + // If needed we can render the top layer of the object + if let Some(top_texture) = &obj_def.top_texture { + // We need to detect if the player is in the footprint of the object + let mut tint = Color::WHITE; + if let Some(footprint_radius) = + obj_def.footprint_radius + { + let player_dist_to_object = + (obj_ref.position - player_position).norm(); + // debug!( + // "Player dist to object: {}", + // player_dist_to_object + // ); + if player_dist_to_object <= footprint_radius { + tint.a = 128; + } + } + + if top_texture.animated.unwrap_or(false) { + let tex = self + .world_objects + .top_animated_textures + .get_mut(&object_key) + .unwrap(); + tex.render_automatic( + draw_handle, + obj_ref.position - (tex.size() / 2.0), + None, + None, + Some(obj_ref.rotation_radians), + Some(tint), + ); + } else { + let tex = self + .world_objects + .top_static_textures + .get_mut(&object_key) + .unwrap(); + let p: Vector2 = obj_ref.position.into(); + draw_handle.draw_texture_ex( + &tex, + p - Vector2::new( + tex.width as f32 / 2.0, + tex.height as f32 / 2.0, + ), + obj_ref.rotation_radians, + 1.0, + tint, + ); + } + } + } + } + if show_debug_grid { draw_handle.draw_rectangle_lines( tile_x * tile_width as i32, diff --git a/game/game_logic/src/scenes/test_fox.rs b/game/game_logic/src/scenes/test_fox.rs index 38bfdb06..a4d19043 100644 --- a/game/game_logic/src/scenes/test_fox.rs +++ b/game/game_logic/src/scenes/test_fox.rs @@ -36,8 +36,8 @@ impl TestFoxScene { let camera = Camera2D { target: Vector2 { x: 0.0, y: 0.0 }, offset: Vector2 { - x: raylib_handle.get_screen_width() as f32, - y: (raylib_handle.get_screen_height() as f32) * -0.5, + x: raylib_handle.get_screen_width() as f32 * 0.5, + y: (raylib_handle.get_screen_height() as f32) * 0.5, }, rotation: 0.0, zoom: 1.0, @@ -64,15 +64,15 @@ impl TestFoxScene { // Clear the screen draw.clear_background(Color::WHITE); - // Render the fox - self.fox_animation.render_automatic( - &mut draw, - na::Vector2::new(0.0, 0.0), - None, - None, - None, - None, - ); + // // Render the fox + // self.fox_animation.render_automatic( + // &mut draw, + // na::Vector2::new(0.0, 0.0), + // None, + // None, + // None, + // None, + // ); // Allow the camera to be moved with wasd if draw.is_key_down(KeyboardKey::KEY_W) { @@ -93,7 +93,19 @@ impl TestFoxScene { let mut ctx2d = draw.begin_mode2D(self.camera); // Render the map - self.world_map.render_map(&mut ctx2d, &self.camera, true); + self.world_map.render_map( + &mut ctx2d, + &self.camera, + true, + na::Vector2::new(self.camera.target.x, self.camera.target.y).into(), + ); } + + draw.draw_circle( + draw.get_screen_width() / 2, + draw.get_screen_height() / 2, + 4.0, + Color::RED, + ); } } From d65dc12299025918c66c6ac6fd0c0bdb1a2c0632 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 16:41:11 -0400 Subject: [PATCH 8/9] Object rotation! --- .../src/rendering/utilities/map_render.rs | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/game/game_logic/src/rendering/utilities/map_render.rs b/game/game_logic/src/rendering/utilities/map_render.rs index 858571bd..6fc5852d 100644 --- a/game/game_logic/src/rendering/utilities/map_render.rs +++ b/game/game_logic/src/rendering/utilities/map_render.rs @@ -8,7 +8,7 @@ use nalgebra as na; use raylib::{ camera::Camera2D, color::Color, - math::Vector2, + math::{Rectangle, Vector2}, prelude::{RaylibDraw, RaylibDrawHandle, RaylibMode2D}, texture::Texture2D, RaylibHandle, RaylibThread, @@ -242,8 +242,8 @@ impl MapRenderer { draw_handle, obj_ref.position - (tex.size() / 2.0), None, - None, - Some(obj_ref.rotation_radians), + Some(tex.size() / 2.0), + Some(obj_ref.rotation_radians.to_degrees()), None, ); } else { @@ -253,14 +253,28 @@ impl MapRenderer { .get_mut(&object_key) .unwrap(); let p: Vector2 = obj_ref.position.into(); - draw_handle.draw_texture_ex( + let r1 = Rectangle { + x: 0.0, + y: 0.0, + width: tex.width as f32, + height: tex.height as f32, + }; + let r2 = Rectangle { + x: p.x, + y: p.y, + width: tex.width as f32, + height: tex.height as f32, + }; + + draw_handle.draw_texture_pro( &tex, - p - Vector2::new( + r1, + r2, + Vector2::new( tex.width as f32 / 2.0, tex.height as f32 / 2.0, ), - obj_ref.rotation_radians, - 1.0, + obj_ref.rotation_radians.to_degrees(), Color::WHITE, ); } @@ -293,8 +307,8 @@ impl MapRenderer { draw_handle, obj_ref.position - (tex.size() / 2.0), None, - None, - Some(obj_ref.rotation_radians), + Some(tex.size() / 2.0), + Some(obj_ref.rotation_radians.to_degrees()), Some(tint), ); } else { @@ -304,14 +318,28 @@ impl MapRenderer { .get_mut(&object_key) .unwrap(); let p: Vector2 = obj_ref.position.into(); - draw_handle.draw_texture_ex( + let r1 = Rectangle { + x: 0.0, + y: 0.0, + width: tex.width as f32, + height: tex.height as f32, + }; + let r2 = Rectangle { + x: p.x, + y: p.y, + width: tex.width as f32, + height: tex.height as f32, + }; + + draw_handle.draw_texture_pro( &tex, - p - Vector2::new( + r1, + r2, + Vector2::new( tex.width as f32 / 2.0, tex.height as f32 / 2.0, ), - obj_ref.rotation_radians, - 1.0, + obj_ref.rotation_radians.to_degrees(), tint, ); } From 93c869c53da92ca50a9691b79223069e7d04ec05 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 18:50:39 -0400 Subject: [PATCH 9/9] Correctly merge together object code --- game/game_logic/src/scenes/player_interaction.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game/game_logic/src/scenes/player_interaction.rs b/game/game_logic/src/scenes/player_interaction.rs index 32aca9f3..638b08c3 100644 --- a/game/game_logic/src/scenes/player_interaction.rs +++ b/game/game_logic/src/scenes/player_interaction.rs @@ -29,7 +29,7 @@ impl PlayableScene { constants: &ProjectConstants, ) -> Self { - let map_renderer = MapRenderer::new("map_gameMap.tmx", raylib_handle, thread).unwrap(); + let map_renderer = MapRenderer::new("map_gameMap.tmx", "map_gameMap.objects.json", raylib_handle, thread).unwrap(); Self { has_updated_discord_rpc: false, @@ -96,7 +96,7 @@ impl PlayableScene { let mut ctx2d = draw.begin_mode2D(self.camera); // Render the map - self.world_map.render_map(&mut ctx2d, &self.camera, true); + self.world_map.render_map(&mut ctx2d, &self.camera, true, self.player.position); let player_size = (constants.tile_size as f32 * constants.player.start_size * self.player.size) as i32;