rubysketch 0.9.5 → 0.10.0
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 +4 -4
- data/.github/workflows/release-gem.yml +10 -1
- data/.github/workflows/test.yml +9 -0
- data/ChangeLog.md +13 -0
- data/VERSION +1 -1
- data/bin/rubysketch +8 -4
- data/examples/constraint.rb +89 -0
- data/lib/rubysketch/all.rb +2 -0
- data/lib/rubysketch/constraint.rb +422 -0
- data/lib/rubysketch/context.rb +17 -9
- data/lib/rubysketch/extension.rb +1 -1
- data/lib/rubysketch/helper.rb +10 -0
- data/lib/rubysketch/pin.rb +108 -0
- data/lib/rubysketch/shape.rb +1 -1
- data/lib/rubysketch/sprite.rb +442 -48
- data/pod.rake +1 -1
- data/rubysketch.gemspec +7 -7
- data/test/helper.rb +23 -0
- data/test/test_constraint.rb +230 -0
- data/test/test_context.rb +55 -18
- data/test/test_sprite.rb +2 -8
- data/test/test_sprite_world.rb +66 -0
- metadata +23 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4f8d3591f90ee825cf8f8c1d6379c7841d7a03e90c211fdb5be0ba378514e74
|
|
4
|
+
data.tar.gz: c82032ec68d87488fcf2036177ebd6aea6168e91c3d6e6de7508af17a0c9daf9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c3e94f02d383ff622f082058e8146dbf1b913e26b902f94c7a4dc6d46b95d3ab743a5b638cc48d50d13237689650d7e4db3a3312466bad7044ed76cd17af99a
|
|
7
|
+
data.tar.gz: ae869f7c81595a77724f02410b65eb5f638ccfaa77184572b5ad13ca990ea9a33fd256f240af578a1b06c4846fc72faa1e320e1b58df959090b8a98bb34d9958
|
|
@@ -26,8 +26,17 @@ jobs:
|
|
|
26
26
|
- name: setup dependencies
|
|
27
27
|
run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
|
|
28
28
|
|
|
29
|
+
- name: packages
|
|
30
|
+
run: bundle exec rake packages
|
|
31
|
+
|
|
32
|
+
- name: setup zig
|
|
33
|
+
if: github.event.repository.name == 'reflex-terminal'
|
|
34
|
+
uses: mlugg/setup-zig@v2
|
|
35
|
+
with:
|
|
36
|
+
version: 0.16.0
|
|
37
|
+
|
|
29
38
|
- name: test
|
|
30
|
-
run: bundle exec rake
|
|
39
|
+
run: bundle exec rake test
|
|
31
40
|
|
|
32
41
|
- name: create gem
|
|
33
42
|
id: gem
|
data/.github/workflows/test.yml
CHANGED
|
@@ -27,6 +27,15 @@ jobs:
|
|
|
27
27
|
- name: packages
|
|
28
28
|
run: bundle exec rake verbose packages
|
|
29
29
|
|
|
30
|
+
- name: setup zig
|
|
31
|
+
if: github.event.repository.name == 'reflex-terminal'
|
|
32
|
+
uses: mlugg/setup-zig@v2
|
|
33
|
+
with:
|
|
34
|
+
version: 0.16.0
|
|
35
|
+
|
|
36
|
+
- name: vendor
|
|
37
|
+
run: bundle exec rake vendor
|
|
38
|
+
|
|
30
39
|
- name: lib
|
|
31
40
|
run: bundle exec rake verbose lib
|
|
32
41
|
|
data/ChangeLog.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# rubysketch ChangeLog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [v0.10.0] - 2026-08-04
|
|
5
|
+
|
|
6
|
+
- [BREAKING] Remove the context: parameter from Sprite.new and SpriteWorld#createSprite
|
|
7
|
+
- Add constraint mechanism backed by Reflex constraints
|
|
8
|
+
- Add mouseOver/mouseOut blocks to Sprite, and Sprite#mouseOver to read the state
|
|
9
|
+
- Add sprite(world) support to draw all sprites in a world
|
|
10
|
+
- Add position/size methods to SpriteWorld
|
|
11
|
+
- Deprecate addSprite/removeSprite array params in favor of to:/from: keywords
|
|
12
|
+
- Reject adding a sprite to two worlds, or removing it from another world
|
|
13
|
+
|
|
14
|
+
- Fix SpriteWorld#oy=
|
|
15
|
+
|
|
16
|
+
|
|
4
17
|
## [v0.9.5] - 2026-06-23
|
|
5
18
|
|
|
6
19
|
- Add packager support with bin/rubysketch CLI
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.10.0
|
data/bin/rubysketch
CHANGED
|
@@ -11,7 +11,7 @@ profile = Reflex::Packager::Profile.new(
|
|
|
11
11
|
libraries: %w[Xot Rucy Beeps Rays Reflex Processing RubySketch],
|
|
12
12
|
extensions: %w[beeps_ext rays_ext reflex_ext],
|
|
13
13
|
config_files: %w[rubysketch.yml rubysketch.yaml],
|
|
14
|
-
|
|
14
|
+
templates: {'main.rb': <<~MAIN, 'rubysketch.yml': <<~CONFIG})
|
|
15
15
|
require 'rubysketch'
|
|
16
16
|
using RubySketch
|
|
17
17
|
|
|
@@ -21,9 +21,13 @@ profile = Reflex::Packager::Profile.new(
|
|
|
21
21
|
|
|
22
22
|
draw do
|
|
23
23
|
background 100
|
|
24
|
-
|
|
25
|
-
ellipse width / 2, height / 2, 100, 100
|
|
24
|
+
text 'hello, world!', 100, 100
|
|
26
25
|
end
|
|
27
|
-
|
|
26
|
+
MAIN
|
|
27
|
+
name: {{name}}
|
|
28
|
+
version: 1.0.0
|
|
29
|
+
#bundle_id: org.xord.rubysketch.example.{{name_id}}
|
|
30
|
+
#icon: icon.png
|
|
31
|
+
CONFIG
|
|
28
32
|
|
|
29
33
|
Reflex::Packager::CLI.new(profile).run ARGV.dup
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
%w[xot rucy beeps rays reflex processing rubysketch]
|
|
2
|
+
.map {|s| File.expand_path "../../#{s}/lib", __dir__}
|
|
3
|
+
.each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
|
|
4
|
+
|
|
5
|
+
require 'rubysketch'
|
|
6
|
+
using RubySketch
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def setup()
|
|
10
|
+
noStroke
|
|
11
|
+
gravity 0, 1000
|
|
12
|
+
|
|
13
|
+
$statics = [
|
|
14
|
+
createSprite(0, height - 10, width, 10),
|
|
15
|
+
createSprite(0, 0, 10, height),
|
|
16
|
+
createSprite(width - 10, 0, 10, height)
|
|
17
|
+
]
|
|
18
|
+
walls = $statics[1..]
|
|
19
|
+
$balls = []
|
|
20
|
+
|
|
21
|
+
# pendulum: snap the hanging ball to the anchor
|
|
22
|
+
pivot = anchor 100, 100
|
|
23
|
+
weight = ball 170, 100, 30
|
|
24
|
+
pivot.snap weight
|
|
25
|
+
|
|
26
|
+
# motored arm: half a turn per second
|
|
27
|
+
hinge = anchor 250, 100
|
|
28
|
+
arm = ball 250, 140, 20
|
|
29
|
+
hinge.snap arm, motor: PI
|
|
30
|
+
|
|
31
|
+
# spring chain: balls linked with springs
|
|
32
|
+
prev = anchor 400, 60
|
|
33
|
+
4.times do |i|
|
|
34
|
+
node = ball 400, 100 + i * 40, 20
|
|
35
|
+
node.link prev, spring: 4, damping: 0.5, collide: true
|
|
36
|
+
prev = node
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# car: each tire rides on the body with a wheel constraint -- a vertical
|
|
40
|
+
# suspension spring and a drive motor, reversed whenever the body bumps
|
|
41
|
+
# into a wall
|
|
42
|
+
body = createSprite 60, height - 80, 60, 14
|
|
43
|
+
body.dynamic = true
|
|
44
|
+
axles = [10, 50].map do |x|
|
|
45
|
+
tire = ball 50 + x, height - 60, 18
|
|
46
|
+
tire.pin(9, 9).wheel body.pin(x, 12),
|
|
47
|
+
axis: [0, 1], spring: 6, damping: 0.7, motor: TWO_PI
|
|
48
|
+
end
|
|
49
|
+
body.contact do |o|
|
|
50
|
+
axles.each {|a| a.motor = -a.motor} if walls.include?(o)
|
|
51
|
+
end
|
|
52
|
+
$car = body
|
|
53
|
+
|
|
54
|
+
# chaser: follows the mouse pointer with a soft spring
|
|
55
|
+
chaser = ball 100, 300, 24
|
|
56
|
+
chaser.gravityScale = 0
|
|
57
|
+
chaser.sensor = true # do not bump the pendulum
|
|
58
|
+
$chase = chaser.chase [100, 300], spring: 2, damping: 0.7
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def draw()
|
|
62
|
+
background 0
|
|
63
|
+
|
|
64
|
+
$chase.target = [mouseX, mouseY]
|
|
65
|
+
|
|
66
|
+
fill 200
|
|
67
|
+
sprite *$statics
|
|
68
|
+
fill 240, 240, 240
|
|
69
|
+
sprite $car
|
|
70
|
+
fill 150, 240, 150
|
|
71
|
+
sprite *$balls
|
|
72
|
+
|
|
73
|
+
textSize 16
|
|
74
|
+
fill 255, 200, 150
|
|
75
|
+
text "#{frameRate.to_i} FPS - the ball chases the mouse pointer", 20, 30
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def ball(x, y, size)
|
|
79
|
+
sp = createSprite x, y, shape: Circle.new(0, 0, size)
|
|
80
|
+
sp.dynamic = true
|
|
81
|
+
$balls << sp
|
|
82
|
+
sp
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def anchor(x, y)
|
|
86
|
+
sp = createSprite x, y, 10, 10 # static by default
|
|
87
|
+
$statics << sp
|
|
88
|
+
sp
|
|
89
|
+
end
|
data/lib/rubysketch/all.rb
CHANGED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
module RubySketch
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# Constrains the motion of sprites.
|
|
5
|
+
# Constraints are created with Sprite#snap, #link, #wheel and #chase
|
|
6
|
+
# (or the same verbs on Sprite#pin), not with new.
|
|
7
|
+
#
|
|
8
|
+
class Constraint
|
|
9
|
+
|
|
10
|
+
include Xot::Setter
|
|
11
|
+
|
|
12
|
+
# @private
|
|
13
|
+
def initialize(constraint)
|
|
14
|
+
@constraint__ = constraint
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Removes the constraint permanently.
|
|
18
|
+
#
|
|
19
|
+
# @return [Constraint] self
|
|
20
|
+
#
|
|
21
|
+
def remove()
|
|
22
|
+
@constraint__.remove
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Sets the spring stiffness in hertz.
|
|
27
|
+
#
|
|
28
|
+
# @param [Numeric, nil] hertz stiffness, or nil to make it rigid
|
|
29
|
+
#
|
|
30
|
+
# @return [Numeric, nil] hertz
|
|
31
|
+
#
|
|
32
|
+
def spring=(hertz)
|
|
33
|
+
@constraint__.spring = hertz
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the spring stiffness in hertz.
|
|
37
|
+
#
|
|
38
|
+
# @return [Numeric, nil] hertz, or nil if the constraint is rigid
|
|
39
|
+
#
|
|
40
|
+
def spring()
|
|
41
|
+
@constraint__.spring
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Sets the spring damping ratio.
|
|
45
|
+
#
|
|
46
|
+
# @param [Numeric] ratio 0 (no damping) to 1 (critical damping)
|
|
47
|
+
#
|
|
48
|
+
# @return [Numeric] damping ratio
|
|
49
|
+
#
|
|
50
|
+
def damping=(ratio)
|
|
51
|
+
@constraint__.damping = ratio
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Returns the spring damping ratio.
|
|
55
|
+
#
|
|
56
|
+
# @return [Numeric] damping ratio
|
|
57
|
+
#
|
|
58
|
+
def damping()
|
|
59
|
+
@constraint__.damping
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Sets whether the constrained sprites collide with each other.
|
|
63
|
+
#
|
|
64
|
+
# @param [Boolean] bool collide or not
|
|
65
|
+
#
|
|
66
|
+
# @return [Boolean] collide or not
|
|
67
|
+
#
|
|
68
|
+
def collide=(bool)
|
|
69
|
+
@constraint__.collide = bool
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns whether the constrained sprites collide with each other.
|
|
73
|
+
#
|
|
74
|
+
# @return [Boolean] collide or not
|
|
75
|
+
#
|
|
76
|
+
def collide?()
|
|
77
|
+
@constraint__.collide?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Sets the maximum force (or torque) that drives the constraint.
|
|
81
|
+
#
|
|
82
|
+
# @param [Numeric, nil] force
|
|
83
|
+
# maximum force, or nil for the default strength.
|
|
84
|
+
# 0 makes the drive powerless
|
|
85
|
+
#
|
|
86
|
+
# @return [Numeric, nil] force
|
|
87
|
+
#
|
|
88
|
+
def force=(force)
|
|
89
|
+
@constraint__.force = force
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns the maximum force that drives the constraint.
|
|
93
|
+
#
|
|
94
|
+
# @return [Numeric, nil] force, or nil for the default strength
|
|
95
|
+
#
|
|
96
|
+
def force()
|
|
97
|
+
@constraint__.force
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
universal_accessor :spring, :damping, :force, collide: {reader: :collide?}
|
|
101
|
+
|
|
102
|
+
# Returns whether the constraint is active in a physics world.
|
|
103
|
+
#
|
|
104
|
+
# @return [Boolean] active or not
|
|
105
|
+
#
|
|
106
|
+
def active?()
|
|
107
|
+
@constraint__.active?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Returns whether the constraint was removed.
|
|
111
|
+
#
|
|
112
|
+
# @return [Boolean] removed or not
|
|
113
|
+
#
|
|
114
|
+
def removed?()
|
|
115
|
+
@constraint__.removed?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Returns the sprites the constraint is fastened to.
|
|
119
|
+
#
|
|
120
|
+
# @return [Array<Sprite, nil>] nil for a world anchor
|
|
121
|
+
#
|
|
122
|
+
def sprites()
|
|
123
|
+
@sprites__ ||= @constraint__.views.map {_1&.sprite}.freeze
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @private
|
|
127
|
+
def ==(o)
|
|
128
|
+
o.is_a?(Constraint) && @constraint__ == o.getInternal__
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
alias eql? ==
|
|
132
|
+
|
|
133
|
+
# @private
|
|
134
|
+
def hash()
|
|
135
|
+
@constraint__.hash
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @private
|
|
139
|
+
def getInternal__()
|
|
140
|
+
@constraint__
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# @private
|
|
144
|
+
def self.wrap__(constraint)
|
|
145
|
+
klass =
|
|
146
|
+
case constraint
|
|
147
|
+
when Reflex::SnapConstraint then SnapConstraint
|
|
148
|
+
when Reflex::LinkConstraint then LinkConstraint
|
|
149
|
+
when Reflex::WheelConstraint then WheelConstraint
|
|
150
|
+
when Reflex::ChaseConstraint then ChaseConstraint
|
|
151
|
+
else raise ArgumentError, "unknown constraint type: #{constraint.class}"
|
|
152
|
+
end
|
|
153
|
+
klass.new constraint
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def getContext__()
|
|
159
|
+
sprites.first&.getContext__ || Processing.context
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def toDegrees__(angle)
|
|
163
|
+
getContext__.toDegrees__ angle
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def fromDegrees__(degrees)
|
|
167
|
+
getContext__.fromDegrees__ degrees
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
end# Constraint
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# Snaps two points together like a hinge.
|
|
174
|
+
#
|
|
175
|
+
class SnapConstraint < Constraint
|
|
176
|
+
|
|
177
|
+
# Sets the range of the relative rotation angle.
|
|
178
|
+
#
|
|
179
|
+
# @param [Range, Numeric, nil] angle
|
|
180
|
+
# radians or degrees depending on angleMode().
|
|
181
|
+
# nil rotates freely, 0 fixes the rotation
|
|
182
|
+
#
|
|
183
|
+
# @return [Range, Numeric, nil] angle
|
|
184
|
+
#
|
|
185
|
+
def angle=(angle)
|
|
186
|
+
@constraint__.angle =
|
|
187
|
+
case angle
|
|
188
|
+
when Range then Range.new toDegrees__(angle.begin), toDegrees__(angle.end)
|
|
189
|
+
when Numeric then toDegrees__ angle
|
|
190
|
+
else angle
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Returns the range of the relative rotation angle.
|
|
195
|
+
#
|
|
196
|
+
# @return [Range, nil] radians or degrees depending on angleMode()
|
|
197
|
+
#
|
|
198
|
+
def angle()
|
|
199
|
+
angle = @constraint__.angle
|
|
200
|
+
angle ? Range.new(fromDegrees__(angle.begin), fromDegrees__(angle.end)) : nil
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Sets the motor speed that drives the relative rotation.
|
|
204
|
+
#
|
|
205
|
+
# @param [Numeric, nil] speed
|
|
206
|
+
# angular velocity per second, radians or degrees depending on
|
|
207
|
+
# angleMode(). nil stops the motor
|
|
208
|
+
#
|
|
209
|
+
# @return [Numeric, nil] speed
|
|
210
|
+
#
|
|
211
|
+
def motor=(speed)
|
|
212
|
+
@constraint__.motor = speed && toDegrees__(speed)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Returns the motor speed.
|
|
216
|
+
#
|
|
217
|
+
# @return [Numeric, nil] angular velocity per second
|
|
218
|
+
#
|
|
219
|
+
def motor()
|
|
220
|
+
speed = @constraint__.motor
|
|
221
|
+
speed && fromDegrees__(speed)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
universal_accessor :angle, :motor
|
|
225
|
+
|
|
226
|
+
end# SnapConstraint
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# Keeps two points apart at a distance, or slides them along an axis
|
|
230
|
+
# like a rail.
|
|
231
|
+
#
|
|
232
|
+
class LinkConstraint < Constraint
|
|
233
|
+
|
|
234
|
+
# Sets the axis to slide along.
|
|
235
|
+
# With an axis, the separation is measured along it instead of
|
|
236
|
+
# radially, and the relative rotation is locked like a rail.
|
|
237
|
+
#
|
|
238
|
+
# @param [Vector, Array<Numeric>, nil] axis
|
|
239
|
+
# direction in the target local space, or nil to link radially
|
|
240
|
+
#
|
|
241
|
+
# @return [Vector, Array<Numeric>, nil] axis
|
|
242
|
+
#
|
|
243
|
+
def axis=(axis)
|
|
244
|
+
@constraint__.axis = RubySketch.unwrap__ axis
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Returns the axis to slide along.
|
|
248
|
+
#
|
|
249
|
+
# @return [Vector, nil] axis, or nil for a radial link
|
|
250
|
+
#
|
|
251
|
+
def axis()
|
|
252
|
+
@constraint__.axis&.toVector
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Sets the distance to keep.
|
|
256
|
+
#
|
|
257
|
+
# @param [Numeric] distance distance in pixels
|
|
258
|
+
#
|
|
259
|
+
# @return [Numeric] distance
|
|
260
|
+
#
|
|
261
|
+
def distance=(distance)
|
|
262
|
+
@constraint__.distance = distance
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Returns the distance to keep.
|
|
266
|
+
#
|
|
267
|
+
# @return [Numeric] distance in pixels
|
|
268
|
+
#
|
|
269
|
+
def distance()
|
|
270
|
+
@constraint__.distance
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Returns the current distance between the two points.
|
|
274
|
+
#
|
|
275
|
+
# @return [Numeric] distance in pixels, or 0 if not active in a world
|
|
276
|
+
#
|
|
277
|
+
def currentDistance()
|
|
278
|
+
@constraint__.current_distance
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Sets the range of the separation.
|
|
282
|
+
#
|
|
283
|
+
# @param [Range, Numeric, nil] range
|
|
284
|
+
# distance range like a rope, or the translation range along the axis
|
|
285
|
+
#
|
|
286
|
+
# @return [Range, Numeric, nil] range
|
|
287
|
+
#
|
|
288
|
+
def range=(range)
|
|
289
|
+
@constraint__.range = range
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Returns the range of the separation.
|
|
293
|
+
#
|
|
294
|
+
# @return [Range, nil] separation range
|
|
295
|
+
#
|
|
296
|
+
def range()
|
|
297
|
+
@constraint__.range
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Sets the motor speed that drives the separation.
|
|
301
|
+
#
|
|
302
|
+
# @param [Numeric, nil] speed speed in pixels per second, or nil to stop
|
|
303
|
+
#
|
|
304
|
+
# @return [Numeric, nil] speed
|
|
305
|
+
#
|
|
306
|
+
def motor=(speed)
|
|
307
|
+
@constraint__.motor = speed
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Returns the motor speed.
|
|
311
|
+
#
|
|
312
|
+
# @return [Numeric, nil] speed in pixels per second
|
|
313
|
+
#
|
|
314
|
+
def motor()
|
|
315
|
+
@constraint__.motor
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
universal_accessor :axis, :distance, :range, :motor
|
|
319
|
+
|
|
320
|
+
alias dist= distance=
|
|
321
|
+
alias dist distance
|
|
322
|
+
|
|
323
|
+
end# LinkConstraint
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# Rides on the target like a wheel: slides along an axis for the
|
|
327
|
+
# suspension while spinning freely.
|
|
328
|
+
#
|
|
329
|
+
class WheelConstraint < Constraint
|
|
330
|
+
|
|
331
|
+
# Sets the axis to slide along for the suspension.
|
|
332
|
+
#
|
|
333
|
+
# @param [Vector, Array<Numeric>] axis direction in the target local space
|
|
334
|
+
#
|
|
335
|
+
# @return [Vector, Array<Numeric>] axis
|
|
336
|
+
#
|
|
337
|
+
def axis=(axis)
|
|
338
|
+
@constraint__.axis = RubySketch.unwrap__ axis
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Returns the axis to slide along.
|
|
342
|
+
#
|
|
343
|
+
# @return [Vector] axis
|
|
344
|
+
#
|
|
345
|
+
def axis()
|
|
346
|
+
@constraint__.axis&.toVector
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Sets the range of the translation along the axis.
|
|
350
|
+
#
|
|
351
|
+
# @param [Range, Numeric, nil] range translation range in pixels
|
|
352
|
+
#
|
|
353
|
+
# @return [Range, Numeric, nil] range
|
|
354
|
+
#
|
|
355
|
+
def range=(range)
|
|
356
|
+
@constraint__.range = range
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Returns the range of the translation along the axis.
|
|
360
|
+
#
|
|
361
|
+
# @return [Range, nil] translation range
|
|
362
|
+
#
|
|
363
|
+
def range()
|
|
364
|
+
@constraint__.range
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Sets the motor speed that spins the wheel.
|
|
368
|
+
#
|
|
369
|
+
# @param [Numeric, nil] speed
|
|
370
|
+
# angular velocity per second, radians or degrees depending on
|
|
371
|
+
# angleMode(). nil stops the motor
|
|
372
|
+
#
|
|
373
|
+
# @return [Numeric, nil] speed
|
|
374
|
+
#
|
|
375
|
+
def motor=(speed)
|
|
376
|
+
@constraint__.motor = speed && toDegrees__(speed)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Returns the motor speed.
|
|
380
|
+
#
|
|
381
|
+
# @return [Numeric, nil] angular velocity per second
|
|
382
|
+
#
|
|
383
|
+
def motor()
|
|
384
|
+
speed = @constraint__.motor
|
|
385
|
+
speed && fromDegrees__(speed)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
universal_accessor :axis, :range, :motor
|
|
389
|
+
|
|
390
|
+
end# WheelConstraint
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
# Moves a point toward the target every frame.
|
|
394
|
+
#
|
|
395
|
+
class ChaseConstraint < Constraint
|
|
396
|
+
|
|
397
|
+
# Sets the target to chase.
|
|
398
|
+
#
|
|
399
|
+
# @param [Sprite, Pin, Vector, Array<Numeric>, nil] target
|
|
400
|
+
# the center of a sprite, a pin, or a point in the world.
|
|
401
|
+
# nil chases nothing
|
|
402
|
+
#
|
|
403
|
+
# @return [Sprite, Pin, Vector, Array<Numeric>, nil] target
|
|
404
|
+
#
|
|
405
|
+
def target=(target)
|
|
406
|
+
@constraint__.target = RubySketch.unwrap__ target
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Returns the target to chase.
|
|
410
|
+
#
|
|
411
|
+
# @return [Pin] the target pin
|
|
412
|
+
#
|
|
413
|
+
def target()
|
|
414
|
+
Pin.new nil, pin__: @constraint__.target
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
universal_accessor :target
|
|
418
|
+
|
|
419
|
+
end# ChaseConstraint
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
end# RubySketch
|
data/lib/rubysketch/context.rb
CHANGED
|
@@ -265,29 +265,29 @@ module RubySketch
|
|
|
265
265
|
# @return [Sprite] the new sprite object
|
|
266
266
|
#
|
|
267
267
|
def createSprite(*args, **kwargs)
|
|
268
|
-
@world__.createSprite(*args,
|
|
268
|
+
@world__.createSprite(*args, **kwargs)
|
|
269
269
|
end
|
|
270
270
|
|
|
271
271
|
# Adds sprite to the physics engine.
|
|
272
272
|
#
|
|
273
|
-
# @param [Array] array user array to store the sprite
|
|
274
273
|
# @param [Sprite] sprite sprite object
|
|
274
|
+
# @param [Array] to user array to store the sprite
|
|
275
275
|
#
|
|
276
276
|
# @return [Sprite] the added sprite
|
|
277
277
|
#
|
|
278
|
-
def addSprite(
|
|
279
|
-
@world__.addSprite
|
|
278
|
+
def addSprite(...)
|
|
279
|
+
@world__.addSprite(...)
|
|
280
280
|
end
|
|
281
281
|
|
|
282
282
|
# Removes sprite from the physics engine.
|
|
283
283
|
#
|
|
284
|
-
# @param [Array] array user array to remove the sprite
|
|
285
284
|
# @param [Sprite] sprite sprite object
|
|
285
|
+
# @param [Array] from user array to remove the sprite
|
|
286
286
|
#
|
|
287
287
|
# @return [Sprite] the removed sprite
|
|
288
288
|
#
|
|
289
|
-
def removeSprite(
|
|
290
|
-
@world__.removeSprite
|
|
289
|
+
def removeSprite(...)
|
|
290
|
+
@world__.removeSprite(...)
|
|
291
291
|
end
|
|
292
292
|
|
|
293
293
|
alias drawSprite sprite
|
|
@@ -307,7 +307,11 @@ module RubySketch
|
|
|
307
307
|
# @return [SpriteWorld] first added world
|
|
308
308
|
#
|
|
309
309
|
def addWorld(*worlds)
|
|
310
|
-
worlds.
|
|
310
|
+
raise ArgumentError if worlds.any? {_1.getContext__}
|
|
311
|
+
worlds.each do |world|
|
|
312
|
+
@window__.add_overlay world.getInternal__
|
|
313
|
+
world.attached__
|
|
314
|
+
end
|
|
311
315
|
worlds.first
|
|
312
316
|
end
|
|
313
317
|
|
|
@@ -318,7 +322,11 @@ module RubySketch
|
|
|
318
322
|
# @return [SpriteWorld] first removed world
|
|
319
323
|
#
|
|
320
324
|
def removeWorld(*worlds)
|
|
321
|
-
worlds.
|
|
325
|
+
raise ArgumentError if worlds.any? {_1.getContext__ != self}
|
|
326
|
+
worlds.each do |world|
|
|
327
|
+
@window__.remove_overlay world.getInternal__
|
|
328
|
+
world.detached__
|
|
329
|
+
end
|
|
322
330
|
worlds.first
|
|
323
331
|
end
|
|
324
332
|
|
data/lib/rubysketch/extension.rb
CHANGED
data/lib/rubysketch/helper.rb
CHANGED