chingu 0.7.7.5 → 0.8rc1

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.
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