1
- use std:: cmp :: Ordering ;
1
+ use std:: collections :: VecDeque ;
2
2
use std:: time:: { Duration , Instant } ;
3
3
4
4
use bevy:: prelude:: * ;
5
5
use derivative:: Derivative ;
6
6
7
7
use crate :: MainCamera ;
8
- use crate :: utils:: CartesianDirection ;
8
+ use crate :: utils:: { CartesianDirection , SeeDirection } ;
9
9
10
- #[ derive( Debug , Default , Clone , Copy ) ]
10
+ #[ derive( Debug , Default , Clone ) ]
11
11
pub ( crate ) struct RotationData {
12
12
rotation_state : RotationState ,
13
- future_rotation_state : RotationState ,
14
13
/// The rotation state that is currently targeted by the ongoing animation(s). An animation around the side face only sets the top to `Some`, and vice versa. This is to allow simultaneous animations of the side and the top, without interference once one of them reaches the goal.
15
- top_rotation_animation : Option < RotationAnimationData > ,
16
- side_rotation_animation : Option < RotationAnimationData > ,
14
+ future_rotation_state : RotationState ,
15
+ /// List of ongoing animations, oldest animation is first
16
+ animations : VecDeque < RotationAnimationData > ,
17
17
}
18
18
19
19
#[ derive( Debug , Derivative , Clone , Copy , PartialEq , Eq ) ]
@@ -48,13 +48,43 @@ impl RotationState {
48
48
}
49
49
rotation_state
50
50
}
51
+
52
+ /// Set the rotation state field from the see direction
53
+ fn set_see_direction ( & mut self , see_direction : SeeDirection , value : CartesianDirection ) {
54
+ match see_direction {
55
+ SeeDirection :: Top => self . top = value,
56
+ SeeDirection :: Left => self . side = value,
57
+ _ => { }
58
+ }
59
+ }
60
+
61
+ /// Panics in some cases if the rotation state is not possible. That is, if the side and top are parallel
62
+ fn get_see_direction ( & self , see_direction : SeeDirection ) -> CartesianDirection {
63
+ match see_direction {
64
+ SeeDirection :: Top => self . top ,
65
+ SeeDirection :: Left => self . side ,
66
+ SeeDirection :: Right => self
67
+ . top
68
+ . cross ( self . side )
69
+ . expect ( "Rotation state is not possible" ) ,
70
+ SeeDirection :: BackLeft => self
71
+ . top
72
+ . cross ( self . side )
73
+ . expect ( "Rotation state is not possible" )
74
+ . opposite ( ) ,
75
+ SeeDirection :: Bottom => self . top . opposite ( ) ,
76
+ SeeDirection :: BackRight => self . side . opposite ( ) ,
77
+ }
78
+ }
51
79
}
52
80
53
81
#[ derive( Debug , Clone , Copy ) ]
54
82
pub ( crate ) struct RotationAnimationData {
55
83
from : CartesianDirection ,
56
84
target : CartesianDirection ,
57
85
animation_started : Instant ,
86
+ /// What side seen from the camera that from and target are referring to
87
+ side_changing : SeeDirection ,
58
88
}
59
89
60
90
impl RotationAnimationData {
@@ -97,26 +127,9 @@ pub(crate) fn iterate(
97
127
let mut transform = camera. 0 ;
98
128
transform. translation = rotation_data. rotation_state . camera_location ( ) * 2. ;
99
129
100
- // Needed to prevent dropping this value
101
- let animations = [
102
- rotation_data. top_rotation_animation ,
103
- rotation_data. side_rotation_animation ,
104
- ] ;
105
- let mut animations = animations
106
- . iter ( )
107
- . flatten ( )
108
- . collect :: < Vec < & RotationAnimationData > > ( ) ;
109
- // Sort by when the animation started. If this is not done, the animations may be added in the wrong order resulting in wrong rotation
110
- animations. sort_by ( |c1, c2| {
111
- if c1. animation_started < c2. animation_started {
112
- Ordering :: Greater
113
- } else {
114
- Ordering :: Less
115
- }
116
- } ) ;
117
130
transform. translate_around (
118
131
Vec3 :: ZERO ,
119
- total_animation_rotation ( & animations, rotation_duration) ,
132
+ total_animation_rotation ( & rotation_data . animations , rotation_duration) ,
120
133
) ;
121
134
122
135
transform. look_at (
@@ -129,60 +142,48 @@ pub(crate) fn iterate(
129
142
}
130
143
131
144
fn conclude_finished_animations ( rotation_data : & mut RotationData , rotation_duration : Duration ) {
132
- if let Some ( animation) = & rotation_data. side_rotation_animation {
145
+ let mut num_finished_animations = 0 ;
146
+ for animation in & rotation_data. animations {
133
147
if ( Instant :: now ( ) - animation. animation_started ) > rotation_duration {
134
- rotation_data. rotation_state . top = animation. target ;
135
- rotation_data. side_rotation_animation = None ;
148
+ rotation_data
149
+ . rotation_state
150
+ . set_see_direction ( animation. side_changing , animation. target ) ;
151
+ num_finished_animations += 1 ;
136
152
}
137
153
}
138
154
139
- if let Some ( animation) = & rotation_data. top_rotation_animation {
140
- if ( Instant :: now ( ) - animation. animation_started ) > rotation_duration {
141
- rotation_data. rotation_state . side = animation. target ;
142
- rotation_data. top_rotation_animation = None ;
143
- }
155
+ for _ in 0 ..num_finished_animations {
156
+ rotation_data. animations . pop_front ( ) ;
144
157
}
145
158
}
146
159
147
160
fn input_handling ( input : Res < Input < KeyCode > > , rotation_data : & mut RotationData ) {
148
- if rotation_data. top_rotation_animation . is_none ( ) {
149
- let rotation = if input. just_pressed ( KeyCode :: Right ) {
150
- Some ( rotation_data. future_rotation_state . top . opposite ( ) )
151
- } else if input. just_pressed ( KeyCode :: Left ) {
152
- Some ( rotation_data. future_rotation_state . top )
153
- } else {
154
- None
155
- } ;
156
- if let Some ( rotation) = rotation {
157
- start_rotation ( rotation_data, rotation) ;
158
- }
161
+ let fs = rotation_data. future_rotation_state ; // Shorthand
162
+ if input. just_pressed ( KeyCode :: Right ) {
163
+ start_rotation ( rotation_data, fs. top . opposite ( ) , SeeDirection :: Top ) ;
164
+ } else if input. just_pressed ( KeyCode :: Left ) {
165
+ start_rotation ( rotation_data, fs. top , SeeDirection :: Top ) ;
159
166
}
160
-
161
- if rotation_data. side_rotation_animation . is_none ( ) {
162
- let rotation = if input. just_pressed ( KeyCode :: Up ) {
163
- Some ( rotation_data. future_rotation_state . side . opposite ( ) )
164
- } else if input. just_pressed ( KeyCode :: Down ) {
165
- Some ( rotation_data. future_rotation_state . side )
166
- } else {
167
- None
168
- } ;
169
- if let Some ( rotation) = rotation {
170
- start_rotation ( rotation_data, rotation) ;
171
- }
167
+ if input. just_pressed ( KeyCode :: Up ) {
168
+ start_rotation ( rotation_data, fs. side . opposite ( ) , SeeDirection :: Left ) ;
169
+ } else if input. just_pressed ( KeyCode :: Down ) {
170
+ start_rotation ( rotation_data, fs. side , SeeDirection :: Left ) ;
172
171
}
173
172
}
174
173
175
- fn start_rotation ( rotation_data : & mut RotationData , rotation : CartesianDirection ) {
174
+ /// @param see_direction: The side (seen from the camera) that this rotation is rotating around
175
+ fn start_rotation ( rotation_data : & mut RotationData , rotation : CartesianDirection , _see_direction : SeeDirection ) {
176
176
// If the rotation axis is not parallel to the top axis, then this rotation will modify the side axis
177
177
if !rotation. is_parallel_to ( rotation_data. future_rotation_state . side ) {
178
178
let target = rotation_data
179
179
. future_rotation_state
180
180
. after_rotation ( rotation)
181
181
. side ;
182
- rotation_data. top_rotation_animation = Some ( RotationAnimationData {
182
+ rotation_data. animations . push_back ( RotationAnimationData {
183
183
from : rotation_data. future_rotation_state . side ,
184
184
target,
185
185
animation_started : Instant :: now ( ) ,
186
+ side_changing : SeeDirection :: Left ,
186
187
} ) ;
187
188
rotation_data. future_rotation_state . side = target;
188
189
}
@@ -192,42 +193,34 @@ fn start_rotation(rotation_data: &mut RotationData, rotation: CartesianDirection
192
193
. future_rotation_state
193
194
. after_rotation ( rotation)
194
195
. top ;
195
- rotation_data. side_rotation_animation = Some ( RotationAnimationData {
196
+ rotation_data. animations . push_back ( RotationAnimationData {
196
197
from : rotation_data. future_rotation_state . top ,
197
198
target,
198
199
animation_started : Instant :: now ( ) ,
200
+ side_changing : SeeDirection :: Top ,
199
201
} ) ;
200
202
rotation_data. future_rotation_state . top = target;
201
203
}
202
204
}
203
205
204
206
fn total_animation_rotation (
205
- animations : & [ & RotationAnimationData ] ,
207
+ animations : & VecDeque < RotationAnimationData > ,
206
208
rotation_time : Duration ,
207
209
) -> Quat {
208
210
let mut output = Quat :: IDENTITY ;
209
- // let mut output = animations.iter().flatten().last().map_or(Quat::IDENTITY, |p|p.partial_camera_translation(rotation_time));
210
- // Iterate without Nones
211
- for animation in animations {
211
+ for animation in animations. iter ( ) . rev ( ) {
212
212
output *= animation. partial_camera_translation ( rotation_time) ;
213
213
}
214
214
output
215
215
}
216
216
217
217
fn camera_up_vector ( rotation_data : & RotationData , rotation_time : Duration ) -> Vec3 {
218
218
let mut output = rotation_data. rotation_state . top . as_vec3 ( ) ;
219
- for animation in [
220
- rotation_data. top_rotation_animation ,
221
- rotation_data. side_rotation_animation ,
222
- ]
223
- . iter ( )
224
- . flatten ( )
225
- {
226
- let top = rotation_data. rotation_state . top ;
227
- if ( animation. target . is_parallel_to ( top) || animation. from . is_parallel_to ( top) )
219
+ for animation in & rotation_data. animations {
220
+ if ( animation. side_changing == SeeDirection :: Top || animation. side_changing == SeeDirection :: Bottom )
228
221
&& animation. target != animation. from
229
222
{
230
- output = animation. camera_up_vector ( rotation_time) ;
223
+ output + = animation. camera_up_vector ( rotation_time) - animation . from . as_vec3 ( ) ;
231
224
}
232
225
}
233
226
output
@@ -249,9 +242,6 @@ fn rotation_curve(time: f32) -> f32 {
249
242
}
250
243
251
244
mod tests {
252
- #[ test]
253
- fn camera_location_test ( ) { }
254
-
255
245
#[ test]
256
246
fn rotation_state_after_rotation_test ( ) {
257
247
use super :: RotationState ;
@@ -262,4 +252,16 @@ mod tests {
262
252
RotationState { top: X , side: Z }
263
253
) ;
264
254
}
265
- }
255
+
256
+ use super :: * ;
257
+ use bevy:: math:: Quat ;
258
+ use std:: time:: Duration ;
259
+
260
+ #[ test]
261
+ fn total_animation_rotation_with_no_animations ( ) {
262
+ let animations = VecDeque :: < RotationAnimationData > :: new ( ) ;
263
+ let rotation_time = Duration :: from_secs ( 1 ) ;
264
+ let result = total_animation_rotation ( & animations, rotation_time) ;
265
+ assert_eq ! ( result, Quat :: IDENTITY ) ;
266
+ }
267
+ }
0 commit comments