chingu 0.9rc3 → 0.9rc4
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.
- data/chingu.gemspec +3 -2
- data/examples/example7_gfx_helpers.rb +15 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/classic_game_object.rb +1 -1
- data/lib/chingu/console.rb +1 -22
- data/lib/chingu/fpscounter.rb +13 -1
- data/lib/chingu/game_object.rb +1 -1
- data/lib/chingu/game_object_list.rb +8 -24
- data/lib/chingu/game_state_manager.rb +9 -2
- data/lib/chingu/game_states/network_client.rb +21 -20
- data/lib/chingu/game_states/network_server.rb +70 -40
- data/lib/chingu/helpers/fps_counter.rb +39 -0
- data/lib/chingu/helpers/game_object.rb +120 -134
- data/lib/chingu/helpers/game_state.rb +9 -27
- data/lib/chingu/helpers/gfx.rb +134 -52
- data/lib/chingu/window.rb +2 -23
- data/spec/chingu/network_spec.rb +4 -5
- metadata +11 -10
data/chingu.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{chingu}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.9rc4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["ippa"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-03-07}
|
13
13
|
s.description = %q{OpenGL accelerated 2D game framework for Ruby. Builds on Gosu (Ruby/C++) which provides all the core functionality. Chingu adds simple yet powerful game states, prettier input handling, deployment safe asset-handling, a basic re-usable game object and stackable game logic.}
|
14
14
|
s.email = %q{ippa@rubylicio.us}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -151,6 +151,7 @@ Gem::Specification.new do |s|
|
|
151
151
|
"lib/chingu/game_states/popup.rb",
|
152
152
|
"lib/chingu/gosu_ext/image.rb",
|
153
153
|
"lib/chingu/helpers/class_inheritable_accessor.rb",
|
154
|
+
"lib/chingu/helpers/fps_counter.rb",
|
154
155
|
"lib/chingu/helpers/game_object.rb",
|
155
156
|
"lib/chingu/helpers/game_state.rb",
|
156
157
|
"lib/chingu/helpers/gfx.rb",
|
@@ -19,6 +19,7 @@ class Game < Chingu::Window
|
|
19
19
|
push_game_state(FillGradient)
|
20
20
|
push_game_state(FillGradientRect)
|
21
21
|
push_game_state(FillGradientMultipleColors)
|
22
|
+
push_game_state(DrawCircle)
|
22
23
|
push_game_state(Particles)
|
23
24
|
end
|
24
25
|
|
@@ -27,6 +28,20 @@ class Game < Chingu::Window
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
31
|
+
class DrawCircle < Chingu::GameState
|
32
|
+
def draw
|
33
|
+
$window.caption = "circles and arcs (space to continue)"
|
34
|
+
draw_circle(0, 0, 300, Color::RED)
|
35
|
+
fill_circle($window.width, $window.height, 200, Color::RED)
|
36
|
+
|
37
|
+
colors = [Color::RED, Color::YELLOW, Color::GREEN, Color::BLUE]
|
38
|
+
0.step(360, 90).each_cons(2).zip(colors).each do |(a1, a2), color|
|
39
|
+
fill_arc(400, 100, 100, a1, a2, color)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
30
45
|
class Fill < Chingu::GameState
|
31
46
|
def draw
|
32
47
|
$window.caption = "fill (space to continue)"
|
data/lib/chingu.rb
CHANGED
data/lib/chingu/console.rb
CHANGED
@@ -25,6 +25,7 @@ module Chingu
|
|
25
25
|
#
|
26
26
|
#
|
27
27
|
class Console
|
28
|
+
include Chingu::Helpers::FPSCounter # Adds FPSCounter delegators
|
28
29
|
include Chingu::Helpers::GameState # Easy access to the global game state-queue
|
29
30
|
include Chingu::Helpers::GameObject # Adds game_objects_of_class etc ...
|
30
31
|
|
@@ -73,28 +74,6 @@ module Chingu
|
|
73
74
|
game_state_manager.inside_state || game_state_manager.current_game_state || self
|
74
75
|
end
|
75
76
|
|
76
|
-
#
|
77
|
-
# Frames per second, access with $window.fps or $window.framerate
|
78
|
-
#
|
79
|
-
def fps
|
80
|
-
@fps_counter.fps
|
81
|
-
end
|
82
|
-
alias :framerate :fps
|
83
|
-
|
84
|
-
#
|
85
|
-
# Total amount of game iterations (ticks)
|
86
|
-
#
|
87
|
-
def ticks
|
88
|
-
@fps_counter.ticks
|
89
|
-
end
|
90
|
-
|
91
|
-
#
|
92
|
-
# Mathematical short name for "milliseconds since last tick"
|
93
|
-
#
|
94
|
-
def dt
|
95
|
-
@milliseconds_since_last_tick
|
96
|
-
end
|
97
|
-
|
98
77
|
#
|
99
78
|
# Chingus core-logic / loop. Gosu will call this each game-iteration.
|
100
79
|
#
|
data/lib/chingu/fpscounter.rb
CHANGED
@@ -26,7 +26,19 @@ module Chingu
|
|
26
26
|
# register_tick() must be called every game loop iteration
|
27
27
|
#
|
28
28
|
class FPSCounter
|
29
|
-
|
29
|
+
attr_reader :milliseconds_since_last_tick
|
30
|
+
alias :dt :milliseconds_since_last_tick
|
31
|
+
|
32
|
+
#
|
33
|
+
# Frames per second, access with $window.fps or $window.framerate
|
34
|
+
#
|
35
|
+
attr_reader :fps
|
36
|
+
alias :framerate :fps
|
37
|
+
|
38
|
+
#
|
39
|
+
# Total amount of game iterations (ticks)
|
40
|
+
#
|
41
|
+
attr_reader :ticks
|
30
42
|
|
31
43
|
def initialize
|
32
44
|
@current_second = Gosu::milliseconds / 1000
|
data/lib/chingu/game_object.rb
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
#
|
20
20
|
#++
|
21
21
|
|
22
|
+
require 'forwardable'
|
22
23
|
|
23
24
|
module Chingu
|
24
25
|
#
|
@@ -26,18 +27,21 @@ module Chingu
|
|
26
27
|
# An instance of GameObjectList is automaticly created as "game_objects" if using Chingu::Window
|
27
28
|
#
|
28
29
|
class GameObjectList
|
30
|
+
extend Forwardable
|
31
|
+
|
29
32
|
attr_reader :visible_game_objects, :unpaused_game_objects
|
30
33
|
|
31
34
|
def initialize(options = {})
|
32
35
|
@game_objects = options[:game_objects] || []
|
33
36
|
@visible_game_objects = []
|
34
37
|
@unpaused_game_objects = []
|
35
|
-
|
36
|
-
#@game_objects = {}
|
37
|
-
#@visible_game_objects = {}
|
38
|
-
#@unpaused_game_objects = {}
|
39
38
|
end
|
40
39
|
|
40
|
+
def_delegator :@game_objects, :size
|
41
|
+
def_delegator :@game_objects, :empty?
|
42
|
+
def_delegator :@game_objects, :first
|
43
|
+
def_delegator :@game_objects, :last
|
44
|
+
|
41
45
|
def to_s
|
42
46
|
"#{@game_objects.size} game objects."
|
43
47
|
end
|
@@ -69,10 +73,6 @@ module Chingu
|
|
69
73
|
@game_objects.push(object)
|
70
74
|
@visible_game_objects.push(object) if object.respond_to?(:visible) && object.visible
|
71
75
|
@unpaused_game_objects.push(object) if object.respond_to?(:paused) && !object.paused
|
72
|
-
|
73
|
-
#@game_objects[object] = true
|
74
|
-
#@visible_game_objects[object] = true if object.respond_to?(:visible) && object.visible
|
75
|
-
#@unpaused_game_objects[object] = true if object.respond_to?(:paused) && !object.paused
|
76
76
|
end
|
77
77
|
|
78
78
|
def remove_game_object(object)
|
@@ -85,14 +85,6 @@ module Chingu
|
|
85
85
|
@game_objects.select { |object| object.destroy if yield(object) }
|
86
86
|
end
|
87
87
|
|
88
|
-
def size
|
89
|
-
@game_objects.size
|
90
|
-
end
|
91
|
-
|
92
|
-
def empty?
|
93
|
-
@game_objects.empty?
|
94
|
-
end
|
95
|
-
|
96
88
|
def update
|
97
89
|
@unpaused_game_objects.each { |go| go.update_trait; go.update; }
|
98
90
|
end
|
@@ -131,14 +123,6 @@ module Chingu
|
|
131
123
|
@game_objects.map { |object| yield object }
|
132
124
|
end
|
133
125
|
|
134
|
-
def first
|
135
|
-
@game_objects.first
|
136
|
-
end
|
137
|
-
|
138
|
-
def last
|
139
|
-
@game_objects.last
|
140
|
-
end
|
141
|
-
|
142
126
|
#
|
143
127
|
# Disable automatic calling of update() and update_trait() each game loop for all game objects
|
144
128
|
#
|
@@ -236,8 +236,15 @@ module Chingu
|
|
236
236
|
# Pops through all game states until matching a given game state
|
237
237
|
#
|
238
238
|
def pop_until_game_state(new_state)
|
239
|
-
|
240
|
-
|
239
|
+
if new_state.is_a? Class
|
240
|
+
raise ArgumentError, "No state of given class is on the stack" unless @game_states.map {|s| s.class }.include? new_state
|
241
|
+
|
242
|
+
@game_states.pop until current_game_state.is_a? new_state
|
243
|
+
|
244
|
+
else
|
245
|
+
raise ArgumentError, "State is not on the stack" unless @game_states.include? new_state
|
246
|
+
|
247
|
+
@game_states.pop while current_game_state != new_state
|
241
248
|
end
|
242
249
|
end
|
243
250
|
|
@@ -71,18 +71,20 @@ module Chingu
|
|
71
71
|
#
|
72
72
|
class NetworkClient < Chingu::GameState
|
73
73
|
attr_reader :latency, :socket, :packet_counter, :packet_buffer, :ip, :port
|
74
|
+
alias_method :address, :ip
|
74
75
|
|
75
76
|
def initialize(options = {})
|
76
77
|
super
|
77
78
|
@timeout = options[:timeout] || 4
|
78
79
|
@debug = options[:debug]
|
79
80
|
@ip = options[:ip] || "0.0.0.0"
|
80
|
-
@port = options[:port] ||
|
81
|
+
@port = options[:port] || NetworkServer::DEFAULT_PORT
|
82
|
+
@max_read_per_update = options[:max_read_per_update] || 50000
|
81
83
|
|
82
84
|
@socket = nil
|
83
85
|
@latency = 0
|
84
86
|
@packet_counter = 0
|
85
|
-
@packet_buffer =
|
87
|
+
@packet_buffer = NetworkServer::PacketBuffer.new
|
86
88
|
end
|
87
89
|
|
88
90
|
#
|
@@ -110,7 +112,6 @@ module Chingu
|
|
110
112
|
begin
|
111
113
|
status = Timeout::timeout(@timeout) do
|
112
114
|
@socket = TCPSocket.new(@ip, @port)
|
113
|
-
@socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
114
115
|
on_connect
|
115
116
|
end
|
116
117
|
rescue Errno::ECONNREFUSED
|
@@ -154,14 +155,14 @@ module Chingu
|
|
154
155
|
# Call this from your update() to read from socket.
|
155
156
|
# handle_incoming_data will call on_data(raw_data) when stuff comes on on the socket.
|
156
157
|
#
|
157
|
-
def handle_incoming_data(amount =
|
158
|
+
def handle_incoming_data(amount = @max_read_per_update)
|
158
159
|
return unless @socket
|
159
160
|
|
160
161
|
if IO.select([@socket], nil, nil, 0.0)
|
161
162
|
begin
|
162
163
|
packet, sender = @socket.recvfrom(amount)
|
163
164
|
on_data(packet)
|
164
|
-
rescue Errno::ECONNABORTED
|
165
|
+
rescue Errno::ECONNABORTED, Errno::ECONNRESET
|
165
166
|
on_disconnect
|
166
167
|
end
|
167
168
|
end
|
@@ -171,17 +172,10 @@ module Chingu
|
|
171
172
|
# on_data(data) will be called from handle_incoming_data() by default.
|
172
173
|
#
|
173
174
|
def on_data(data)
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
YAML::load_documents(@packet_buffer) { |msg| on_msg(msg) if msg }
|
179
|
-
@packet_buffer = msgs.last
|
180
|
-
else
|
181
|
-
@packet_buffer << msgs.join
|
182
|
-
end
|
183
|
-
rescue ArgumentError
|
184
|
-
puts "Bad YAML recieved:\n#{data}"
|
175
|
+
@packet_buffer.buffer_data data
|
176
|
+
|
177
|
+
while packet = @packet_buffer.next_packet
|
178
|
+
on_msg(Marshal.load(packet))
|
185
179
|
end
|
186
180
|
end
|
187
181
|
|
@@ -190,16 +184,23 @@ module Chingu
|
|
190
184
|
# Can be whatever ruby-structure that responds to #to_yaml
|
191
185
|
#
|
192
186
|
def send_msg(msg)
|
193
|
-
|
194
|
-
data = msg.to_yaml + "--- \n"
|
195
|
-
send_data(data)
|
187
|
+
send_data(Marshal.dump(msg))
|
196
188
|
end
|
197
189
|
|
198
190
|
#
|
199
191
|
# Send whatever raw data to the server
|
200
192
|
#
|
201
193
|
def send_data(data)
|
202
|
-
|
194
|
+
begin
|
195
|
+
@socket.write([data.length].pack(NetworkServer::PACKET_HEADER_FORMAT))
|
196
|
+
@socket.write(data)
|
197
|
+
rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::ENOTCONN
|
198
|
+
on_disconnect
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Ensure that the buffer is cleared of data to write (call at the end of update or, at least after all sends).
|
203
|
+
def flush
|
203
204
|
@socket.flush
|
204
205
|
end
|
205
206
|
|
@@ -69,20 +69,62 @@ module Chingu
|
|
69
69
|
# A good idea is to have a socket-ivar in your Player-model and a Player.find_by_socket(socket)
|
70
70
|
#
|
71
71
|
class NetworkServer < Chingu::GameState
|
72
|
-
|
72
|
+
PACKET_HEADER_LENGTH = 4
|
73
|
+
PACKET_HEADER_FORMAT = "N"
|
74
|
+
DEFAULT_PORT = 7778
|
75
|
+
|
76
|
+
class PacketBuffer
|
77
|
+
def initialize
|
78
|
+
@data = '' # Buffered data.
|
79
|
+
@length = nil # Length of the next packet. nil if header not read yet.
|
80
|
+
end
|
81
|
+
|
82
|
+
# Add data string to the buffer.
|
83
|
+
def buffer_data(data)
|
84
|
+
@data << data
|
85
|
+
end
|
86
|
+
|
87
|
+
# Call after adding data with #buffer_data until there are no more packets left.
|
88
|
+
def next_packet
|
89
|
+
# Read the header to find out the length of the next packet.
|
90
|
+
unless @length
|
91
|
+
if @data.length >= PACKET_HEADER_LENGTH
|
92
|
+
@length = @data[0...PACKET_HEADER_LENGTH].unpack(PACKET_HEADER_FORMAT)[0]
|
93
|
+
@data[0...PACKET_HEADER_LENGTH] = ''
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# If there is enough data after the header for the full packet, return it.
|
98
|
+
if @length and @length <= @data.length
|
99
|
+
begin
|
100
|
+
packet = @data[0...@length]
|
101
|
+
@data[0...@length] = ''
|
102
|
+
@length = nil
|
103
|
+
return packet
|
104
|
+
rescue TypeError => ex
|
105
|
+
puts "Bad data received:\n#{@data.inspect}"
|
106
|
+
raise ex
|
107
|
+
end
|
108
|
+
else
|
109
|
+
return nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :socket, :sockets, :ip, :port
|
115
|
+
|
116
|
+
alias_method :address, :ip
|
73
117
|
|
74
118
|
def initialize(options = {})
|
75
119
|
super
|
76
120
|
|
77
121
|
@ip = options[:ip] || "0.0.0.0"
|
78
|
-
@port = options[:port] ||
|
122
|
+
@port = options[:port] || DEFAULT_PORT
|
79
123
|
@debug = options[:debug]
|
80
124
|
@socket = nil
|
81
125
|
@sockets = []
|
82
|
-
@buffered_output = YAML::Stream.new
|
83
126
|
@max_read_per_update = options[:max_read_per_update] || 20000
|
84
|
-
|
85
|
-
@packet_counter = 0
|
127
|
+
|
86
128
|
@packet_buffers = Hash.new
|
87
129
|
end
|
88
130
|
|
@@ -94,7 +136,6 @@ module Chingu
|
|
94
136
|
@port = port if port
|
95
137
|
begin
|
96
138
|
@socket = TCPServer.new(@ip, @port)
|
97
|
-
@socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
98
139
|
on_start
|
99
140
|
rescue
|
100
141
|
on_start_error($!)
|
@@ -134,11 +175,9 @@ module Chingu
|
|
134
175
|
if @socket && !@socket.closed?
|
135
176
|
handle_incoming_connections
|
136
177
|
handle_incoming_data
|
137
|
-
super
|
138
|
-
handle_outgoing_data
|
139
|
-
else
|
140
|
-
super
|
141
178
|
end
|
179
|
+
|
180
|
+
super
|
142
181
|
end
|
143
182
|
|
144
183
|
#
|
@@ -157,10 +196,11 @@ module Chingu
|
|
157
196
|
|
158
197
|
def handle_incoming_connections
|
159
198
|
begin
|
160
|
-
socket = @socket.accept_nonblock
|
161
|
-
|
162
|
-
|
163
|
-
|
199
|
+
while socket = @socket.accept_nonblock
|
200
|
+
@sockets << socket
|
201
|
+
@packet_buffers[socket] = PacketBuffer.new
|
202
|
+
on_connect(socket)
|
203
|
+
end
|
164
204
|
rescue IO::WaitReadable, Errno::EINTR
|
165
205
|
end
|
166
206
|
end
|
@@ -177,6 +217,7 @@ module Chingu
|
|
177
217
|
on_data(socket, packet)
|
178
218
|
rescue Errno::ECONNABORTED, Errno::ECONNRESET
|
179
219
|
@packet_buffers[socket] = nil
|
220
|
+
|
180
221
|
on_disconnect(socket)
|
181
222
|
end
|
182
223
|
end
|
@@ -187,28 +228,12 @@ module Chingu
|
|
187
228
|
# on_data(data) will be called from handle_incoming_data() by default.
|
188
229
|
#
|
189
230
|
def on_data(socket, data)
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
else
|
197
|
-
@packet_buffers[socket] << msgs.join
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
#
|
203
|
-
# Send all buffered outgoing data
|
204
|
-
#
|
205
|
-
def handle_outgoing_data
|
206
|
-
# the "---" part is a little hack to make server understand the YAML is fully transmitted.
|
207
|
-
|
208
|
-
data = @buffered_output.emit
|
209
|
-
if data.size > 0
|
210
|
-
@sockets.each { |socket| send_data(socket, data + "--- \n") }
|
211
|
-
@buffered_output = YAML::Stream.new
|
231
|
+
buffer = @packet_buffers[socket]
|
232
|
+
|
233
|
+
buffer.buffer_data data
|
234
|
+
|
235
|
+
while packet = buffer.next_packet
|
236
|
+
on_msg(socket, Marshal.load(packet))
|
212
237
|
end
|
213
238
|
end
|
214
239
|
|
@@ -217,7 +242,8 @@ module Chingu
|
|
217
242
|
# Output is buffered and dispatched once each server-loop
|
218
243
|
#
|
219
244
|
def broadcast_msg(msg)
|
220
|
-
|
245
|
+
data = Marshal.dump(msg)
|
246
|
+
@sockets.each {|s| send_data(s, data) }
|
221
247
|
end
|
222
248
|
|
223
249
|
#
|
@@ -225,8 +251,7 @@ module Chingu
|
|
225
251
|
# 'msg' must responds to #to_yaml
|
226
252
|
#
|
227
253
|
def send_msg(socket, msg)
|
228
|
-
|
229
|
-
send_data(socket, msg.to_yaml + "--- \n")
|
254
|
+
send_data(socket, Marshal.dump(msg))
|
230
255
|
end
|
231
256
|
|
232
257
|
#
|
@@ -234,8 +259,8 @@ module Chingu
|
|
234
259
|
#
|
235
260
|
def send_data(socket, data)
|
236
261
|
begin
|
262
|
+
socket.write([data.length].pack(PACKET_HEADER_FORMAT))
|
237
263
|
socket.write(data)
|
238
|
-
socket.flush
|
239
264
|
rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::ENOTCONN
|
240
265
|
on_disconnect(socket)
|
241
266
|
end
|
@@ -247,6 +272,11 @@ module Chingu
|
|
247
272
|
def disconnect_client(socket)
|
248
273
|
socket.close
|
249
274
|
end
|
275
|
+
|
276
|
+
# Ensure that the buffer is cleared of data to write (call at the end of update or, at least after all sends).
|
277
|
+
def flush
|
278
|
+
@sockets.each {|s| s.flush }
|
279
|
+
end
|
250
280
|
|
251
281
|
#
|
252
282
|
# Stops server
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Chingu -- OpenGL accelerated 2D game framework for Ruby
|
4
|
+
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
20
|
+
#++
|
21
|
+
|
22
|
+
require 'forwardable'
|
23
|
+
|
24
|
+
module Chingu
|
25
|
+
module Helpers
|
26
|
+
|
27
|
+
#
|
28
|
+
# Convenience-methods for classes that have an FPS counter
|
29
|
+
# Mixed into Chingu::Window and Chingu::Console
|
30
|
+
#
|
31
|
+
module FPSCounter
|
32
|
+
extend Forwardable
|
33
|
+
def_delegator :@fps_counter, :ticks
|
34
|
+
def_delegators :@fps_counter, :fps, :framerate # TODO: switch to Gosu::fps
|
35
|
+
def_delegators :@fps_counter, :dt, :milliseconds_since_last_tick
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -1,135 +1,121 @@
|
|
1
|
-
#--
|
2
|
-
#
|
3
|
-
# Chingu -- OpenGL accelerated 2D game framework for Ruby
|
4
|
-
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
5
|
-
#
|
6
|
-
# This library is free software; you can redistribute it and/or
|
7
|
-
# modify it under the terms of the GNU Lesser General Public
|
8
|
-
# License as published by the Free Software Foundation; either
|
9
|
-
# version 2.1 of the License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# This library is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# Lesser General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU Lesser General Public
|
17
|
-
# License along with this library; if not, write to the Free Software
|
18
|
-
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
-
#
|
20
|
-
#++
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def
|
47
|
-
@game_objects.
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
attr_hash[attr] = game_object.send(attr)
|
122
|
-
rescue NoMethodError
|
123
|
-
# silently ignore attributes that doesn't exist on the particular game object
|
124
|
-
end
|
125
|
-
end
|
126
|
-
objects << {game_object.class.to_s => attr_hash}
|
127
|
-
end
|
128
|
-
|
129
|
-
File.open(file, 'w') { |out| YAML.dump(objects, out) }
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Chingu -- OpenGL accelerated 2D game framework for Ruby
|
4
|
+
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
20
|
+
#++
|
21
|
+
|
22
|
+
require 'forwardable'
|
23
|
+
|
24
|
+
module Chingu
|
25
|
+
module Helpers
|
26
|
+
|
27
|
+
#
|
28
|
+
# Convenience-methods for classes that hold game objects
|
29
|
+
# Mixed into Chingu::Window and Chingu::GameState
|
30
|
+
#
|
31
|
+
module GameObject
|
32
|
+
extend Forwardable
|
33
|
+
|
34
|
+
attr_reader :game_objects
|
35
|
+
|
36
|
+
def_delegator :@game_objects, :add_game_object
|
37
|
+
def_delegator :@game_objects, :remove_game_object
|
38
|
+
def_delegator :@game_objects, :show_game_object
|
39
|
+
def_delegator :@game_objects, :hide_game_object
|
40
|
+
def_delegator :@game_objects, :pause_game_object
|
41
|
+
def_delegator :@game_objects, :unpause_game_object
|
42
|
+
|
43
|
+
#
|
44
|
+
# Fetch game objects of a certain type/class
|
45
|
+
#
|
46
|
+
def game_objects_of_class(klass)
|
47
|
+
@game_objects.select { |game_object| game_object.is_a? klass }
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Creates game objects from a Chingu-spezed game objects file (created with game state 'Edit')
|
52
|
+
#
|
53
|
+
def load_game_objects(options = {})
|
54
|
+
file = options[:file] || self.filename + ".yml"
|
55
|
+
debug = options[:debug]
|
56
|
+
except = Array(options[:except]) || []
|
57
|
+
|
58
|
+
require 'yaml'
|
59
|
+
|
60
|
+
puts "* Loading game objects from #{file}" if debug
|
61
|
+
if File.exists?(file)
|
62
|
+
objects = YAML.load_file(file)
|
63
|
+
objects.each do |object|
|
64
|
+
object.each_pair do |klassname, attributes|
|
65
|
+
begin
|
66
|
+
klass = Kernel::const_get(klassname)
|
67
|
+
unless klass.class == "GameObject" && !except.include?(klass)
|
68
|
+
puts "Creating #{klassname.to_s}: #{attributes.to_s}" if debug
|
69
|
+
object = klass.create(attributes)
|
70
|
+
object.options[:created_with_editor] = true if object.options
|
71
|
+
end
|
72
|
+
rescue
|
73
|
+
puts "Couldn't create class '#{klassname}'"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Save given game_objects to a file. Hashoptions
|
82
|
+
#
|
83
|
+
# :file - a String, name of file to write to, default is current game_state class name.
|
84
|
+
# :game_objects - an Array, game objects to save
|
85
|
+
# :classes - an Array, save only game objects of theese classes
|
86
|
+
#
|
87
|
+
# NOTE: To save a color do: :color => game_object.color.argb
|
88
|
+
#
|
89
|
+
def save_game_objects(options = {})
|
90
|
+
#
|
91
|
+
# TODO: Move this to GameObjectList#save ?
|
92
|
+
#
|
93
|
+
file = options[:file] || "#{self.class.to_s.downcase}.yml"
|
94
|
+
game_objects = options[:game_objects]
|
95
|
+
classes = options[:classes]
|
96
|
+
attributes = options[:attributes] || [:x, :y, :angle, :zorder, :factor_x, :factor_y, :alpha]
|
97
|
+
|
98
|
+
require 'yaml'
|
99
|
+
objects = []
|
100
|
+
game_objects.each do |game_object|
|
101
|
+
# Only save specified classes, if given.
|
102
|
+
next if classes and !classes.empty? and !classes.include?(game_object.class)
|
103
|
+
|
104
|
+
attr_hash = {}
|
105
|
+
attributes.each do |attr|
|
106
|
+
begin
|
107
|
+
attr_hash[attr] = game_object.send(attr)
|
108
|
+
rescue NoMethodError
|
109
|
+
# silently ignore attributes that doesn't exist on the particular game object
|
110
|
+
end
|
111
|
+
end
|
112
|
+
objects << {game_object.class.to_s => attr_hash}
|
113
|
+
end
|
114
|
+
|
115
|
+
File.open(file, 'w') { |out| YAML.dump(objects, out) }
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
135
121
|
end
|
@@ -19,6 +19,7 @@
|
|
19
19
|
#
|
20
20
|
#++
|
21
21
|
|
22
|
+
require 'forwardable'
|
22
23
|
|
23
24
|
module Chingu
|
24
25
|
module Helpers
|
@@ -29,33 +30,14 @@ module Chingu
|
|
29
30
|
# It will make call new() on a class, and just push an object.
|
30
31
|
#
|
31
32
|
module GameState
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def pop_game_state(options = {})
|
41
|
-
game_state_manager.pop_game_state(options)
|
42
|
-
end
|
43
|
-
|
44
|
-
def switch_game_state(state, options = {})
|
45
|
-
game_state_manager.switch_game_state(state, options)
|
46
|
-
end
|
47
|
-
|
48
|
-
def transitional_game_state(state, options = {})
|
49
|
-
game_state_manager.transitional_game_state(state, options)
|
50
|
-
end
|
51
|
-
|
52
|
-
def current_game_state
|
53
|
-
game_state_manager.current_game_state
|
54
|
-
end
|
55
|
-
|
56
|
-
def clear_game_states
|
57
|
-
game_state_manager.clear_game_states
|
58
|
-
end
|
33
|
+
extend Forwardable
|
34
|
+
def_delegator :game_state_manager, :game_states
|
35
|
+
def_delegator :game_state_manager, :push_game_state
|
36
|
+
def_delegator :game_state_manager, :pop_game_state
|
37
|
+
def_delegator :game_state_manager, :switch_game_state
|
38
|
+
def_delegator :game_state_manager, :transitional_game_state
|
39
|
+
def_delegator :game_state_manager, :current_game_state
|
40
|
+
def_delegator :game_state_manager, :clear_game_states
|
59
41
|
end
|
60
42
|
|
61
43
|
end
|
data/lib/chingu/helpers/gfx.rb
CHANGED
@@ -27,7 +27,7 @@ module Chingu
|
|
27
27
|
# All drawings depend on the global variable $window which should be an instance of Gosu::Window or Chingu::Window
|
28
28
|
#
|
29
29
|
module GFX
|
30
|
-
|
30
|
+
|
31
31
|
#
|
32
32
|
# Fills whole window with specified 'color' and 'zorder'
|
33
33
|
#
|
@@ -48,52 +48,33 @@ module Chingu
|
|
48
48
|
# :orientation - Either :vertical (top to bottom) or :horizontal (left to right)
|
49
49
|
#
|
50
50
|
|
51
|
-
def fill(
|
51
|
+
def fill(material, zorder = 0, mode = :default)
|
52
52
|
#
|
53
53
|
# if only 1 color-argument is given, assume fullscreen simple color fill.
|
54
54
|
#
|
55
|
-
if
|
56
|
-
|
57
|
-
|
58
|
-
$window.width, $window.height, options,
|
59
|
-
0, $window.height, options, zorder, :default)
|
55
|
+
if material.is_a?(Gosu::Color)
|
56
|
+
rect = Rect.new([0, 0, $window.width, $window.height])
|
57
|
+
_fill_rect(rect, material, material, material, material, zorder, mode)
|
60
58
|
else
|
61
|
-
fill_gradient(
|
59
|
+
fill_gradient(material)
|
62
60
|
end
|
63
61
|
end
|
64
62
|
|
65
63
|
#
|
66
64
|
# Draws an unfilled rect in given color
|
67
65
|
#
|
68
|
-
def draw_rect(rect, color, zorder)
|
69
|
-
|
70
|
-
|
71
|
-
$window.draw_line(rect.right, rect.bottom, color, rect.x, rect.bottom, color, zorder)
|
72
|
-
$window.draw_line(rect.x, rect.bottom, color, rect.x, rect.y, color, zorder)
|
66
|
+
def draw_rect(rect, color, zorder = 0, mode = :default)
|
67
|
+
rect = Rect.new(rect) unless rect.is_a? Rect
|
68
|
+
_stroke_rect(rect, color, color, color, color, zorder, mode)
|
73
69
|
end
|
74
70
|
|
75
71
|
|
76
|
-
#
|
77
|
-
# Draws an unfilled circle, thanks shawn24!
|
78
|
-
#
|
79
|
-
CIRCLE_STEP = 10
|
80
|
-
def draw_circle(cx,cy,r,color)
|
81
|
-
0.step(360, CIRCLE_STEP) do |a1|
|
82
|
-
a2 = a1 + CIRCLE_STEP
|
83
|
-
$window.draw_line cx + Gosu.offset_x(a1, r), cy + Gosu.offset_y(a1, r), color, cx + Gosu.offset_x(a2, r), cy + Gosu.offset_y(a2, r), color, 9999
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
72
|
#
|
88
73
|
# Fills a given Rect 'rect' with Color 'color', drawing with zorder 'zorder'
|
89
74
|
#
|
90
|
-
def fill_rect(rect, color, zorder = 0)
|
91
|
-
rect = Rect.new(rect)
|
92
|
-
|
93
|
-
rect.right, rect.y, color,
|
94
|
-
rect.right, rect.bottom, color,
|
95
|
-
rect.x, rect.bottom, color,
|
96
|
-
zorder, :default)
|
75
|
+
def fill_rect(rect, color, zorder = 0, mode = :default)
|
76
|
+
rect = Rect.new(rect) unless rect.is_a? Rect
|
77
|
+
_fill_rect(rect, color, color, color, color, zorder, mode)
|
97
78
|
end
|
98
79
|
|
99
80
|
#
|
@@ -105,46 +86,147 @@ module Chingu
|
|
105
86
|
# :orientation - Either :vertical (top to bottom) or :horizontal (left to right)
|
106
87
|
#
|
107
88
|
def fill_gradient(options)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
}
|
116
|
-
options = default_options.merge(options)
|
89
|
+
options = { :from => Gosu::Color::BLACK,
|
90
|
+
:to => Gosu::Color::WHITE,
|
91
|
+
:orientation => :vertical,
|
92
|
+
:rect => [0, 0, $window.width, $window.height],
|
93
|
+
:zorder => 0,
|
94
|
+
:mode => :default
|
95
|
+
}.merge!(options)
|
117
96
|
|
118
97
|
rect = Rect.new(options[:rect])
|
119
98
|
colors = options[:colors] || options.values_at(:from, :to)
|
99
|
+
zorder = options[:zorder]
|
100
|
+
mode = options[:mode]
|
120
101
|
|
121
102
|
case options[:orientation]
|
122
103
|
when :vertical
|
123
104
|
rect.height /= colors.count - 1
|
124
105
|
colors.each_cons(2) do |from, to|
|
125
|
-
|
126
|
-
rect.right, rect.top, from,
|
127
|
-
rect.right, rect.bottom, to,
|
128
|
-
rect.left, rect.bottom, to,
|
129
|
-
options[:zorder], options[:mode]
|
130
|
-
)
|
106
|
+
_fill_rect(rect, from, to, to, from, zorder, mode)
|
131
107
|
rect.top += rect.height
|
132
108
|
end
|
133
109
|
when :horizontal
|
134
110
|
rect.width /= colors.count - 1
|
135
111
|
colors.each_cons(2) do |from, to|
|
136
|
-
|
137
|
-
rect.left, rect.bottom, from,
|
138
|
-
rect.right, rect.bottom, to,
|
139
|
-
rect.right, rect.top, to,
|
140
|
-
options[:zorder], options[:mode]
|
141
|
-
)
|
112
|
+
_fill_rect(rect, from, from, to, to, zorder, mode)
|
142
113
|
rect.left += rect.width
|
143
114
|
end
|
144
115
|
else
|
145
116
|
raise ArgumentError, "bad gradient orientation: #{options[:orientation]}"
|
146
117
|
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Draws an unfilled circle, thanks shawn24!
|
123
|
+
#
|
124
|
+
def draw_circle(cx, cy, r, color, zorder = 0, mode = :default)
|
125
|
+
draw_arc(cx, cy, r, 0, 360, color, zorder, mode)
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Draws an unfilled arc from a1 to a2
|
130
|
+
#
|
131
|
+
def draw_arc(cx, cy, r, from, to, color, zorder = 0, mode = :default)
|
132
|
+
from, to = to, from if from > to
|
133
|
+
$window.translate(cx, cy) do
|
134
|
+
$window.scale(r) do
|
135
|
+
detail = _circle_segments(r)
|
136
|
+
_walk_arc(from, to, detail) do |x1, y1, x2, y2|
|
137
|
+
$window.draw_line(x1, y1, color,
|
138
|
+
x2, y2, color,
|
139
|
+
zorder, mode)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Draws a filled circle
|
147
|
+
#
|
148
|
+
def fill_circle(cx, cy, r, color, zorder = 0, mode = :default)
|
149
|
+
fill_arc(cx, cy, r, 0, 360, color, zorder, mode)
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Draws a filled arc from a1 to a2
|
154
|
+
#
|
155
|
+
def fill_arc(cx, cy, r, from, to, color, zorder = 0, mode = :default)
|
156
|
+
from, to = to, from if from > to
|
157
|
+
$window.translate(cx, cy) do
|
158
|
+
$window.scale(r) do
|
159
|
+
detail = _circle_segments(r)
|
160
|
+
_walk_arc(from, to, detail) do |x1, y1, x2, y2|
|
161
|
+
$window.draw_triangle(0, 0, color,
|
162
|
+
x1, y1, color,
|
163
|
+
x2, y2, color,
|
164
|
+
zorder, mode)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
147
168
|
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def _fill_rect(rect, color_a, color_b, color_c, color_d, zorder, mode)
|
173
|
+
left, top = *rect.topleft
|
174
|
+
right, bottom = *rect.bottomright
|
175
|
+
$window.draw_quad(left, top, color_a,
|
176
|
+
left, bottom, color_b,
|
177
|
+
right, bottom, color_c,
|
178
|
+
right, top, color_d,
|
179
|
+
zorder, mode)
|
180
|
+
end
|
181
|
+
|
182
|
+
def _stroke_rect(rect, color_a, color_b, color_c, color_d, zorder, mode)
|
183
|
+
left, top = *rect.topleft
|
184
|
+
right, bottom = *rect.bottomright
|
185
|
+
$window.draw_line(left, top, color_a, left, bottom, color_b, zorder, mode)
|
186
|
+
$window.draw_line(left, bottom, color_b, right, bottom, color_c, zorder, mode)
|
187
|
+
$window.draw_line(right, bottom, color_c, right, top, color_d, zorder, mode)
|
188
|
+
$window.draw_line(right, top, color_d, left, top, color_a, zorder, mode)
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Calculates a reasonable number of segments for a circle of the given
|
193
|
+
# radius. Forgive the use of a magic number.
|
194
|
+
#
|
195
|
+
# Adapted from SiegeLord's "An Efficient Way to Draw Approximate Circles
|
196
|
+
# in OpenGL" <http://slabode.exofire.net/circle_draw.shtml>.
|
197
|
+
#
|
198
|
+
def _circle_segments(r)
|
199
|
+
10 * Math.sqrt(r)
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Appriximates an arc as a series of line segments and passes each segment
|
204
|
+
# to the block. Makes clever use of a transformation matrix to avoid
|
205
|
+
# repeated calls to sin and cos.
|
206
|
+
#
|
207
|
+
# Adapted from SiegeLord's "An Efficient Way to Draw Approximate Circles
|
208
|
+
# in OpenGL" <http://slabode.exofire.net/circle_draw.shtml>.
|
209
|
+
#
|
210
|
+
def _walk_arc(from, to, detail, &block)
|
211
|
+
walk_segments = ((to - from).to_f * (detail - 1) / 360).floor
|
212
|
+
|
213
|
+
theta = 2 * Math::PI / detail
|
214
|
+
c = Math.cos(theta)
|
215
|
+
s = Math.sin(theta)
|
216
|
+
|
217
|
+
x1 = Gosu.offset_x(from, 1)
|
218
|
+
y1 = Gosu.offset_y(from, 1)
|
219
|
+
|
220
|
+
0.upto(walk_segments) do
|
221
|
+
x2 = c * x1 - s * y1
|
222
|
+
y2 = s * x1 + c * y1
|
223
|
+
|
224
|
+
block[x1, y1, x2, y2]
|
225
|
+
|
226
|
+
x1, y1 = x2, y2
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
148
230
|
end
|
149
231
|
|
150
232
|
end
|
data/lib/chingu/window.rb
CHANGED
@@ -32,6 +32,7 @@ module Chingu
|
|
32
32
|
# - Tracking of button_up/button_down etc to enable Chingus pretty inputhandling
|
33
33
|
#
|
34
34
|
class Window < Gosu::Window
|
35
|
+
include Chingu::Helpers::FPSCounter # Adds FPSCounter delegators
|
35
36
|
include Chingu::Helpers::GFX # Adds fill(), fade() etc to each game state
|
36
37
|
include Chingu::Helpers::GameState # Easy access to the global game state-queue
|
37
38
|
include Chingu::Helpers::GameObject # Adds game_objects_of_class etc ...
|
@@ -96,28 +97,6 @@ module Chingu
|
|
96
97
|
game_state_manager.inside_state || game_state_manager.current_game_state || self
|
97
98
|
end
|
98
99
|
|
99
|
-
#
|
100
|
-
# Frames per second, access with $window.fps or $window.framerate
|
101
|
-
#
|
102
|
-
def fps
|
103
|
-
@fps_counter.fps # TODO: switch to Gosu::fps
|
104
|
-
end
|
105
|
-
alias :framerate :fps
|
106
|
-
|
107
|
-
#
|
108
|
-
# Total amount of game iterations (ticks)
|
109
|
-
#
|
110
|
-
def ticks
|
111
|
-
@fps_counter.ticks
|
112
|
-
end
|
113
|
-
|
114
|
-
#
|
115
|
-
# Mathematical short name for "milliseconds since last tick"
|
116
|
-
#
|
117
|
-
def dt
|
118
|
-
@milliseconds_since_last_tick
|
119
|
-
end
|
120
|
-
|
121
100
|
#
|
122
101
|
# Chingus core-logic / loop. Gosu will call this each game-iteration.
|
123
102
|
#
|
@@ -216,4 +195,4 @@ module Chingu
|
|
216
195
|
$window = nil
|
217
196
|
end
|
218
197
|
end
|
219
|
-
end
|
198
|
+
end
|
data/spec/chingu/network_spec.rb
CHANGED
@@ -6,7 +6,8 @@ def data_set
|
|
6
6
|
"a String" => ["Woof!"],
|
7
7
|
"an Array" => [[1, 2, 3]],
|
8
8
|
"a stream of packets" => [{ :foo => :bar }, "Woof!", [1, 2, 3]],
|
9
|
-
"huge packet" => [[:frogspawn] * 1000]
|
9
|
+
"huge packet" => [[:frogspawn] * 1000],
|
10
|
+
"100 small packets" => 100.times.map { rand(100000) },
|
10
11
|
}
|
11
12
|
end
|
12
13
|
|
@@ -94,15 +95,13 @@ module Chingu
|
|
94
95
|
it "should send/recv #{name}" do
|
95
96
|
@server.update # Accept the clients, so know about their existence to broadcast.
|
96
97
|
|
97
|
-
# Data should be cached.
|
98
|
-
data.each {|packet| @server.broadcast_msg(packet) }
|
99
|
-
|
100
98
|
data.each do |packet|
|
101
99
|
@client.should_receive(:on_msg).with(packet)
|
102
100
|
@client2.should_receive(:on_msg).with(packet)
|
103
101
|
end
|
104
102
|
|
105
|
-
@server.
|
103
|
+
data.each {|packet| @server.broadcast_msg(packet) }
|
104
|
+
|
106
105
|
@client.update
|
107
106
|
@client2.update
|
108
107
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chingu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9rc4
|
5
5
|
prerelease: 3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-03-07 00:00:00.000000000 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: gosu
|
17
|
-
requirement: &
|
17
|
+
requirement: &25121820 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 0.7.27.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *25121820
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec
|
28
|
-
requirement: &
|
28
|
+
requirement: &25121472 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 2.1.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *25121472
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: watchr
|
39
|
-
requirement: &
|
39
|
+
requirement: &25120920 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *25120920
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rcov
|
50
|
-
requirement: &
|
50
|
+
requirement: &25120464 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *25120464
|
59
59
|
description: OpenGL accelerated 2D game framework for Ruby. Builds on Gosu (Ruby/C++)
|
60
60
|
which provides all the core functionality. Chingu adds simple yet powerful game
|
61
61
|
states, prettier input handling, deployment safe asset-handling, a basic re-usable
|
@@ -201,6 +201,7 @@ files:
|
|
201
201
|
- lib/chingu/game_states/popup.rb
|
202
202
|
- lib/chingu/gosu_ext/image.rb
|
203
203
|
- lib/chingu/helpers/class_inheritable_accessor.rb
|
204
|
+
- lib/chingu/helpers/fps_counter.rb
|
204
205
|
- lib/chingu/helpers/game_object.rb
|
205
206
|
- lib/chingu/helpers/game_state.rb
|
206
207
|
- lib/chingu/helpers/gfx.rb
|