chingu 0.7.7.5 → 0.8rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/History.txt +1 -1
  2. data/Rakefile +4 -2
  3. data/chingu.gemspec +25 -10
  4. data/examples/example10_traits_retrofy.rb +3 -2
  5. data/examples/example11_animation.rb +3 -2
  6. data/examples/example12_trait_timer.rb +3 -2
  7. data/examples/example13_high_scores.rb +3 -2
  8. data/examples/example14_bounding_box_circle.rb +6 -5
  9. data/examples/example15_trait_timer2.rb +3 -2
  10. data/examples/example16_online_high_scores.rb +3 -2
  11. data/examples/example17_gosu_tutorial.rb +104 -103
  12. data/examples/example18_animation_trait.rb +3 -2
  13. data/examples/example19_edit_viewport.rb +3 -2
  14. data/examples/example1_basics.rb +3 -2
  15. data/examples/example20_trait_inheritence_test.rb +3 -2
  16. data/examples/example21.yml +306 -306
  17. data/examples/example21_sidescroller_with_edit.rb +3 -2
  18. data/examples/example22_text.rb +3 -2
  19. data/examples/example23_chipmunk.rb +3 -2
  20. data/examples/example24_enter_name.rb +19 -0
  21. data/examples/example24_input_codes.rb +41 -0
  22. data/examples/example25.yml +625 -0
  23. data/examples/example25_fibers_state_machine.rb +167 -0
  24. data/examples/example2_gamestate_basics.rb +3 -2
  25. data/examples/example3_parallax.rb +3 -2
  26. data/examples/example4_gamestates.rb +3 -2
  27. data/examples/example5_gamestates_in_pure_gosu.rb +3 -2
  28. data/examples/example6_transitional_game_state.rb +3 -2
  29. data/examples/example7_gfx_helpers.rb +3 -2
  30. data/examples/example8_traits.rb +3 -2
  31. data/examples/example9_collision_detection.rb +3 -2
  32. data/examples/game1.rb +3 -2
  33. data/examples/game_of_life.rb +291 -290
  34. data/lib/chingu.rb +6 -1
  35. data/lib/chingu/animation.rb +3 -2
  36. data/lib/chingu/game_object.rb +7 -1
  37. data/lib/chingu/game_object_map.rb +6 -12
  38. data/lib/chingu/game_states/edit.rb +63 -66
  39. data/lib/chingu/game_states/enter_name.rb +97 -0
  40. data/lib/chingu/helpers/game_object.rb +10 -21
  41. data/lib/chingu/input.rb +2 -0
  42. data/lib/chingu/online_high_score_list.rb +1 -4
  43. data/lib/chingu/rect.rb +2 -1
  44. data/lib/chingu/window.rb +10 -1
  45. data/spec/chingu/game_object_spec.rb +22 -22
  46. data/spec/chingu/input_spec.rb +22 -0
  47. metadata +48 -22
  48. data/spec/chingu/rect_20x20.png +0 -0
data/lib/chingu.rb CHANGED
@@ -24,6 +24,10 @@ ROOT = File.dirname(File.expand_path($0))
24
24
 
25
25
  require 'rubygems' unless RUBY_VERSION =~ /1\.9/
26
26
  require 'gosu'
27
+ require 'yaml'
28
+ require 'rest_client'
29
+ require 'crack/xml'
30
+
27
31
  require File.join(CHINGU_ROOT,"chingu","require_all") # Thanks to http://github.com/tarcieri/require_all !
28
32
 
29
33
  # Seems like we need to include chingu/helpers first for BasicGameObject
@@ -33,7 +37,8 @@ require_all "#{CHINGU_ROOT}/chingu/traits"
33
37
  require_all "#{CHINGU_ROOT}/chingu"
34
38
 
35
39
  module Chingu
36
- VERSION = "0.7.7.5"
40
+ # VERSION = "0.7.7.5"
41
+ VERSION = "0.8rc1"
37
42
 
38
43
  DEBUG_COLOR = Gosu::Color.new(0xFFFF0000)
