ruby-sfml 3.0.0.6 → 3.0.0.7
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/.rdoc_options +44 -0
- data/CHANGELOG.md +40 -3
- data/README.md +71 -25
- data/lib/sfml/app.rb +5 -0
- data/lib/sfml/assets.rb +2 -0
- data/lib/sfml/audio/listener.rb +7 -0
- data/lib/sfml/audio/music.rb +51 -0
- data/lib/sfml/audio/sound.rb +41 -0
- data/lib/sfml/audio/sound_buffer.rb +4 -0
- data/lib/sfml/audio/sound_buffer_recorder.rb +2 -0
- data/lib/sfml/audio/sound_cone.rb +1 -0
- data/lib/sfml/audio/sound_recorder.rb +5 -0
- data/lib/sfml/audio/sound_stream.rb +46 -0
- data/lib/sfml/graphics/animation.rb +10 -0
- data/lib/sfml/graphics/blend_mode.rb +1 -0
- data/lib/sfml/graphics/circle_shape.rb +16 -0
- data/lib/sfml/graphics/color.rb +31 -0
- data/lib/sfml/graphics/convex_shape.rb +9 -0
- data/lib/sfml/graphics/font.rb +2 -0
- data/lib/sfml/graphics/image.rb +2 -0
- data/lib/sfml/graphics/particle_system.rb +5 -0
- data/lib/sfml/graphics/rectangle_shape.rb +11 -0
- data/lib/sfml/graphics/render_target.rb +1 -0
- data/lib/sfml/graphics/render_texture.rb +7 -0
- data/lib/sfml/graphics/render_window.rb +26 -0
- data/lib/sfml/graphics/shape.rb +5 -0
- data/lib/sfml/graphics/shape_inspectable.rb +2 -0
- data/lib/sfml/graphics/sprite.rb +4 -0
- data/lib/sfml/graphics/sprite_sheet.rb +2 -0
- data/lib/sfml/graphics/stencil_mode.rb +1 -0
- data/lib/sfml/graphics/text.rb +19 -0
- data/lib/sfml/graphics/texture.rb +5 -0
- data/lib/sfml/graphics/texture_atlas.rb +2 -0
- data/lib/sfml/graphics/transform.rb +2 -0
- data/lib/sfml/graphics/transformable.rb +12 -0
- data/lib/sfml/graphics/vertex_array.rb +18 -0
- data/lib/sfml/graphics/vertex_buffer.rb +4 -0
- data/lib/sfml/graphics/view.rb +5 -0
- data/lib/sfml/network/ftp.rb +34 -0
- data/lib/sfml/network/http.rb +1 -0
- data/lib/sfml/network/ip_address.rb +1 -0
- data/lib/sfml/network/packet.rb +28 -0
- data/lib/sfml/network/socket_selector.rb +1 -0
- data/lib/sfml/network/tcp_listener.rb +3 -0
- data/lib/sfml/network/tcp_socket.rb +4 -0
- data/lib/sfml/network/udp_socket.rb +3 -0
- data/lib/sfml/scene.rb +2 -0
- data/lib/sfml/system/clock.rb +1 -0
- data/lib/sfml/system/rect.rb +27 -5
- data/lib/sfml/system/time.rb +22 -2
- data/lib/sfml/system/vector2.rb +42 -2
- data/lib/sfml/system/vector3.rb +45 -2
- data/lib/sfml/version.rb +1 -1
- data/lib/sfml/window/clipboard.rb +1 -0
- data/lib/sfml/window/context_settings.rb +1 -0
- data/lib/sfml/window/event.rb +2 -0
- data/lib/sfml/window/joystick.rb +3 -0
- data/lib/sfml/window/sensor.rb +1 -0
- data/lib/sfml/window/video_mode.rb +2 -0
- data/lib/sfml/window/window.rb +12 -0
- data/ruby-sfml.gemspec +6 -2
- metadata +3 -2
data/lib/sfml/network/ftp.rb
CHANGED
|
@@ -45,6 +45,8 @@ module SFML
|
|
|
45
45
|
1002 => :connection_closed, 1003 => :invalid_file,
|
|
46
46
|
}.freeze
|
|
47
47
|
|
|
48
|
+
# Create a new FTP client. Call `#connect` next to open a
|
|
49
|
+
# session.
|
|
48
50
|
def initialize
|
|
49
51
|
ptr = C::Network.sfFtp_create
|
|
50
52
|
raise NetworkError, "sfFtp_create returned NULL" if ptr.null?
|
|
@@ -61,61 +63,78 @@ module SFML
|
|
|
61
63
|
Response._take_ownership(C::Network.sfFtp_connect(@handle, addr, Integer(port), t.to_native))
|
|
62
64
|
end
|
|
63
65
|
|
|
66
|
+
# Log in as anonymous. Returns a `Response`.
|
|
64
67
|
def login_anonymous
|
|
65
68
|
Response._take_ownership(C::Network.sfFtp_loginAnonymous(@handle))
|
|
66
69
|
end
|
|
67
70
|
|
|
71
|
+
# Log in with credentials.
|
|
68
72
|
def login(user, password)
|
|
69
73
|
Response._take_ownership(C::Network.sfFtp_login(@handle, user.to_s, password.to_s))
|
|
70
74
|
end
|
|
71
75
|
|
|
76
|
+
# Close the connection.
|
|
72
77
|
def disconnect = Response._take_ownership(C::Network.sfFtp_disconnect(@handle))
|
|
78
|
+
# Send a no-op to keep the connection alive against server timeouts.
|
|
73
79
|
def keep_alive = Response._take_ownership(C::Network.sfFtp_keepAlive(@handle))
|
|
74
80
|
|
|
81
|
+
# Current working directory as a `DirectoryResponse`.
|
|
75
82
|
def working_directory
|
|
76
83
|
DirectoryResponse._take_ownership(C::Network.sfFtp_getWorkingDirectory(@handle))
|
|
77
84
|
end
|
|
78
85
|
|
|
86
|
+
# List `directory` (default = current). Returns a `ListingResponse`.
|
|
79
87
|
def directory_listing(directory = "")
|
|
80
88
|
ListingResponse._take_ownership(C::Network.sfFtp_getDirectoryListing(@handle, directory.to_s))
|
|
81
89
|
end
|
|
82
90
|
|
|
91
|
+
# `cd` to a directory.
|
|
83
92
|
def change_directory(directory)
|
|
84
93
|
Response._take_ownership(C::Network.sfFtp_changeDirectory(@handle, directory.to_s))
|
|
85
94
|
end
|
|
86
95
|
|
|
96
|
+
# `cd ..`.
|
|
87
97
|
def parent_directory
|
|
88
98
|
Response._take_ownership(C::Network.sfFtp_parentDirectory(@handle))
|
|
89
99
|
end
|
|
90
100
|
|
|
101
|
+
# `mkdir` — returns a `DirectoryResponse` with the new path.
|
|
91
102
|
def create_directory(name)
|
|
92
103
|
DirectoryResponse._take_ownership(C::Network.sfFtp_createDirectory(@handle, name.to_s))
|
|
93
104
|
end
|
|
94
105
|
|
|
106
|
+
# `rmdir`.
|
|
95
107
|
def delete_directory(name)
|
|
96
108
|
Response._take_ownership(C::Network.sfFtp_deleteDirectory(@handle, name.to_s))
|
|
97
109
|
end
|
|
98
110
|
|
|
111
|
+
# Rename / move a file on the server.
|
|
99
112
|
def rename_file(file, new_name)
|
|
100
113
|
Response._take_ownership(C::Network.sfFtp_renameFile(@handle, file.to_s, new_name.to_s))
|
|
101
114
|
end
|
|
102
115
|
|
|
116
|
+
# Delete a single file.
|
|
103
117
|
def delete_file(name)
|
|
104
118
|
Response._take_ownership(C::Network.sfFtp_deleteFile(@handle, name.to_s))
|
|
105
119
|
end
|
|
106
120
|
|
|
121
|
+
# Pull `remote` from the server to local path. `mode` is
|
|
122
|
+
# `:binary` (default), `:ascii`, or `:ebcdic`.
|
|
107
123
|
def download(remote, local, mode: :binary)
|
|
108
124
|
idx = C::Network::FTP_TRANSFER_MODES.index(mode) ||
|
|
109
125
|
raise(ArgumentError, "Unknown FTP transfer mode: #{mode.inspect}")
|
|
110
126
|
Response._take_ownership(C::Network.sfFtp_download(@handle, remote.to_s, local.to_s, idx))
|
|
111
127
|
end
|
|
112
128
|
|
|
129
|
+
# Push `local` to `remote`. `append: true` extends an existing
|
|
130
|
+
# remote file rather than replacing it.
|
|
113
131
|
def upload(local, remote, mode: :binary, append: false)
|
|
114
132
|
idx = C::Network::FTP_TRANSFER_MODES.index(mode) ||
|
|
115
133
|
raise(ArgumentError, "Unknown FTP transfer mode: #{mode.inspect}")
|
|
116
134
|
Response._take_ownership(C::Network.sfFtp_upload(@handle, local.to_s, remote.to_s, idx, !!append))
|
|
117
135
|
end
|
|
118
136
|
|
|
137
|
+
# Send a raw FTP command (e.g. "STAT") and an optional parameter.
|
|
119
138
|
def send_command(command, parameter = "")
|
|
120
139
|
Response._take_ownership(C::Network.sfFtp_sendCommand(@handle, command.to_s, parameter.to_s))
|
|
121
140
|
end
|
|
@@ -124,9 +143,13 @@ module SFML
|
|
|
124
143
|
|
|
125
144
|
# Generic response: most FTP operations return this.
|
|
126
145
|
class Response
|
|
146
|
+
# `true` if ok.
|
|
127
147
|
def ok? = C::Network.sfFtpResponse_isOk(@handle)
|
|
148
|
+
# Returns the status.
|
|
128
149
|
def status = C::Network.sfFtpResponse_getStatus(@handle)
|
|
150
|
+
# Returns the status symbol.
|
|
129
151
|
def status_symbol = STATUS_NAMES[status] || status
|
|
152
|
+
# Returns the message.
|
|
130
153
|
def message = C::Network.sfFtpResponse_getMessage(@handle).to_s
|
|
131
154
|
attr_reader :handle # :nodoc:
|
|
132
155
|
|
|
@@ -142,10 +165,15 @@ module SFML
|
|
|
142
165
|
# Returned by working_directory and create_directory — adds the
|
|
143
166
|
# `#directory` accessor on top of Response.
|
|
144
167
|
class DirectoryResponse
|
|
168
|
+
# `true` if ok.
|
|
145
169
|
def ok? = C::Network.sfFtpDirectoryResponse_isOk(@handle)
|
|
170
|
+
# Returns the status.
|
|
146
171
|
def status = C::Network.sfFtpDirectoryResponse_getStatus(@handle)
|
|
172
|
+
# Returns the status symbol.
|
|
147
173
|
def status_symbol = STATUS_NAMES[status] || status
|
|
174
|
+
# Returns the message.
|
|
148
175
|
def message = C::Network.sfFtpDirectoryResponse_getMessage(@handle).to_s
|
|
176
|
+
# Returns the directory.
|
|
149
177
|
def directory = C::Network.sfFtpDirectoryResponse_getDirectory(@handle).to_s
|
|
150
178
|
attr_reader :handle # :nodoc:
|
|
151
179
|
|
|
@@ -160,13 +188,19 @@ module SFML
|
|
|
160
188
|
|
|
161
189
|
# Returned by directory_listing — adds the `#names` array.
|
|
162
190
|
class ListingResponse
|
|
191
|
+
# `true` if ok.
|
|
163
192
|
def ok? = C::Network.sfFtpListingResponse_isOk(@handle)
|
|
193
|
+
# Returns the status.
|
|
164
194
|
def status = C::Network.sfFtpListingResponse_getStatus(@handle)
|
|
195
|
+
# Returns the status symbol.
|
|
165
196
|
def status_symbol = STATUS_NAMES[status] || status
|
|
197
|
+
# Returns the message.
|
|
166
198
|
def message = C::Network.sfFtpListingResponse_getMessage(@handle).to_s
|
|
199
|
+
# Returns the count.
|
|
167
200
|
def count = C::Network.sfFtpListingResponse_getCount(@handle)
|
|
168
201
|
attr_reader :handle # :nodoc:
|
|
169
202
|
|
|
203
|
+
# Filenames returned by the listing, as an Array of Strings.
|
|
170
204
|
def names
|
|
171
205
|
Array.new(count) { |i| C::Network.sfFtpListingResponse_getName(@handle, i).to_s }
|
|
172
206
|
end
|
data/lib/sfml/network/http.rb
CHANGED
data/lib/sfml/network/packet.rb
CHANGED
|
@@ -52,8 +52,11 @@ module SFML
|
|
|
52
52
|
ptr.read_bytes(size).force_encoding(Encoding::ASCII_8BIT)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# Returns the size.
|
|
55
56
|
def size = C::Network.sfPacket_getDataSize(@handle)
|
|
57
|
+
# Returns the read position.
|
|
56
58
|
def read_position = C::Network.sfPacket_getReadPosition(@handle)
|
|
59
|
+
# `true` if end of packet.
|
|
57
60
|
def end_of_packet? = C::Network.sfPacket_endOfPacket(@handle)
|
|
58
61
|
|
|
59
62
|
# `false` if the last read overran the packet — sfPacket "fails"
|
|
@@ -62,20 +65,35 @@ module SFML
|
|
|
62
65
|
def ok? = C::Network.sfPacket_canRead(@handle)
|
|
63
66
|
|
|
64
67
|
# ---- typed writers ----
|
|
68
|
+
# All writers append to the end of the packet and return self
|
|
69
|
+
# for chaining.
|
|
70
|
+
|
|
71
|
+
# Append a Bool.
|
|
65
72
|
def write_bool(v)
|
|
66
73
|
C::Network.sfPacket_writeBool(@handle, v ? true : false); self
|
|
67
74
|
end
|
|
75
|
+
# Append a signed 8-bit Integer.
|
|
68
76
|
def write_int8(v) = (C::Network.sfPacket_writeInt8(@handle, Integer(v)); self)
|
|
77
|
+
# Append an unsigned 8-bit Integer.
|
|
69
78
|
def write_uint8(v) = (C::Network.sfPacket_writeUint8(@handle, Integer(v)); self)
|
|
79
|
+
# Append a signed 16-bit Integer.
|
|
70
80
|
def write_int16(v) = (C::Network.sfPacket_writeInt16(@handle, Integer(v)); self)
|
|
81
|
+
# Append an unsigned 16-bit Integer.
|
|
71
82
|
def write_uint16(v) = (C::Network.sfPacket_writeUint16(@handle, Integer(v)); self)
|
|
83
|
+
# Append a signed 32-bit Integer.
|
|
72
84
|
def write_int32(v) = (C::Network.sfPacket_writeInt32(@handle, Integer(v)); self)
|
|
85
|
+
# Append an unsigned 32-bit Integer.
|
|
73
86
|
def write_uint32(v) = (C::Network.sfPacket_writeUint32(@handle, Integer(v)); self)
|
|
87
|
+
# Append a signed 64-bit Integer.
|
|
74
88
|
def write_int64(v) = (C::Network.sfPacket_writeInt64(@handle, Integer(v)); self)
|
|
89
|
+
# Append an unsigned 64-bit Integer.
|
|
75
90
|
def write_uint64(v) = (C::Network.sfPacket_writeUint64(@handle, Integer(v)); self)
|
|
91
|
+
# Append a single-precision Float.
|
|
76
92
|
def write_float(v) = (C::Network.sfPacket_writeFloat(@handle, Float(v)); self)
|
|
93
|
+
# Append a double-precision Float.
|
|
77
94
|
def write_double(v) = (C::Network.sfPacket_writeDouble(@handle, Float(v)); self)
|
|
78
95
|
|
|
96
|
+
# Append a length-prefixed UTF-8 String.
|
|
79
97
|
def write_string(str)
|
|
80
98
|
C::Network.sfPacket_writeString(@handle, str.to_s)
|
|
81
99
|
self
|
|
@@ -83,15 +101,25 @@ module SFML
|
|
|
83
101
|
|
|
84
102
|
# ---- typed readers ----
|
|
85
103
|
def read_bool = C::Network.sfPacket_readBool(@handle)
|
|
104
|
+
# Returns the read int8.
|
|
86
105
|
def read_int8 = C::Network.sfPacket_readInt8(@handle)
|
|
106
|
+
# Returns the read uint8.
|
|
87
107
|
def read_uint8 = C::Network.sfPacket_readUint8(@handle)
|
|
108
|
+
# Returns the read int16.
|
|
88
109
|
def read_int16 = C::Network.sfPacket_readInt16(@handle)
|
|
110
|
+
# Returns the read uint16.
|
|
89
111
|
def read_uint16 = C::Network.sfPacket_readUint16(@handle)
|
|
112
|
+
# Returns the read int32.
|
|
90
113
|
def read_int32 = C::Network.sfPacket_readInt32(@handle)
|
|
114
|
+
# Returns the read uint32.
|
|
91
115
|
def read_uint32 = C::Network.sfPacket_readUint32(@handle)
|
|
116
|
+
# Returns the read int64.
|
|
92
117
|
def read_int64 = C::Network.sfPacket_readInt64(@handle)
|
|
118
|
+
# Returns the read uint64.
|
|
93
119
|
def read_uint64 = C::Network.sfPacket_readUint64(@handle)
|
|
120
|
+
# Returns the read float.
|
|
94
121
|
def read_float = C::Network.sfPacket_readFloat(@handle)
|
|
122
|
+
# Returns the read double.
|
|
95
123
|
def read_double = C::Network.sfPacket_readDouble(@handle)
|
|
96
124
|
|
|
97
125
|
# Read a length-prefixed string. CSFML expects a caller-allocated
|
|
@@ -47,12 +47,15 @@ module SFML
|
|
|
47
47
|
[status, sock]
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# `true` if blocking.
|
|
50
51
|
def blocking? = C::Network.sfTcpListener_isBlocking(@handle)
|
|
51
52
|
|
|
53
|
+
# Set the blocking.
|
|
52
54
|
def blocking=(value)
|
|
53
55
|
C::Network.sfTcpListener_setBlocking(@handle, value ? true : false)
|
|
54
56
|
end
|
|
55
57
|
|
|
58
|
+
# Returns the local port.
|
|
56
59
|
def local_port = C::Network.sfTcpListener_getLocalPort(@handle)
|
|
57
60
|
|
|
58
61
|
attr_reader :handle # :nodoc:
|
|
@@ -74,13 +74,17 @@ module SFML
|
|
|
74
74
|
[status, status == :done ? pkt : nil]
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
# `true` if blocking.
|
|
77
78
|
def blocking? = C::Network.sfTcpSocket_isBlocking(@handle)
|
|
78
79
|
|
|
80
|
+
# Set the blocking.
|
|
79
81
|
def blocking=(value)
|
|
80
82
|
C::Network.sfTcpSocket_setBlocking(@handle, value ? true : false)
|
|
81
83
|
end
|
|
82
84
|
|
|
85
|
+
# Returns the local port.
|
|
83
86
|
def local_port = C::Network.sfTcpSocket_getLocalPort(@handle)
|
|
87
|
+
# Returns the remote port.
|
|
84
88
|
def remote_port = C::Network.sfTcpSocket_getRemotePort(@handle)
|
|
85
89
|
|
|
86
90
|
def remote_address
|
|
@@ -80,12 +80,15 @@ module SFML
|
|
|
80
80
|
[status, pkt, IpAddress.wrap(sender_addr), sender_port.read(:uint16)]
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# `true` if blocking.
|
|
83
84
|
def blocking? = C::Network.sfUdpSocket_isBlocking(@handle)
|
|
84
85
|
|
|
86
|
+
# Set the blocking.
|
|
85
87
|
def blocking=(value)
|
|
86
88
|
C::Network.sfUdpSocket_setBlocking(@handle, value ? true : false)
|
|
87
89
|
end
|
|
88
90
|
|
|
91
|
+
# Returns the local port.
|
|
89
92
|
def local_port = C::Network.sfUdpSocket_getLocalPort(@handle)
|
|
90
93
|
|
|
91
94
|
attr_reader :handle # :nodoc:
|
data/lib/sfml/scene.rb
CHANGED
|
@@ -48,7 +48,9 @@ module SFML
|
|
|
48
48
|
|
|
49
49
|
# Convenience accessors that match `SFML::App`'s.
|
|
50
50
|
def window = @app.window
|
|
51
|
+
# Returns the width.
|
|
51
52
|
def width = @app.width
|
|
53
|
+
# Returns the height.
|
|
52
54
|
def height = @app.height
|
|
53
55
|
|
|
54
56
|
# Switch the host app to a new scene from inside this one.
|
data/lib/sfml/system/clock.rb
CHANGED
data/lib/sfml/system/rect.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module SFML
|
|
2
|
-
# An axis-aligned rectangle. Mirrors sfFloatRect / sfIntRect — those
|
|
3
|
-
# are just (position: Vector2, size: Vector2)
|
|
4
|
-
# Ruby class for both the float and int
|
|
5
|
-
# `case bounds in {position: {x:,
|
|
6
|
-
# users reach for either way.
|
|
2
|
+
# An axis-aligned rectangle. Mirrors sfFloatRect / sfIntRect — those
|
|
3
|
+
# structs are just `(position: Vector2, size: Vector2)`. We
|
|
4
|
+
# deliberately keep one Ruby class for both the float and int
|
|
5
|
+
# variants since pattern-matching `case bounds in {position: {x:,
|
|
6
|
+
# y:}, size: {x: w, y: h}}` is what users reach for either way.
|
|
7
7
|
#
|
|
8
8
|
# r = SFML::Rect.new([10, 20], [100, 50])
|
|
9
9
|
# r.contains?([50, 30]) #=> true
|
|
@@ -13,26 +13,38 @@ module SFML
|
|
|
13
13
|
class Rect
|
|
14
14
|
attr_reader :position, :size
|
|
15
15
|
|
|
16
|
+
# `position` and `size` may each be a `Vector2` OR a `[x, y]` Array.
|
|
16
17
|
def initialize(position, size)
|
|
17
18
|
@position = position.is_a?(Vector2) ? position : Vector2.new(*position)
|
|
18
19
|
@size = size.is_a?(Vector2) ? size : Vector2.new(*size)
|
|
19
20
|
freeze
|
|
20
21
|
end
|
|
21
22
|
|
|
23
|
+
# Top-left X.
|
|
22
24
|
def x = @position.x
|
|
25
|
+
# Top-left Y.
|
|
23
26
|
def y = @position.y
|
|
27
|
+
# Width.
|
|
24
28
|
def width = @size.x
|
|
29
|
+
# Height.
|
|
25
30
|
def height = @size.y
|
|
26
31
|
alias left x
|
|
27
32
|
alias top y
|
|
33
|
+
|
|
34
|
+
# X of the right edge (`x + width`).
|
|
28
35
|
def right = @position.x + @size.x
|
|
36
|
+
# Y of the bottom edge (`y + height`).
|
|
29
37
|
def bottom = @position.y + @size.y
|
|
30
38
|
|
|
39
|
+
# `true` if `point` (Vector2 or `[x, y]`) is inside this rect.
|
|
40
|
+
# The right and bottom edges are exclusive.
|
|
31
41
|
def contains?(point)
|
|
32
42
|
px, py = point.is_a?(Vector2) ? [point.x, point.y] : [point[0], point[1]]
|
|
33
43
|
px >= left && px < right && py >= top && py < bottom
|
|
34
44
|
end
|
|
35
45
|
|
|
46
|
+
# `true` if this rect overlaps `other` at all (any non-empty
|
|
47
|
+
# intersection counts).
|
|
36
48
|
def intersects?(other)
|
|
37
49
|
left < other.right &&
|
|
38
50
|
right > other.left &&
|
|
@@ -40,17 +52,27 @@ module SFML
|
|
|
40
52
|
bottom > other.top
|
|
41
53
|
end
|
|
42
54
|
|
|
55
|
+
# Value equality — same position + same size.
|
|
43
56
|
def ==(other)
|
|
44
57
|
other.is_a?(Rect) && @position == other.position && @size == other.size
|
|
45
58
|
end
|
|
46
59
|
alias eql? ==
|
|
60
|
+
# Hash key support.
|
|
47
61
|
def hash = [@position, @size].hash
|
|
48
62
|
|
|
63
|
+
# `[x, y, width, height]`.
|
|
49
64
|
def to_a = [x, y, width, height]
|
|
65
|
+
|
|
66
|
+
# `{position:, size:}`.
|
|
50
67
|
def to_h = { position: @position, size: @size }
|
|
68
|
+
|
|
69
|
+
# Pattern-match support for `in [x, y, w, h]`.
|
|
51
70
|
def deconstruct = [x, y, width, height]
|
|
71
|
+
|
|
72
|
+
# Pattern-match support for `in {position:, size:}`.
|
|
52
73
|
def deconstruct_keys(_keys) = { position: @position, size: @size }
|
|
53
74
|
|
|
75
|
+
# String representation for debugging.
|
|
54
76
|
def to_s = "Rect(x=#{x}, y=#{y}, w=#{width}, h=#{height})"
|
|
55
77
|
alias inspect to_s
|
|
56
78
|
|
data/lib/sfml/system/time.rb
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
module SFML
|
|
2
|
-
# Represents a time value. Stored internally as microseconds (int64),
|
|
3
|
-
# as sfTime in CSFML. Immutable and
|
|
2
|
+
# Represents a time value. Stored internally as microseconds (int64),
|
|
3
|
+
# same as `sfTime` in CSFML. Immutable and Comparable, so two Times
|
|
4
|
+
# can be `==` / `<` / `>` / sorted.
|
|
4
5
|
#
|
|
5
6
|
# SFML::Time.seconds(1.5) #=> 1_500_000 µs
|
|
6
7
|
# SFML::Time.milliseconds(500)
|
|
7
8
|
# SFML::Time.microseconds(42)
|
|
8
9
|
# SFML::Time.zero
|
|
10
|
+
#
|
|
11
|
+
# t1 + t2 # sum of two Times
|
|
12
|
+
# t.as_seconds # Float seconds
|
|
9
13
|
class Time
|
|
10
14
|
include Comparable
|
|
11
15
|
|
|
12
16
|
attr_reader :microseconds
|
|
13
17
|
|
|
18
|
+
# Build a Time from a Float of seconds.
|
|
14
19
|
def self.seconds(value) = new((value * 1_000_000).to_i)
|
|
20
|
+
# Build a Time from an Integer of milliseconds.
|
|
15
21
|
def self.milliseconds(value) = new(Integer(value) * 1_000)
|
|
22
|
+
# Build a Time directly from microseconds.
|
|
16
23
|
def self.microseconds(value) = new(Integer(value))
|
|
24
|
+
# The zero Time.
|
|
17
25
|
def self.zero = new(0)
|
|
18
26
|
|
|
19
27
|
def initialize(microseconds)
|
|
@@ -21,19 +29,31 @@ module SFML
|
|
|
21
29
|
freeze
|
|
22
30
|
end
|
|
23
31
|
|
|
32
|
+
# As Float seconds.
|
|
24
33
|
def as_seconds = @microseconds / 1_000_000.0
|
|
34
|
+
# As Integer milliseconds (truncated).
|
|
25
35
|
def as_milliseconds = @microseconds / 1_000
|
|
36
|
+
# As Integer microseconds — the raw stored value.
|
|
26
37
|
def as_microseconds = @microseconds
|
|
27
38
|
|
|
39
|
+
# Sum of two Times — returns a fresh Time.
|
|
28
40
|
def +(other) = Time.new(@microseconds + other.microseconds)
|
|
41
|
+
# Difference between two Times.
|
|
29
42
|
def -(other) = Time.new(@microseconds - other.microseconds)
|
|
43
|
+
# Negate (useful when computing a "ago" offset).
|
|
30
44
|
def -@ = Time.new(-@microseconds)
|
|
45
|
+
|
|
46
|
+
# Compare two Times — implements `Comparable`, so `<`, `<=`, `>=`,
|
|
47
|
+
# `>`, `clamp`, and `Array#sort` all work.
|
|
31
48
|
def <=>(other) = @microseconds <=> other.microseconds
|
|
32
49
|
|
|
50
|
+
# Hash key support — Times can be Hash keys / Set members.
|
|
33
51
|
def hash = @microseconds.hash
|
|
52
|
+
# Value equality.
|
|
34
53
|
def eql?(other) = other.is_a?(Time) && @microseconds == other.microseconds
|
|
35
54
|
alias == eql?
|
|
36
55
|
|
|
56
|
+
# String representation for debugging.
|
|
37
57
|
def to_s = "#<SFML::Time #{as_seconds}s>"
|
|
38
58
|
alias inspect to_s
|
|
39
59
|
|
data/lib/sfml/system/vector2.rb
CHANGED
|
@@ -9,8 +9,12 @@ module SFML
|
|
|
9
9
|
class Vector2
|
|
10
10
|
attr_reader :x, :y
|
|
11
11
|
|
|
12
|
+
# Compact constructor: `Vector2[3, 4]` reads naturally as a literal.
|
|
12
13
|
def self.[](x, y) = new(x, y)
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
# The (0, 0) vector. Reused as a singleton-style fallback (e.g.
|
|
16
|
+
# `#normalize` returns this for the zero vector).
|
|
17
|
+
def self.zero = new(0, 0)
|
|
14
18
|
|
|
15
19
|
def initialize(x = 0, y = 0)
|
|
16
20
|
@x = x
|
|
@@ -18,10 +22,15 @@ module SFML
|
|
|
18
22
|
freeze
|
|
19
23
|
end
|
|
20
24
|
|
|
25
|
+
# Component-wise addition.
|
|
21
26
|
def +(other) = Vector2.new(@x + other.x, @y + other.y)
|
|
27
|
+
# Component-wise subtraction.
|
|
22
28
|
def -(other) = Vector2.new(@x - other.x, @y - other.y)
|
|
29
|
+
# Multiply both components by `scalar`.
|
|
23
30
|
def *(scalar) = Vector2.new(@x * scalar, @y * scalar)
|
|
31
|
+
# Divide both components by `scalar`. Always promotes to Float.
|
|
24
32
|
def /(scalar) = Vector2.new(@x / scalar.to_f, @y / scalar.to_f)
|
|
33
|
+
# Negate both components.
|
|
25
34
|
def -@ = Vector2.new(-@x, -@y)
|
|
26
35
|
|
|
27
36
|
# Lets Ruby evaluate `2 * vec` as `vec * 2`. Without this, Numeric#*
|
|
@@ -31,24 +40,40 @@ module SFML
|
|
|
31
40
|
[self, other]
|
|
32
41
|
end
|
|
33
42
|
|
|
43
|
+
# Value equality — two Vector2s are equal when both components match.
|
|
34
44
|
def ==(other) = other.is_a?(Vector2) && @x == other.x && @y == other.y
|
|
35
45
|
alias eql? ==
|
|
46
|
+
# Hash key support — Vector2s can be Hash keys / Set members.
|
|
36
47
|
def hash = [@x, @y].hash
|
|
37
48
|
|
|
49
|
+
# Euclidean length √(x² + y²). For comparisons prefer `length_sq` —
|
|
50
|
+
# avoids the square root.
|
|
38
51
|
def length = Math.sqrt(length_sq)
|
|
52
|
+
# Squared length (x² + y²) — comparisons can use this without the
|
|
53
|
+
# `sqrt` call.
|
|
39
54
|
def length_sq = (@x * @x) + (@y * @y)
|
|
40
55
|
|
|
56
|
+
# Unit vector pointing the same way as `self`. Returns the zero
|
|
57
|
+
# vector unchanged (no division by zero).
|
|
41
58
|
def normalize
|
|
42
59
|
len = length
|
|
43
60
|
return Vector2.zero if len.zero?
|
|
44
61
|
self / len
|
|
45
62
|
end
|
|
46
63
|
|
|
64
|
+
# Scalar dot product. Positive when both vectors point roughly the
|
|
65
|
+
# same way, negative when opposite, zero when perpendicular.
|
|
47
66
|
def dot(other) = (@x * other.x) + (@y * other.y)
|
|
67
|
+
|
|
68
|
+
# Scalar 2D cross product (a.k.a. perpendicular dot). Positive when
|
|
69
|
+
# `other` is counter-clockwise from `self`, negative when clockwise.
|
|
48
70
|
def cross(other) = (@x * other.y) - (@y * other.x)
|
|
49
71
|
|
|
50
|
-
# Euclidean distance
|
|
72
|
+
# Euclidean distance to `other` — accepts a Vector2 or `[x, y]`.
|
|
51
73
|
def distance(other) = (self - _coerce(other)).length
|
|
74
|
+
|
|
75
|
+
# Squared distance to `other` — skip the `sqrt` if you only need to
|
|
76
|
+
# compare two distances.
|
|
52
77
|
def distance_sq(other) = (self - _coerce(other)).length_sq
|
|
53
78
|
|
|
54
79
|
# Angle of this vector relative to +X axis, in radians (-π..π].
|
|
@@ -64,6 +89,7 @@ module SFML
|
|
|
64
89
|
# if you already have radians.
|
|
65
90
|
def rotated(degrees) = rotated_rad(degrees * Math::PI / 180.0)
|
|
66
91
|
|
|
92
|
+
# Vector rotated by `radians` counter-clockwise.
|
|
67
93
|
def rotated_rad(radians)
|
|
68
94
|
c, s = Math.cos(radians), Math.sin(radians)
|
|
69
95
|
Vector2.new(@x * c - @y * s, @x * s + @y * c)
|
|
@@ -109,15 +135,29 @@ module SFML
|
|
|
109
135
|
self * (target / len)
|
|
110
136
|
end
|
|
111
137
|
|
|
138
|
+
# `true` iff both components are zero.
|
|
112
139
|
def zero? = @x.zero? && @y.zero?
|
|
140
|
+
|
|
141
|
+
# Per-component absolute value.
|
|
113
142
|
def abs = Vector2.new(@x.abs, @y.abs)
|
|
143
|
+
|
|
144
|
+
# Promote to a Vector3 with optional `z` (default 0).
|
|
114
145
|
def to_v3(z = 0.0) = Vector3.new(@x, @y, z)
|
|
115
146
|
|
|
147
|
+
# As a 2-element `[x, y]` Array — supports splat destructuring:
|
|
148
|
+
# `x, y = vec`.
|
|
116
149
|
def to_a = [@x, @y]
|
|
150
|
+
|
|
151
|
+
# As a `{x:, y:}` Hash.
|
|
117
152
|
def to_h = { x: @x, y: @y }
|
|
153
|
+
|
|
154
|
+
# Pattern-match support for `in [x, y]`.
|
|
118
155
|
def deconstruct = [@x, @y]
|
|
156
|
+
|
|
157
|
+
# Pattern-match support for `in {x:, y:}`.
|
|
119
158
|
def deconstruct_keys(_keys) = { x: @x, y: @y }
|
|
120
159
|
|
|
160
|
+
# String representation for debugging.
|
|
121
161
|
def to_s = "Vector2(#{@x}, #{@y})"
|
|
122
162
|
alias inspect to_s
|
|
123
163
|
|