micro_games_kit/
character.rs

1use crate::{context::GameContext, game::GameObject};
2use emergent::task::Task;
3use raui_core::{Managed, ManagedRefMut};
4use spitfire_input::{InputMapping, InputMappingRef};
5use typid::ID;
6
7pub struct CharacterMemory<State> {
8    pub delta_time: f32,
9    pub state: ManagedRefMut<State>,
10}
11
12#[derive(Default)]
13pub enum CharacterController<State> {
14    #[default]
15    None,
16    Input {
17        mapping: InputMappingRef,
18        id: Option<ID<InputMapping>>,
19    },
20    Ai(Box<dyn Task<CharacterMemory<State>>>),
21}
22
23impl<State> CharacterController<State> {
24    pub fn input(mapping: impl Into<InputMappingRef>) -> Self {
25        Self::Input {
26            mapping: mapping.into(),
27            id: None,
28        }
29    }
30
31    pub fn ai(task: impl Task<CharacterMemory<State>> + 'static) -> Self {
32        Self::Ai(Box::new(task))
33    }
34}
35
36pub struct Character<State: GameObject> {
37    pub state: Managed<State>,
38    task: Box<dyn Task<CharacterMemory<State>>>,
39    controller: CharacterController<State>,
40}
41
42impl<State: GameObject> Character<State> {
43    pub fn new(
44        state: State,
45        task: impl Task<CharacterMemory<State>> + 'static,
46        controller: CharacterController<State>,
47    ) -> Self {
48        Self {
49            state: Managed::new(state),
50            task: Box::new(task),
51            controller,
52        }
53    }
54
55    pub fn activated(mut self, context: &mut GameContext) -> Self {
56        self.activate(context);
57        self
58    }
59}
60
61impl<State: GameObject> GameObject for Character<State> {
62    fn activate(&mut self, context: &mut GameContext) {
63        match &mut self.controller {
64            CharacterController::None => {}
65            CharacterController::Input { mapping, id } => {
66                if id.is_none() {
67                    *id = Some(context.input.push_mapping(mapping.to_owned()));
68                }
69            }
70            CharacterController::Ai(task) => {
71                task.on_enter(&mut CharacterMemory {
72                    delta_time: 0.0,
73                    state: self.state.borrow_mut().unwrap(),
74                });
75            }
76        }
77        let mut memory = CharacterMemory {
78            delta_time: 0.0,
79            state: self.state.borrow_mut().unwrap(),
80        };
81        self.state.write().unwrap().activate(context);
82        self.task.on_enter(&mut memory);
83    }
84
85    fn deactivate(&mut self, context: &mut GameContext) {
86        match &mut self.controller {
87            CharacterController::None => {}
88            CharacterController::Input { id, .. } => {
89                if let Some(id) = id {
90                    context.input.remove_mapping(*id);
91                }
92                *id = None;
93            }
94            CharacterController::Ai(task) => {
95                task.on_exit(&mut CharacterMemory {
96                    delta_time: 0.0,
97                    state: self.state.borrow_mut().unwrap(),
98                });
99            }
100        }
101        let mut memory = CharacterMemory {
102            delta_time: 0.0,
103            state: self.state.borrow_mut().unwrap(),
104        };
105        self.task.on_exit(&mut memory);
106        self.state.write().unwrap().deactivate(context);
107    }
108
109    fn process(&mut self, context: &mut GameContext, delta_time: f32) {
110        if let CharacterController::Ai(task) = &mut self.controller {
111            let mut memory = CharacterMemory {
112                delta_time,
113                state: self.state.borrow_mut().unwrap(),
114            };
115            task.on_process(&mut memory);
116            task.on_update(&mut memory);
117        }
118        let mut memory = CharacterMemory {
119            delta_time,
120            state: self.state.borrow_mut().unwrap(),
121        };
122        self.task.on_process(&mut memory);
123        self.task.on_update(&mut memory);
124        self.state.write().unwrap().process(context, delta_time);
125    }
126
127    fn draw(&mut self, context: &mut GameContext) {
128        self.state.write().unwrap().draw(context);
129    }
130}