reight 0.1.2

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/release-gem.yml +62 -0
  3. data/.github/workflows/tag.yml +35 -0
  4. data/.github/workflows/test.yml +37 -0
  5. data/.github/workflows/utils.rb +56 -0
  6. data/.gitignore +1 -0
  7. data/ChangeLog.md +23 -0
  8. data/Gemfile +6 -0
  9. data/LICENSE +21 -0
  10. data/README.md +62 -0
  11. data/Rakefile +30 -0
  12. data/VERSION +1 -0
  13. data/bin/r8 +35 -0
  14. data/lib/reight/all.rb +59 -0
  15. data/lib/reight/app/map/brush.rb +27 -0
  16. data/lib/reight/app/map/brush_base.rb +54 -0
  17. data/lib/reight/app/map/canvas.rb +150 -0
  18. data/lib/reight/app/map/chips.rb +84 -0
  19. data/lib/reight/app/map/editor.rb +117 -0
  20. data/lib/reight/app/map/line.rb +35 -0
  21. data/lib/reight/app/map/rect.rb +29 -0
  22. data/lib/reight/app/map/tool.rb +32 -0
  23. data/lib/reight/app/map.rb +8 -0
  24. data/lib/reight/app/music/editor.rb +25 -0
  25. data/lib/reight/app/music.rb +1 -0
  26. data/lib/reight/app/navigator.rb +172 -0
  27. data/lib/reight/app/runner.rb +275 -0
  28. data/lib/reight/app/sound/editor.rb +25 -0
  29. data/lib/reight/app/sound.rb +1 -0
  30. data/lib/reight/app/sprite/brush.rb +43 -0
  31. data/lib/reight/app/sprite/canvas.rb +254 -0
  32. data/lib/reight/app/sprite/chips.rb +92 -0
  33. data/lib/reight/app/sprite/color.rb +30 -0
  34. data/lib/reight/app/sprite/editor.rb +272 -0
  35. data/lib/reight/app/sprite/fill.rb +45 -0
  36. data/lib/reight/app/sprite/line.rb +37 -0
  37. data/lib/reight/app/sprite/select.rb +58 -0
  38. data/lib/reight/app/sprite/shape.rb +43 -0
  39. data/lib/reight/app/sprite/tool.rb +27 -0
  40. data/lib/reight/app/sprite.rb +10 -0
  41. data/lib/reight/app.rb +123 -0
  42. data/lib/reight/button.rb +93 -0
  43. data/lib/reight/chip.rb +150 -0
  44. data/lib/reight/extension.rb +24 -0
  45. data/lib/reight/helpers.rb +69 -0
  46. data/lib/reight/history.rb +135 -0
  47. data/lib/reight/map.rb +264 -0
  48. data/lib/reight/project.rb +115 -0
  49. data/lib/reight/reight.rb +83 -0
  50. data/lib/reight.rb +18 -0
  51. data/reight.gemspec +40 -0
  52. data/res/icons.png +0 -0
  53. data/test/helper.rb +15 -0
  54. data/test/test_chip.rb +108 -0
  55. data/test/test_chip_list.rb +68 -0
  56. data/test/test_map.rb +232 -0
  57. data/test/test_map_chunk.rb +226 -0
  58. metadata +244 -0
