oxygengine_visual_novel/
character.rs1use crate::{Color, Position, Scale};
2use anim::{animation::Interpolation, transition::Transition};
3use core::{prefab::Prefab, Scalar};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7pub type CharacterStyle = Transition<String>;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Character {
11 name: String,
12 pub styles: HashMap<String, String>,
14 #[serde(default)]
15 style: CharacterStyle,
16 #[serde(default)]
17 visibility: Interpolation<Scalar>,
18 #[serde(default)]
19 name_color: Interpolation<Color>,
20 #[serde(default)]
22 position: Interpolation<Position>,
23 #[serde(default)]
25 alignment: Interpolation<Position>,
26 #[serde(default)]
27 rotation: Interpolation<Scalar>,
28 #[serde(default)]
29 scale: Interpolation<Scale>,
30 #[serde(skip)]
31 pub(crate) dirty: bool,
32}
33
34impl Prefab for Character {
35 fn post_from_prefab(&mut self) {
36 self.dirty = true;
37 }
38}
39
40impl Default for Character {
41 fn default() -> Self {
42 Self {
43 name: Default::default(),
44 styles: Default::default(),
45 style: Default::default(),
46 visibility: Interpolation::instant(1.0),
47 name_color: Interpolation::instant((1.0, 1.0, 1.0).into()),
48 position: Default::default(),
49 alignment: Default::default(),
50 rotation: Default::default(),
51 scale: Interpolation::instant((1.0, 1.0).into()),
52 dirty: true,
53 }
54 }
55}
56
57impl Character {
58 pub fn new(name: &str) -> Self {
59 Self {
60 name: name.to_owned(),
61 ..Default::default()
62 }
63 }
64
65 pub fn initialize(&mut self) {
66 self.style.end();
67 self.visibility.end();
68 self.name_color.end();
69 self.position.end();
70 self.alignment.end();
71 self.rotation.end();
72 self.scale.end();
73 }
74
75 pub fn is_dirty(&self) -> bool {
76 self.dirty
77 || self.style.in_progress()
78 || self.visibility.in_progress()
79 || self.name_color.in_progress()
80 || self.position.in_progress()
81 || self.alignment.in_progress()
82 || self.rotation.in_progress()
83 || self.scale.in_progress()
84 }
85
86 pub fn rebuild(&mut self) {
87 self.dirty = true;
88 }
89
90 pub fn name(&self) -> &str {
91 &self.name
92 }
93
94 pub fn set_name(&mut self, value: String) {
95 self.name = value;
96 self.dirty = true;
97 }
98
99 pub fn styles(&self) -> impl Iterator<Item = (&str, &str)> {
101 self.styles.iter().map(|(k, v)| (k.as_str(), v.as_str()))
102 }
103
104 pub fn style(&self) -> (&str, Scalar, &str) {
106 let from = self.style.from().as_str();
107 let to = self.style.to().as_str();
108 let phase = self.style.phase();
109 (from, phase, to)
110 }
111
112 pub fn style_transition(&self) -> &CharacterStyle {
113 &self.style
114 }
115
116 pub fn style_transition_mut(&mut self) -> &mut CharacterStyle {
117 &mut self.style
118 }
119
120 pub fn set_style(&mut self, value: String) {
121 self.style.set(value);
122 self.style.playing = true;
123 }
124
125 pub fn visibility(&self) -> Scalar {
126 self.visibility.value()
127 }
128
129 pub fn visibility_anim(&self) -> &Interpolation<Scalar> {
130 &self.visibility
131 }
132
133 pub fn visibility_anim_mut(&mut self) -> &mut Interpolation<Scalar> {
134 &mut self.visibility
135 }
136
137 pub fn set_visibility(&mut self, value: Scalar) {
138 self.visibility.set(value);
139 self.visibility.playing = true;
140 }
141
142 pub fn hide(&mut self) {
143 self.set_visibility(0.0);
144 }
145
146 pub fn show(&mut self) {
147 self.set_visibility(1.0);
148 }
149
150 pub fn name_color(&self) -> Color {
151 self.name_color.value()
152 }
153
154 pub fn name_color_anim(&self) -> &Interpolation<Color> {
155 &self.name_color
156 }
157
158 pub fn name_color_anim_mut(&mut self) -> &mut Interpolation<Color> {
159 &mut self.name_color
160 }
161
162 pub fn set_name_color(&mut self, value: Color) {
163 self.name_color.set(value);
164 self.name_color.playing = true;
165 }
166
167 pub fn position(&self) -> Position {
168 self.position.value()
169 }
170
171 pub fn position_anim(&self) -> &Interpolation<Position> {
172 &self.position
173 }
174
175 pub fn position_anim_mut(&mut self) -> &mut Interpolation<Position> {
176 &mut self.position
177 }
178
179 pub fn set_position(&mut self, value: Position) {
180 self.position.set(value);
181 self.position.playing = true;
182 }
183
184 pub fn alignment(&self) -> Position {
185 self.alignment.value()
186 }
187
188 pub fn alignment_anim(&self) -> &Interpolation<Position> {
189 &self.alignment
190 }
191
192 pub fn alignment_anim_mut(&mut self) -> &mut Interpolation<Position> {
193 &mut self.alignment
194 }
195
196 pub fn set_alignment(&mut self, value: Position) {
197 self.alignment.set(value);
198 self.alignment.playing = true;
199 }
200
201 pub fn rotation(&self) -> Scalar {
202 self.rotation.value()
203 }
204
205 pub fn rotation_anim(&self) -> &Interpolation<Scalar> {
206 &self.rotation
207 }
208
209 pub fn rotation_anim_mut(&mut self) -> &mut Interpolation<Scalar> {
210 &mut self.rotation
211 }
212
213 pub fn set_rotation(&mut self, value: Scalar) {
214 self.rotation.set(value);
215 self.rotation.playing = true;
216 }
217
218 pub fn scale(&self) -> Scale {
219 self.scale.value()
220 }
221
222 pub fn scale_anim(&self) -> &Interpolation<Scale> {
223 &self.scale
224 }
225
226 pub fn scale_anim_mut(&mut self) -> &mut Interpolation<Scale> {
227 &mut self.scale
228 }
229
230 pub fn set_scale(&mut self, value: Scale) {
231 self.scale.set(value);
232 self.scale.playing = true;
233 }
234
235 pub fn process(&mut self, delta_time: Scalar) {
236 self.dirty = false;
237 self.style.process(delta_time);
238 self.visibility.process(delta_time);
239 self.name_color.process(delta_time);
240 self.position.process(delta_time);
241 self.alignment.process(delta_time);
242 self.rotation.process(delta_time);
243 self.scale.process(delta_time);
244 }
245}