moonpxi-nimo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +15 -0
  5. data/Rakefile +47 -0
  6. data/VERSION +1 -0
  7. data/examples/bouncy.rb +101 -0
  8. data/examples/eventy.rb +19 -0
  9. data/examples/images/dg_classm32.png +0 -0
  10. data/examples/images/dg_dungeon32.png +0 -0
  11. data/examples/images/jeeklabs.png +0 -0
  12. data/examples/images/tcheco.png +0 -0
  13. data/examples/imagey.rb +82 -0
  14. data/examples/screeny.rb +80 -0
  15. data/examples/simplest.rb +23 -0
  16. data/examples/sounds/KDE-Sys-Log-Out.ogg +0 -0
  17. data/examples/sounds/k3b_error1.wav +0 -0
  18. data/examples/soundy.rb +40 -0
  19. data/examples/spritey.rb +90 -0
  20. data/lib/nimo.rb +35 -0
  21. data/lib/nimo/behavior/deflector.rb +39 -0
  22. data/lib/nimo/behavior/moveable.rb +33 -0
  23. data/lib/nimo/behavior/projectile.rb +23 -0
  24. data/lib/nimo/behavior/with_velocity.rb +28 -0
  25. data/lib/nimo/game_object.rb +58 -0
  26. data/lib/nimo/game_window.rb +59 -0
  27. data/lib/nimo/listeners/event_listener.rb +27 -0
  28. data/lib/nimo/listeners/input_listener.rb +70 -0
  29. data/lib/nimo/representations/image_representation.rb +18 -0
  30. data/lib/nimo/representations/object_representation.rb +67 -0
  31. data/lib/nimo/representations/quad_representation.rb +23 -0
  32. data/lib/nimo/representations/sprite_representation.rb +78 -0
  33. data/lib/nimo/representations/text_representation.rb +27 -0
  34. data/lib/nimo/screen.rb +103 -0
  35. data/lib/nimo/utils/game.rb +63 -0
  36. data/lib/nimo/utils/intersection.rb +30 -0
  37. data/lib/nimo/utils/object_extension.rb +17 -0
  38. data/lib/nimo/utils/resources.rb +51 -0
  39. data/nimo.gemspec +117 -0
  40. data/spec/nimo/behavior/deflector_spec.rb +51 -0
  41. data/spec/nimo/behavior/moveable_spec.rb +81 -0
  42. data/spec/nimo/behavior/projectile_spec.rb +34 -0
  43. data/spec/nimo/behavior/with_velocity_spec.rb +18 -0
  44. data/spec/nimo/game_object_spec.rb +169 -0
  45. data/spec/nimo/game_window_spec.rb +88 -0
  46. data/spec/nimo/listeners/event_listener_spec.rb +34 -0
  47. data/spec/nimo/listeners/input_listener_spec.rb +87 -0
  48. data/spec/nimo/representations/image_representation_spec.rb +41 -0
  49. data/spec/nimo/representations/object_representation_spec.rb +74 -0
  50. data/spec/nimo/representations/sprite_representation_spec.rb +73 -0
  51. data/spec/nimo/representations/text_representation_spec.rb +21 -0
  52. data/spec/nimo/screen_spec.rb +114 -0
  53. data/spec/nimo/utils/game_spec.rb +44 -0
  54. data/spec/nimo/utils/object_extension_spec.rb +21 -0
  55. data/spec/nimo/utils/resources_spec.rb +59 -0
  56. data/spec/spec_helper.rb +9 -0
  57. metadata +133 -0
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Nimo::GameWindow do
4
+
5
+ before(:each) do
6
+ @game_window = Nimo::GameWindow.new("Test", 640, 480)
7
+ end
8
+
9
+ describe "(screen transition)" do
10
+ before(:each) do
11
+ @game_window.add_screen(:first, Nimo::Screen.new(:first, nil, nil))
12
+ @game_window.add_screen(:second, Nimo::Screen.new(:second, nil, nil))
13
+ @game_window.add_screen(:third, Nimo::Screen.new(:third, nil, nil))
14
+ end
15
+
16
+ it "should have the first screen added as the current screen" do
17
+ @game_window.current_screen.id.should == :first
18
+ end
19
+
20
+ it "should cycle through available screens" do
21
+ @game_window.go_to(:second)
22
+ @game_window.current_screen.id.should == :second
23
+ @game_window.go_to(:third)
24
+ @game_window.current_screen.id.should == :third
25
+ @game_window.go_to(:first)
26
+ @game_window.current_screen.id.should == :first
27
+ end
28
+
29
+ it "should open and close a 'menu' screen" do
30
+ @game_window.open_menu(:second)
31
+ @game_window.current_screen.id.should == :second
32
+ @game_window.open_menu(:third)
33
+ @game_window.current_screen.id.should == :third
34
+ @game_window.close_menu
35
+ @game_window.current_screen.id.should == :second
36
+ @game_window.close_menu
37
+ @game_window.current_screen.id.should == :first
38
+ end
39
+
40
+ it "should throw error if screen is not available" do
41
+ lambda { @game_window.go_to(:wrong_screen) }.should raise_error("There is no screen named wrong_screen")
42
+ end
43
+
44
+ end
45
+
46
+ describe "(game loop)" do
47
+ it "should proxy updates and draws to current screen" do
48
+ mock_screen = new_mock_screen("screen")
49
+
50
+ expect(:update, mock_screen)
51
+ expect(:draw, mock_screen)
52
+ end
53
+
54
+ it "should proxy draws to background screens" do
55
+ mock_screen1 = new_mock_screen("mock1")
56
+ mock_screen2 = new_mock_screen("mock2")
57
+
58
+ @game_window.open_menu("mock2")
59
+
60
+ expect(:update, mock_screen2)
61
+ expect(:draw, mock_screen1, mock_screen2)
62
+ end
63
+
64
+ it "should not proxy draw for background screen after closing the menu" do
65
+ mock_screen1 = new_mock_screen("mock1")
66
+ mock_screen2 = new_mock_screen("mock2")
67
+
68
+ @game_window.open_menu("mock2")
69
+ @game_window.close_menu
70
+
71
+ expect(:update, mock_screen1)
72
+ expect(:draw, mock_screen1)
73
+ end
74
+
75
+ def new_mock_screen(name)
76
+ mock_screen = mock(name)
77
+ mock_screen.should_receive(:notify).once
78
+ @game_window.add_screen(name, mock_screen)
79
+ return mock_screen
80
+ end
81
+
82
+ def expect(method_name, *instances)
83
+ instances.each { |instance| instance.should_receive(method_name) }
84
+ @game_window.send(method_name)
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe "Nimo::EventListener module" do
4
+
5
+ class SomeEventListener
6
+ include Nimo::EventListener
7
+ attr_accessor :was_notified
8
+
9
+ def initialize
10
+ @was_notified = false
11
+ end
12
+ end
13
+
14
+ it "should register and execute event" do
15
+ listener = new_listener(:an_event)
16
+
17
+ listener.notify(:an_event)
18
+ listener.was_notified.should be_true
19
+ end
20
+
21
+ it "should not execute action for different event" do
22
+ listener = new_listener(:an_event)
23
+
24
+ listener.notify(:another_event)
25
+ listener.was_notified.should be_false
26
+ end
27
+
28
+ def new_listener(event)
29
+ listener = SomeEventListener.new
30
+ listener.listen_to(event) { listener.was_notified = true }
31
+ return listener
32
+ end
33
+
34
+ end
@@ -0,0 +1,87 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe "Nimo::InputListener module" do
4
+
5
+ class SomeInputListener
6
+ include Nimo::InputListener
7
+ attr_reader :num_of_updates
8
+
9
+ def initialize(acting_upon = self)
10
+ @num_of_updates = 0
11
+ @acting_upon = acting_upon
12
+ end
13
+
14
+ def act_upon
15
+ @acting_upon
16
+ end
17
+ end
18
+
19
+ before(:each) do
20
+ @mock_window = mock("game window")
21
+ end
22
+
23
+ describe "(key actions)" do
24
+ it "should not execute key event when key was not pressed" do
25
+ listener = new_listener(false)
26
+ listener.process_inputs(@mock_window)
27
+
28
+ listener.num_of_updates.should == 0
29
+ end
30
+
31
+ it "should execute key event when key is pressed" do
32
+ listener = new_listener(true)
33
+ listener.process_inputs(@mock_window)
34
+
35
+ listener.num_of_updates.should == 1
36
+ end
37
+
38
+ it "should execute key event multiple times when it is repeatable" do
39
+ listener = new_listener(true)
40
+ 2.times { listener.process_inputs(@mock_window) }
41
+
42
+ listener.num_of_updates.should == 2
43
+ end
44
+
45
+ it "should execute non repeatable key event once before clearing the button" do
46
+ listener = new_listener(true, :repeatable => false)
47
+ 2.times { listener.process_inputs(@mock_window) }
48
+
49
+ listener.num_of_updates.should == 1
50
+ end
51
+
52
+ def new_listener(is_button_down, options = {})
53
+ @mock_window.should_receive(:button_down?).with(Gosu::Button::KbLeft).at_least(1).and_return(is_button_down)
54
+ listener = SomeInputListener.new
55
+ listener.when_key(Gosu::Button::KbLeft, options) { @num_of_updates += 1 }
56
+ return listener
57
+ end
58
+ end
59
+
60
+ describe "(any key actions)" do
61
+ it "should execute the 'any key' action when any button is pressed" do
62
+ was_called = false
63
+ listener = SomeInputListener.new(nil)
64
+ listener.any_key { was_called = true }
65
+
66
+ listener.button_down(nil)
67
+
68
+ was_called.should be_true
69
+ end
70
+ end
71
+
72
+ describe "(acting upon an external object)" do
73
+ it "should act upon an external object" do
74
+ external = Struct.new(:count).new
75
+ external.count = 0
76
+
77
+ @mock_window.should_receive(:button_down?).with(Gosu::Button::KbLeft).and_return(true)
78
+ listener = SomeInputListener.new(external)
79
+ listener.when_key(Gosu::Button::KbLeft, options) { self.count += 1 }
80
+
81
+ listener.process_inputs(@mock_window)
82
+
83
+ external.count.should == 1
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Nimo::ImageRepresentation do
4
+
5
+ before(:each) do
6
+ @resources = mock("resources")
7
+ @image_file = mock("image file")
8
+ @game_object = Nimo::GameObject.new(:x => 0, :y => 0, :width => 10, :height => 10)
9
+ end
10
+
11
+ it "should load image from resources and draw it" do
12
+ expect_image_access(:some_file_tag, @image_file)
13
+ representation = load_representation(:image => :some_file_tag)
14
+
15
+ @image_file.should_receive(:draw)
16
+ representation.draw
17
+ end
18
+
19
+ it "should load image from tile resource and draw it" do
20
+ expect_image_access(:some_file_tag, [nil, @image_file, nil])
21
+ representation = load_representation(:image => :some_file_tag, :index => 1)
22
+
23
+ @image_file.should_receive(:draw)
24
+ representation.draw
25
+ end
26
+
27
+ it "should raise exception when loading with a missing :image param" do
28
+ lambda { load_representation({}) }.should raise_error("Must provide :image param for image loading")
29
+ end
30
+
31
+ def load_representation(params)
32
+ representation = Nimo::ImageRepresentation.new(nil, @game_object)
33
+ representation.load(@resources, params)
34
+ return representation
35
+ end
36
+
37
+ def expect_image_access(tag, image)
38
+ @resources.should_receive(:image).with(tag).and_return(image)
39
+ end
40
+
41
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Nimo::ObjectRepresentation do
4
+
5
+ describe "(always actions)" do
6
+ it "should execute registered update event" do
7
+ was_updated = false
8
+ representation = Nimo::ObjectRepresentation.new(nil, nil)
9
+ representation.always { was_updated = true }
10
+
11
+ representation.update
12
+
13
+ was_updated.should be_true
14
+ end
15
+ end
16
+
17
+ describe "(listener actions)" do
18
+ it "should execute action when receive notification" do
19
+ was_updated = false
20
+ mock_object = mock("object")
21
+
22
+ representation = Nimo::ObjectRepresentation.new(nil, mock_object)
23
+ mock_object.should_receive(:register_listener).with(:some_event, representation)
24
+
25
+ representation.listen_to(:some_event) { was_updated = true }
26
+ representation.notify(:some_event)
27
+
28
+ was_updated.should be_true
29
+ end
30
+
31
+ it "should ignore event if not registered" do
32
+ was_updated = false
33
+ mock_object = mock("object")
34
+
35
+ representation = Nimo::ObjectRepresentation.new(nil, mock_object)
36
+ mock_object.should_receive(:register_listener).with(:some_event, representation)
37
+
38
+ representation.listen_to(:some_event) { was_updated = true }
39
+ representation.notify(:another_event)
40
+
41
+ was_updated.should be_false
42
+ end
43
+ end
44
+
45
+ describe "(observer actions)" do
46
+ it "observer called after actions" do
47
+ always_called = false
48
+ key_called = false
49
+ was_updated = false
50
+
51
+ mock_window = mock("game window")
52
+ mock_window.should_receive(:button_down?).with(Gosu::Button::KbLeft).and_return(true)
53
+
54
+ representation = Nimo::ObjectRepresentation.new(mock_window, nil)
55
+ representation.always { always_called = true }
56
+ representation.when_key(Gosu::Button::KbLeft) { key_called = true }
57
+ representation.with_observer { |rep, obj| was_updated = true }
58
+
59
+ representation.update
60
+
61
+ was_updated.should be_true
62
+ end
63
+ end
64
+
65
+ describe "(exceptions for methods that should be overriden)" do
66
+ it "should raise exception when load was not override" do
67
+ lambda { Nimo::ObjectRepresentation.new(nil, nil).load(nil, nil) }.should raise_error("Load should be overriden by representation")
68
+ end
69
+
70
+ it "should raise exception when draw was not override" do
71
+ lambda { Nimo::ObjectRepresentation.new(nil, nil).draw }.should raise_error("Draw should be overriden by representation")
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Nimo::SpriteRepresentation do
4
+
5
+ before(:each) do
6
+ @mock_window = mock("game window")
7
+ mock_resources = mock("resources")
8
+ @tiles = [mock("sprite tile 1"), mock("sprite tile 2"), mock("sprite tile 3"), mock("sprite tile 4")]
9
+
10
+ mock_resources.should_receive(:image).with(:test_tiles).and_return(@tiles)
11
+
12
+ obj = Nimo::GameObject.new(:x => 0, :y => 0, :width => 20, :height => 20, :current_state => :state_one)
13
+ @sprite = Nimo::SpriteRepresentation.new(@mock_window, obj).
14
+ with_animation(:state_one, [0, 1]).
15
+ with_animation(:state_two, [2, 3], :loop => false)
16
+ @sprite.load(mock_resources, :image => :test_tiles)
17
+ end
18
+
19
+ it "should draw animation based on game object's current state" do
20
+ @tiles[0].should_receive(:draw).with(0, 0, 0)
21
+ @sprite.draw
22
+ end
23
+
24
+ it "should draw the same frame when draw called before frame timeout" do
25
+ @tiles[0].should_receive(:draw).twice.with(0, 0, 0)
26
+
27
+ 2.times { @sprite.draw }
28
+ end
29
+
30
+ it "should cycle to the next frame of animation after the frame timeout" do
31
+ @tiles[0].should_receive(:draw).with(0, 0, 0)
32
+ @tiles[1].should_receive(:draw).with(0, 0, 0)
33
+
34
+ 2.times { @sprite.draw; sleep 0.2 }
35
+ end
36
+
37
+ it "should cycle to beginning if it loops animation (by default it should loop)" do
38
+ @tiles[0].should_receive(:draw).twice.with(0, 0, 0)
39
+ @tiles[1].should_receive(:draw).with(0, 0, 0)
40
+
41
+ 3.times { @sprite.draw; sleep 0.2 }
42
+ end
43
+
44
+ it "should change animation when changing state" do
45
+ @tiles[0].should_receive(:draw).with(0, 0, 0)
46
+ @tiles[2].should_receive(:draw).with(0, 0, 0)
47
+
48
+ @sprite.draw
49
+ @sprite.change_to(:state_two)
50
+ @sprite.draw
51
+ end
52
+
53
+ it "should not change animation when game object changes to a state with no animation" do
54
+ @tiles[0].should_receive(:draw).twice.with(0, 0, 0)
55
+
56
+ @sprite.draw
57
+ @sprite.change_to(:state_none)
58
+ @sprite.draw
59
+ end
60
+
61
+ it "should keep drawing last frame animation do not loop" do
62
+ @tiles[2].should_receive(:draw).with(0, 0, 0)
63
+ @tiles[3].should_receive(:draw).twice.with(0, 0, 0)
64
+
65
+ @sprite.change_to(:state_two)
66
+ 3.times { @sprite.draw; sleep 0.2 }
67
+ end
68
+
69
+ it "should raise exception when trying to load sprite with missing :image param" do
70
+ empty_resources = mock("resources")
71
+ lambda { @sprite.load(empty_resources, {}) }.should raise_error("Must provide :image param for sprite loading")
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Nimo::TextRepresentation do
4
+
5
+ it "should raise exception when loading with a missing :image param" do
6
+ lambda { load_representation_with(:text => :some_text, :color => :some_color) }.should raise_error("Must provide :font param for font loading")
7
+ end
8
+
9
+ it "should raise exception when loading with a missing :color param" do
10
+ lambda { load_representation_with(:text => :some_text, :font => :some_font) }.should raise_error("Must provide :color param for font loading")
11
+ end
12
+
13
+ it "should raise exception when loading with a missing :text param" do
14
+ lambda { load_representation_with(:font => :some_font, :color => :some_color) }.should raise_error("Must provide :text param for font loading")
15
+ end
16
+
17
+ def load_representation_with(params)
18
+ Nimo::TextRepresentation.new(nil, nil).load(nil, params)
19
+ end
20
+
21
+ end
@@ -0,0 +1,114 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Nimo::Screen do
4
+
5
+ it "should register and execute event" do
6
+ event_called = false
7
+
8
+ screen = Nimo::Screen.new(:id, nil, nil)
9
+ screen.listen_to(:on_enter) { event_called = true }
10
+
11
+ event_called.should == false
12
+ screen.notify(:on_enter)
13
+ event_called.should == true
14
+ end
15
+
16
+ it "should register new representation" do
17
+ screen = Nimo::Screen.new(:id, nil, nil)
18
+ screen.respond_to?(:new_representation).should be_false
19
+
20
+ Nimo::Screen.register_representation(:new_representation, nil)
21
+
22
+ screen.respond_to?(:new_representation).should be_true
23
+ end
24
+
25
+ describe "(loading representations)" do
26
+ before(:each) do
27
+ @representation_class = mock("representation class")
28
+ @representation = mock("representation")
29
+ @representation_class.should_receive(:new).and_return(@representation)
30
+ @screen = Nimo::Screen.new(:id, nil, nil)
31
+ end
32
+
33
+ it "should load representation using the :with params" do
34
+ with_params = { :blah => "something" }
35
+ @representation.should_receive(:load).with(nil, with_params)
36
+ @screen.add(@representation_class, {:with => with_params})
37
+ end
38
+
39
+ it "should forward updates and draws to representations" do
40
+ @representation.should_receive(:load).with(nil, {})
41
+ @screen.add(@representation_class, {})
42
+
43
+ @representation.should_receive(:update)
44
+ @screen.update
45
+
46
+ @representation.should_receive(:draw)
47
+ @screen.draw
48
+ end
49
+ end
50
+
51
+ describe "(timer events)" do
52
+ it "should not execute timer action before it's time" do
53
+ was_called = false
54
+
55
+ screen = screen_with_timer(100) { was_called = true }
56
+ screen.update
57
+
58
+ was_called.should be_false
59
+ end
60
+
61
+ it "should execute timer action only once" do
62
+ number_of_executions = 0
63
+
64
+ screen = screen_with_timer(0.1) { number_of_executions += 1 }
65
+ sleep 0.2
66
+ 5.times { screen.update }
67
+
68
+ number_of_executions.should == 1
69
+ end
70
+
71
+ it "should define and execute multiple timers" do
72
+ first_called = second_called = false
73
+
74
+ screen = screen_with_timer(0.1) { first_called = true }
75
+ screen.timer_for(0.1) { second_called = true }
76
+
77
+ sleep 0.2
78
+ screen.update
79
+
80
+ first_called.should be_true
81
+ second_called.should be_true
82
+ end
83
+
84
+ def screen_with_timer(delay, &action)
85
+ screen = Nimo::Screen.new(:id, nil, nil)
86
+ screen.timer_for(delay, &action)
87
+ return screen
88
+ end
89
+
90
+ end
91
+
92
+ describe "(forwarding screen transition methods to game window)" do
93
+ [:go_to, :open_menu, :close_menu].each do |method_name|
94
+ it "should forward #{method_name} method to game_window" do
95
+ mock_window = mock("window")
96
+ mock_window.should_receive(method_name)
97
+
98
+ Nimo::Screen.new(:id, mock_window, nil).send(method_name)
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "(forwarding resource usage methods to resources)" do
104
+ [:sounds, :images, :fonts].each do |method_name|
105
+ it "should forward #{method_name} method to game_window" do
106
+ resources = mock("resources")
107
+ resources.should_receive(method_name)
108
+
109
+ Nimo::Screen.new(:id, nil, resources).send(method_name)
110
+ end
111
+ end
112
+ end
113
+
114
+ end