39
44
  DEBUG_ZORDER = 9999
@@ -86,7 +86,8 @@ module Chingu
86
86
  #
87
87
  def frame_names=(names)
88
88
  names.each do |key, value|
89
- @sub_animations[key] = self.new_from_frames(value) if value.is_a? Range
89
+ @sub_animations[key] = self.new_from_frames(value) if value.is_a? Range
90
+ @sub_animations[key] = @frames[value] if value.is_a? Fixnum
90
91
  #
91
92
  # TODO: Add support for [1,4,5] array frame selection
92
93
  #
@@ -136,7 +137,7 @@ module Chingu
136
137
  def [](index)
137
138
  return @frames[index] if index.is_a?(Fixnum)
138
139
  return self.new_from_frames(index) if index.is_a?(Range)
139
- return @sub_animations[index] if index.is_a?(Symbol)
140
+ return @sub_animations[index] if index.is_a?(Symbol)
140
141
  end
141
142
 
142
143
  #
@@ -93,7 +93,13 @@ module Chingu
93
93
  setup
94
94
 
95
95
  end
96
-
96
+
97
+ def to_s
98
+ "#{self.class.to_s} @ #{x.to_i} / #{y.to_i} " <<
99
+ "(#{width.to_i} x #{height.to_i}) - " <<
100
+ " ratio: #{sprintf("%.2f",width/height)} scale: #{sprintf("%.2f", factor_x)}/#{sprintf("%.2f", factor_y)} angle: #{angle.to_i} zorder: #{zorder} alpha: #{alpha}"
101
+ end
102
+
97
103
  #
98
104
  # Get all settings from a game object in one array.
99
105
  # Complemented by the GameObject#attributes= setter.
@@ -62,17 +62,11 @@ module Chingu
62
62
  #
63
63
  def insert(game_object)
64
64
  start_x = ( game_object.bb.left / @grid[0] ).to_i
65
- stop_x = ( (game_object.bb.right) / @grid[0] ).to_i
66
-
67
- #if game_object.zorder == 80
68
- # puts "x: #{game_object.x}, y: #{game_object.y}"
69
- # puts "width: #{game_object.width}, height: #{game_object.height}"
70
- # puts "start_x: #{start_x}, stop_x: #{stop_x}"
71
- #end
72
-
65
+ stop_x = ( game_object.bb.right / @grid[0] ).to_i
66
+
73
67
  (start_x ... stop_x).each do |x|
74
- start_y = (game_object.bb.top / @grid[1] ).to_i
75
- stop_y = ( (game_object.bb.bottom) / @grid[1] ).to_i
68
+ start_y = ( game_object.bb.top / @grid[1] ).to_i
69
+ stop_y = ( game_object.bb.bottom / @grid[1] ).to_i
76
70
 
77
71
  @game_object_positions[game_object] = [(start_x ... stop_x), (start_y ... stop_y)]
78
72
 
@@ -119,11 +113,11 @@ module Chingu
119
113
  start_x = (game_object.bb.left / @grid[0]).to_i
120
114
  stop_x = (game_object.bb.right / @grid[0]).to_i
121
115
 
122
- (start_x ... stop_x).each do |x|
116
+ (start_x .. stop_x).each do |x|
123
117
  start_y = (game_object.bb.top / @grid[1]).to_i
124
118
  stop_y = (game_object.bb.bottom / @grid[1]).to_i
125
119
 
126
- (start_y ... stop_y).each do |y|
120
+ (start_y .. stop_y).each do |y|
127
121
  return @map[x][y] if @map[x] && @map[x][y]
128
122
  end
129
123
 
@@ -62,8 +62,13 @@ module Chingu
62
62
  @except = options[:except] || []
63
63
  @classes -= Array(@except)
64
64
  @debug = options[:debug]
65
- @zorder = 10000
66
65
 
66
+ #
67
+ # Turn on cursor + turn it back to its original value in finalize()
68
+ #
69
+ @original_cursor = $window.cursor
70
+ $window.cursor = true
71
+
67
72
  p @classes if @debug
