chingu 0.7.5 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +60 -14
- data/Rakefile +1 -1
- data/chingu.gemspec +16 -6
- data/examples/example14_bounding_box_circle.rb +8 -1
- data/examples/{example19_game_objects.yml → example19.yml} +1014 -4
- data/examples/example19_edit_viewport.rb +34 -8
- data/examples/example21.yml +2145 -0
- data/examples/example21_sidescroller_with_edit.rb +298 -0
- data/examples/game_of_life.rb +3 -3
- data/examples/media/battery.png +0 -0
- data/examples/media/big_star.png +0 -0
- data/examples/media/big_stone_wall.bmp +0 -0
- data/examples/media/black_block.png +0 -0
- data/examples/media/cog_wheel.png +0 -0
- data/examples/media/saw.png +0 -0
- data/examples/media/tube.png +0 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/animation.rb +8 -3
- data/lib/chingu/basic_game_object.rb +3 -1
- data/lib/chingu/game_object.rb +23 -11
- data/lib/chingu/game_state.rb +11 -0
- data/lib/chingu/game_states/edit.rb +405 -137
- data/lib/chingu/helpers/game_object.rb +15 -9
- data/lib/chingu/input.rb +2 -2
- data/lib/chingu/traits/animation.rb +5 -4
- data/lib/chingu/traits/bounding_box.rb +9 -4
- data/lib/chingu/traits/bounding_circle.rb +2 -0
- data/lib/chingu/traits/collision_detection.rb +32 -16
- data/lib/chingu/traits/velocity.rb +37 -19
- data/lib/chingu/traits/viewport.rb +1 -0
- data/lib/chingu/viewport.rb +10 -5
- metadata +18 -8
@@ -29,40 +29,93 @@ module Chingu
|
|
29
29
|
#
|
30
30
|
# requires the global $window set to the instance of Gosu::Window (automaticly handled if you use Chingu::Window)
|
31
31
|
#
|
32
|
+
# Edit will only edit game objects created with the editor itself or that's been loaded with load_game_objects.
|
33
|
+
# This makes mixing of loaded game objects and code create game objects possible, in the game, and in the editor.
|
34
|
+
#
|
35
|
+
# Various shortcuts are available in the editor
|
36
|
+
#
|
37
|
+
# 1-5: create object 1..5 shown in toolbar
|
38
|
+
# DEL: delete selected objects
|
39
|
+
# CTRL+A: select all objects (not code-created ones though)
|
40
|
+
# S: Save
|
41
|
+
# E: Save and Quit
|
42
|
+
# Right Mouse Button Click: Copy object that was clicked on for fast duplication
|
43
|
+
# Arrows: Scroll within a viewport
|
44
|
+
# Page up/down: Modify the zorder of selected game objects
|
45
|
+
#
|
32
46
|
class Edit < Chingu::GameState
|
47
|
+
attr_accessor :grid, :debug, :file, :hud_color
|
48
|
+
attr_reader :classes, :exclude
|
33
49
|
|
34
50
|
def initialize(options = {})
|
35
51
|
super
|
36
52
|
@grid = options[:grid] || [8,8]
|
37
|
-
@classes = options[:classes] ||
|
38
|
-
@
|
53
|
+
@classes = Array(options[:classes] || game_object_classes)
|
54
|
+
@except = options[:except] || []
|
55
|
+
@classes -= Array(@except)
|
56
|
+
|
39
57
|
@debug = options[:debug]
|
40
|
-
@file = options[:file] || "#{previous_game_state.class.to_s.downcase}.yml"
|
41
58
|
@zorder = 10000
|
42
|
-
|
43
|
-
@hud_color = Gosu::Color.new(
|
59
|
+
|
60
|
+
@hud_color = Gosu::Color.new(180,70,70,70)
|
44
61
|
@selected_game_object = nil
|
45
|
-
self.input = {
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
self.input = {
|
63
|
+
:left_mouse_button => :left_mouse_button,
|
64
|
+
:released_left_mouse_button => :released_left_mouse_button,
|
65
|
+
:right_mouse_button => :right_mouse_button,
|
66
|
+
:released_right_mouse_button => :released_right_mouse_button,
|
67
|
+
|
68
|
+
:delete => :destroy_selected_game_objects,
|
69
|
+
:backspace => :reset_selected_game_objects,
|
70
|
+
|
71
|
+
:holding_numpad_7 => :scale_down,
|
72
|
+
:holding_numpad_9 => :scale_up,
|
73
|
+
:holding_numpad_4 => :tilt_left,
|
74
|
+
:holding_numpad_8 => :tilt_right,
|
75
|
+
:holding_numpad_1 => :dec_alpha,
|
76
|
+
:holding_numpad_3 => :inc_alpha,
|
77
|
+
|
78
|
+
:r => :scale_up,
|
79
|
+
:f => :scale_down,
|
80
|
+
:t => :tilt_left,
|
81
|
+
:g => :tilt_right,
|
82
|
+
:y => :inc_zorder,
|
83
|
+
:h => :dec_zorder,
|
84
|
+
:u => :inc_alpha,
|
85
|
+
:j => :dec_alpha,
|
86
|
+
|
87
|
+
:page_up => :inc_zorder,
|
88
|
+
:page_down => :dec_zorder,
|
89
|
+
|
90
|
+
:s => :try_save,
|
91
|
+
:a => :try_select_all,
|
92
|
+
|
93
|
+
:e => :save_and_quit,
|
94
|
+
|
95
|
+
:esc => :esc,
|
96
|
+
:q => :quit,
|
97
|
+
|
98
|
+
:up_arrow => :move_up,
|
99
|
+
:down_arrow => :move_down,
|
100
|
+
:left_arrow => :move_left,
|
101
|
+
:right_arrow => :move_right,
|
102
|
+
|
103
|
+
:holding_up_arrow => :try_scroll_up,
|
104
|
+
:holding_down_arrow => :try_scroll_down,
|
105
|
+
:holding_left_arrow => :try_scroll_left,
|
106
|
+
:holding_right_arrow => :try_scroll_right,
|
107
|
+
|
108
|
+
:plus => :scale_up,
|
109
|
+
:minus => :scale_down,
|
110
|
+
:mouse_wheel_up => :mouse_wheel_up,
|
111
|
+
:mouse_wheel_down => :mouse_wheel_down,
|
112
|
+
|
113
|
+
:"1" => :create_object_1,
|
114
|
+
:"2" => :create_object_2,
|
115
|
+
:"3" => :create_object_3,
|
116
|
+
:"4" => :create_object_4,
|
117
|
+
:"5" => :create_object_5,
|
118
|
+
}
|
66
119
|
|
67
120
|
x = 20
|
68
121
|
y = 60
|
@@ -71,71 +124,37 @@ module Chingu
|
|
71
124
|
|
72
125
|
# We initialize x,y,zorder,rotation_center after creation
|
73
126
|
# so they're not overwritten by the class initialize/setup or simular
|
74
|
-
game_object = klass.create
|
127
|
+
game_object = klass.create(:paused => true)
|
75
128
|
game_object.x = x
|
76
129
|
game_object.y = y
|
77
130
|
game_object.zorder = @zorder
|
131
|
+
game_object.options[:toolbar] = true
|
78
132
|
|
79
133
|
# Scale down big objects, don't scale objects under [32, 32]
|
80
134
|
if game_object.image
|
81
|
-
game_object.factor_x = 32 / game_object.image.width if game_object.image.width > 32
|
82
|
-
game_object.factor_y = 32 / game_object.image.height if game_object.image.height >
|
83
|
-
|
135
|
+
game_object.factor_x = 32.0 / game_object.image.width if game_object.image.width > 32
|
136
|
+
game_object.factor_y = 32.0 / game_object.image.height if game_object.image.height > 3
|
137
|
+
game_object.cache_bounding_box if game_object.respond_to?(:bounding_box)
|
138
|
+
end
|
84
139
|
x += 40
|
85
140
|
end
|
86
141
|
end
|
87
|
-
|
88
|
-
|
142
|
+
|
143
|
+
#
|
144
|
+
# SETUP
|
145
|
+
#
|
146
|
+
def setup
|
147
|
+
@scroll_border_thickness = 50
|
148
|
+
@file = options[:file] || previous_game_state.filename + ".yml"
|
89
149
|
@title = Text.create("File: #{@file}", :x => 5, :y => 2, :factor => 1, :size => 16, :zorder => @zorder)
|
90
150
|
@title.text += " - Grid: #{@grid}" if @grid
|
91
|
-
@text = Text.create("", :x =>
|
151
|
+
@text = Text.create("", :x => 300, :y => 20, :factor => 1, :size => 16, :zorder => @zorder)
|
92
152
|
@status_text = Text.create("-", :x => 5, :y => 20, :factor => 1, :size => 16, :zorder => @zorder)
|
93
|
-
#@title2 = Text.create("(1-10) Create object at mouse pos (DEL) Delete selected object (S) Save (E) Save and Quit (ESC) Quit without saving", :x => 5, :y => 30, :factor => 1)
|
94
|
-
end
|
95
|
-
|
96
|
-
def create_object_nr(number)
|
97
|
-
c = @classes[number].create(:x => x, :y => y, :parent => previous_game_state) if @classes[number]
|
98
|
-
c.update
|
99
|
-
#@text.text = "Created a #{c.class} @ #{c.x} / #{c.y}"
|
100
|
-
end
|
101
|
-
|
102
|
-
def create_object_1; create_object_nr(0); end
|
103
|
-
def create_object_2; create_object_nr(1); end
|
104
|
-
def create_object_3; create_object_nr(2); end
|
105
|
-
def create_object_4; create_object_nr(3); end
|
106
|
-
def create_object_5; create_object_nr(4); end
|
107
|
-
|
108
|
-
def draw
|
109
|
-
# Draw prev game state onto screen (the level we're editing)
|
110
|
-
previous_game_state.draw
|
111
|
-
|
112
|
-
super
|
113
|
-
|
114
|
-
#
|
115
|
-
# Draw an edit HUD
|
116
|
-
#
|
117
|
-
$window.draw_quad( 0,0,@hud_color,
|
118
|
-
$window.width,0,@hud_color,
|
119
|
-
$window.width,100,@hud_color,
|
120
|
-
0,100,@hud_color, @zorder-1)
|
121
|
-
|
122
|
-
#
|
123
|
-
# Draw red rectangles/circles around all selected game objects
|
124
|
-
#
|
125
|
-
selected_game_objects.each { |game_object| game_object.draw_debug }
|
126
|
-
|
127
|
-
if @cursor_game_object
|
128
|
-
@cursor_game_object.draw_at($window.mouse_x, $window.mouse_y)
|
129
|
-
else
|
130
|
-
#
|
131
|
-
# draw a simple triagle-shaped cursor
|
132
|
-
#
|
133
|
-
$window.draw_triangle( $window.mouse_x, $window.mouse_y, Color::WHITE,
|
134
|
-
$window.mouse_x, $window.mouse_y + 10, Color::WHITE,
|
135
|
-
$window.mouse_x + 10, $window.mouse_y + 10, Color::WHITE, @zorder + 10)
|
136
|
-
end
|
137
153
|
end
|
138
|
-
|
154
|
+
|
155
|
+
#
|
156
|
+
# UPDATE
|
157
|
+
#
|
139
158
|
def update
|
140
159
|
# Sync all changes to previous game states game objects list
|
141
160
|
# This is needed since we don't call update on it.
|
@@ -143,11 +162,11 @@ module Chingu
|
|
143
162
|
|
144
163
|
super
|
145
164
|
|
146
|
-
#
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
@text.text
|
165
|
+
@status_text.text = "#{self.mouse_x} / #{self.mouse_y}"
|
166
|
+
|
167
|
+
if s = @selected_game_object
|
168
|
+
@text.text = "#{s.class.to_s} @ #{s.x.to_i} / #{s.y.to_i}"
|
169
|
+
@text.text += " [Scale: #{sprintf("%.2f", s.factor_x)}/#{sprintf("%.2f", s.factor_y)} Angle: #{s.angle.to_i} Z: #{s.zorder}]"
|
151
170
|
end
|
152
171
|
|
153
172
|
#
|
@@ -155,8 +174,8 @@ module Chingu
|
|
155
174
|
#
|
156
175
|
if @left_mouse_button && @selected_game_object
|
157
176
|
selected_game_objects.each do |selected_game_object|
|
158
|
-
selected_game_object.x = self.
|
159
|
-
selected_game_object.y = self.
|
177
|
+
selected_game_object.x = self.mouse_x + selected_game_object.options[:mouse_x_offset]
|
178
|
+
selected_game_object.y = self.mouse_y + selected_game_object.options[:mouse_y_offset]
|
160
179
|
selected_game_object.x -= selected_game_object.x % @grid[0]
|
161
180
|
selected_game_object.y -= selected_game_object.y % @grid[1]
|
162
181
|
end
|
@@ -166,68 +185,110 @@ module Chingu
|
|
166
185
|
@selected_game_object.bounding_box.x = @selected_game_object.x
|
167
186
|
@selected_game_object.bounding_box.y = @selected_game_object.y
|
168
187
|
end
|
188
|
+
elsif @left_mouse_button
|
189
|
+
if defined?(self.previous_game_state.viewport)
|
190
|
+
self.previous_game_state.viewport.x = @left_mouse_click_at[0] - $window.mouse_x
|
191
|
+
self.previous_game_state.viewport.y = @left_mouse_click_at[1] - $window.mouse_y
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
if inside_window?($window.mouse_x, $window.mouse_y)
|
196
|
+
scroll_right if $window.mouse_x > $window.width - @scroll_border_thickness
|
197
|
+
scroll_left if $window.mouse_x < @scroll_border_thickness
|
198
|
+
scroll_up if $window.mouse_y < @scroll_border_thickness
|
199
|
+
scroll_down if $window.mouse_y > $window.height - @scroll_border_thickness
|
169
200
|
end
|
170
201
|
|
171
|
-
@status_text.text = "Mouseposition: #{x} / #{y}"
|
172
|
-
end
|
173
|
-
|
174
|
-
def selected_game_objects
|
175
|
-
previous_game_state.game_objects.select { |o| o.options[:selected] }
|
176
202
|
end
|
177
203
|
|
178
|
-
|
179
|
-
|
204
|
+
#
|
205
|
+
# DRAW
|
206
|
+
#
|
207
|
+
def draw
|
208
|
+
# Draw prev game state onto screen (the level we're editing)
|
209
|
+
previous_game_state.draw
|
210
|
+
|
211
|
+
super
|
212
|
+
|
213
|
+
#
|
214
|
+
# Draw an edit HUD
|
215
|
+
#
|
216
|
+
$window.draw_quad( 0,0,@hud_color,
|
217
|
+
$window.width,0,@hud_color,
|
218
|
+
$window.width,100,@hud_color,
|
219
|
+
0,100,@hud_color, @zorder-1)
|
220
|
+
|
221
|
+
#
|
222
|
+
# Draw red rectangles/circles around all selected game objects
|
223
|
+
#
|
224
|
+
selected_game_objects.each { |game_object| game_object.draw_debug }
|
225
|
+
|
226
|
+
if @cursor_game_object
|
227
|
+
@cursor_game_object.draw_at($window.mouse_x, $window.mouse_y)
|
228
|
+
else
|
229
|
+
draw_cursor_at($window.mouse_x, $window.mouse_y)
|
230
|
+
end
|
180
231
|
end
|
181
|
-
|
232
|
+
|
182
233
|
#
|
183
234
|
# CLICKED LEFT MOUSE BUTTON
|
184
235
|
#
|
185
236
|
def left_mouse_button
|
186
|
-
@left_mouse_button
|
237
|
+
@left_mouse_button = true
|
238
|
+
@selected_game_object = false
|
187
239
|
|
188
|
-
if
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
game_object.x = x
|
193
|
-
game_object.y = y
|
240
|
+
if defined?(self.previous_game_state.viewport)
|
241
|
+
@left_mouse_click_at = [self.previous_game_state.viewport.x + $window.mouse_x, self.previous_game_state.viewport.y + $window.mouse_y]
|
242
|
+
else
|
243
|
+
@left_mouse_click_at = [$window.mouse_x, $window.mouse_y]
|
194
244
|
end
|
195
245
|
|
196
|
-
#
|
197
|
-
@selected_game_object =
|
246
|
+
# Put out a new game object in the editor window and select it right away
|
247
|
+
@selected_game_object = create_new_game_object_from(@cursor_game_object) if @cursor_game_object
|
198
248
|
|
199
249
|
# Check if user clicked on anything in the icon-toolbar of available game objects
|
200
250
|
@cursor_game_object = game_object_icon_at($window.mouse_x, $window.mouse_y)
|
201
|
-
|
251
|
+
|
252
|
+
# Get editable game object that was clicked at (if any)
|
253
|
+
@selected_game_object ||= game_object_at(self.mouse_x, self.mouse_y)
|
254
|
+
|
255
|
+
if @selected_game_object && defined?(self.previous_game_state.viewport)
|
256
|
+
self.previous_game_state.viewport.center_around(@selected_game_object) if @left_double_click
|
257
|
+
end
|
258
|
+
|
202
259
|
if @selected_game_object
|
203
260
|
#
|
204
261
|
# If clicking on a new object that's wasn't previosly selected
|
205
262
|
# --> deselect all objects unless holding left_ctrl
|
206
263
|
#
|
207
264
|
if @selected_game_object.options[:selected] == nil
|
208
|
-
selected_game_objects.each { |
|
265
|
+
selected_game_objects.each { |object| object.options[:selected] = nil } unless holding?(:left_ctrl)
|
209
266
|
end
|
210
267
|
|
211
|
-
@selected_game_object.options[:selected] =
|
268
|
+
@selected_game_object.options[:selected] = !@selected_game_object.options[:selected]
|
269
|
+
|
212
270
|
#
|
213
271
|
# Re-align all objects x/y offset in relevance to the cursor
|
214
272
|
#
|
215
273
|
selected_game_objects.each do |selected_game_object|
|
216
|
-
selected_game_object.options[:mouse_x_offset] = selected_game_object.x - self.
|
217
|
-
selected_game_object.options[:mouse_y_offset] = selected_game_object.y - self.
|
274
|
+
selected_game_object.options[:mouse_x_offset] = selected_game_object.x - self.mouse_x + 20
|
275
|
+
selected_game_object.options[:mouse_y_offset] = selected_game_object.y - self.mouse_y + 20
|
218
276
|
end
|
219
277
|
else
|
220
|
-
|
278
|
+
deselect_selected_game_objects unless holding?(:left_ctrl)
|
221
279
|
end
|
222
280
|
end
|
223
281
|
|
224
282
|
def right_mouse_button
|
225
|
-
@cursor_game_object
|
226
|
-
|
283
|
+
if @cursor_game_object
|
284
|
+
@cursor_game_object = nil
|
285
|
+
else
|
286
|
+
@cursor_game_object = game_object_at(self.mouse_x, self.mouse_y)
|
287
|
+
end
|
227
288
|
end
|
228
289
|
def released_right_mouse_button
|
229
290
|
end
|
230
|
-
|
291
|
+
|
231
292
|
#
|
232
293
|
# RELASED LEFT MOUSE BUTTON
|
233
294
|
#
|
@@ -235,66 +296,273 @@ module Chingu
|
|
235
296
|
@left_mouse_button = false
|
236
297
|
end
|
237
298
|
|
299
|
+
#
|
300
|
+
# Returns a list of game objects the editor can create. 2 types of object gets this flag:
|
301
|
+
# - An object loaded with load_game_objects
|
302
|
+
# - An object created from within the editor
|
303
|
+
#
|
304
|
+
# This helps us mix code-created with editor-created objects inside the editor and not muck around with
|
305
|
+
# the code-created ones.
|
306
|
+
#
|
307
|
+
def editable_game_objects
|
308
|
+
previous_game_state.game_objects.select { |o| o.options[:created_with_editor] }
|
309
|
+
end
|
310
|
+
|
311
|
+
#
|
312
|
+
# Returns a list of selected game objects
|
313
|
+
#
|
314
|
+
def selected_game_objects
|
315
|
+
editable_game_objects.select { |o| o.options[:selected] }
|
316
|
+
end
|
317
|
+
|
318
|
+
#
|
319
|
+
# Call destroy on all selected game objects
|
320
|
+
#
|
321
|
+
def destroy_selected_game_objects
|
322
|
+
selected_game_objects.each(&:destroy)
|
323
|
+
end
|
324
|
+
|
325
|
+
def deselect_selected_game_objects
|
326
|
+
selected_game_objects.each { |object| object.options[:selected] = nil }
|
327
|
+
end
|
328
|
+
|
329
|
+
def empty_area_at_cursor
|
330
|
+
game_object_at(self.mouse_x, self.mouse_y)==nil &&
|
331
|
+
game_object_icon_at($window.mouse_x, $window.mouse_y) == nil
|
332
|
+
end
|
333
|
+
|
334
|
+
#
|
335
|
+
# Get all classes based on GameObject except Chingus internal classes.
|
336
|
+
#
|
337
|
+
def game_object_classes
|
338
|
+
ObjectSpace.enum_for(:each_object, class << GameObject; self; end).to_a.select do |game_class|
|
339
|
+
game_class.instance_methods && !game_class.to_s.include?("Chingu::")
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def create_object_nr(number)
|
344
|
+
c = @classes[number].create(:x => self.mouse_x, :y => self.mouse_y, :parent => previous_game_state) if @classes[number]
|
345
|
+
c.options[:created_with_editor] = true
|
346
|
+
c.update
|
347
|
+
#@text.text = "Created a #{c.class} @ #{c.x} / #{c.y}"
|
348
|
+
end
|
349
|
+
|
350
|
+
def create_object_1; create_object_nr(0); end
|
351
|
+
def create_object_2; create_object_nr(1); end
|
352
|
+
def create_object_3; create_object_nr(2); end
|
353
|
+
def create_object_4; create_object_nr(3); end
|
354
|
+
def create_object_5; create_object_nr(4); end
|
355
|
+
|
356
|
+
#
|
357
|
+
# Resets selected game objects defaults, angle=0, scale=1.
|
358
|
+
#
|
359
|
+
def reset_selected_game_objects
|
360
|
+
selected_game_objects.each do |game_object|
|
361
|
+
game_object.angle = 0
|
362
|
+
game_object.scale = 1
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
238
366
|
def game_object_icon_at(x, y)
|
239
367
|
game_objects.select do |game_object|
|
240
368
|
game_object.respond_to?(:collision_at?) && game_object.collision_at?(x,y)
|
241
369
|
end.first
|
242
370
|
end
|
243
371
|
|
372
|
+
#
|
373
|
+
# Get editable object at X/Y .. if there's many objects at the same coordinate..
|
374
|
+
# .. get the one with highest zorder.
|
375
|
+
#
|
244
376
|
def game_object_at(x, y)
|
245
|
-
|
377
|
+
editable_game_objects.select do |game_object|
|
246
378
|
game_object.respond_to?(:collision_at?) && game_object.collision_at?(x,y)
|
247
|
-
end.first
|
379
|
+
end.sort {|x,y| y.zorder <=> x.zorder }.first
|
248
380
|
end
|
249
|
-
|
250
|
-
|
251
|
-
|
381
|
+
|
382
|
+
#
|
383
|
+
# draw a simple triangle-shaped cursor
|
384
|
+
#
|
385
|
+
def draw_cursor_at(x, y, c = Color::WHITE)
|
386
|
+
$window.draw_triangle(x, y, c, x, y+10, c, x+10, y+10, c, @zorder + 10)
|
387
|
+
end
|
388
|
+
|
389
|
+
def try_select_all
|
390
|
+
editable_game_objects.each { |x| x.options[:selected] = true } if holding?(:left_ctrl)
|
391
|
+
end
|
392
|
+
def try_save
|
393
|
+
save if holding?(:left_ctrl)
|
252
394
|
end
|
253
395
|
|
396
|
+
def quit
|
397
|
+
pop_game_state(:setup => false)
|
398
|
+
end
|
399
|
+
def save
|
400
|
+
save_game_objects(:game_objects => editable_game_objects, :file => @file, :classes => @classes)
|
401
|
+
end
|
254
402
|
def save_and_quit
|
255
|
-
save
|
403
|
+
save unless holding?(:left_ctrl)
|
256
404
|
quit
|
257
405
|
end
|
406
|
+
|
407
|
+
def move_left
|
408
|
+
scroll_left && return if selected_game_objects.empty?
|
409
|
+
selected_game_objects.each { |game_object| game_object.x -= 1 }
|
410
|
+
end
|
411
|
+
def move_right
|
412
|
+
scroll_right && return if selected_game_objects.empty?
|
413
|
+
selected_game_objects.each { |game_object| game_object.x += 1 }
|
414
|
+
end
|
415
|
+
def move_up
|
416
|
+
scroll_up && return if selected_game_objects.empty?
|
417
|
+
selected_game_objects.each { |game_object| game_object.y -= 1 }
|
418
|
+
end
|
419
|
+
def move_down
|
420
|
+
scroll_down && return if selected_game_objects.empty?
|
421
|
+
selected_game_objects.each { |game_object| game_object.y += 1 }
|
422
|
+
end
|
258
423
|
|
259
|
-
def
|
260
|
-
|
424
|
+
def try_scroll_left
|
425
|
+
scroll_left if selected_game_objects.empty?
|
426
|
+
end
|
427
|
+
def try_scroll_right
|
428
|
+
scroll_right if selected_game_objects.empty?
|
429
|
+
end
|
430
|
+
def try_scroll_up
|
431
|
+
scroll_up if selected_game_objects.empty?
|
432
|
+
end
|
433
|
+
def try_scroll_down
|
434
|
+
scroll_down if selected_game_objects.empty?
|
435
|
+
end
|
436
|
+
|
437
|
+
def mouse_wheel_up
|
438
|
+
if selected_game_objects.empty?
|
439
|
+
scroll_up(40)
|
440
|
+
else
|
441
|
+
tilt_left && return if holding?(:left_shift)
|
442
|
+
inc_zorder && return if holding?(:left_ctrl)
|
443
|
+
inc_alpha && return if holding?(:left_alt)
|
444
|
+
scale_up
|
445
|
+
end
|
261
446
|
end
|
262
447
|
|
263
|
-
def
|
264
|
-
|
265
|
-
|
448
|
+
def mouse_wheel_down
|
449
|
+
if selected_game_objects.empty?
|
450
|
+
scroll_down(40)
|
451
|
+
else
|
452
|
+
tilt_right && return if holding?(:left_shift)
|
453
|
+
dec_zorder && return if holding?(:left_ctrl)
|
454
|
+
dec_alpha && return if holding?(:left_alt)
|
455
|
+
scale_down
|
266
456
|
end
|
267
457
|
end
|
458
|
+
|
459
|
+
def tilt_left
|
460
|
+
selected_game_objects.each { |game_object| game_object.angle -= 5 }
|
461
|
+
end
|
462
|
+
def tilt_right
|
463
|
+
selected_game_objects.each { |game_object| game_object.angle += 5 }
|
464
|
+
end
|
465
|
+
def scale_up
|
466
|
+
scale_up_x && scale_up_y
|
467
|
+
end
|
468
|
+
def scale_down
|
469
|
+
scale_down_x && scale_down_y
|
470
|
+
end
|
471
|
+
def inc_zorder
|
472
|
+
selected_game_objects.each { |game_object| game_object.zorder += 1 }
|
473
|
+
end
|
474
|
+
def dec_zorder
|
475
|
+
selected_game_objects.each { |game_object| game_object.zorder -= 1 }
|
476
|
+
end
|
477
|
+
def inc_alpha
|
478
|
+
selected_game_objects.each { |game_object| game_object.alpha += 1 }
|
479
|
+
end
|
480
|
+
def dec_alpha
|
481
|
+
selected_game_objects.each { |game_object| game_object.alpha -= 1 }
|
482
|
+
end
|
483
|
+
def scale_up_x
|
484
|
+
selected_game_objects.each { |game_object| game_object.factor_x += grid_factor_x_for(game_object) }
|
485
|
+
end
|
486
|
+
def scale_up_y
|
487
|
+
selected_game_objects.each { |game_object| game_object.factor_y += grid_factor_x_for(game_object) }
|
488
|
+
end
|
489
|
+
def scale_down_x
|
490
|
+
selected_game_objects.each { |game_object| game_object.factor_x -= grid_factor_y_for(game_object) }
|
491
|
+
end
|
492
|
+
def scale_down_y
|
493
|
+
selected_game_objects.each { |game_object| game_object.factor_y -= grid_factor_y_for(game_object) }
|
494
|
+
end
|
268
495
|
|
496
|
+
def grid_factor_x_for(object)
|
497
|
+
@grid[0].to_f / object.image.width.to_f
|
498
|
+
end
|
499
|
+
def grid_factor_y_for(object)
|
500
|
+
@grid[0].to_f / object.image.height.to_f
|
501
|
+
end
|
502
|
+
|
503
|
+
def esc
|
504
|
+
deselect_selected_game_objects
|
505
|
+
@cursor_game_object = nil
|
506
|
+
end
|
269
507
|
def page_up
|
270
|
-
|
271
|
-
#self.previous_game_state.viewport.y -= $window.height if defined?(self.previous_game_state.viewport)
|
508
|
+
self.previous_game_state.viewport.y -= $window.height if defined?(self.previous_game_state.viewport)
|
272
509
|
end
|
273
510
|
def page_down
|
274
|
-
|
275
|
-
#self.previous_game_state.viewport.y += $window.height if defined?(self.previous_game_state.viewport)
|
511
|
+
self.previous_game_state.viewport.y += $window.height if defined?(self.previous_game_state.viewport)
|
276
512
|
end
|
277
|
-
def scroll_up
|
278
|
-
self.previous_game_state.viewport.y -=
|
513
|
+
def scroll_up(amount = 10)
|
514
|
+
self.previous_game_state.viewport.y -= amount if defined?(self.previous_game_state.viewport)
|
279
515
|
end
|
280
|
-
def scroll_down
|
281
|
-
self.previous_game_state.viewport.y +=
|
516
|
+
def scroll_down(amount = 10)
|
517
|
+
self.previous_game_state.viewport.y += amount if defined?(self.previous_game_state.viewport)
|
282
518
|
end
|
283
|
-
def scroll_left
|
284
|
-
self.previous_game_state.viewport.x -=
|
519
|
+
def scroll_left(amount = 10)
|
520
|
+
self.previous_game_state.viewport.x -= amount if defined?(self.previous_game_state.viewport)
|
285
521
|
end
|
286
|
-
def scroll_right
|
287
|
-
self.previous_game_state.viewport.x +=
|
522
|
+
def scroll_right(amount = 10)
|
523
|
+
self.previous_game_state.viewport.x += amount if defined?(self.previous_game_state.viewport)
|
288
524
|
end
|
289
|
-
def
|
290
|
-
x = $window.mouse_x
|
525
|
+
def mouse_x
|
526
|
+
x = $window.mouse_x
|
291
527
|
x += self.previous_game_state.viewport.x if defined?(self.previous_game_state.viewport)
|
292
528
|
end
|
293
|
-
def
|
529
|
+
def mouse_y
|
294
530
|
y = $window.mouse_y
|
295
531
|
y += self.previous_game_state.viewport.y if defined?(self.previous_game_state.viewport)
|
296
532
|
end
|
297
533
|
|
534
|
+
def inside_window?(x = $window.mouse_x, y = $window.mouse_y)
|
535
|
+
x >= 0 && x <= $window.width && y >= 0 && y <= $window.height
|
536
|
+
end
|
537
|
+
|
538
|
+
def create_new_game_object_from(template)
|
539
|
+
game_object = template.class.create(:parent => previous_game_state)
|
540
|
+
game_object.update
|
541
|
+
#game_object.options[:selected] = true
|
542
|
+
game_object.options[:created_with_editor] = true
|
543
|
+
game_object.x = self.mouse_x
|
544
|
+
game_object.y = self.mouse_y
|
545
|
+
|
546
|
+
unless template.options[:toolbar]
|
547
|
+
game_object.angle = template.angle
|
548
|
+
game_object.factor_x = template.factor_x
|
549
|
+
game_object.factor_y = template.factor_y
|
550
|
+
game_object.color = template.color.dup
|
551
|
+
game_object.zorder = template.zorder
|
552
|
+
game_object.update
|
553
|
+
else
|
554
|
+
# Resize the new game object to fit the grid perfectly!
|
555
|
+
wanted_width = game_object.image.width + @grid[0] - (game_object.image.width % @grid[0])
|
556
|
+
wanted_height = game_object.image.height + @grid[1] - (game_object.image.height % @grid[1])
|
557
|
+
game_object.factor_x = wanted_width.to_f / game_object.image.width.to_f
|
558
|
+
game_object.factor_y = wanted_height.to_f / game_object.image.height.to_f
|
559
|
+
end
|
560
|
+
|
561
|
+
game_object.options[:mouse_x_offset] = game_object.x - self.mouse_x
|
562
|
+
game_object.options[:mouse_y_offset] = game_object.y - self.mouse_y
|
563
|
+
return game_object
|
564
|
+
end
|
565
|
+
|
298
566
|
#
|
299
567
|
# If we're editing a game state with automaticly called special methods,
|
300
568
|
# the following takes care of those.
|