reight 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +12 -0
  3. data/CONTRIBUTING.md +7 -0
  4. data/ChangeLog.md +76 -0
  5. data/README.md +6 -5
  6. data/Rakefile +5 -2
  7. data/VERSION +1 -1
  8. data/bin/r8 +18 -8
  9. data/lib/reight/all.rb +7 -2
  10. data/lib/reight/app/chips.rb +124 -0
  11. data/lib/reight/app/map/brush.rb +1 -1
  12. data/lib/reight/app/map/brush_base.rb +3 -3
  13. data/lib/reight/app/map/canvas.rb +10 -15
  14. data/lib/reight/app/map/editor.rb +44 -17
  15. data/lib/reight/app/map/line.rb +5 -5
  16. data/lib/reight/app/map/rect.rb +2 -2
  17. data/lib/reight/app/map.rb +0 -1
  18. data/lib/reight/app/navigator.rb +33 -47
  19. data/lib/reight/app/runner.rb +123 -86
  20. data/lib/reight/app/sound/brush.rb +32 -0
  21. data/lib/reight/app/sound/canvas.rb +190 -0
  22. data/lib/reight/app/sound/editor.rb +170 -10
  23. data/lib/reight/app/sound/eraser.rb +28 -0
  24. data/lib/reight/app/sound/tool.rb +29 -0
  25. data/lib/reight/app/sound.rb +4 -0
  26. data/lib/reight/app/sprite/canvas.rb +23 -18
  27. data/lib/reight/app/sprite/color.rb +3 -1
  28. data/lib/reight/app/sprite/editor.rb +58 -47
  29. data/lib/reight/app/sprite/line.rb +1 -1
  30. data/lib/reight/app/sprite/shape.rb +1 -1
  31. data/lib/reight/app/sprite.rb +0 -1
  32. data/lib/reight/app.rb +24 -5
  33. data/lib/reight/button.rb +10 -7
  34. data/lib/reight/chip.rb +32 -6
  35. data/lib/reight/context.rb +168 -0
  36. data/lib/reight/helpers.rb +2 -2
  37. data/lib/reight/index.rb +87 -0
  38. data/lib/reight/map.rb +141 -11
  39. data/lib/reight/project.rb +45 -6
  40. data/lib/reight/reight.rb +11 -15
  41. data/lib/reight/sound.rb +238 -0
  42. data/lib/reight/sprite.rb +42 -0
  43. data/lib/reight/text.rb +124 -0
  44. data/lib/reight.rb +7 -3
  45. data/reight.gemspec +7 -7
  46. data/res/icons.png +0 -0
  47. data/test/helper.rb +16 -0
  48. data/test/test_map.rb +7 -7
  49. data/test/test_map_chunk.rb +6 -6
  50. data/test/test_sprite.rb +28 -0
  51. metadata +42 -32
  52. data/lib/reight/app/map/chips.rb +0 -84
  53. data/lib/reight/app/music/editor.rb +0 -25
  54. data/lib/reight/app/music.rb +0 -1
  55. data/lib/reight/app/sprite/chips.rb +0 -92
