@@ -10,26 +10,22 @@ use dolly::prelude::*;
10
10
11
11
#[ derive( Default ) ]
12
12
pub struct OglePlugin {
13
- pub initial_settings : Option < OgleSettings > ,
13
+ pub initial_settings : OgleSettings ,
14
14
}
15
15
16
16
impl Plugin for OglePlugin {
17
17
fn build ( & self , app : & mut App ) {
18
18
app. init_resource :: < OgleRig > ( )
19
19
. init_resource :: < OgleTarget > ( )
20
20
. init_state :: < OgleMode > ( )
21
- . insert_resource ( self . initial_settings . unwrap_or_default ( ) )
21
+ . insert_resource ( self . initial_settings )
22
22
. add_plugins ( bevy_pancam:: PanCamPlugin )
23
23
. add_systems ( Startup , setup)
24
24
. add_systems (
25
25
Update ,
26
- ( follow_target) . run_if ( in_state ( OgleMode :: Following ) ) ,
26
+ ( ( follow_target, keep_within_settings) . chain ( ) )
27
+ . run_if ( in_state ( OgleMode :: Following ) ) ,
27
28
)
28
- // TODO: Implement choreographing
29
- //.add_systems(
30
- // Update,
31
- // choreograph_target.run_if(in_state(OgleMode::Choreographed)),
32
- //)
33
29
. add_systems ( OnEnter ( OgleMode :: Frozen ) , on_enter_frozen)
34
30
. add_systems ( OnExit ( OgleMode :: Frozen ) , on_exit_frozen)
35
31
. add_systems ( OnEnter ( OgleMode :: Pancam ) , on_enter_pancam)
@@ -39,13 +35,18 @@ impl Plugin for OglePlugin {
39
35
}
40
36
}
41
37
42
- fn setup ( mut commands : Commands ) {
43
- // TODO: Settings for pancam handled consistently with other ogle settings
38
+ fn setup ( mut commands : Commands , settings : Res < OgleSettings > ) {
44
39
commands. spawn ( (
45
40
Camera2dBundle :: default ( ) ,
46
- // Because the default mode of ogle is `OgleMode::Frozen`, not `OgleMode::Pancam`, we need to disable it.
47
41
bevy_pancam:: PanCam {
42
+ // Because the default mode of ogle is `OgleMode::Frozen`, not `OgleMode::Pancam`, we need to disable it.
48
43
enabled : false ,
44
+ min_scale : settings. min_scale ,
45
+ max_scale : settings. max_scale ,
46
+ min_x : settings. min_x ,
47
+ max_x : settings. max_x ,
48
+ min_y : settings. min_y ,
49
+ max_y : settings. max_y ,
49
50
..default ( )
50
51
} ,
51
52
) ) ;
@@ -71,20 +72,7 @@ fn on_exit_pancam(mut query: Query<&mut bevy_pancam::PanCam>) {
71
72
pancam. enabled = false ;
72
73
}
73
74
74
- fn on_enter_following (
75
- query_cam : Query < & Transform , With < Camera > > ,
76
- query_proj : Query < & OrthographicProjection > ,
77
- mut rig : ResMut < OgleRig > ,
78
- ) {
79
- let camera_transform = query_cam. single ( ) ; // TODO: error handling
80
- let projection = query_proj. single ( ) ;
81
-
82
- rig. driver_mut :: < Position > ( ) . position = mint:: Point3 {
83
- x : camera_transform. translation . x ,
84
- y : camera_transform. translation . y ,
85
- z : projection. scale ,
86
- } ;
87
- //rig.driver_mut::<Arm>().offset.z = projection.scale;
75
+ fn on_enter_following ( ) {
88
76
info ! ( "Enabling follow camera" ) ;
89
77
}
90
78
@@ -98,13 +86,12 @@ fn follow_target(
98
86
target : Res < OgleTarget > ,
99
87
mut rig : ResMut < OgleRig > ,
100
88
query_transform : Query < & Transform , Without < Camera > > ,
101
- settings : Res < OgleSettings > ,
102
89
mut query_cam : Query < ( & mut OrthographicProjection , & mut Transform ) , With < Camera > > ,
103
90
mut scroll_events : EventReader < MouseWheel > ,
104
- primary_window : Query < & Window , With < PrimaryWindow > > ,
105
91
) {
106
- // TODO: Handle errors
107
- let ( mut proj, mut camera_transform) = query_cam. single_mut ( ) ;
92
+ let Ok ( ( mut proj, mut camera_transform) ) = query_cam. get_single_mut ( ) else {
93
+ return ;
94
+ } ;
108
95
let prev_z = rig. driver :: < Position > ( ) . position . z ;
109
96
match * target {
110
97
OgleTarget :: Position ( pos) => {
@@ -115,14 +102,14 @@ fn follow_target(
115
102
} ;
116
103
}
117
104
OgleTarget :: Entity ( e) => {
118
- // TODO: Handle errors
119
- let transform = query_transform
120
- . get ( e )
121
- . expect ( "entity target has no transform" ) ;
122
- rig . driver_mut :: < Position > ( ) . position = mint :: Point3 {
123
- x : transform . translation . x ,
124
- y : transform . translation . y ,
125
- z : prev_z ,
105
+ if let Ok ( transform ) = query_transform . get ( e ) {
106
+ rig . driver_mut :: < Position > ( ) . position = mint :: Point3 {
107
+ x : transform . translation . x ,
108
+ y : transform. translation . y ,
109
+ z : prev_z ,
110
+ } ;
111
+ } else {
112
+ error ! ( "entity target has no transform" ) ;
126
113
} ;
127
114
}
128
115
OgleTarget :: None => { }
@@ -138,67 +125,94 @@ fn follow_target(
138
125
. sum :: < f32 > ( ) ;
139
126
140
127
if scroll != 0. {
141
- let window = primary_window. single ( ) ;
142
- let window_size = Vec2 :: new ( window. width ( ) , window. height ( ) ) ;
143
-
144
- let old_scale = rig. driver :: < Arm > ( ) . offset . z ;
145
- let mut new_scale = ( old_scale * ( 1. + -scroll * 0.001 ) ) . max ( settings. min_scale ) ;
146
-
147
- // Apply max scale constraint
148
- if let Some ( max_scale) = settings. max_scale {
149
- new_scale = new_scale. min ( max_scale) ;
150
- }
151
-
152
- // If there is both a min and max boundary, that limits how far we can zoom. Make sure we don't exceed that
153
- let scale_constrained = BVec2 :: new (
154
- settings. min_x . is_some ( ) && settings. max_x . is_some ( ) ,
155
- settings. min_y . is_some ( ) && settings. max_y . is_some ( ) ,
156
- ) ;
157
-
158
- if scale_constrained. x || scale_constrained. y {
159
- let bounds_width = if let ( Some ( min_x) , Some ( max_x) ) = ( settings. min_x , settings. max_x )
160
- {
161
- max_x - min_x
162
- } else {
163
- f32:: INFINITY
164
- } ;
165
-
166
- let bounds_height = if let ( Some ( min_y) , Some ( max_y) ) = ( settings. min_y , settings. max_y )
167
- {
168
- max_y - min_y
169
- } else {
170
- f32:: INFINITY
171
- } ;
172
-
173
- let bounds_size = vec2 ( bounds_width, bounds_height) ;
174
- let max_safe_scale = max_scale_within_bounds ( bounds_size, & proj, window_size) ;
175
-
176
- if scale_constrained. x {
177
- new_scale = new_scale. min ( max_safe_scale. x ) ;
178
- }
179
-
180
- if scale_constrained. y {
181
- new_scale = new_scale. min ( max_safe_scale. y ) ;
182
- }
183
- }
184
-
185
- rig. driver_mut :: < Position > ( ) . position . z = new_scale;
186
- rig. driver_mut :: < Arm > ( ) . offset . z = new_scale;
128
+ rig. driver_mut :: < Position > ( ) . position . z *= 1. + -scroll * 0.001 ;
187
129
}
188
130
189
131
rig. update ( time. delta_seconds ( ) ) ;
190
132
191
- camera_transform. translation . x = rig. final_transform . position . x ;
192
- camera_transform. translation . y = rig. final_transform . position . y ;
193
133
camera_transform. rotation = Quat :: from_xyzw (
194
134
rig. final_transform . rotation . v . x ,
195
135
rig. final_transform . rotation . v . y ,
196
136
rig. final_transform . rotation . v . z ,
197
137
rig. final_transform . rotation . s ,
198
138
) ;
139
+ camera_transform. translation . x = rig. final_transform . position . x ;
140
+ camera_transform. translation . y = rig. final_transform . position . y ;
199
141
proj. scale = rig. final_transform . position . z ;
200
142
}
201
143
144
+ fn keep_within_settings (
145
+ mut rig : ResMut < OgleRig > ,
146
+ primary_window : Query < & Window , With < PrimaryWindow > > ,
147
+ settings : Res < OgleSettings > ,
148
+ mut query_cam : Query < ( & mut OrthographicProjection , & mut Transform ) , With < Camera > > ,
149
+ ) {
150
+ let Ok ( ( mut proj, mut camera_transform) ) = query_cam. get_single_mut ( ) else {
151
+ return ;
152
+ } ;
153
+
154
+ let window = primary_window. single ( ) ;
155
+ let window_size = Vec2 :: new ( window. width ( ) , window. height ( ) ) ;
156
+
157
+ // Apply scaling constraints
158
+ let ( min_scale, max_scale) = (
159
+ settings. min_scale ,
160
+ settings. max_scale . unwrap_or ( f32:: INFINITY ) ,
161
+ ) ;
162
+
163
+ // If there is both a min and max boundary, that limits how far we can zoom. Make sure we don't exceed that
164
+ let scale_constrained = BVec2 :: new (
165
+ settings. min_x . is_some ( ) && settings. max_x . is_some ( ) ,
166
+ settings. min_y . is_some ( ) && settings. max_y . is_some ( ) ,
167
+ ) ;
168
+
169
+ if scale_constrained. x || scale_constrained. y {
170
+ let bounds_width = if let ( Some ( min_x) , Some ( max_x) ) = ( settings. min_x , settings. max_x ) {
171
+ max_x - min_x
172
+ } else {
173
+ f32:: INFINITY
174
+ } ;
175
+
176
+ let bounds_height = if let ( Some ( min_y) , Some ( max_y) ) = ( settings. min_y , settings. max_y ) {
177
+ max_y - min_y
178
+ } else {
179
+ f32:: INFINITY
180
+ } ;
181
+
182
+ let bounds_size = vec2 ( bounds_width, bounds_height) ;
183
+ let max_safe_scale = max_scale_within_bounds ( bounds_size, & proj, window_size) ;
184
+
185
+ if scale_constrained. x {
186
+ proj. scale = proj. scale . min ( max_safe_scale. x ) ;
187
+ }
188
+ if scale_constrained. y {
189
+ proj. scale = proj. scale . min ( max_safe_scale. y ) ;
190
+ }
191
+ }
192
+ proj. scale = proj. scale . clamp ( min_scale, max_scale) ;
193
+ rig. driver_mut :: < Position > ( ) . position . z = proj. scale ;
194
+
195
+ // Keep within bounds
196
+ let proj_size = proj. area . size ( ) ;
197
+ let half_of_viewport = proj_size / 2. ;
198
+ if let Some ( min_x_bound) = settings. min_x {
199
+ let min_safe_cam_x = min_x_bound + half_of_viewport. x ;
200
+ camera_transform. translation . x = camera_transform. translation . x . max ( min_safe_cam_x) ;
201
+ }
202
+ if let Some ( max_x_bound) = settings. max_x {
203
+ let max_safe_cam_x = max_x_bound - half_of_viewport. x ;
204
+ camera_transform. translation . x = camera_transform. translation . x . min ( max_safe_cam_x) ;
205
+ }
206
+ if let Some ( min_y_bound) = settings. min_y {
207
+ let min_safe_cam_y = min_y_bound + half_of_viewport. y ;
208
+ camera_transform. translation . y = camera_transform. translation . y . max ( min_safe_cam_y) ;
209
+ }
210
+ if let Some ( max_y_bound) = settings. max_y {
211
+ let max_safe_cam_y = max_y_bound - half_of_viewport. y ;
212
+ camera_transform. translation . y = camera_transform. translation . y . min ( max_safe_cam_y) ;
213
+ }
214
+ }
215
+
202
216
/// max_scale_within_bounds is used to find the maximum safe zoom out/projection
203
217
/// scale when we have been provided with minimum and maximum x boundaries for
204
218
/// the camera.
0 commit comments