68
73
 
69
74
  @hud_color = Gosu::Color.new(200,70,70,70)
@@ -141,15 +146,13 @@ module Chingu
141
146
  game_object = klass.create(:paused => true)
142
147
  game_object.x = x + 10
143
148
  game_object.y = y
144
- game_object.zorder = @zorder
145
149
  game_object.options[:toolbar] = true
146
150
  game_object.rotation_center = :center_center
147
151
 
148
152
  # Scale down object to fit our toolbar
149
153
  if game_object.image
150
- Text.create("#{klass.to_s[0..9]}\n#{game_object.width.to_i}x#{game_object.height.to_i}", :size => 12, :x=>x-16, :y=>y+18, :zorder => @zorder, :max_width => 55, :rotation_center => :top_left, :align => :center, :factor => 1)
154
+ Text.create("#{klass.to_s[0..9]}\n#{game_object.width.to_i}x#{game_object.height.to_i}", :size => 12, :x=>x-16, :y=>y+18, :max_width => 55, :rotation_center => :top_left, :align => :center, :factor => 1)
151
155
  game_object.size = @toolbar_icon_size
152
- game_object.cache_bounding_box if game_object.respond_to?(:cache_bounding_box)
153
156
  x += 50
154
157
  else
155
158
  puts "Skipping #{klass} - no image" if @debug
@@ -212,10 +215,10 @@ END_OF_STRING
212
215
  start_y = -previous_game_state.viewport.y % @grid.last
213
216
  end
214
217
  (start_x .. $window.width).step(@grid.first).each do |x|
215
- $window.draw_line(x, 1, @grid_color, x, $window.height, @grid_color, @zorder-10, :additive)
218
+ $window.draw_line(x, 1, @grid_color, x, $window.height, @grid_color, 0, :additive)
216
219
  end
217
220
  (start_y .. $window.height).step(@grid.last).each do |y|
218
- $window.draw_line(1, y, @grid_color, $window.width, y, @grid_color, @zorder-10, :additive)
221
+ $window.draw_line(1, y, @grid_color, $window.width, y, @grid_color, 0, :additive)
219
222
  end
220
223
 
221
224
  end
@@ -226,10 +229,10 @@ END_OF_STRING
226
229
  def setup
227
230
  @scroll_border_thickness = 30
228
231
  @file = options[:file] || previous_game_state.filename + ".yml"
229
- @title = Text.create("File: #{@file}", :x => 5, :y => 2, :factor => 1, :size => 16, :zorder => @zorder)
232
+ @title = Text.create("File: #{@file}", :x => 5, :y => 2, :factor => 1, :size => 16)
230
233
  @title.text += " - Grid: #{@grid}" if @grid
231
- @text = Text.create("", :x => 300, :y => 20, :factor => 1, :size => 16, :zorder => @zorder)
232
- @status_text = Text.create("-", :x => 5, :y => 20, :factor => 1, :size => 16, :zorder => @zorder)
234
+ @text = Text.create("", :x => 300, :y => 20, :factor => 1, :size => 16)
235
+ @status_text = Text.create("-", :x => 5, :y => 20, :factor => 1, :size => 16)
233
236
 
234
237
  if defined?(previous_game_state.viewport)
235
238
  @game_area_backup = previous_game_state.viewport.game_area.dup
@@ -249,12 +252,8 @@ END_OF_STRING
249
252
  super
250
253
 
251
254
  @status_text.text = "#{self.mouse_x.to_i} / #{self.mouse_y.to_i}"
252
-
253
- if s = @selected_game_object
254
- @text.text = "#{s.class.to_s} @ #{s.x.to_i} / #{s.y.to_i}"
255
- @text.text = "Size: #{s.width.to_i} x #{s.height.to_i} Ratio: #{sprintf("%.2f",s.width/s.height)}"
256
- @text.text += " [Scale: #{sprintf("%.2f", s.factor_x)}/#{sprintf("%.2f", s.factor_y)} Angle: #{s.angle.to_i} Z: #{s.zorder} Alpha: #{s.alpha}]"
257
- end
255
+
256
+ @text.text = @selected_game_object.to_s
258
257
 