@@ -0,0 +1,87 @@
1
+ using Reight
2
+
3
+
4
+ class Reight::Index
5
+
6
+ include Reight::Activatable
7
+ include Reight::Hookable
8
+ include Reight::HasHelp
9
+
10
+ def initialize(index = 0, min: 0, max: nil, &changed)
11
+ hook :changed
12
+
13
+ super()
14
+ @min, @max = min, max
15
+
16
+ self.changed(&changed) if changed
17
+ self.index = index
18
+ end
19
+
20
+ attr_reader :index
21
+
22
+ def index=(index)
23
+ index = index.clamp(@max ? (@min..@max) : (@min..))
24
+ return if index == @index
25
+ @index = index.to_i
26
+ changed! @index
27
+ end
28
+
29
+ def draw()
30
+ no_stroke
31
+
32
+ sp = sprite
33
+ w, h = sp.w, sp.h
34
+ dec = pressing? && prev?
35
+ inc = pressing? && next?
36
+ decy = dec ? 1 : 0
37
+ incy = inc ? 1 : 0
38
+
39
+ fill 220
40
+ rect 0, decy, h, h, 2 if dec
41
+ rect w - h, incy, h, h, 2 if inc
42
+
43
+ text_align CENTER, CENTER
44
+ fill 220
45
+ text '<', 0, decy + 1, h, h
46
+ text '>', w - h, incy + 1, h, h
47
+ text index, 0, 1, w, h
48
+ fill 50
49
+ text '<', 0, decy, h, h
50
+ text '>', w - h, incy, h, h
51
+ text index, 0, 0, w, h
52
+ end
53
+
54
+ def prev? = sprite.mouse_x < sprite.w / 2
55
+
56
+ def next? = !prev?
57
+
58
+ def pressed(x, y)
59
+ @pressing = true
60
+ end
61
+
62
+ def released(x, y)
63
+ @pressing = false
64
+ end
65
+
66
+ def pressing? = @pressing
67
+
68
+ def hover(x, y)
69
+ r8.flash x < (sprite.w / 2) ? 'Prev' : 'Next'
70
+ end
71
+
72
+ def clicked()
73
+ self.index += 1 if next?
74
+ self.index -= 1 if prev?
75
+ end
76
+
77
+ def sprite()
78
+ @sprite ||= RubySketch::Sprite.new(physics: false).tap do |sp|
79
+ sp.draw {draw}
80
+ sp.mouse_pressed {pressed sp.mouse_x, sp.mouse_y}
81
+ sp.mouse_released {released sp.mouse_x, sp.mouse_y}
82
+ sp.mouse_moved {hover sp.mouse_x, sp.mouse_y}
83
+ sp.mouse_clicked {clicked}
84
+ end
85
+ end
86
+
87
+ end# Index
data/lib/reight/map.rb CHANGED
@@ -12,10 +12,32 @@ class Reight::Map
12
12
  raise ArgumentError, "Invalid chunk_size: #{chunk_size}" if
13
13
  chunk_size.to_i != chunk_size || chunk_size % chip_size != 0
14
14
 
15
- @chip_size, @chunk_size = [chip_size, chunk_size].map &:to_i
15
+ @chip_size, @chunk_size = [chip_size, chunk_size].map(&:to_i)
16
16
  @chunks = {}
17
17
  end
18
18
 
19
+ def activate(x, y, w, h, world = nil, &activated)
20
+ @sprites = nil if !activated && @sprites && @sprites.world != world
21
+ @sprites ||= SpriteArray.new(world: world) {|*a, &b| each_chunk(*a, &b)}
22
+ @sprites.activate(x, y, w, h, &activated)
23
+ @sprites
24
+ end
25
+
26
+ def to_sprites()
27
+ map(&:to_sprite)
28
+ end
29
+
30
+ def sprites()
31
+ @sprites ||= SpriteArray.new(sprites: to_sprites)
32
+ end
33
+
34
+ alias sprites_at activate
35
+
36
+ def clear_sprites()
37
+ @chunks.each_value {_1&.clear_sprites}
38
+ @sprites = nil
39
+ end
40
+
19
41
  def put(x, y, chip)
20
42
  return unless chip
21
43
  each_chunk x, y, chip.w, chip.h, create: true do |chunk|
@@ -23,16 +45,16 @@ class Reight::Map
23
45
  end
24
46
  end
25
47
 
26
- def delete(x, y)
48
+ def remove(x, y)
27
49
  chip = self[x, y] or return
28
50
  cx, cy, cw, ch = chip.then {[_1.pos.x, _1.pos.y, _1.w, _1.h]}
29
51
  each_chunk cx, cy, cw, ch, create: false do |chunk|
30
- each_chip_pos(cx, cy, cw, ch) {|xx, yy| chunk.delete xx, yy}
52
+ each_chip_pos(cx, cy, cw, ch) {|xx, yy| chunk.remove xx, yy}
31
53
  end
32
54
  end
33
55
 
34
- def delete_chip(chip)
35
- delete chip.pos.x, chip.pos.y
56
+ def remove_chip(chip)
57
+ remove chip.pos.x, chip.pos.y
36
58
  end
37
59
 
38
60
  def each_chip(x = nil, y = nil, w = nil, h = nil, clip_by_chunk: false, &block)
@@ -62,18 +84,34 @@ class Reight::Map
62
84
  chunk_at(x, y)&.[](x, y)
63
85
  end
64
86
 
