Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 78 additions & 56 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,64 @@
use image::ImageReader;

use rusty_ache::engine::Engine;
use rusty_ache::engine::scene::game_object::GameObject;
use rusty_ache::engine::scene::game_object::components::ComponentType::Action;
use rusty_ache::engine::scene::game_object::components::script::Script;
use rusty_ache::engine::scene::game_object::components::sprite::Sprite;
use rusty_ache::engine::scene::game_object::components::{Component, ComponentType};
use rusty_ache::engine::scene::game_object::position::Position;
use rusty_ache::interface::{create_obj_with_img, init_end_scene, init_engine, init_scene};

use rusty_ache::screen::{HEIGHT, WIDTH};
use std::any::Any;

use std::thread;
use std::time::Duration;

#[derive(Clone)]
pub struct MyScript {
is_downed: bool,
movement: u64,
}

impl Script for MyScript {
fn action(&mut self, game_object: &mut GameObject) {
self.movement += 1;
println!("movement: {}", self.movement);
if self.movement < 30 {
game_object.position.y -= 1;
} else if self.movement < 60 {
game_object.position.y += 1;
} else {
self.movement = 0;
}
}

fn new(is_downed: bool) -> MyScript {
MyScript {
is_downed,
movement: 1,
}
}

fn clone_box(&self) -> Box<dyn Script + Send + Sync> {
Box::new(self.clone())
}
}

impl Component for MyScript {
fn as_any(&self) -> &dyn Any {
self
}

fn get_component_type(&self) -> ComponentType {
Action
}

fn clone_box(&self) -> Box<dyn Component + Send + Sync> {
Box::new(self.clone())
}
}

