Class: Zif::Layers::Camera
- Inherits:
-
Object
- Object
- Zif::Layers::Camera
- Includes:
- Actions::Actionable
- Defined in:
- lib/zif/layers/camera.rb
Overview
Designed to be used with LayerGroup.
The Camera is given a set of sprites, typically the containing sprites for a set of Layerables via LayerGroup#layer_containing_sprites.
It is responsible for directing the layers to reposition based on camera movements. Specifically, it alters each layer’s source_x
and source_y
values for panning.
This class includes Actions::Actionable, so you can pan the camera using a Actions::Action.
It has the capability of issuing camera movements based on following a particular sprite on a layer (like a player character).
It also has the capability of zooming in and out, by controlling each layer’s source_w
and source_h
. It can be registered as a scrollable with Services::InputSerive.
Constant Summary collapse
- DEFAULT_SCREEN_WIDTH =
1280
- DEFAULT_SCREEN_HEIGHT =
720
Instance Attribute Summary collapse
-
#cur_h ⇒ Float
The current height of the camera (maps to
source_h
on layers). -
#cur_w ⇒ Float
The current width of the camera (maps to
source_w
on layers). -
#follow_duration ⇒ Integer
How many ticks should camera following take? Defaults to 0.5 seconds.
-
#follow_easing ⇒ Symbol
The easing function (Actions::Action::EASING_FUNCS) to use for camera following.
-
#follow_margins ⇒ Array<Integer>
The margins on the screen which will stop camera panning.
-
#last_camera_movement ⇒ Zif::Actions::Action
The most recent camera movement Actions::Action.
-
#last_follow ⇒ Array<Float>
The center point [x, y] of the last followed sprite.
-
#layers ⇒ Array<Zif::Sprite>
The layer sprites this camera will move in unison.
-
#max_h ⇒ Integer
Of the given #layers, the largest height value.
-
#max_w ⇒ Integer
Of the given #layers, the largest width value.
- #max_x ⇒ Integer
- #max_y ⇒ Integer
-
#max_zoom_in ⇒ Float
The maximum zoom in level.
-
#max_zoom_out ⇒ Float
The maximum zoom out level.
-
#min_x ⇒ Integer
The minimum X value the #layers
source_x
can have, typically0
. -
#min_y ⇒ Integer
The minimum Y value the #layers
source_y
can have, typically0
. -
#native_screen_height ⇒ Integer
readonly
The native height of the screen, defaults to 720.
-
#native_screen_width ⇒ Integer
readonly
The native width of the screen, defaults to 1280.
-
#pos_x ⇒ Float
The current X position of the camera (lower left, maps to
source_x
on layers). -
#pos_y ⇒ Float
The current Y position of the camera (lower left, maps to
source_y
on layers). -
#target_x ⇒ Float
The relative change in X the camera is moving towards with #last_camera_movement.
-
#target_y ⇒ Float
The relative change in Y the camera is moving towards with #last_camera_movement.
-
#zoom_step ⇒ Integer
The index of #zoom_steps pointing to the current zoom level.
-
#zoom_steps ⇒ Array<Float>
An ordered array of discrete zoom levels.
Attributes included from Actions::Actionable
Instance Method Summary collapse
-
#center(from = pos) ⇒ Array<Float>
Calculates the difference between [{cur_w}/2, {cur_h}/2] and
from
. - #center_screen(around = center) ⇒ Object
-
#each_layer(&block) ⇒ Enumerator
Iterate over each element of #layers.
-
#follow_x ⇒ Float
To support moving the default zoom point while following something.
- #follow_x=(x) ⇒ Object
-
#follow_y ⇒ Float
The Y value of #last_follow.
- #follow_y=(y) ⇒ Object
-
#full_view_rect ⇒ Array<Integer>
[{cur_w}, {cur_h}].
-
#initialize(layer_sprites:, starting_width: DEFAULT_SCREEN_WIDTH, starting_height: DEFAULT_SCREEN_HEIGHT, initial_x: 4000, initial_y: 2000) ⇒ Camera
constructor
Setup vars, min/max camera position, arbitrary initial x/y Width/height should be an integer multiple of 16:9 ratio! This class expects to register itself with the Services::ActionService during initialize, at $game.services.named(:action_service).
-
#max_view_rect ⇒ Array<Integer>
[w, h] The maximum width and height of the camera viewport, assuming fully zoomed out.
-
#min_view_rect ⇒ Array<Integer>
[w, h] The minimum width and height of the camera viewport, assuming fully zoomed in.
-
#move(x, y) ⇒ Array<Float>
Adjust pos_x and pos_y together, return difference.
-
#move_rel(x = nil, y = nil) ⇒ Object
Relative positional change where [1, 1] means add 1 to x/y instead of (1,1) Accepts nil to support behavior of directional_vector.
- #pos ⇒ Array<Float>
-
#scrolled?(_point, direction) ⇒ Boolean
This method is used as a hook for Services::InputService, when given this obj with Services::InputService#register_scrollable.
-
#start_following(sprite) ⇒ Object
Cause the Camera to start an Actions::Action on itself to pan #pos_x and #pos_y towards the center point of the given
sprite
. -
#translate_pos(given) ⇒ Array<Float>
Translate a 2 element point from the screen’s perspective to the map’s perspective.
-
#zoom_factor ⇒ Float
The current zoom factor, this value is compared against #max_zoom_out and #max_zoom_in when zooming.
-
#zoom_in(point = (@last_follow || center)) ⇒ Object
Zooms in by a single value in #zoom_steps, around the given
point
. -
#zoom_out(point = (@last_follow || center)) ⇒ Object
Zooms out by a single value in #zoom_steps, around the given
point
. -
#zoom_to(factor = 1.0, point = (@last_follow || center)) ⇒ Object
Zooms to a specific zoom
factor
, around the givenpoint
. -
#zoom_unit ⇒ Array<Integer>
A zoom factor of 1.0 corresponds to this resolution.
Methods included from Actions::Actionable
#bounce_forever_around, #delayed_action, #fade_in, #fade_out, #fade_out_and_in_forever, #new_action, #perform_actions, #run_action, #running_actions?, #stop_action
Constructor Details
#initialize(layer_sprites:, starting_width: DEFAULT_SCREEN_WIDTH, starting_height: DEFAULT_SCREEN_HEIGHT, initial_x: 4000, initial_y: 2000) ⇒ Camera
Setup vars, min/max camera position, arbitrary initial x/y Width/height should be an integer multiple of 16:9 ratio! This class expects to register itself with the Services::ActionService during initialize, at $game.services.named(:action_service)
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/zif/layers/camera.rb', line 93 def initialize(layer_sprites:, starting_width: DEFAULT_SCREEN_WIDTH, starting_height: DEFAULT_SCREEN_HEIGHT, initial_x: 4000, initial_y: 2000) @native_screen_width = DEFAULT_SCREEN_WIDTH @native_screen_height = DEFAULT_SCREEN_HEIGHT # Camera views a game-window-sized chunk of target at zoom level 1.0 # These mirror the source_w/h attrs on the sprite layers @cur_w = starting_width @cur_h = starting_height @max_w = layer_sprites.map(&:w).max @max_h = layer_sprites.map(&:h).max @max_x = @max_w - @cur_w @max_y = @max_h - @cur_h @layers = layer_sprites.map do |layer| layer.assign( w: @native_screen_width, h: @native_screen_height ) end # These values are the allowable extremes for zooming, described as a multiple of the native screen width/height @max_zoom_in = 0.5 @max_zoom_out = 2.0 # Each scroll action will increase or decrease zoom factor by this amount: @zoom_steps = [0.5, 0.8, 1.0, 1.28, 1.6, 2.0] # Index of above @zoom_step = 2 self.cur_w = starting_width self.cur_h = starting_height @min_x = 0 @min_y = 0 @pos_x = 0 @pos_y = 0 # Default follow params @follow_margins = [300, 600, 300, 600] # These values will be multiplied by the zoom factor @follow_duration = 0.5.seconds @follow_easing = :smooth_stop # Following will not work unless registered with an ActionService $game&.services&.named(:action_service)&.register_actionable(self) move(initial_x, initial_y) end |
Instance Attribute Details
#cur_h ⇒ Float
Returns The current height of the camera (maps to source_h
on layers).
55 56 57 |
# File 'lib/zif/layers/camera.rb', line 55 def cur_h @cur_h end |
#cur_w ⇒ Float
Returns The current width of the camera (maps to source_w
on layers).
53 54 55 |
# File 'lib/zif/layers/camera.rb', line 53 def cur_w @cur_w end |
#follow_duration ⇒ Integer
Returns How many ticks should camera following take? Defaults to 0.5 seconds.
76 77 78 |
# File 'lib/zif/layers/camera.rb', line 76 def follow_duration @follow_duration end |
#follow_easing ⇒ Symbol
Returns The easing function (Actions::Action::EASING_FUNCS) to use for camera following.
78 79 80 |
# File 'lib/zif/layers/camera.rb', line 78 def follow_easing @follow_easing end |
#follow_margins ⇒ Array<Integer>
Returns The margins on the screen which will stop camera panning. [top, right, bottom, left] These values are multiplied by the zoom factor when used. Defaults to [300, 600, 300, 600].
74 75 76 |
# File 'lib/zif/layers/camera.rb', line 74 def follow_margins @follow_margins end |
#last_camera_movement ⇒ Zif::Actions::Action
Returns The most recent camera movement Actions::Action.
63 64 65 |
# File 'lib/zif/layers/camera.rb', line 63 def last_camera_movement @last_camera_movement end |
#last_follow ⇒ Array<Float>
Returns The center point [x, y] of the last followed sprite. Used to center zooming.
70 71 72 |
# File 'lib/zif/layers/camera.rb', line 70 def last_follow @last_follow end |
#layers ⇒ Array<Zif::Sprite>
Returns The layer sprites this camera will move in unison.
22 23 24 |
# File 'lib/zif/layers/camera.rb', line 22 def layers @layers end |
#max_h ⇒ Integer
Returns Of the given #layers, the largest height value.
31 32 33 |
# File 'lib/zif/layers/camera.rb', line 31 def max_h @max_h end |
#max_w ⇒ Integer
Returns Of the given #layers, the largest width value.
29 30 31 |
# File 'lib/zif/layers/camera.rb', line 29 def max_w @max_w end |
#max_x ⇒ Integer
58 59 60 |
# File 'lib/zif/layers/camera.rb', line 58 def max_x @max_x end |
#max_y ⇒ Integer
60 61 62 |
# File 'lib/zif/layers/camera.rb', line 60 def max_y @max_y end |
#max_zoom_in ⇒ Float
Returns The maximum zoom in level. Defaults to 0.5. A value of 1.0 is no zoom at all.
34 35 36 |
# File 'lib/zif/layers/camera.rb', line 34 def max_zoom_in @max_zoom_in end |
#max_zoom_out ⇒ Float
Returns The maximum zoom out level. Defaults to 2.0. A value of 1.0 is no zoom at all.
36 37 38 |
# File 'lib/zif/layers/camera.rb', line 36 def max_zoom_out @max_zoom_out end |
#min_x ⇒ Integer
Returns The minimum X value the #layers source_x
can have, typically 0
.
25 26 27 |
# File 'lib/zif/layers/camera.rb', line 25 def min_x @min_x end |
#min_y ⇒ Integer
Returns The minimum Y value the #layers source_y
can have, typically 0
.
27 28 29 |
# File 'lib/zif/layers/camera.rb', line 27 def min_y @min_y end |
#native_screen_height ⇒ Integer (readonly)
Returns The native height of the screen, defaults to 720.
46 47 48 |
# File 'lib/zif/layers/camera.rb', line 46 def native_screen_height @native_screen_height end |
#native_screen_width ⇒ Integer (readonly)
Right now, the native screen size can’t be changed.
Returns The native width of the screen, defaults to 1280.
44 45 46 |
# File 'lib/zif/layers/camera.rb', line 44 def native_screen_width @native_screen_width end |
#pos_x ⇒ Float
Returns The current X position of the camera (lower left, maps to source_x
on layers).
49 50 51 |
# File 'lib/zif/layers/camera.rb', line 49 def pos_x @pos_x end |
#pos_y ⇒ Float
Returns The current Y position of the camera (lower left, maps to source_y
on layers).
51 52 53 |
# File 'lib/zif/layers/camera.rb', line 51 def pos_y @pos_y end |
#target_x ⇒ Float
Returns The relative change in X the camera is moving towards with #last_camera_movement.
65 66 67 |
# File 'lib/zif/layers/camera.rb', line 65 def target_x @target_x end |
#target_y ⇒ Float
Returns The relative change in Y the camera is moving towards with #last_camera_movement.
67 68 69 |
# File 'lib/zif/layers/camera.rb', line 67 def target_y @target_y end |
#zoom_step ⇒ Integer
Returns The index of #zoom_steps pointing to the current zoom level.
38 39 40 |
# File 'lib/zif/layers/camera.rb', line 38 def zoom_step @zoom_step end |
#zoom_steps ⇒ Array<Float>
Returns An ordered array of discrete zoom levels. Defaults to [0.5, 0.8, 1.0, 1.28, 1.6, 2.0].
40 41 42 |
# File 'lib/zif/layers/camera.rb', line 40 def zoom_steps @zoom_steps end |
Instance Method Details
#center(from = pos) ⇒ Array<Float>
Calculates the difference between [{cur_w}/2, {cur_h}/2] and from
301 302 303 304 305 306 307 308 309 310 |
# File 'lib/zif/layers/camera.rb', line 301 def center(from=pos) Zif.add_positions( from, Zif.position_math( :idiv, [@cur_w, @cur_h], [2, 2] ) ) end |
#center_screen(around = center) ⇒ Object
280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/zif/layers/camera.rb', line 280 def center_screen(around=center) center_to = Zif.sub_positions( around, Zif.position_math( :idiv, [@cur_w, @cur_h], [2, 2] ) ) move(*center_to) end |
#each_layer(&block) ⇒ Enumerator
Returns Iterate over each element of #layers.
164 165 166 |
# File 'lib/zif/layers/camera.rb', line 164 def each_layer(&block) @layers.each(&block) end |
#follow_x ⇒ Float
To support moving the default zoom point while following something
187 188 189 |
# File 'lib/zif/layers/camera.rb', line 187 def follow_x @last_follow[0] end |
#follow_x=(x) ⇒ Object
192 193 194 |
# File 'lib/zif/layers/camera.rb', line 192 def follow_x=(x) @last_follow[0] = x end |
#follow_y ⇒ Float
Returns The Y value of #last_follow.
197 198 199 |
# File 'lib/zif/layers/camera.rb', line 197 def follow_y @last_follow[1] end |
#follow_y=(y) ⇒ Object
202 203 204 |
# File 'lib/zif/layers/camera.rb', line 202 def follow_y=(y) @last_follow[1] = y end |
#full_view_rect ⇒ Array<Integer>
Returns [{cur_w}, {cur_h}].
158 159 160 |
# File 'lib/zif/layers/camera.rb', line 158 def full_view_rect [@cur_w, @cur_h] end |
#max_view_rect ⇒ Array<Integer>
Returns [w, h] The maximum width and height of the camera viewport, assuming fully zoomed out.
153 154 155 |
# File 'lib/zif/layers/camera.rb', line 153 def max_view_rect [(@native_screen_width * @max_zoom_out).to_i, (@native_screen_height * @max_zoom_out).to_i] end |
#min_view_rect ⇒ Array<Integer>
Returns [w, h] The minimum width and height of the camera viewport, assuming fully zoomed in.
148 149 150 |
# File 'lib/zif/layers/camera.rb', line 148 def min_view_rect [(@native_screen_width * @max_zoom_in).to_i, (@native_screen_height * @max_zoom_in).to_i] end |
#move(x, y) ⇒ Array<Float>
Adjust pos_x and pos_y together, return difference
210 211 212 213 214 215 216 217 218 |
# File 'lib/zif/layers/camera.rb', line 210 def move(x, y) orig_pos_x = @pos_x orig_pos_y = @pos_y self.pos_x = x self.pos_y = y [@pos_x - orig_pos_x, @pos_y - orig_pos_y] end |
#move_rel(x = nil, y = nil) ⇒ Object
Relative positional change where [1, 1] means add 1 to x/y instead of (1,1) Accepts nil to support behavior of directional_vector
224 225 226 227 228 229 |
# File 'lib/zif/layers/camera.rb', line 224 def move_rel(x=nil, y=nil) return unless x && y self.pos_x = @pos_x + x.round self.pos_y = @pos_y + y.round end |
#pos ⇒ Array<Float>
294 295 296 |
# File 'lib/zif/layers/camera.rb', line 294 def pos [@pos_x, @pos_y] end |
#scrolled?(_point, direction) ⇒ Boolean
This could be used to zoom in and out based on where the mouse is pointed - currently ignored. Feel free to override if you need this behavior, or submit a PR to split the Camera for this feature.
This method is used as a hook for Services::InputService, when given this obj with Services::InputService#register_scrollable. By default, it will attempt to zoom to either the last followed object, or center of the screen.
345 346 347 348 349 350 351 352 353 |
# File 'lib/zif/layers/camera.rb', line 345 def scrolled?(_point, direction) # translated_point = translate_pos(point) # puts "Camera scrolled: #{point}->#{translated_point} #{direction}" if direction == :down zoom_out # (translated_point) else zoom_in # (translated_point) end end |
#start_following(sprite) ⇒ Object
Cause the Camera to start an Actions::Action on itself to pan #pos_x and #pos_y towards the center point of the given sprite
. Obeys #follow_margins. Stops any existing #last_camera_movement. Panning will take #follow_duration and use #follow_easing.
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/zif/layers/camera.rb', line 235 def start_following(sprite) # We want to start following the leading sprite if it reaches the margins: top_margin, right_margin, down_margin, left_margin = @follow_margins top_margin, right_margin = Zif.position_math(:mult, [top_margin, right_margin], zoom_factor) down_margin, left_margin = Zif.position_math(:mult, [down_margin, left_margin], zoom_factor) relative_x = (sprite.x - @pos_x).to_i relative_y = (sprite.y - @pos_y).to_i @target_x = if relative_x < left_margin -(left_margin - relative_x) elsif relative_x > (@cur_w - right_margin) relative_x - (@cur_w - right_margin) else 0 end @target_y = if relative_y < down_margin -(down_margin - relative_y) elsif relative_y > (@cur_h - top_margin) relative_y - (@cur_h - top_margin) else 0 end return if @target_x.zero? && @target_y.zero? stop_action(@last_camera_movement) if @last_camera_movement # puts "Camera#start_following: Running action #{{pos_x: @pos_x + @target_x, pos_y: @pos_y + @target_y}}" @last_camera_movement = new_action( { pos_x: @pos_x + @target_x, pos_y: @pos_y + @target_y }, duration: @follow_duration, easing: @follow_easing ) { @last_follow = sprite.center } run_action(@last_camera_movement) end |
#translate_pos(given) ⇒ Array<Float>
Translate a 2 element point from the screen’s perspective to the map’s perspective
394 395 396 |
# File 'lib/zif/layers/camera.rb', line 394 def translate_pos(given) Zif.add_positions(Zif.position_math(:mult, given, zoom_factor), pos) end |
#zoom_factor ⇒ Float
The current zoom factor, this value is compared against #max_zoom_out and #max_zoom_in when zooming.
386 387 388 |
# File 'lib/zif/layers/camera.rb', line 386 def zoom_factor Zif.position_math(:fdiv, [@cur_w, @cur_h], zoom_unit) end |
#zoom_in(point = (@last_follow || center)) ⇒ Object
Zooms in by a single value in #zoom_steps, around the given point
364 365 366 367 |
# File 'lib/zif/layers/camera.rb', line 364 def zoom_in(point=(@last_follow || center)) @zoom_step = [@zoom_step - 1, 0].max zoom_to(@zoom_steps[@zoom_step], point) end |
#zoom_out(point = (@last_follow || center)) ⇒ Object
Zooms out by a single value in #zoom_steps, around the given point
357 358 359 360 |
# File 'lib/zif/layers/camera.rb', line 357 def zoom_out(point=(@last_follow || center)) @zoom_step = [@zoom_step + 1, @zoom_steps.length - 1].min zoom_to(@zoom_steps[@zoom_step], point) end |
#zoom_to(factor = 1.0, point = (@last_follow || center)) ⇒ Object
373 374 375 376 377 378 379 380 381 |
# File 'lib/zif/layers/camera.rb', line 373 def zoom_to(factor=1.0, point=(@last_follow || center)) base_mult = (factor.round(2) * 80) self.cur_w = (base_mult * 16) self.cur_h = (base_mult * 9) # puts "#zoom_to: Zoomed to #{zoom_factor}" center_screen(point) end |
#zoom_unit ⇒ Array<Integer>
A zoom factor of 1.0 corresponds to this resolution
334 335 336 |
# File 'lib/zif/layers/camera.rb', line 334 def zoom_unit [@native_screen_width, @native_screen_height] end |