65
- def <=>(o)
87
+ def inspect()
88
+ "#<#{self.class.name}:0x#{object_id}>"
89
+ end
90
+
91
+ # @private
92
+ def cmp__(o)
66
93
  a = [@chip_size, @chunk_size, @chunks]
67
94
  b = o.instance_eval {[@chip_size, @chunk_size, @chunks]}
68
95
  a <=> b
69
96
  end
70
97
 
98
+ # @private
99
+ def drawSprite__(context)
100
+ if @sprites
101
+ @sprites.drawSprite__ context
102
+ else
103
+ @chunks.each_value {_1.drawSprite__ context}
104
+ end
105
+ end
106
+
71
107
  def self.restore(hash, source_chips)
72
- hash => {chip_size:, chunk_size:, chunks:}
108
+ chip_size, chunk_size, chunks = hash.values_at :chip_size, :chunk_size, :chunks
109
+ #hash => {chip_size:, chunk_size:, chunks:}
73
110
  new(chip_size: chip_size, chunk_size: chunk_size).tap do |obj|
74
111
  obj.instance_eval do
75
112
  @chunks = chunks.each.with_object({}) do |chunk_hash, result|
76
- chunk_hash => {x:, y:}
113
+ x, y = chunk_hash.values_at :x, :y
114
+ #chunk_hash => {x:, y:}
77
115
  result[[x, y]] = Chunk.restore chunk_hash, source_chips
78
116
  end
79
117
  end
@@ -135,8 +173,10 @@ class Reight::Map
135
173
  end# Map
136
174
 
137
175
 
176
+ # @private
138
177
  class Reight::Map::Chunk
139
178
 
179
+ include Enumerable
140
180
  include Comparable
141
181
 
142
182
  def initialize(x, y, w, h, chip_size: 8)
@@ -150,6 +190,14 @@ class Reight::Map::Chunk
150
190
 
151
191
  attr_reader :x, :y, :w, :h
152
192
 
193
+ def sprites()
194
+ @sprites ||= map(&:sprite).each {_1.map_chunk = self}
195
+ end
196
+
197
+ def clear_sprites()
198
+ @sprites = nil
199
+ end
200
+
153
201
  def put(x, y, chip)
154
202
  x, y = align_chip_pos x, y
155
203
  raise "Invalid chip size" if
@@ -162,15 +210,17 @@ class Reight::Map::Chunk
162
210
  each_chip_pos x, y, chip.w, chip.h do |xx, yy|
163
211
  @chips[pos2index xx, yy] = get_chip.call
164
212
  end
213
+ invalidate_cache__
165
214
  end
166
215
 
167
- def delete(x, y)
216
+ def remove(x, y)
168
217
  chip = self[x, y] or return
169
218
  each_chip_pos chip.pos.x, chip.pos.y, chip.w, chip.h do |xx, yy|
170
219
  index = pos2index xx, yy
171
220
  @chips[index] = nil if @chips[index]&.id == chip.id
172
221
  end
173
222
  delete_last_nils
223
+ invalidate_cache__
174
224
  end
175
225
 
176
226
  def each_chip(x = nil, y = nil, w = nil, h = nil, include_hidden: false, &block)
@@ -201,6 +251,8 @@ class Reight::Map::Chunk
201
251
  end
202
252
  end
203
253
 
254
+ def each(&block) = each_chip {block.call _1}
255
+
204
256
  def frame = [@x, @y, @w, @h]
205
257
 
206
258
  def to_hash()
@@ -216,14 +268,44 @@ class Reight::Map::Chunk
216
268
  @chips[index]
217
269
  end
218
270
 
219
- def <=>(o)
271
+ def inspect()
272
+ "#<#{self.class.name}:0x#{object_id}>"
273
+ end
274
+
275
+ # @private
276
+ def cmp__(o)
220
277
  a = [@x, @y, @w, @h, @chip_size, @chips]
221
278
  b = o.instance_eval {[@x, @y, @w, @h, @chip_size, @chips]}
222
279
  a <=> b
223
280
  end
224
281
 
282
+ # @private
283
+ def invalidate_cache__()
284
+ @cached = false
285
+ end
286
+
287
+ # @private
288
+ def drawSprite__(context)
289
+ @cached ||= true.tap do
290
+ @cache ||= create_graphics @w, @h
291
+ @cache.begin_draw do |g|
292
+ g.background 0, 0
293
+ g.translate -@x, -@y
294
+ sprites.each {_1.drawSprite__ g}
295
+ end
296
+ end
297
+ context.image @cache, @x, @y
298
+ end
299
+
300
+ # @private
301
+ def delete_sprite__(sprite)
302
+ @sprites.delete sprite
303
+ invalidate_cache__
304
+ end
305
+
225
306
  def self.restore(hash, source_chips)