fn main() {
let tower_obj = create_obj_with_img("src/bin/resources/tower.png", 82, 37, true);
Expand All @@ -15,8 +70,8 @@ fn main() {
let main_ship_obj = create_obj_with_img("src/bin/resources/white_ship.png", 0, 0, true);

let hermit_house_obj = create_obj_with_img("src/bin/resources/junk_house.png", 400, 240, true);

let scene = init_scene(
let mut uids: Vec<usize> = vec![];
let mut scene = init_scene(
&[
cabin_obj,
skyscraper_obj,
Expand All @@ -27,60 +82,43 @@ fn main() {
pool_house_obj,
],
main_ship_obj,
&mut uids,
);

uids.push(scene.manager.add_game_object(
vec![Box::new(Sprite::new(
Some(ImageReader::open("src/bin/resources/white_ship.png").unwrap().decode().unwrap()),
true,
(0, 0),
))],
Position {
x: 60,
y: -10,
z: 40,
is_relative: false,
},
));

let script = MyScript::new(false);
let end_scene = init_end_scene("src/bin/resources/game_over.jpg", None);
let mut engine = init_engine(scene, end_scene, WIDTH, HEIGHT);

let main_pos_arc = engine.main_pos.clone();
let end_scene_flag = engine.is_end_scene_active.clone();
std::thread::spawn(move || {
let is_removed = false;

thread::spawn(move || {
loop {
let (x, y) = *main_pos_arc.read().unwrap();
println!("position of main object is ({}, {})", x, y);
if x > 150 {
end_scene_flag.store(true, std::sync::atomic::Ordering::SeqCst);
}
thread::sleep(Duration::from_millis(1000));
}
});

engine.render().unwrap();
engine.run().unwrap()
}

#[derive(Clone)]
pub struct MyScript {
is_downed: bool,
}

impl Script for MyScript {
fn new(is_downed: bool) -> MyScript {
MyScript { is_downed }
}

fn action(&mut self, game_object: &mut GameObject) {
if !self.is_downed {
game_object.position = Position {
x: game_object.position.x,
y: game_object.position.y - 1,
z: game_object.position.z,
is_relative: game_object.position.is_relative,
};
self.is_downed = true;
} else {
game_object.position = Position {
x: game_object.position.x,
y: game_object.position.y + 1,
z: game_object.position.z,
is_relative: game_object.position.is_relative,
};
self.is_downed = false;
}
}

fn clone_box(&self) -> Box<dyn Script + Send + Sync> {
Box::new(self.clone())
}
engine.run(vec![(8, Box::new(script))]).unwrap()
}

#[cfg(test)]
Expand Down Expand Up @@ -110,20 +148,4 @@ mod tests {
assert_eq!(game_object.position.y, 24);
assert_eq!(game_object.position.z, 35);
}

#[test]
fn test_actions_is_downed_true() {
let mut script = MyScript::new(true);
let position = Position {
x: 15,
y: 25,
z: 35,
is_relative: false,
};
let game_object = &mut GameObject::new(vec![], None, position);
script.action(game_object);
assert_eq!(game_object.position.x, 15);
assert_eq!(game_object.position.y, 26);
assert_eq!(game_object.position.z, 35);
}
}
19 changes: 13 additions & 6 deletions src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::render::renderer::{DEFAULT_BACKGROUND_COLOR, Renderer};
use crate::screen::{App, HEIGHT, WIDTH};
// use crate::end_scene::EndScene;
//use image::ImageReader;
use crate::engine::scene::game_object::components::script::Script;
use std::io::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
Expand All @@ -46,7 +47,7 @@ pub trait Engine {
fn render(&mut self) -> Result<(), Error>;

/// Starts and runs the engine main loop.
fn run(&mut self) -> Result<(), Error>;
fn run(&mut self, actionable: Vec<(usize, Box<dyn Script>)>) -> Result<(), Error>;

/// Creates a new engine instance from configuration and initial scene.
fn new(config: Box<dyn Config + Send>, scene: Scene, end_scene: EndScene) -> Self
Expand Down Expand Up @@ -111,7 +112,7 @@ impl Engine for GameEngine {
/// Spawns a producer thread that updates the main object's position based on key input
/// and triggers rendering updates.
/// Runs the `winit` event loop with the associated GUI application.
fn run(&mut self) -> Result<(), Error> {
fn run(&mut self, mut actionable: Vec<(usize, Box<dyn Script>)>) -> Result<(), Error> {
let initial_resolution = Resolution {
width: WIDTH,
height: HEIGHT,
Expand Down Expand Up @@ -148,6 +149,7 @@ impl Engine for GameEngine {
.end_scene
.background
.clone();
const SCREEN_SIZE: usize = (WIDTH * HEIGHT) as usize;

thread::spawn(move || {
let window_arc: Arc<Window> = loop {
Expand All @@ -159,15 +161,15 @@ impl Engine for GameEngine {

//dbg!("Producer has started");

let screen_size = (WIDTH * HEIGHT) as usize;
loop {
if is_end_scene_active.load(Ordering::SeqCst) {
let prev_background = renderer
.write()
.unwrap()
.set_background(new_background.clone());
let empty_object = create_obj_with_img(EMPTY, 0, 0, false);
let scene = init_scene(&[], empty_object);
let mut uids: Vec<usize> = vec![];
let scene = init_scene(&[], empty_object, &mut uids);
let timeout_ms = renderer.read().unwrap().scene_manager.end_scene.timeout_ms;
renderer.write().unwrap().scene_manager =
SceneManager::new(scene, EndScene::new(new_background.clone(), timeout_ms));
Expand All @@ -185,7 +187,7 @@ impl Engine for GameEngine {
.write()
.expect("Producer couldn't lock pixel data");

for (idx, p) in pixels.iter_mut().take(screen_size).enumerate() {
for (idx, p) in pixels.iter_mut().take(SCREEN_SIZE).enumerate() {
*p = colors[idx];
}

Expand Down Expand Up @@ -233,6 +235,10 @@ impl Engine for GameEngine {
.main_object
.add_position((vector_move.0, vector_move.1));

for (uid, script) in actionable.iter_mut() {
script.action(renderer.write().unwrap().scene_manager.ref_mut_by_uid(*uid))
}

{
let pos = renderer
.read()
Expand All @@ -253,7 +259,7 @@ impl Engine for GameEngine {
.write()
.expect("Producer couldn't lock pixel data");

for (idx, p) in pixels.iter_mut().take(screen_size).enumerate() {
for (idx, p) in pixels.iter_mut().take(SCREEN_SIZE).enumerate() {
*p = colors[idx];
}

Expand Down Expand Up @@ -300,6 +306,7 @@ mod tests {
z: 0,
is_relative: false,
},
&mut vec![],
)
}
}
2 changes: 1 addition & 1 deletion src/engine/scene/game_object/components/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::engine::scene::game_object::GameObject;
/// - a `new` constructor with an initialization parameter `is_downed`
///
/// Implementors can define custom behavior for initialization and per-frame updates.
pub trait Script {
pub trait Script: Send {
/// Apply the script's action on the given mutable game object reference.
///
/// Allows modifying object state, trigger events, or update components.
Expand Down
13 changes: 11 additions & 2 deletions src/engine/scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod object_manager;
#[derive(Clone)]
pub struct Scene {
/// Manager responsible for storing and controlling multiple game objects.
manager: GameObjectManager,
pub manager: GameObjectManager,
/// The main game object within this scene.
pub main_object: GameObject,
}
Expand All @@ -40,10 +40,11 @@ impl Scene {
objects: Vec<GameObject>,
main_components: Vec<Box<dyn Component + Send + Sync>>,
main_position: Position,
uids: &mut Vec<usize>,
) -> Self {
let mut obj_manager = GameObjectManager::new(256);
for obj in objects {
obj_manager.add_game_object(obj.components, obj.position)
uids.push(obj_manager.add_game_object(obj.components, obj.position));
}
Scene {
manager: obj_manager,
Expand Down Expand Up @@ -111,6 +112,10 @@ impl Scene {
self.manager.remove_game_object(uid);
self.init()
}

pub fn ref_mut_by_uid(&mut self, uid: usize) -> &mut GameObject {
self.manager.game_objects.get_mut(&uid).unwrap()
}
}

#[cfg(test)]
Expand All @@ -128,6 +133,7 @@ mod tests {
z: 3,
is_relative: false,
},
&mut vec![],
);
assert_eq!(scene.manager.game_objects.len(), 0);
assert_eq!(scene.main_object.components.len(), 0);
Expand Down Expand Up @@ -168,6 +174,7 @@ mod tests {
z: 0,
is_relative: false,
},
&mut vec![],
);
assert_eq!(scene.manager.game_objects.len(), 2);
}
Expand All @@ -183,6 +190,7 @@ mod tests {
z: 2,
is_relative: false,
},
&mut vec![],
);
assert_eq!(scene.main_object.components.len(), 0);
}
Expand All @@ -208,6 +216,7 @@ mod tests {
z: 0,
is_relative: false,
},
&mut vec![],
);
let result = scene.init();
assert_eq!(result.len(), 0);
Expand Down
9 changes: 5 additions & 4 deletions src/engine/scene/object_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use crate::engine::scene::game_object::Position;
use crate::engine::scene::game_object::components::Component;
use crate::engine::scene::game_object::{GameObject, Object};
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeMap, HashSet};

/// Factory struct for creating game objects with unique IDs.
///
Expand Down Expand Up @@ -281,14 +281,14 @@ mod factory_tests {

#[derive(Clone)]
pub struct GameObjectManager {
pub game_objects: HashMap<usize, GameObject>,
pub game_objects: BTreeMap<usize, GameObject>,
factory: GameObjectFactory,
}

impl GameObjectManager {
pub fn new(max_objects: usize) -> Self {
GameObjectManager {
game_objects: HashMap::new(),
game_objects: BTreeMap::new(),
factory: GameObjectFactory::new(max_objects),
}
}
Expand All @@ -297,9 +297,10 @@ impl GameObjectManager {
&mut self,
components: Vec<Box<dyn Component + Send + Sync>>,
position: Position,
) {
) -> usize {
let (uid, object) = self.factory.create_object(components, position);
self.game_objects.insert(uid, object);
uid
}

pub fn remove_game_object(&mut self, uid: usize) {
Expand Down
Loading