moonpxi-nimo 0.1.0

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