Class: ExampleApp::World

Inherits:
ZifExampleScene show all
Defined in:
app/scenes/world.rb

Overview

An example which uses Zif::Layers::LayerGroup and Zif::Layers::Camera

Instance Attribute Summary collapse

Attributes inherited from ZifExampleScene

#next_scene, #scene_timer, #tracer_service_name

Attributes included from Zif::Traceable

#tracer_service_name

Instance Method Summary collapse

Methods inherited from ZifExampleScene

#display_context_labels, #display_timer_bar

Methods included from Zif::Traceable

#mark, #mark_and_print, #mark_prefix, #tracer

Methods inherited from Zif::Scene

#unload_scene

Methods included from Zif::Serializable

#exclude_from_serialize, #inspect, #serialize, #to_s

Constructor Details

#initializeWorld

Returns a new instance of World.



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
# File 'app/scenes/world.rb', line 9

def initialize
  super
  @next_scene = :load_double_buffer_render_test
  mark('#initialize: Begin')
  @map = Zif::Layers::LayerGroup.new(logical_width: 50, logical_height: 50)
  @map.new_tiled_layer(:tiles)
  @map.new_active_layer(:avatar)
  mark('#initialize: Map + layers created')
  @map.force_refresh
  @map.layers[:tiles].should_render = false
  mark('#initialize: Map refreshed')

  @avatar = Avatar.new(
    $game.services[:sprite_registry].construct('dragon_1'),
    500,
    700,
    @map.max_width,
    @map.max_height
  )

  @pixie = Pixie.new
  @pixie.x = 1659
  @pixie.y = 1659
  @pixie.spin
  @pixie.float_to(@avatar)

  @map.layers[:avatar].sprites << @avatar
  @map.layers[:avatar].sprites << @pixie

  @ready = false
  @progress = Hash.new(0)
  @finished_at = Hash.new((@map.logical_width * @map.logical_height) - 1)
  puts "World#initialize: Initializing #{@map.logical_width}x#{@map.logical_height}"
  puts "  =#{@finished_at[:tiles] + 1} Tiles"

  mark_and_print('#initialize: Nearly finished')
  initialize_tiles

  mark_and_print('#initialize: Tiles initialized')
end

Instance Attribute Details

#avatarObject

Returns the value of attribute avatar.



4
5
6
# File 'app/scenes/world.rb', line 4

def avatar
  @avatar
end

#cameraObject

Returns the value of attribute camera.



4
5
6
# File 'app/scenes/world.rb', line 4

def camera
  @camera
end

#finished_atObject

For init



7
8
9
# File 'app/scenes/world.rb', line 7

def finished_at
  @finished_at
end

#last_rendered_cameraObject

Returns the value of attribute last_rendered_camera.



4
5
6
# File 'app/scenes/world.rb', line 4

def last_rendered_camera
  @last_rendered_camera
end

#mapObject

Returns the value of attribute map.



4
5
6
# File 'app/scenes/world.rb', line 4

def map
  @map
end

#pixieObject

Returns the value of attribute pixie.



4
5
6
# File 'app/scenes/world.rb', line 4

def pixie
  @pixie
end

#progressObject

For init



7
8
9
# File 'app/scenes/world.rb', line 7

def progress
  @progress
end

#readyObject

For init



7
8
9
# File 'app/scenes/world.rb', line 7

def ready
  @ready
end

Instance Method Details

#distance_from_center(x1, y1, x2 = @map.logical_width.idiv(2), y2 = @map.logical_height.idiv(2)) ⇒ Object



106
107
108
109
# File 'app/scenes/world.rb', line 106

def distance_from_center(x1, y1, x2=@map.logical_width.idiv(2), y2=@map.logical_height.idiv(2))
  dist = Zif.distance(x1, y1, x2, y2)
  1.0 - dist.fdiv(@map.logical_width.idiv(2))
end

#finish_initializationObject



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
# File 'app/scenes/world.rb', line 111

def finish_initialization
  puts 'World#finish_initialization: Begin'
  @camera = Zif::Layers::Camera.new(
    layer_sprites:   @map.layer_containing_sprites,
    starting_width:  Zif::Layers::Camera::DEFAULT_SCREEN_WIDTH,
    starting_height: Zif::Layers::Camera::DEFAULT_SCREEN_HEIGHT,
    initial_x:       0,
    initial_y:       400
  )

  @map.layers[:tiles].should_render = true
  refresh_map
  @map.layers[:tiles].should_render = false

  @map.layers[:tiles].containing_sprite.on_mouse_up = lambda do |sprite, point|
    map_clicked(sprite, translate_point_to_camera(point))
  end

  @map.layers[:tiles].containing_sprite.on_mouse_down = ->(_sprite, point) { puts "Map clicked down! #{point}" }

  $game.services[:action_service].register_actionable(@avatar)
  $game.services[:action_service].register_actionable(@camera)
  $game.services[:action_service].register_actionable(@pixie)
  $game.services[:input_service].register_clickable(@map.layers[:tiles].containing_sprite)

  $game.services[:input_service].register_scrollable(@camera)

  $gtk.args.outputs.static_sprites << @camera.layers
  # $gtk.args.outputs.static_labels  << @hud_labels
  puts 'World#finish_initialization: Initialized World'