259
258
  #
260
259
  # We got a selected game object and the left mouse button is held down
@@ -269,12 +268,6 @@ END_OF_STRING
269
268
  selected_game_object.y -= selected_game_object.y % @grid[1]
270
269
  end
271
270
  end
272
-
273
- # TODO: better cleaner sollution
274
- if @selected_game_object.respond_to?(:bounding_box)
275
- @selected_game_object.bounding_box.x = @selected_game_object.x
276
- @selected_game_object.bounding_box.y = @selected_game_object.y
277
- end
278
271
  elsif @left_mouse_button
279
272
  if defined?(self.previous_game_state.viewport)
280
273
  self.previous_game_state.viewport.x = @left_mouse_click_at[0] - $window.mouse_x
@@ -297,33 +290,39 @@ END_OF_STRING
297
290
  # Draw prev game state onto screen (the level we're editing)
298
291
  previous_game_state.draw
299
292
 
300
- super
301
-
293
+ # Restart z-ordering, everything after this will be drawn on top
294
+ $window.flush
295
+
302
296
  draw_grid if @draw_grid
303
297
 
304
298
  #
305
299
  # Draw an edit HUD
306
300
  #
307
- $window.draw_quad( 0,0,@hud_color,
308
- $window.width,0,@hud_color,
309
- $window.width,@hud_height,@hud_color,
310
- 0,@hud_height,@hud_color, @zorder-1)
301
+ $window.draw_quad( 0,0,@hud_color, $window.width,0,@hud_color,
302
+ $window.width,@hud_height,@hud_color,0,@hud_height,@hud_color)
303
+
304
+ #
305
+ # Draw gameobjects
306
+ #
307
+ super
311
308
 
312
309
  #
313
310
  # Draw red rectangles/circles around all selected game objects
314
- #
311
+ #
315
312
  if defined?(previous_game_state.viewport)
316
- previous_game_state.viewport.apply { selected_game_objects.each { |game_object| game_object.draw_debug } }
313
+ previous_game_state.viewport.apply { draw_selections }
317
314
  else
318
- selected_game_objects.each { |game_object| game_object.draw_debug }
319
- end
320
-
321
- if @cursor_game_object
322
- @cursor_game_object.draw_at($window.mouse_x, $window.mouse_y)
323
- else
324
- draw_cursor_at($window.mouse_x, $window.mouse_y)
315
+ draw_selections
325
316
  end
326
317
 
318
+ @cursor_game_object.draw_at($window.mouse_x, $window.mouse_y) if @cursor_game_object
319
+ end
320
+
321
+ #
322
+ # Draw a red rectangle around all selected objects
323
+ #
324
+ def draw_selections
325
+ selected_game_objects.each { |game_object| draw_rect(bounding_box(game_object), Color::RED, 10000) }
327
326
  end
328
327
 
329
328
  #
@@ -340,7 +339,7 @@ END_OF_STRING
340
339
  end
341
340
 
342
341
  # Put out a new game object in the editor window and select it right away
343
- @selected_game_object = create_new_game_object_from(@cursor_game_object) if @cursor_game_object
342
+ @selected_game_object = copy_game_object(@cursor_game_object) if @cursor_game_object
344
343
 
345
344
  # Check if user clicked on anything in the icon-toolbar of available game objects
346
345
  @cursor_game_object = game_object_icon_at($window.mouse_x, $window.mouse_y)
@@ -368,7 +367,6 @@ END_OF_STRING
368
367
  end
369
368
 
370
369
  if holding?(:left_shift)
371
- #puts @selected_game_object.class.all.size
372
370
  previous_game_state.game_objects.select { |x| x.class == @selected_game_object.class }.each do |game_object|
373
371
  game_object.options[:selected] = true
374
372
  end
@@ -387,11 +385,7 @@ END_OF_STRING
387
385
  end
388
386
 
