micro_games_kit/
character.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::{context::GameContext, game::GameObject};
use emergent::task::Task;
use raui_core::{Managed, ManagedRefMut};
use spitfire_input::{InputMapping, InputMappingRef};
use typid::ID;

pub struct CharacterMemory<State> {
    pub delta_time: f32,
    pub state: ManagedRefMut<State>,
}

#[derive(Default)]
pub enum CharacterController<State> {
    #[default]
    None,
    Input {
        mapping: InputMappingRef,
        id: Option<ID<InputMapping>>,
    },
    Ai(Box<dyn Task<CharacterMemory<State>>>),
}

impl<State> CharacterController<State> {
    pub fn input(mapping: impl Into<InputMappingRef>) -> Self {
        Self::Input {
            mapping: mapping.into(),
            id: None,
        }
    }

    pub fn ai(task: impl Task<CharacterMemory<State>> + 'static) -> Self {
        Self::Ai(Box::new(task))
    }
}

pub struct Character<State: GameObject> {
    pub state: Managed<State>,
    task: Box<dyn Task<CharacterMemory<State>>>,
    controller: CharacterController<State>,
}

impl<State: GameObject> Character<State> {
    pub fn new(
        state: State,
        task: impl Task<CharacterMemory<State>> + 'static,
        controller: CharacterController<State>,
    ) -> Self {
        Self {
            state: Managed::new(state),
            task: Box::new(task),
            controller,
        }
    }

    pub fn activated(mut self, context: &mut GameContext) -> Self {
        self.activate(context);
        self
    }
}

impl<State: GameObject> GameObject for Character<State> {
    fn activate(&mut self, context: &mut GameContext) {
        match &mut self.controller {
            CharacterController::None => {}
            CharacterController::Input { mapping, id } => {
                if id.is_none() {
                    *id = Some(context.input.push_mapping(mapping.to_owned()));
                }
            }
            CharacterController::Ai(task) => {
                task.on_enter(&mut CharacterMemory {
                    delta_time: 0.0,
                    state: self.state.borrow_mut().unwrap(),
                });
            }
        }
        let mut memory = CharacterMemory {
            delta_time: 0.0,
            state: self.state.borrow_mut().unwrap(),
        };
        self.state.write().unwrap().activate(context);
        self.task.on_enter(&mut memory);
    }

    fn deactivate(&mut self, context: &mut GameContext) {
        match &mut self.controller {
            CharacterController::None => {}
            CharacterController::Input { id, .. } => {
                if let Some(id) = id {
                    context.input.remove_mapping(*id);
                }
                *id = None;
            }
            CharacterController::Ai(task) => {
                task.on_exit(&mut CharacterMemory {
                    delta_time: 0.0,
                    state: self.state.borrow_mut().unwrap(),
                });
            }
        }
        let mut memory = CharacterMemory {
            delta_time: 0.0,
            state: self.state.borrow_mut().unwrap(),
        };
        self.task.on_exit(&mut memory);
        self.state.write().unwrap().deactivate(context);
    }

    fn process(&mut self, context: &mut GameContext, delta_time: f32) {
        if let CharacterController::Ai(task) = &mut self.controller {
            let mut memory = CharacterMemory {
                delta_time,
                state: self.state.borrow_mut().unwrap(),
            };
            task.on_process(&mut memory);
            task.on_update(&mut memory);
        }
        let mut memory = CharacterMemory {
            delta_time,
            state: self.state.borrow_mut().unwrap(),
        };
        self.task.on_process(&mut memory);
        self.task.on_update(&mut memory);
        self.state.write().unwrap().process(context, delta_time);
    }

    fn draw(&mut self, context: &mut GameContext) {
        self.state.write().unwrap().draw(context);
    }
}