@@ -0,0 +1,150 @@
1
+ using Reight
2
+
3
+
4
+ class Reight::Chip
5
+
6
+ include Comparable
7
+
8
+ def initialize(id, image, x, y, w, h, pos: nil, shape: nil, sensor: nil)
9
+ @id, @image, @x, @y, @w, @h, @pos, @shape, @sensor =
10
+ id, image, x, y, w, h, pos, shape, (sensor || false)
11
+ end
12
+
13
+ attr_accessor :shape
14
+
15
+ attr_writer :sensor
16
+
17
+ attr_reader :id, :image, :x, :y, :w, :h, :pos
18
+
19
+ def frame = [x, y, w, h]
20
+
21
+ def sensor? = @sensor
22
+
23
+ def empty?()
24
+ pixels.all? {red(_1) == 0 && green(_1) == 0 && blue(_1) == 0}
25
+ end
26
+
27
+ def with(**kwargs)
28
+ id, image, x, y, w, h, pos, shape, sensor =
29
+ kwargs.values_at :id, :image, :x, :y, :w, :h, :pos, :shape, :sensor
30
+ self.class.new(
31
+ id || @id,
32
+ image || @image,
33
+ x || @x,
34
+ y || @y,
35
+ w || @w,
36
+ h || @h,
37
+ pos: kwargs.key?(:pos) ? pos : @pos,
38
+ shape: kwargs.key?(:shape) ? shape : @shape,
39
+ sensor: kwargs.key?(:sensor) ? sensor : @sensor)
40
+ end
41
+
42
+ def to_sprite()
43
+ physics, shape =
44
+ case @shape
45
+ when :rect then [true, nil]
46
+ when :circle then [true, RubySketch::Circle.new(0, 0, w)]
47
+ else [false, nil]
48
+ end
49
+ Sprite.new(
50
+ 0, 0, w, h, image: image, offset: [x, y], shape: shape, physics: physics
51
+ ).tap do |sp|
52
+ sp.x, sp.y = pos.x, pos.y if pos
53
+ if physics
54
+ sp.sensor = true if sensor?
55
+ sp.fix_angle
56
+ end
57
+ end
58
+ end
59
+
60
+ def to_hash()
61
+ {
62
+ id: id, x: x, y: y, w: w, h: h
63
+ }.tap do |h|
64
+ h[:pos] = pos.to_a(2) if pos
65
+ h[:shape] = shape if shape
66
+ h[:sensor] = true if sensor?
67
+ end
68
+ end
69
+
70
+ def <=>(o)
71
+ a = [@id, @image.object_id, @x, @y, @w, @h, @pos, @shape, @sensor]
72
+ b = o.instance_eval {[@id, @image.object_id, @x, @y, @w, @h, @pos, @shape, @sensor]}
73
+ a <=> b
74
+ end
75
+
76
+ def self.restore(hash, image)
77
+ id, x, y, w, h, pos, shape, sensor =
78
+ hash.values_at :id, :x, :y, :w, :h, :pos, :shape, :sensor
79
+ new(
80
+ id, image, x, y, w, h, pos: pos&.then {create_vector(*_1)},
81
+ shape: shape&.to_sym, sensor: sensor || false)
82
+ end
83
+
84
+ private
85
+
86
+ def pixels()
87
+ g = createGraphics w, h
88
+ g.beginDraw do
89
+ g.copy image, x, y, w, h, 0, 0, w, h
90
+ end
91
+ g.load_pixels
92
+ g.pixels
93
+ end
94
+
95
+ end# Chip
96
+
97
+
98
+ class Reight::ChipList
99
+
100
+ include Comparable
101
+
102
+ def initialize(image)
103
+ @image = image
104
+ @next_id, @id2chip, @frame2chip = 1, {}, {}
105
+ end
106
+
107
+ attr_reader :image
108
+
109
+ def at(x, y, w, h)
110
+ @frame2chip[[x, y, w, h]] ||= create_chip x, y, w, h
111
+ end
112
+
113
+ def to_hash()
114
+ {next_id: @next_id, chips: @id2chip.values.map {_1.to_hash}}
115
+ end
116
+
117
+ def [](id)
118
+ @id2chip[id]
119
+ end
120
+
121
+ def <=>(o)
122
+ a = [@image, @next_id, @id2chip, @frame2chip]
123
+ b = o.instance_eval {[@image, @next_id, @id2chip, @frame2chip]}
124
+ a <=> b
125
+ end
126
+
127
+ def self.restore(hash, image)
128
+ hash => {next_id:, chips:}
129
+ new(image).tap do |obj|
130
+ obj.instance_eval do
131
+ @next_id = next_id
132
+ @id2chip = chips
133
+ .map {|hash| Reight::Chip.restore hash, image}
134
+ .map {|chip| [chip.id, chip]}
135
+ .to_h
136
+ @frame2chip = @id2chip.each_value
137
+ .with_object({}) {|chip, hash| hash[chip.frame] = chip}
138
+ end
139
+ end
140
+ end
141
+
142
+ private
143
+
144
+ def create_chip(x, y, w, h)
145
+ id = @next_id
146
+ @next_id += 1
147
+ @id2chip[id] = Reight::Chip.new(id, @image, x, y, w, h, shape: :rect)
148
+ end
149
+
150
+ end# ChipList
@@ -0,0 +1,24 @@
1
+ module Reight
2
+
3
+
4
+ # @private
5
+ module Extension
6
+
7
+ module_function
8
+
9
+ def name()
10
+ super.split('::')[-2]
11
+ end
12
+
13
+ def version()
14
+ File.read(root_dir 'VERSION')[/[\d\.]+/]
15
+ end
16
+
17
+ def root_dir(path = '')
18
+ File.expand_path "../../#{path}", __dir__
19
+ end
20
+
21
+ end# Extension
22
+
23
+
24
+ end# Reight
@@ -0,0 +1,69 @@
1
+ module Reight::Activatable
2
+
3
+ def initialize(...)
4
+ super
5
+ @active, @activateds = false, []
6
+ end
7
+
8
+ def active=(active)
9
+ active = !!active
10
+ return if active == @active
11
+ @active = active
12
+ activated!
13
+ end
14
+
15
+ def active? = @active
16
+
17
+ def activated(&block)
18
+ @activateds.push block if block
19
+ end
20
+
21
+ def activated!()
22
+ @activateds.each {_1.call active}
23
+ end
24
+
25
+ end# Activatable
26
+
27
+
28
+ module Reight::Hookable
29
+
30
+ def hook(*names)
31
+ names.each do |name|
32
+ singleton_class.__send__ :define_method, name do |&block|
33
+ @hookable_hooks ||= {}
34
+ (@hookable_hooks[name] ||= []).push block
35
+ end
36
+ singleton_class.__send__ :define_method, "#{name}!" do |*args|
37
+ @hookable_hooks&.[](name)&.each {|block| block.call(*args)}
38
+ end
39
+ end
40
+ end
41
+
42
+ end# Hookable
43
+
44
+
45
+ module Reight::HasHelp
46
+
47
+ def initialize(...)
48
+ super
49
+ set_help name: name
50
+ end
51
+
52
+ def name = @name || self.class.name
53
+
54
+ def set_help(name: nil, left: nil, right: nil)
55
+ @helps = {name: name, left: left, right: right}
56
+ end
57
+
58
+ def help()
59
+ name = @helps[:name]
60
+ mouses = @helps
61
+ .values_at(:left, :right)
62
+ .zip([:L, :R])
63
+ .map {|help, char| help ? "#{char}: #{help}" : nil}
64
+ .compact
65
+ .then {_1.empty? ? nil : _1.join(' ')}
66
+ [name, mouses].compact.join ' '
67
+ end
68
+
69
+ end# HasHelp
@@ -0,0 +1,135 @@
1
+ class Reight::History
2
+
3
+ def initialize(undos = [], redos = [])
4
+ super()
5
+ @undos, @redos = undos, redos
6
+ @group, @enabled = nil, true
7
+ end
8
+
9
+ def append(*actions)
10
+ return false if actions.empty? || disabled?
11
+ if @group
12
+ @group.push(*actions)
13
+ else
14
+ @undos.push actions
15
+ @redos.clear
16
+ update
17
+ end
18
+ true
19
+ end
20
+
21
+ def begin_grouping(&block)
22
+ raise "Grouping cannot be nested" if @group
23
+ @group = []
24
+ block.call if block
25
+ ensure
26
+ end_grouping if block
27
+ end
28
+
29
+ alias group begin_grouping
30
+
31
+ def end_grouping()
32
+ raise "'begin_grouping' is missing" unless @group
33
+ actions, @group = @group, nil
34
+ append(*actions)
35
+ end
36
+
37
+ def undo(&block)
38
+ actions = @undos.pop || return
39
+ disable do
40
+ actions.reverse.each {|action| block.call action}
41
+ end
42
+ @redos.push actions
43
+ update
44
+ end
45
+
46
+ def redo(&block)
47
+ actions = @redos.pop || return
48
+ disable do
49
+ actions.each {|action| block.call action}
50
+ end
51
+ @undos.push actions
52
+ update
53
+ end
54
+
55
+ def enable(state = true)
56
+ return if state == @enabled
57
+ @enabled = state
58
+ @enabled ? enabled : disabled
59
+ end
60
+
61
+ def disable(&block)
62
+ old = enabled?
63
+ enable false
64
+ if block
65
+ begin
66
+ block.call
67
+ ensure
68
+ enable old
69
+ end
70
+ end
71
+ end
72
+
73
+ def can_undo?()
74
+ !@undos.empty?
75
+ end
76
+
77
+ def can_redo?()
78
+ !@redos.empty?
79
+ end
80
+
81
+ def updated(&block)
82
+ @updated = block
83
+ end
84
+
85
+ def enabled?()
86
+ @enabled
87
+ end
88
+
89
+ def disabled?()
90
+ !enabled?
91
+ end
92
+
93
+ def enabled()
94
+ end
95
+
96
+ def disabled()
97
+ end
98
+
99
+ def to_h(&dump_object)
100
+ {
101
+ version: 1,
102
+ undos: self.class.dump(@undos, &dump_object),
103
+ redos: self.class.dump(@redos, &dump_object)
104
+ }
105
+ end
106
+
107
+ def self.load(hash, &restore_object)
108
+ undos = restore hash['undos'], &restore_object
109
+ redos = restore hash['redos'], &restore_object
110
+ self.new undos, redos
111
+ end
112
+
113
+ private
114
+
115
+ def update()
116
+ @updated.call if @updated
117
+ end
118
+
119
+ def self.dump(xdos, &dump_object)
120
+ xdos.map do |actions|
121
+ actions.map do |action, *args|
122
+ [action.to_s, *args.map {|obj| dump_object.call(obj) || obj}]
123
+ end
124
+ end
125
+ end
126
+
127
+ def self.restore(xdos, &restore_object)
128
+ xdos.map do |actions|
129
+ actions.map do |action, *args|
130
+ [action.intern, *args.map {|obj| restore_object.call(obj) || obj}]
131
+ end
132
+ end
133
+ end
134
+
135
+ end# History
data/lib/reight/map.rb ADDED
@@ -0,0 +1,264 @@
1
+ using Reight
2
+
3
+
4
+ class Reight::Map
5
+
6
+ include Enumerable
7
+ include Comparable
8
+
9
+ def initialize(chip_size: 8, chunk_size: 128)
10
+ raise ArgumentError, "Invalid chip_size: #{chip_size}" if
11
+ chip_size.to_i != chip_size
12
+ raise ArgumentError, "Invalid chunk_size: #{chunk_size}" if
13
+ chunk_size.to_i != chunk_size || chunk_size % chip_size != 0
14
+
15
+ @chip_size, @chunk_size = [chip_size, chunk_size].map &:to_i
16
+ @chunks = {}
17
+ end
18
+
19
+ def put(x, y, chip)
20
+ return unless chip
21
+ each_chunk x, y, chip.w, chip.h, create: true do |chunk|
22
+ chunk.put x, y, chip
23
+ end
24
+ end
25
+
26
+ def delete(x, y)
27
+ chip = self[x, y] or return
28
+ cx, cy, cw, ch = chip.then {[_1.pos.x, _1.pos.y, _1.w, _1.h]}
29
+ each_chunk cx, cy, cw, ch, create: false do |chunk|
30
+ each_chip_pos(cx, cy, cw, ch) {|xx, yy| chunk.delete xx, yy}
31
+ end
32
+ end
33
+
34
+ def delete_chip(chip)
35
+ delete chip.pos.x, chip.pos.y
36
+ end
37
+
38
+ def each_chip(x = nil, y = nil, w = nil, h = nil, clip_by_chunk: false, &block)
39
+ return enum_for :each_chip, x, y, w, h, clip_by_chunk: clip_by_chunk unless block
40
+ enum =
41
+ case [x, y, w, h]
42
+ in [nil, nil, nil, nil] then @chunks.values.each
43
+ in [Numeric, Numeric, Numeric, Numeric] then each_chunk x, y, w, h
44
+ else raise ArgumentError, "Invalid bounds"
45
+ end
46
+ x = y = w = h = nil if clip_by_chunk
47
+ enum.each do |chunk|
48
+ chunk.each_chip(x, y, w, h) {|chip, _, _| block.call chip}
49
+ end
50
+ end
51
+
52
+ def each(&block) = each_chip(&block)
53
+
54
+ def to_hash()
55
+ {
56
+ chip_size: @chip_size, chunk_size: @chunk_size,
57
+ chunks: @chunks.values.map(&:to_hash)
58
+ }
59
+ end
60
+
61
+ def [](x, y)
62
+ chunk_at(x, y)&.[](x, y)
63
+ end
64
+
65
+ def <=>(o)
66
+ a = [@chip_size, @chunk_size, @chunks]
67
+ b = o.instance_eval {[@chip_size, @chunk_size, @chunks]}
68
+ a <=> b
69
+ end
70
+
71
+ def self.restore(hash, source_chips)
72
+ hash => {chip_size:, chunk_size:, chunks:}
73
+ new(chip_size: chip_size, chunk_size: chunk_size).tap do |obj|
74
+ obj.instance_eval do
75
+ @chunks = chunks.each.with_object({}) do |chunk_hash, result|
76
+ chunk_hash => {x:, y:}
77
+ result[[x, y]] = Chunk.restore chunk_hash, source_chips
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def each_chunk(x, y, w = 0, h = 0, create: false, &block)
86
+ return enum_for :each_chunk, x, y, w, h, create: create unless block
87
+ x, w = x + w, -w if w < 0
88
+ y, h = y + h, -h if h < 0
89
+ x1, x2 = x, x + w
90
+ y1, y2 = y, y + h
91
+ x2 -= 1 if x2 > x1
92
+ y2 -= 1 if y2 > y1
93
+ x1, y1 = align_chunk_pos x1, y1
94
+ x2, y2 = align_chunk_pos x2, y2
95
+ (y1..y2).step @chunk_size do |yy|
96
+ (x1..x2).step @chunk_size do |xx|
97
+ chunk = chunk_at xx, yy, create: create
98
+ block.call chunk if chunk
99
+ end
100
+ end
101
+ end
102
+
103
+ def chunk_at(x, y, create: false)
104
+ x, y = align_chunk_pos x, y
105
+ if create
106
+ @chunks[[x, y]] ||=
107
+ Chunk.new x, y, @chunk_size, @chunk_size, chip_size: @chip_size
108
+ else
109
+ @chunks[[x, y]]
110
+ end
111
+ end
112
+
113
+ def each_chip_pos(x, y, w, h, &block)
114
+ x, w = x + w, -w if w < 0
115
+ y, h = y + h, -h if h < 0
116
+ x1, y1 = align_chip_pos x, y
117
+ x2, y2 = align_chip_pos x + w + @chip_size - 1, y + h + @chip_size - 1
118
+ (y1...y2).step @chip_size do |yy|
119
+ (x1...x2).step @chip_size do |xx|
120
+ block.call xx, yy
121
+ end
122
+ end
123
+ end
124
+
125
+ def align_chunk_pos(x, y)
126
+ s = @chunk_size
127
+ [x.to_i / s * s, y.to_i / s * s]
128
+ end
129
+
130
+ def align_chip_pos(x, y)
131
+ s = @chip_size
132
+ [x.to_i / s * s, y.to_i / s * s]
133
+ end
134
+
135
+ end# Map
136
+
137
+
138
+ class Reight::Map::Chunk
139
+
140
+ include Comparable
141
+
142
+ def initialize(x, y, w, h, chip_size: 8)
143
+ raise ArgumentError, "Invalid chip_size: #{chip_size}" if chip_size.to_i != chip_size
144
+ raise ArgumentError, "Invalid w: #{w}" if w % chip_size != 0
145
+ raise ArgumentError, "Invalid h: #{h}" if h % chip_size != 0
146
+
147
+ @x, @y, @w, @h, @chip_size = [x, y, w, h, chip_size].map &:to_i
148
+ @chips, @ncolumn = [], @w / @chip_size
149
+ end
150
+
151
+ attr_reader :x, :y, :w, :h
152
+
153
+ def put(x, y, chip)
154
+ x, y = align_chip_pos x, y
155
+ raise "Invalid chip size" if
156
+ chip.w % @chip_size != 0 || chip.h % @chip_size != 0
157
+ raise "Conflicts with other chips" if
158
+ each_chip_pos(x, y, chip.w, chip.h).any? {|xx, yy| self[xx, yy]}
159
+
160
+ new_chip = nil
161
+ get_chip = -> {new_chip ||= chip.with pos: create_vector(x, y)}
162
+ each_chip_pos x, y, chip.w, chip.h do |xx, yy|
163
+ @chips[pos2index xx, yy] = get_chip.call
164
+ end
165
+ end
166
+
167
+ def delete(x, y)
168
+ chip = self[x, y] or return
169
+ each_chip_pos chip.pos.x, chip.pos.y, chip.w, chip.h do |xx, yy|
170
+ index = pos2index xx, yy
171
+ @chips[index] = nil if @chips[index]&.id == chip.id
172
+ end
173
+ delete_last_nils
174
+ end
175
+
176
+ def each_chip(x = nil, y = nil, w = nil, h = nil, include_hidden: false, &block)
177
+ return enum_for(:each_chip, x, y, w, h, include_hidden: include_hidden) unless block
178
+ x, w = x + w, -w if x && w && w < 0
179
+ y, h = y + h, -h if y && h && h < 0
180
+ @chips.each.with_index do |chip, index|
181
+ next unless chip
182
+ xx, yy = index2pos index
183
+ pos = chip.pos
184
+ next if x && !intersect?(x, y, w, h, pos.x, pos.y, chip.w, chip.h)
185
+ block.call chip, xx, yy if include_hidden || (xx == pos.x && yy == pos.y)
186
+ end
187
+ end
188
+
189
+ def each_chip_pos(x, y, w, h, &block)
190
+ return enum_for :each_chip_pos, x, y, w, h unless block
191
+ x, w = x + w, -w if w < 0
192
+ y, h = y + h, -h if h < 0
193
+ x1, y1 = align_chip_pos x, y
194
+ x2, y2 = align_chip_pos x + w + @chip_size - 1, y + h + @chip_size - 1
195
+ x1, x2 = [x1, x2].map {_1.clamp @x, @x + @w}
196
+ y1, y2 = [y1, y2].map {_1.clamp @y, @y + @h}
197
+ (y1...y2).step @chip_size do |yy|
198
+ (x1...x2).step @chip_size do |xx|
199
+ block.call xx, yy
200
+ end
201
+ end
202
+ end
203
+
204
+ def frame = [@x, @y, @w, @h]
205
+
206
+ def to_hash()
207
+ {
208
+ x: @x, y: @y, w: @w, h: @h, chip_size: @chip_size,
209
+ chips: @chips.map {|chip| chip ? [chip.id, chip.pos.x, chip.pos.y] : nil}
210
+ }
211
+ end
212
+
213
+ def [](x, y)
214
+ index = pos2index x, y
215
+ return nil if index < 0 || (@w * @h) <= index
216
+ @chips[index]
217
+ end
218
+
219
+ def <=>(o)
220
+ a = [@x, @y, @w, @h, @chip_size, @chips]
221
+ b = o.instance_eval {[@x, @y, @w, @h, @chip_size, @chips]}
222
+ a <=> b
223
+ end
224
+
225
+ def self.restore(hash, source_chips)
226
+ hash => {x:, y:, w:, h:, chip_size: chip_size, chips: chip_ids}
227
+ tmp_chips = {}
228
+ get_chip = -> id, x, y {
229
+ tmp_chips[[id, x, y]] ||= source_chips[id].with(pos: create_vector(x, y))
230
+ }
231
+ new(x, y, w, h, chip_size: chip_size).tap do |obj|
232
+ obj.instance_eval do
233
+ @chips = chip_ids.map {|id, x, y| id ? get_chip.call(id, x, y) : nil}
234
+ end
235
+ end
236
+ end
237
+
238
+ private
239
+
240
+ def pos2index(x, y) =
241
+ (y.to_i - @y) / @chip_size * @ncolumn + (x.to_i - @x) / @chip_size
242
+
243
+ def index2pos(index) = [
244
+ @x + (index % @ncolumn) * @chip_size,
245
+ @y + (index / @ncolumn) * @chip_size
246
+ ]
247
+
248
+ def align_chip_pos(x, y)
249
+ s = @chip_size
250
+ [x.to_i / s * s, y.to_i / s * s]
251
+ end
252
+
253
+ def delete_last_nils()
254
+ last = @chips.rindex {_1 != nil}
255
+ @chips = @chips[..last] if last
256
+ end
257
+
258
+ def intersect?(ax, ay, aw, ah, bx, by, bw, bh)
259
+ ax2, ay2 = ax + aw, ay + ah
260
+ bx2, by2 = bx + bw, by + bh
261
+ ax < bx2 && bx < ax2 && ay < by2 && by < ay2
262
+ end
263
+
264
+ end# Chunk