bomp 1.0.5 → 1.0.5.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 849824a0e41a0e0cb75915a9f509c877d1f9040a9cfc371ba17419d82204ce66
4
- data.tar.gz: 0d45d271ea0ee59e11f9002f73eaafda275c2adaa89bded010bf777d4850fb43
3
+ metadata.gz: 06a8f25bf7a4ca659cf83abf8fba9cf4bb305ba64bef872964aa6fbbb8ce6ba7
4
+ data.tar.gz: 98290ff5312e27ceaae2347085c6b5b502e2cea716f3854a7a9782694a5aff15
5
5
  SHA512:
6
- metadata.gz: b73a18265721e05347a5cf30ea5d3d6ce88c460ca2ad4d5c80005cd2c9bcfb954498190d7131db2263fa61b705ae14a4b5203c4cd84de0fa3fb595038284b47d
7
- data.tar.gz: 5d2785ed6bd8a46f66713e2db01523c20741e33212ddc1518406385296729153830a8a0af173b3e659b56088caa426e4b72cd6f509df22490f292f34d50cd39f
6
+ metadata.gz: 3cd6bb90cd3d9d16662ebbc3eb1b05d62ae5bdf5f22826eedec0365c0032c8a3775ad00775cbaa788f7f3c736d39fad31c65d87838af1693c2f60e3dc113c96d
7
+ data.tar.gz: 584778eca57105a264de6331bcfefc36bf9203c707b892a7f5c71d966d6c6530672bcbde2bf4a7952c5d1d544955d51204e1f2a0dd5e006105af28b4ddf01c2f
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 SealtielFreak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # bomp.rb
2
+
3
+ ![Ruby](https://img.shields.io/badge/Ruby-CC342D?logo=ruby)
4
+ ![Gem Version](https://img.shields.io/gem/v/bomp)
5
+ ![Gem Downloads (for latest version)](https://img.shields.io/gem/dtv/bomp)
6
+ ![Gem download rank](https://img.shields.io/gem/rt/bomp)
7
+
8
+ A collision detection library for Ruby, works in [Ruby2D](https://github.com/ruby2d/ruby2d), [Gosu](https://github.com/gosu/gosu) and [Tic-80](https://github.com/nesbox/TIC-80)
9
+
10
+ ## Introduction
11
+
12
+ A collision detection library for Ruby that makes it easy to detect collisions between 2D objects in your game or application. The library implements two popular collision detection algorithms AABB and SAT.
13
+
14
+ ## Installation
15
+
16
+ Ensure you have the latest versions of [Ruby](https://www.ruby-lang.org/) and [Gem](https://rubygems.org/pages/download) installed on your system to work with containerization.
17
+
18
+ ### Initial Setup
19
+
20
+ 1. **Clone the Repository**:
21
+ ```
22
+ git clone https://github.com/sealtielfreak/bomp.rb.git
23
+ cd bomp.rb
24
+ ```
25
+ 2. **Install Gemfile**:
26
+ - Follow the instructions at [Install gems](https://www.bacancytechnology.com/blog/install-ruby-gems).
27
+
28
+ ## Contributing
29
+
30
+ Contributions are what make the open-source community an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
31
+
32
+ ### Setting Up Your Development Environment
33
+
34
+ Before you start contributing, it's important to set up your development environment. This includes installing necessary tools and configuring pre-commit hooks to ensure code quality.
35
+
36
+ #### Pre-Commit Hooks
37
+
38
+ To maintain code quality and consistency, we use pre-commit hooks. Follow these steps to set up pre-commit hooks in your local development environment:
39
+
40
+ 1. **Install Pre-Commit**:
41
+ - Ensure you have Python installed on your system.
42
+ - Install pre-commit globally using pip:
43
+ ```
44
+ pip install pre-commit
45
+ ```
46
+
47
+ 2. **Clone the Repository** (if not already done):
48
+ ```
49
+ git clone https://github.com/sealtielfreak/bomp.rb.git
50
+ cd bomp.rb
51
+ ```
52
+
53
+ 3. **Set Up Pre-Commit Hooks**:
54
+ - In the root directory of the cloned repository, run:
55
+ ```
56
+ pre-commit install
57
+ ```
58
+ - The hook repository must have a `*.gemspec`. It will be installed via gem build `*.gemspec && gem install *.gem`. The installed package will produce an executable that will match the entry.
59
+
60
+ 4. **Usage**:
61
+ - Pre-commit hooks will now run automatically on the files you've staged whenever you commit.
62
+ - You can manually run the hooks on all files in the repository at any time with:
63
+ ```
64
+ pre-commit run --all-files
65
+ ```
66
+
67
+ ### Creating a Pull Request with your changes
68
+
69
+ Now that you have done some changes and want to merge them in our repository, feel free to:
70
+
71
+ 1. Create your Feature Branch (`git checkout -b feature/amazing_feature`)
72
+ 2. Commit your Changes (`git commit -m "Add some AmazingFeature"`)
73
+ 3. Push to the Branch (`git push origin feature/amazing_feature`)
74
+ 4. Open a Pull Request
data/bomp.gemspec ADDED
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bomp'
3
+ s.version = '1.0.5.1'
4
+ s.summary = 'A collision detection library for Ruby'
5
+ s.description = "Ruby collision-detection library for axis-aligned rectangles, inspired by 'bump.lua' but using native Ruby capabilities"
6
+ s.authors = 'SealtielFreak'
7
+ s.email = 'SealtielFreak@yandex.com'
8
+ s.files = Dir['**/**'].grep_v(/.gem$/)
9
+ s.require_paths = %w[lib sample]
10
+ s.homepage = 'https://github.com/SealtielFreak/bomp.rb'
11
+ s.license = 'MIT'
12
+ s.required_ruby_version = '>= 2.5.0'
13
+ end
data/lib/bomp.rb ADDED
@@ -0,0 +1,399 @@
1
+ require_relative 'vector2'
2
+ require_relative 'rect'
3
+ require_relative 'collision/collision_aabb'
4
+ require_relative 'collision/collision_sat'
5
+ require_relative 'collision/collisions'
6
+
7
+ module Bomp
8
+ class ColliderSystem
9
+ attr_reader :items
10
+
11
+ # Create collision system
12
+ def initialize
13
+ @items = []
14
+ end
15
+
16
+ # @param [Rect] item Add item
17
+ def add(item)
18
+ @items.push item unless @items.include? item
19
+ end
20
+
21
+ # @param [Rect] item Remove item
22
+ def remove(item)
23
+ @items -= [item]
24
+ end
25
+
26
+ # Sort all items
27
+ def sort(group = nil, reload = true)
28
+ raise NotImplementedError.new
29
+ end
30
+
31
+ # Clean
32
+ def clear!
33
+ @items&.clear
34
+ end
35
+
36
+ # Reload
37
+ def reload!
38
+ raise NotImplementedError.new
39
+ end
40
+
41
+ # Restart
42
+ def restart!
43
+ raise NotImplementedError.new
44
+ end
45
+
46
+ # Cast to array
47
+ # @return [Array]
48
+ def to_a
49
+ self.sort
50
+ end
51
+ end
52
+
53
+ class Lineal < ColliderSystem
54
+ # Initialize lineal collision system
55
+ def initialize
56
+ super
57
+ end
58
+
59
+ def sort(group = nil, reload = true)
60
+ [@items]
61
+ end
62
+
63
+ def clear!
64
+ @items&.clear
65
+ end
66
+
67
+ def reload!; end
68
+
69
+ def restart!; end
70
+ end
71
+
72
+ class QuadTree < ColliderSystem
73
+ class QuadNode < Rect
74
+ attr_reader :items
75
+
76
+ def initialize(x, y, w, h, args = {})
77
+ super(Vector2[x, y], Vector2[w, h])
78
+ limit = args[:limit_w] || 64, args[:limit_h] || 64
79
+ @limit_w = (limit[0]).to_f
80
+ @limit_h = (limit[1]).to_f
81
+ @limit = (args[:limit]) || 16
82
+
83
+ @items = []
84
+ @children = []
85
+ end
86
+
87
+ def empty?
88
+ @items.empty?
89
+ end
90
+
91
+ def subdivided?
92
+ !@children.empty?
93
+ end
94
+
95
+ def insert(item)
96
+ return unless CollisionAABB.is_overlaps? self, item
97
+
98
+ subdivided unless subdivided?
99
+ @children.each { |child| child&.insert item }
100
+
101
+ @items << item unless subdivided? && @items.size <= @limit
102
+ end
103
+
104
+ def clear
105
+ @children.each { |child| child&.clear }
106
+ @items.clear
107
+ end
108
+
109
+ def release
110
+ @children.each { |child| child&.release }
111
+ @children.clear
112
+ end
113
+
114
+ def limit_size
115
+ [@limit_w, @limit_h]
116
+ end
117
+
118
+ def limit_size=(limit)
119
+ self.each { |c| c.limit_size = limit }
120
+ end
121
+
122
+ def each(&block)
123
+ @children.each { |c| c&.each(&block) }
124
+ block.call @items.clone unless @items.empty?
125
+ end
126
+
127
+ def each_children(&block)
128
+ @children.each { |c| c&.each_children(&block) }
129
+ block.call self unless @items.empty?
130
+ end
131
+
132
+ def each_children_by(item, &block)
133
+ @children.each { |c| c&.each_children_by(item, &block) }
134
+ block.call self if CollisionAABB.is_overlaps?(self, item) and not @items.empty?
135
+ end
136
+
137
+ def to_a
138
+ items = []
139
+
140
+ self.each { |item| items.push item }
141
+
142
+ items
143
+ end
144
+
145
+ def group_by(item)
146
+ children = []
147
+
148
+ self.each_children_by(item) { |c| children.push c.items }
149
+
150
+ children
151
+ end
152
+
153
+ private
154
+
155
+ def subdivided
156
+ x = self.x
157
+ y = self.y
158
+ w = self.width / 2
159
+ h = self.height / 2
160
+
161
+ return if self.width <= @limit_w || self.height <= @limit_h
162
+
163
+ @children = [
164
+ QuadNode.new(*config_child(x, y, w, h)),
165
+ QuadNode.new(*config_child(x + w, y, w, h)),
166
+ QuadNode.new(*config_child(x, y + h, w, h)),
167
+ QuadNode.new(*config_child(x + w, y + h, w, h))
168
+ ]
169
+ end
170
+
171
+ def config_child(x, y, w, h)
172
+ [x, y, w, h, {
173
+ limit_w: @limit_w, limit_h: @limit_h,
174
+ limit: @limit
175
+ }]
176
+ end
177
+ end
178
+
179
+ attr_reader :child
180
+
181
+ def initialize(width, height, **opts)
182
+ super()
183
+ @opts = opts
184
+ @child = QuadNode.new(0, 0, width, height, @opts)
185
+ end
186
+
187
+ def sort(group = nil, reload = true)
188
+ reload! if reload
189
+
190
+ if group.nil?
191
+ @child.to_a
192
+ else
193
+ @child.group_by group
194
+ end
195
+ end
196
+
197
+ def reload!
198
+ @child&.clear
199
+ @items.each { |item| @child.insert item }
200
+ end
201
+
202
+ def restart!
203
+ clear!
204
+ @child = QuadNode.new(0, 0, width, height, @opts)
205
+ end
206
+ end
207
+
208
+ class CollisionInfo
209
+ attr_reader :item, :other, :goal, :overlaps, :response
210
+
211
+ def initialize(item, other, goal, overlaps, response)
212
+ @item = item
213
+ @other = other
214
+ @goal = goal
215
+ @overlaps = overlaps
216
+ @response = response
217
+ @normal = Vector2[
218
+ goal[0] <=> 0,
219
+ goal[1] <=> 0
220
+ ]
221
+ end
222
+
223
+ def to_s
224
+ [@item, @other, @goal, @overlaps, @response, @normal].to_s
225
+ end
226
+
227
+ def self.[](*args)
228
+ CollisionInfo.new *args
229
+ end
230
+ end
231
+
232
+ class World
233
+ DEFAULT_FILTER = lambda { |a, b| :slide }
234
+
235
+ attr_reader :system_collision, :response
236
+
237
+ # Create world for collisions processing
238
+ # @param width [Integer] The first number
239
+ # @param height [Integer] The second number
240
+ def initialize(width, height, **opts)
241
+ @opts = opts
242
+ @system_collision = @opts[:system] || QuadTree.new(width, height, **opts)
243
+ @response = { 'bounce': lambda { |item, other, goal| CollisionAABB.bounce(item, other, goal) },
244
+ 'cross': lambda { |item, other, goal| CollisionAABB.cross(item, other, goal) },
245
+ 'touch': lambda { |item, other, goal| CollisionAABB.touch(item, other, goal) },
246
+ 'slide': lambda { |item, other, goal| CollisionAABB.slide(item, other, goal) },
247
+ 'push': lambda { |item, other, goal| CollisionAABB.push(item, other, goal) },
248
+ 'nothing': lambda { |item, other, goal| item } }
249
+ end
250
+
251
+ # Add item to world
252
+ # @param [Rect] item Add item to world
253
+ def add(item)
254
+ @system_collision&.add item
255
+ end
256
+
257
+ # Remove item from world
258
+ # @param [Rect] item Remove item from world
259
+ def remove(item)
260
+ @system_collision&.remove item
261
+ end
262
+
263
+ # Select item from world
264
+ # @param [Rect] index Index
265
+ def [](index)
266
+ @system_collision&.items[index]
267
+ end
268
+
269
+ # @param [Integer] index
270
+ # @param [Rect] item
271
+ def []=(index, item)
272
+ @system_collision&.items[index] = item
273
+ end
274
+
275
+ # @return [Array, nil]
276
+ def items
277
+ @system_collision&.items
278
+ end
279
+
280
+ # Cast to array
281
+ # @return [Array]
282
+ def to_a
283
+ @system_collision&.sort || []
284
+ end
285
+
286
+ # Check if item include in world
287
+ # @param [Rect] item Check if include item
288
+ def include?(item)
289
+ items.include? item
290
+ end
291
+
292
+ # At item
293
+ # @param [Rect] item
294
+ def at(item)
295
+ add item unless include? item
296
+ end
297
+
298
+ # Query point
299
+ # @param [Vector2] point
300
+ # @param [Proc] filter
301
+ def query_point(point, &filter)
302
+ _, cols = check Rect[point[0], point[1], 1, 1], &filter
303
+ cols
304
+ end
305
+
306
+ # Query rect
307
+ # @param [Rect] rect
308
+ # @param [Proc] filter
309
+ def query_rect(rect, &filter)
310
+ raise NotImplementedError.new
311
+ end
312
+
313
+ # Query segment
314
+ # @param [Vector2] p0
315
+ # @param [Vector2] p1
316
+ # @param [Proc] filter
317
+ def query_segment(p0, p1, &filter)
318
+ raise NotImplementedError.new
319
+ end
320
+
321
+ # Add response
322
+ # @param [String] name
323
+ def add_response(name, &block)
324
+ @response[name.to_sym] = block
325
+ end
326
+
327
+ # Move item in the world
328
+ # @param [Rect] item
329
+ # @param [Vector2] goal
330
+ # @param [Proc] filter
331
+ # @return [[Rect, Array]]
332
+ def move(item, goal, &filter)
333
+ filter = DEFAULT_FILTER if filter.nil?
334
+ item = self[item] if item.is_a? Integer
335
+ cols = []
336
+
337
+ all_sort_items = @system_collision&.sort
338
+
339
+ [Vector2[goal[0], 0], Vector2[0, goal[1]]].each do |g|
340
+ item.position += g
341
+
342
+ all_sort_items.each do |others|
343
+ next unless others.include? item
344
+
345
+ others -= [item]
346
+ cols += check_and_resolve item, g, others, filter
347
+ end
348
+ end
349
+
350
+ [item, cols]
351
+ end
352
+
353
+ # Check
354
+ # @param [Rect] item
355
+ # @param [Proc] filter
356
+ # @return [[Rect, Array]]
357
+ def check(item, &filter)
358
+ filter = DEFAULT_FILTER if filter.nil?
359
+ item = self[item] if item.is_a? Integer
360
+ cols = []
361
+
362
+ all_sort_items = @system_collision&.sort
363
+
364
+ all_sort_items.each do |others|
365
+ next unless others.include? item
366
+
367
+ others -= [item]
368
+ cols += check_and_resolve item, [0, 0], others, filter
369
+ end
370
+
371
+ [item, cols]
372
+ end
373
+
374
+ # Check and resolve
375
+ # @param [Rect] item
376
+ # @param [Vector2] goal
377
+ # @param [Array] others
378
+ # @param [Object] filter
379
+ # @return [Array]
380
+ private
381
+ def check_and_resolve(item, goal, others, filter)
382
+ cols = []
383
+
384
+ others.each do |other|
385
+ overlaps = CollisionAABB.is_overlaps? item, other
386
+ res = :nothing
387
+
388
+ if overlaps and goal.sum != 0
389
+ res = filter.call(item, other) || :nothing
390
+ @response[res]&.call item, other, goal
391
+ end
392
+
393
+ cols.push CollisionInfo[item, other, goal, overlaps, res]
394
+ end
395
+
396
+ cols
397
+ end
398
+ end
399
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CollisionAABB
4
+ def self.was_horizontal_aligned?(a, b)
5
+ a.left < b.right && a.right > b.left
6
+ end
7
+
8
+ def self.was_vertical_aligned?(a, b)
9
+ a.top < b.bottom && a.bottom > b.top
10
+ end
11
+
12
+ def self.is_overlaps?(a, b)
13
+ was_vertical_aligned?(a, b) && was_horizontal_aligned?(a, b)
14
+ end
15
+
16
+ def self.bounce(item, other, goal) end
17
+
18
+ def self.cross(item, other, goal)
19
+ x, y = goal.to_a
20
+
21
+ if x != 0
22
+ goal.x *= -1
23
+ item.position.x += x
24
+ end
25
+
26
+ if y != 0
27
+ goal.y *= -1
28
+ item.position.y += y
29
+ end
30
+
31
+ item
32
+ end
33
+
34
+ def self.touch(item, other, goal) end
35
+
36
+ def self.slide(item, other, goal)
37
+ x, y = goal.to_a
38
+
39
+ if x != 0
40
+ item.position.x += x
41
+ if x > 0
42
+ item.right = other.left
43
+ elsif x < 0
44
+ item.left = other.right
45
+ end
46
+ end
47
+
48
+ if y != 0
49
+ item.position.y += y
50
+ if y > 0
51
+ item.bottom = other.top
52
+ elsif y < 0
53
+ item.top = other.bottom
54
+ end
55
+ end
56
+
57
+ item
58
+ end
59
+
60
+ def self.push(item, other, goal)
61
+ x, y = goal.to_a
62
+
63
+ if x != 0
64
+ if x > 0
65
+ other.right = item.left
66
+ elsif x < 0
67
+ other.left = item.right
68
+ end
69
+ end
70
+
71
+ if y != 0
72
+ if y > 0
73
+ other.bottom = item.top
74
+ elsif y < 0
75
+ other.top = item.bottom
76
+ end
77
+ end
78
+
79
+ item
80
+ end
81
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CollisionSAT
4
+ def self.is_overlaps?(a, b)
5
+ raise NotImplementedError.new
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Collisions
4
+ def self.is_overlaps?(a, b)
5
+ raise NotImplementedError.new
6
+ end
7
+ end
data/lib/rect.rb ADDED
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Rect
4
+ attr_accessor :position, :size
5
+
6
+ def initialize(pos, size)
7
+ @position = Vector2[*pos]
8
+ @size = Vector2[*size]
9
+ end
10
+
11
+ def x
12
+ @position.x
13
+ end
14
+
15
+ def y
16
+ @position.y
17
+ end
18
+
19
+ def width
20
+ @size.x
21
+ end
22
+
23
+ def width=(value)
24
+ @size.x = value
25
+ end
26
+
27
+ def height
28
+ @size.y
29
+ end
30
+
31
+ def height=(value)
32
+ @size.y = value
33
+ end
34
+
35
+ def top
36
+ @position.y
37
+ end
38
+
39
+ def top=(value)
40
+ @position.y = value
41
+ end
42
+
43
+ def bottom
44
+ @position.y + height
45
+ end
46
+
47
+ def bottom=(value)
48
+ @position.y += value - self.bottom
49
+ end
50
+
51
+ def left
52
+ @position.x
53
+ end
54
+
55
+ def left=(value)
56
+ @position.x = value
57
+ end
58
+
59
+ def right
60
+ @position.x + width
61
+ end
62
+
63
+ def right=(value)
64
+ @position.x += value - self.right
65
+ end
66
+
67
+ def to_s
68
+ self.to_a.to_s
69
+ end
70
+
71
+ def clone
72
+ Rect.new([@position.x, @position.y], [@size.x, @size.y])
73
+ end
74
+
75
+ def to_a
76
+ [@position.x, @position.y, @size.x, @size.y]
77
+ end
78
+
79
+ def self.[](x, y, w, h)
80
+ Rect.new([x, y], [w, h])
81
+ end
82
+ end
data/lib/vector2.rb ADDED
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Vector2
4
+ attr_accessor :x, :y
5
+
6
+ def initialize(x, y)
7
+ @x = x
8
+ @y = y
9
+ end
10
+
11
+ def +(other)
12
+ Vector2[@x + other[0], @y + other[1]]
13
+ end
14
+
15
+ def -(other)
16
+ Vector2[@x - other[0], @y - other[1]]
17
+ end
18
+
19
+ def *(scalar)
20
+ Vector2[@x * scalar, @y * scalar]
21
+ end
22
+
23
+ def /(scalar)
24
+ Vector2[@x / scalar, @y / scalar]
25
+ end
26
+
27
+ def ==(other)
28
+ @x == other[0] && @y == other[1]
29
+ end
30
+
31
+ def [](index)
32
+ case index
33
+ when 0 then @x
34
+ when 1 then @y
35
+ else nil
36
+ end
37
+ end
38
+
39
+ def []=(index, value)
40
+ case index
41
+ when 0 then @x = value
42
+ when 1 then @y = value
43
+ end
44
+ end
45
+
46
+ def to_s
47
+ self.to_a.to_s
48
+ end
49
+
50
+ def to_a
51
+ [@x, @y]
52
+ end
53
+
54
+ def sum
55
+ @x + @y
56
+ end
57
+
58
+ def self.[](x, y)
59
+ Vector2.new(x, y)
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/bomp'
4
+
5
+ include Bomp
6
+
7
+ world = World.new 640, 480
8
+
9
+ world.add(Rect[0, 0, 10, 10])
10
+ world.add(Rect[2, 3, 10, 10])
11
+ world.add(Rect[300, 300, 10, 10])
12
+
13
+ puts 'Current position: ' + world[0].position.to_s
14
+ cols = world.move(0, Vector2[3, -1]) do |item, other|
15
+ puts 'Other collision is ' + other.to_s
16
+ :push
17
+ end
18
+
19
+ puts 'Current position: ' + world[0].position.to_s
20
+
21
+ cols.each do |col|
22
+ puts 'Collision: ' + col.to_s
23
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby2d'
4
+
5
+ require_relative '../lib/bomp'
6
+ include Bomp
7
+
8
+
9
+ def normalize(vec)
10
+ x, y = vec.to_a
11
+
12
+ length = Math.sqrt(x ** 2 + y ** 2)
13
+
14
+ [x / length, y / length]
15
+ end
16
+
17
+ class MyRect < Rectangle
18
+ attr_reader :world, :rect
19
+
20
+ def initialize(world, **opts)
21
+ super **opts
22
+
23
+ @world = world
24
+ @rect = Rect.new Vector2[0, 0], Vector2[opts[:width] || 0, opts[:height] || 0]
25
+
26
+ @world.add rect
27
+ end
28
+
29
+ def position
30
+ [@rect.left, @rect.top]
31
+ end
32
+
33
+ def position=(pos)
34
+ x, y = pos.to_a
35
+
36
+ self.x = x
37
+ self.y = y
38
+
39
+ @rect.left = x
40
+ @rect.top = y
41
+ end
42
+
43
+ def size=(size)
44
+ w, h = size.to_a
45
+ self.width = w
46
+ self.height = h
47
+ @rect.width = w
48
+ @rect.height = h
49
+ end
50
+
51
+ def move(goal)
52
+ rect, col = @world.move @rect, normalize(goal)
53
+
54
+ @rect = rect
55
+ self.x = @rect.x
56
+ self.y = @rect.y
57
+ self.width = @rect.width
58
+ self.height = @rect.height
59
+
60
+ col
61
+ end
62
+ end
63
+
64
+ @world = World.new 640, 480
65
+
66
+ @player = MyRect.new @world, color: 'red', width: 3, height: 3
67
+ @walls = Array.new(5) { MyRect.new @world, color: 'random' }.map do |o|
68
+ o.position = [rand(0..640), rand(0..480)]
69
+ o.size = [rand(5...25), rand(5...25)]
70
+ end
71
+
72
+ on :key_held do |event|
73
+ goal = Vector2[0, 0]
74
+
75
+ case event.key
76
+ when 'w'
77
+ goal.y -= 5
78
+ when 's'
79
+ goal.y += 5
80
+ when 'a'
81
+ goal.x -= 5
82
+ when 'd'
83
+ goal.x += 5
84
+ end
85
+
86
+ @player.move goal
87
+ end
88
+
89
+ show
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bomp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SealtielFreak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-23 00:00:00.000000000 Z
11
+ date: 2024-03-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby collision-detection library for axis-aligned rectangles, inspired
14
14
  by 'bump.lua' but using native Ruby capabilities
@@ -16,7 +16,18 @@ email: SealtielFreak@yandex.com
16
16
  executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
- files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - bomp.gemspec
23
+ - lib/bomp.rb
24
+ - lib/collision/collision_aabb.rb
25
+ - lib/collision/collision_sat.rb
26
+ - lib/collision/collisions.rb
27
+ - lib/rect.rb
28
+ - lib/vector2.rb
29
+ - sample/hello_world.rb
30
+ - sample/sample_ruby2d.rb
20
31
  homepage: https://github.com/SealtielFreak/bomp.rb
21
32
  licenses:
22
33
  - MIT
@@ -25,6 +36,7 @@ post_install_message:
25
36
  rdoc_options: []
26
37
  require_paths:
27
38
  - lib
39
+ - sample
28
40
  required_ruby_version: !ruby/object:Gem::Requirement
29
41
  requirements:
30
42
  - - ">="