226
- hash => {x:, y:, w:, h:, chip_size: chip_size, chips: chip_ids}
307
+ x, y, w, h, chip_size, chip_ids = hash.values_at :x, :y, :w, :h, :chip_size, :chips
308
+ #hash => {x:, y:, w:, h:, chip_size: chip_size, chips: chip_ids}
227
309
  tmp_chips = {}
228
310
  get_chip = -> id, x, y {
229
311
  tmp_chips[[id, x, y]] ||= source_chips[id].with(pos: create_vector(x, y))
@@ -262,3 +344,51 @@ class Reight::Map::Chunk
262
344
  end
263
345
 
264
346
  end# Chunk
347
+
348
+
349
+ # @private
350
+ class Reight::Map::SpriteArray < Array
351
+
352
+ def initialize(world: nil, sprites: [], &each_chunk)
353
+ @world, @each_chunk = world, each_chunk
354
+ super(sprites)
355
+ end
356
+
357
+ attr_reader :world
358
+
359
+ def activate(x, y, w, h, &activated)
360
+ raise ArgumentError, "missing 'activated' block" if !@world && !activated
361
+
362
+ bounds, old_bounds = [x, y, w, h], @bounds
363
+ return if bounds == old_bounds
364
+
365
+ chunks, old_chunks = @each_chunk.call(x, y, w, h).to_a, @chunks || []
366
+ return if chunks == old_chunks
367
+
368
+ activateds, deactivateds = [chunks - old_chunks, old_chunks - chunks]
369
+ .map {|chunks| chunks.map(&:sprites).flatten.compact}
370
+ if activated
371
+ activated.call activateds, deactivateds
372
+ elsif @world
373
+ activateds.each {@world .add_sprite _1}
374
+ deactivateds.each {@world.remove_sprite _1}
375
+ end
376
+
377
+ @bounds, @chunks = bounds, chunks
378
+ clear.concat @chunks.map(&:sprites).flatten.compact
379
+ end
380
+
381
+ def delete(sprite)
382
+ sprite.map_chunk&.delete_sprite__ sprite
383
+ super
384
+ end
385
+
386
+ def inspect()
387
+ "#<#{self.class.name}:0x#{object_id}>"
388
+ end
389
+
390
+ def drawSprite__(context)
391
+ (@chunks&.each || each).each {_1.drawSprite__ context}
392
+ end
393
+
394
+ end# SpriteArray
@@ -3,6 +3,8 @@ using Reight
3
3
 
4
4
  class Reight::Project
5
5
 
6
+ include Xot::Inspectable
7
+
6
8
  def initialize(project_dir)
7
9
  raise 'the project directory is required' unless project_dir
8
10
  @project_dir = project_dir
@@ -17,7 +19,9 @@ class Reight::Project
17
19
  def code_paths = settings[__method__]&.then {[_1].flatten} || ['game.rb']
18
20
 
19
21
  def codes()
20
- code_paths.map {File.read _1 rescue nil}
22
+ code_paths
23
+ .map {File.expand_path _1, project_dir}
24
+ .map {File.read _1 rescue nil}
21
25
  end
22
26
 
23
27
  def chips_json_name = settings[__method__] || 'chips.json'
@@ -39,7 +43,7 @@ class Reight::Project
39
43
  def chips_image()
40
44
  @chips_image ||= -> {
41
45
  create_graphics(chips_image_width, chips_image_height).tap do |g|
42
- g.begin_draw {g.background 0, 0, 0}
46
+ g.begin_draw {g.background 0, 0, 0, 0}
43
47
  img = load_image chips_image_path
44
48
  g.begin_draw {g.image img, 0, 0}
45
49
  rescue Rays::RaysError
@@ -47,6 +51,17 @@ class Reight::Project
47
51
  }.call
48
52
  end
49
53
 
54
+ def chips_page_width = settings[__method__] || 256
55
+
56
+ def chips_page_height = settings[__method__] || 256
57
+
58
+ def chips_npages()
59
+ w = chips_image_width / chips_page_width .to_f
60
+ h = chips_image_height / chips_page_height.to_f
61
+ raise unless w == w.to_i && h == h.to_i
62
+ (w * h).to_i
63
+ end
64
+
50
65
  def maps_json_name = settings[__method__] || 'maps.json'
51
66
 
52
67
  def maps_json_path = "#{project_dir}/#{maps_json_name}"
@@ -55,19 +70,30 @@ class Reight::Project
55
70
  @maps ||= load_maps
56
71
  end
57
72
 
73
+ def sounds_json_name = settings[__method__] || 'sounds.json'
74
+
75
+ def sounds_json_path = "#{project_dir}/#{sounds_json_name}"
76
+
77
+ def sounds()
78
+ @sounds ||= load_sounds
79
+ end
80
+
58
81
  def font = @font ||= create_font(nil, font_size)
59
82
 
60
83
  def font_size = 8
61
84
 
62
- def palette_colors = %w[
63
- #000000 #1D2B53 #7E2553 #008751 #AB5236 #5F574F #C2C3C7 #FFF1E8
64
- #FF004D #FFA300 #FFEC27 #00E436 #29ADFF #83769C #FF77A8 #FFCCAA
65
- ]
85
+ def palette_colors = Reight::App::PALETTE_COLORS.dup
86
+
87
+ def clear_all_sprites()
88
+ chips.each(&:clear_sprite)
89
+ maps.each(&:clear_sprites)
90
+ end
66
91
 
67
92
  def save()
68
93
  File.write project_path, to_json_string(@settings)
69
94
  save_chips
70
95
  save_maps
96
+ save_sounds
71
97
  end
72
98
 
73
99
  private
@@ -104,6 +130,19 @@ class Reight::Project
104
130
  end
105
131
  end
106
132
 
133
+ def save_sounds()
134
+ File.write sounds_json_path, to_json_string(sounds.map {_1.to_hash})
135
+ end
136
+
137
+ def load_sounds()
138
+ if File.file? sounds_json_path
139
+ json = JSON.parse File.read(sounds_json_path), symbolize_names: true
140
+ json.map {Reight::Sound.restore _1}
141
+ else
142
+ [Reight::Sound.new]
143
+ end
144
+ end
145
+
107
146
  def to_json_string(obj, readable: true)
108
147
  if readable
109
148
  JSON.pretty_generate obj
data/lib/reight/reight.rb CHANGED
@@ -3,32 +3,29 @@ using Reight
3
3
 
4
4
  class Reight::R8
5
5
 
6
- def initialize(path)
6
+ def initialize(path, edit: false)
7
7
  raise if $r8__
8
8
  $r8__ = self
9
9
 
10
- @path = path
10
+ @path, @edit = path, edit
11
11
  self.current = apps.first
12
12
  end
13
13
 
14
14
  attr_reader :current
15
15
 
16
- def version()
17
- '0.1'
18
- end
16
+ def edit? = @edit
19
17
 
20
18
  def project()
21
19
  @project ||= Reight::Project.new @path
22
20
  end
23
21
 
24
22
  def apps()
25
- @apps ||= [
26
- Reight::Runner.new(project),
27
- Reight::SpriteEditor.new(project),
28
- Reight::MapEditor.new(project),
29
- Reight::SoundEditor.new(project),
30
- Reight::MusicEditor.new(project)
31
- ]
23
+ @apps ||= [].tap {|a|
24
+ a << Reight::Runner .new(project)
25
+ a << Reight::SpriteEditor.new(project) if edit?
26
+ a << Reight::MapEditor .new(project) if edit?
27
+ a << Reight::SoundEditor .new(project) if edit?
28
+ }
32
29
  end
33
30
 
34
31
  def flash(...) = current.flash(...)
@@ -43,16 +40,15 @@ class Reight::R8
43
40
  end
44
41
 
45
42
  def current=(app)
46
- return if app == @current
47
43
  @current&.deactivated
48
44
  @current = app
49
45
  @current.activated
50
46
 
51
47
  set_title [
52
48
  self.class.name.split('::').first,
53
- version,
49
+ Reight::Extension.version,
54
50
  '|',
55
- current.class.name.split('::').last
51
+ current.label
56
52
  ].join ' '
57
53
  end
58
54