389
387
  def right_mouse_button
390
- if @cursor_game_object
391
- @cursor_game_object = nil
392
- else
393
- @cursor_game_object = game_object_at(self.mouse_x, self.mouse_y)
394
- end
388
+ @cursor_game_object = @cursor_game_object ? nil : game_object_at(mouse_x, mouse_y)
395
389
  end
396
390
  def released_right_mouse_button
397
391
  end
@@ -471,8 +465,9 @@ END_OF_STRING
471
465
  end
472
466
 
473
467
  def game_object_icon_at(x, y)
474
- game_objects.select do |game_object|
475
- game_object.respond_to?(:collision_at?) && game_object.collision_at?(x,y)
468
+ game_objects.select do |game_object|
469
+ next if game_object.is_a? Text
470
+ bounding_box(game_object).collide_point?(x,y)
476
471
  end.first
477
472
  end
478
473
 
@@ -481,27 +476,18 @@ END_OF_STRING
481
476
  # .. get the one with highest zorder.
482
477
  #
483
478
  def game_object_at(x, y)
484
- editable_game_objects.select do |game_object|
485
- game_object.respond_to?(:collision_at?) && game_object.collision_at?(x,y)
479
+ editable_game_objects.select do |game_object|
480
+ next if game_object.is_a? Text
481
+ bounding_box(game_object).collide_point?(x,y)
486
482
  end.sort {|x,y| y.zorder <=> x.zorder }.first
487
483
  end
488
484
 
489
- #
490
- # draw a simple triangle-shaped cursor
491
- #
492
- def draw_cursor_at(x, y, c = Color::WHITE)
493
- c2 = Color::BLACK
494
- $window.draw_triangle(x-2, y-4, c2, x-2, y+12, c2, x+14, y+12, c2, @zorder + 5)
495
- $window.draw_triangle(x, y, c, x, y+10, c, x+10, y+10, c, @zorder + 10)
496
- end
497
-
498
485
  def try_select_all
499
486
  editable_game_objects.each { |x| x.options[:selected] = true } if holding?(:left_ctrl)
500
487
  end
501
488
  def try_save
502
489
  save if holding?(:left_ctrl)
503
490
  end
504
-
505
491
  def quit
506
492
  pop_game_state
507
493
  end
@@ -517,6 +503,7 @@ END_OF_STRING
517
503
  if defined?(previous_game_state.viewport)
518
504
  previous_game_state.viewport.game_area = @game_area_backup
519
505
  end
506
+ $window.cursor = @original_cursor
520
507
  end
521
508
 
522
509
  def move_left
@@ -571,9 +558,6 @@ END_OF_STRING
571
558
  end
572
559
  end
573
560
 
574
- def recache_bounding_boxes
575
- selected_game_objects.each { |game_object| game_object.cache_bounding_box if game_object.respond_to?(:cache_bounding_box)}
576
- end
577
561
  def tilt_left
578
562
  selected_game_objects.each { |game_object| game_object.angle -= 5 }
579
563
  end
@@ -582,11 +566,9 @@ END_OF_STRING
582
566
  end
583
567
  def scale_up
584
568
  scale_up_x && scale_up_y
585
- recache_bounding_boxes
586
569
  end
587
570
  def scale_down
588
571
  scale_down_x && scale_down_y
589
- recache_bounding_boxes
590
572
  end
591
573
 
592
574
  def inc_zorder
@@ -653,7 +635,7 @@ END_OF_STRING
653
635
  x >= 0 && x <= $window.width && y >= 0 && y <= $window.height
654
636
  end
655
637
 
656
- def create_new_game_object_from(template)
638
+ def copy_game_object(template)
657
639
  game_object = template.class.create(:parent => previous_game_state)
658
640
  # If we don't create it from the toolbar, we're cloning another object
659
641
  # When cloning we wan't the cloned objects attributes
@@ -665,10 +647,25 @@ END_OF_STRING
665
647
  game_object.options[:mouse_x_offset] = (game_object.x - self.mouse_x) rescue 0