end

#initialization_percent(kind = :tiles) ⇒ Object

For loading bar



51
52
53
# File 'app/scenes/world.rb', line 51

def initialization_percent(kind=:tiles)
  @ready ? 1.0 : (@progress[kind] / @finished_at[kind].to_f)
end

#initialize_tilesObject

If we attempt to initialize the entire map in 1 tick, everything will freeze up until it finishes. So this is a method for loading which is designed to prevent this and allow us to show a loading bar. The idea is that we run this once per tick, several times until initialization is finished.



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
# File 'app/scenes/world.rb', line 58

def initialize_tiles
  mark_and_print('#initialize_tiles: Begin')
  return if @ready

  %i[tiles].each do |kind| # stuff
    next if @progress[kind] >= @finished_at[kind]

    cur_y, cur_x = @progress[kind].divmod @map.logical_width
    # puts "World#initialize_tiles(#{kind}): #{@progress[kind]}/#{@finished_at[kind]} ="
    # puts "  #{(initialization_percent * 100).floor}%"

    start_t = Time.now

    center = [@map.logical_width.idiv(2), @map.logical_height.idiv(2)]

    cur_y.upto(@map.logical_height - 1) do |y|
      # Invert Y so sprites lower on the screen overlap higher ones
      actual_y = (@map.logical_height - 1) - y
      cur_x.upto(@map.logical_width - 1) do |x|
        @progress[kind] += 1

        cur_tile = case kind
                   when :tiles
                     $game.services[:sprite_registry].construct(:white_1).tap do |s|
                       rads = Zif.radian_angle_between_points(x, actual_y, *center)
                       hue = (rads + Math::PI).fdiv(2 * Math::PI) * 360
                       r, g, b = Zif.hsv_to_rgb(hue, 100, 100 * distance_from_center(x, actual_y))
                       s.name = "floor_#{x}_#{actual_y}"
                       s.r = r
                       s.g = b
                       s.b = g
                     end
                   when :stuff
                     # TODO: Add some stuff
                   end

        @map.layers[kind].add_positioned_sprite(sprite: cur_tile, logical_x: x, logical_y: actual_y) if cur_tile

        # Allow this to execute for 8ms (half a tick at 60fps).
        return if (Time.now - start_t) >= 0.008 # rubocop:disable Lint/NonLocalExitFromIterator
      end
      cur_x = 0
    end
  end
  puts 'World#initialize_tiles: Finished'
  @ready = true
end

#map_clicked(_sprite, point) ⇒ Object



165
166
167
168
169
# File 'app/scenes/world.rb', line 165

def map_clicked(_sprite, point)
  puts "Map clicked! #{point}"

  @avatar.start_walking(point)
end

#perform_tickObject



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/scenes/world.rb', line 143

def perform_tick
  mark('#perform_tick: Begin')

  $gtk.args.outputs.background_color = [0, 0, 0, 0]
  mark('#perform_tick: Init')

  @camera.start_following(@avatar) if @avatar.walking
  mark('#perform_tick: Main sequence finished')

  refresh_map
  mark('#perform_tick: Map refreshed')

  perform_tick_debug_labels

  mark('#perform_tick: Finished')
  super
end

#perform_tick_debug_labelsObject

rubocop:disable Layout/LineLength



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'app/scenes/world.rb', line 185

def perform_tick_debug_labels
  color = {r: 255, g: 255, b: 255, a: 255}

  if @avatar
    $gtk.args.outputs.labels << { x: 8, y: 720 - 68, text: "Avatar: #{@avatar.xy.join('x')}" }.merge(color)
    # $gtk.args.outputs.labels << { x: 8, y: 720 - 28, text: "Moving: #{$gtk.args.inputs.directional_vector}" }.merge(color) if $gtk.args.inputs.directional_vector
    $gtk.args.outputs.labels << { x: 8, y: 720 - 48, text: "Moving: #{@avatar.moving_to}" }.merge(color) unless @avatar.moving_to&.all?(&:zero?)
  end

  return unless @camera

  point = [$args.inputs.mouse.x, $args.inputs.mouse.y]

  $gtk.args.outputs.labels << { x: 8, y: 720 - 88, text: "Camera: #{@camera.pos.join('x')} -> #{@camera.cur_w}x#{@camera.cur_h}.  Target #{@camera.target_x}x#{@camera.target_y}" }.merge(color)
  $gtk.args.outputs.labels << { x: 8, y: 720 - 108, text: "Mouse: #{point} window -> #{translate_point_to_camera(point)} world" }.merge(color)
end

#prepare_sceneObject



175
176
177
178
179
180
181
182
# File 'app/scenes/world.rb', line 175

def prepare_scene
  mark_and_print('#prepare_scene: Begin')
  super
  finish_initialization if @ready && @camera.nil?

  @avatar.run_animation_sequence(:fly)
  mark_and_print('#prepare_scene: Complete')
end

#refresh_mapObject



171
172
173
# File 'app/scenes/world.rb', line 171

def refresh_map
  @map.refresh
end

#translate_point_to_camera(point) ⇒ Object



161
162
163
# File 'app/scenes/world.rb', line 161

def translate_point_to_camera(point)
  @camera.translate_pos(point)
end