chingu 0.7.5 → 0.7.6
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/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.
|