666
648
  game_object.options[:mouse_y_offset] = (game_object.y - self.mouse_y) rescue 0
667
649
 
668
- game_object.cache_bounding_box if game_object.respond_to?(:cache_bounding_box)
669
650
  return game_object
670
- end
671
-
651
+ end
652
+
653
+ CENTER_TO_FACTOR = { 0 => -1, 0.5 => 0, 1 => 1 }
654
+ #
655
+ # Returns a bounding box (Rect-class) for any gameobject
656
+ # It will take into considerations rotation_center and scaling
657
+ #
658
+ def bounding_box(game_object)
659
+ width, height = game_object.width, game_object.height
660
+ x = game_object.x - width * game_object.center_x
661
+ y = game_object.y - height * game_object.center_y
662
+ x += width * CENTER_TO_FACTOR[game_object.center_x] if game_object.factor_x < 0
663
+ y += height * CENTER_TO_FACTOR[game_object.center_y] if game_object.factor_y < 0
664
+ return Rect.new(x, y, width, height)
665
+ end
666
+ alias :bb :bounding_box
667
+
668
+
672
669
  #
673
670
  # If we're editing a game state with automaticly called special methods,
674
671
  # the following takes care of those.
@@ -0,0 +1,97 @@
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
+ module Chingu
23
+ module GameStates
24
+ #
25
+ # A Chingu::GameState for showing a classic arcade "enter name" screen.
26
+ # Will let the user enter his alias or name with the keyboard or game_pad
27
+ # Intended to be minimalistic. If you wan't something flashy you probably want to do this class yourself.
28
+ #
29
+ class EnterName < Chingu::GameState
30
+
31
+ def initialize(options = {})
32
+ super
33
+
34
+ Text.create("Please enter your name:", :x => 0, :y => 0, :size => 40)
35
+
36
+ on_input([:holding_left, :holding_a, :holding_gamepad_left], :left)
37
+ on_input([:holding_right, :holding_d, :holding_gamepad_right], :right)
38
+ on_input([:space, :x, :enter, :gamepad_button_1, :return], :action)
39
+
40
+ @callback = options[:callback]
41
+
42
+ @string = []
43
+ @texts = []
44
+ @start_y = 200
45
+ @start_x = 0
46
+ @index = 0
47
+ #@letters = %w[ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ! " # % & ( ) [ ] = * _ < GO! ]
48
+ @letters = %w[ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ! _ < GO! ]
49
+ x = @start_x
50
+
51
+ @letters.each do |letter|
52
+ @texts << Text.create(letter, :x => x, :y => @start_y, :rotation_center => :bottom_left, :size => 25)
53
+ x += 25
54
+ end
55
+
56
+ @selected_color = Color::RED
57
+ @signature = Text.create("", :x => $window.width/2, :y => $window.height/2, :size => 80, :align => :center)
58
+ end
59
+
60
+ # Move cursor 1 step to the left
61
+ def left; move_cursor(-1); end
62
+
63
+ # Move cursor 1 step to the right
64
+ def right; move_cursor(1); end
65
+
66
+ # Move cursor any given value (positive or negative). Used by left() and right()
67
+ def move_cursor(amount = 1)
68
+ @index += amount
69
+ @index = 0 if @index >= @letters.size
70
+ sleep(0.1)
71
+ end
72
+
73
+ def action
74
+ case @letters[@index]
75
+ when "<" then @string.pop
76
+ when "_" then @string << " "
77
+ when "GO!" then go
78
+ else @string << @letters[@index]
79
+ end
80
+
81
+ @signature.text = @string.join
82
+ @signature.x = $window.width/2 - @signature.width/2
83
+ end
84
+
85
+ def draw
86
+ @rect = Rect.new(@start_x + (25 * @index), @start_y+25, @texts[@index].width, 10)
87
+ fill_rect(@rect, @selected_color, 0)
88
+ super
89
+ end
90
+
91
+ def go
92
+ pop_game_state(:name => @string.join)
93
+ end
94
+
95
+ end
96
+ end
97
+ end