red_bird 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +23 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +47 -0
  7. data/Rakefile +10 -0
  8. data/bin/setup +8 -0
  9. data/ext/red_bird/bird.c +15 -0
  10. data/ext/red_bird/bird.h +10 -0
  11. data/ext/red_bird/color.c +95 -0
  12. data/ext/red_bird/color.h +27 -0
  13. data/ext/red_bird/dynamic_sprite.c +163 -0
  14. data/ext/red_bird/dynamic_sprite.h +30 -0
  15. data/ext/red_bird/engine.c +354 -0
  16. data/ext/red_bird/engine.h +40 -0
  17. data/ext/red_bird/extconf.rb +9 -0
  18. data/ext/red_bird/font.c +94 -0
  19. data/ext/red_bird/font.h +26 -0
  20. data/ext/red_bird/input_device.c +100 -0
  21. data/ext/red_bird/input_device.h +15 -0
  22. data/ext/red_bird/keycode.c +42 -0
  23. data/ext/red_bird/keycode.h +12 -0
  24. data/ext/red_bird/loader.c +154 -0
  25. data/ext/red_bird/loader.h +54 -0
  26. data/ext/red_bird/main.c +38 -0
  27. data/ext/red_bird/main.h +12 -0
  28. data/ext/red_bird/palette.c +132 -0
  29. data/ext/red_bird/palette.h +23 -0
  30. data/ext/red_bird/rect.c +257 -0
  31. data/ext/red_bird/rect.h +20 -0
  32. data/ext/red_bird/render.c +130 -0
  33. data/ext/red_bird/render.h +25 -0
  34. data/ext/red_bird/sprite.c +130 -0
  35. data/ext/red_bird/sprite.h +27 -0
  36. data/ext/red_bird/text.c +212 -0
  37. data/ext/red_bird/text.h +31 -0
  38. data/ext/red_bird/texture.c +157 -0
  39. data/ext/red_bird/texture.h +33 -0
  40. data/ext/red_bird/texture_imp.cpp +49 -0
  41. data/ext/red_bird/texture_imp.hpp +29 -0
  42. data/ext/red_bird/timer.c +134 -0
  43. data/ext/red_bird/timer.h +25 -0
  44. data/lib/red_bird.rb +15 -0
  45. data/lib/red_bird/animation.rb +133 -0
  46. data/lib/red_bird/camera.rb +61 -0
  47. data/lib/red_bird/controller.rb +44 -0
  48. data/lib/red_bird/dynamic_sprite.rb +38 -0
  49. data/lib/red_bird/engine.rb +81 -0
  50. data/lib/red_bird/entity.rb +74 -0
  51. data/lib/red_bird/entity_collision.rb +31 -0
  52. data/lib/red_bird/input_device.rb +86 -0
  53. data/lib/red_bird/palette.rb +23 -0
  54. data/lib/red_bird/relative_entity.rb +95 -0
  55. data/lib/red_bird/sprite.rb +40 -0
  56. data/lib/red_bird/stage.rb +60 -0
  57. data/lib/red_bird/tile_map.rb +118 -0
  58. data/lib/red_bird/tile_set.rb +56 -0
  59. data/lib/red_bird/uibox.rb +143 -0
  60. data/lib/red_bird/version.rb +3 -0
  61. data/lib/red_bird/vertical_menu.rb +110 -0
  62. data/red_bird.gemspec +37 -0
  63. metadata +149 -0
@@ -0,0 +1,44 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # A Controller receives commands from a {RedBird::InputDevice} and executes
4
+ # codes associated with those commands. Every {RedBird::InputDevice} instance
5
+ # has a variable called +@controller+ that must point to an instance of this
6
+ # class.
7
+ #
8
+ # The purpose of this class is to allow you to change the effect of user
9
+ # input by merely changing the currently active controller; you would do so,
10
+ # for example, when the user pauses the game, or when the user's character
11
+ # enters a vehicle.
12
+ #
13
+ # @see RedBird::InputDevice
14
+ # @author Frederico Linhares
15
+ class Controller
16
+ def initialize
17
+ @commands = {}
18
+
19
+ # By default, quit game when window is closed or another signal to end
20
+ # the game is given.
21
+ self.add_command(:quit_game) do
22
+ Engine::quit_game
23
+ end
24
+ end
25
+
26
+ # Use this method to create an association between a command and a code
27
+ # block.
28
+ #
29
+ # @param command [Symbol]
30
+ # @param function
31
+ # @author Frederico Linhares
32
+ def add_command(command, &function)
33
+ @commands[command] = function
34
+ end
35
+
36
+ # Execute a code block associated with a command.
37
+ #
38
+ # @param command [Symbol]
39
+ # @author Frederico Linhares
40
+ def call_command(command)
41
+ @commands[command].call unless @commands[command].nil?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # A sprite is rectangular part of an texture.
4
+ class DynamicSprite
5
+ # Create an array of sprites and return it. The array has homogeneous
6
+ # sprites that do not overlap and have no gaps between them.
7
+ #
8
+ # To create a grid starting from the position x 20, y 20, containing three
9
+ # columns and two rows, each sprite, having 100x80 pixels:
10
+ #
11
+ # RedBird::Texture.grid sprite, 20, 20, 3, 2, 100, 80
12
+ #
13
+ # @param texture [RedBird::Texture] a texture that will be used as the
14
+ # source for all sprites.
15
+ # @param init_x [Integer] initial x coordinate for the grid.
16
+ # @param init_y [Integer] initial y coordinate for the grid.
17
+ # @param num_hor_sprites [Integer] number of columns the grid will have.
18
+ # @param num_ver_sprites [Integer] number of rows the grid will have.
19
+ # @param width [Integer] width of every sprite.
20
+ # @param height [Integer] height of every sprite.
21
+ # @param mods [Hash]
22
+ # @return [Array]
23
+ # @author Frederico Linhares
24
+ def self.grid(texture, init_x, init_y, num_hor_sprites, num_ver_sprites,
25
+ width, height, mods)
26
+ sprites = []
27
+ num_ver_sprites.times do |v|
28
+ num_hor_sprites.times do |h|
29
+ sprites << new(
30
+ texture, init_x + h * width, init_y + v * height, width, height,
31
+ mods)
32
+ end
33
+ end
34
+
35
+ return sprites
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,81 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ module Engine
4
+ # Maximum frames per second. The Engine will try to maintain the game
5
+ # running at the frame rate defined by this variable.
6
+ @@max_fps = 30
7
+
8
+ # Set frames per second.
9
+ #
10
+ # @param fps [Integer]
11
+ # @author Frederico Linhares
12
+ def self.fps=(fps)
13
+ @@max_fps = fps
14
+ end
15
+
16
+ # Get frames per second.
17
+ #
18
+ # @return [Integer]frames per second.
19
+ def self.fps
20
+ return @@max_fps
21
+ end
22
+
23
+ # Exit the current stage and end the {Engine#run} loop.
24
+ #
25
+ # @author Frederico Linhares
26
+ def self.quit_game
27
+ @@quit_game = true
28
+ @@quit_stage = true
29
+ end
30
+
31
+ # Exit the current stage. The code block sent to {Engine#run} will be
32
+ # called again to get the next stage.
33
+ #
34
+ # @author Frederico Linhares
35
+ def self.quit_stage
36
+ @@quit_stage = true
37
+ end
38
+
39
+ # This method initializes the engine, executes the main loop, and returns
40
+ # when the game is over. This function calls the code block to get the
41
+ # first stage of the game and call it again every time a stage end to get
42
+ # the next one.
43
+ #
44
+ # @param global_data [Object] any object that you want to share between the
45
+ # game. This method sends this object back to the code block received.
46
+ # @yield [global_data] give +global_data+ to the block and expect it to
47
+ # return the next stage.
48
+ def self.run(global_data, &stage_manager)
49
+ @@quit_game = false
50
+
51
+ self.load do
52
+ while not @@quit_game do
53
+ @@quit_stage = false
54
+
55
+ timer = Timer.new(@@max_fps)
56
+ clear_color = Color.new(0, 0, 0, 0)
57
+ current_stage = stage_manager.call(global_data)
58
+
59
+ # The best moment to cleanup memory is before the engine loads a new
60
+ # stage.
61
+ GC.start
62
+
63
+ while not @@quit_stage do
64
+ timer.tick
65
+
66
+ current_stage.input_device.exec_events(current_stage.entities)
67
+
68
+ current_stage.pre_tick
69
+ current_stage.entities.each { |e| e.tick }
70
+ current_stage.post_tick
71
+
72
+ Render.set_color(clear_color)
73
+ Render.clear_screen
74
+ current_stage.entities.each { |e| e.render }
75
+ Render.update_screen
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,74 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # An entity is an object that is managed by the Engine; it has a size, a
4
+ # position, ticks, and is renderable. {RedBird::Engine.run} expects every
5
+ # single entity that it receives from {RedBird::Stage} to have these methods
6
+ # and attributes.
7
+ #
8
+ # @author Frederico Linhares
9
+ class Entity
10
+ # Position
11
+ #
12
+ # @return [Integer]
13
+ attr_reader :pos_x, :pos_y
14
+ # Size
15
+ #
16
+ # @return [Integer]
17
+ attr_reader :width, :height
18
+ # Entities with higher priorit are called first when the
19
+ # {RedBird::Engine.run} calls {#tick} and {#render}.
20
+ #
21
+ # @return [Integer]
22
+ attr_reader :priority
23
+
24
+ # The {RedBird::Engine.run} calls this method every single frame. Overwrite
25
+ # it if you want your entity to do something every frame.
26
+ #
27
+ # @author Frederico Linhares
28
+ def tick
29
+ # By default do nothing
30
+ end
31
+
32
+ # The {RedBird::Engine.run} calls this method whenever the cursor is over
33
+ # this entity. Overwrite this function if you want your entity to react to a
34
+ # cursor hover.
35
+ #
36
+ # @param x [Integer] cursor position.
37
+ # @param y [Integer] cursor position.
38
+ # @author Frederico Linhares
39
+ def cursor_hover(x, y)
40
+ # By default do nothing
41
+ end
42
+
43
+ # The {RedBird::Engine.run} calls this method whenever there is a click over
44
+ # this entity. Overwrite this function if you want your entity to react to a
45
+ # click.
46
+ #
47
+ # @param x [Integer] cursor position.
48
+ # @param y [Integer] cursor position.
49
+ # @author Frederico Linhares
50
+ def cursor_down(x, y)
51
+ # By default do nothing
52
+ end
53
+
54
+ # The {RedBird::Engine.run} calls this method whenever there is a cursor
55
+ # release over this entity. Overwrite this function if you want your entity
56
+ # to react to a cursor release.
57
+ #
58
+ # @param x [Integer] cursor position.
59
+ # @param y [Integer] cursor position.
60
+ # @author Frederico Linhares
61
+ def cursor_up(x, y)
62
+ # By default do nothing
63
+ end
64
+
65
+ # The {RedBird::Engine.run} calls this method to render this entity into
66
+ # the scree. Overwrite this method if you want to change how the entity
67
+ # renders into the screen.
68
+ #
69
+ # @author Frederico Linhares
70
+ def render
71
+ self.current_sprite.render_to_screen(self.pos_x, self.pos_y)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,31 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # This class does collision tests between entities.
4
+ class EntityCollision
5
+ # @param entities [Array<RedBird::Entity>] array containing the entities to
6
+ # test for collusion.
7
+ # @author Frederico Linhares
8
+ def initialize(entities)
9
+ @entities = entities
10
+ end
11
+
12
+ # Loop over entities in the array and test if they collide. In the case of
13
+ # collision, it calls the method +collide+ of the entity and sends the
14
+ # entity it collided to as a single argument.
15
+ #
16
+ # @author Frederico Linhares
17
+ def call
18
+ # Calculate entities rote
19
+ @entities.each_with_index do |e1, i|
20
+ @entities.drop(i + 1).each do |e2|
21
+ if e1.collision_box.collide? e2.collision_box then
22
+ e1.collide(e2)
23
+ e2.collide(e1)
24
+ # If an object responds to 'collision_box' then it is tested.
25
+ end if e1.respond_to?('collision_box')
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,86 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # The InputDevice receives input from the keyboard, joystick, and mouse;
4
+ # then, it translates the input into a meaningful command name and sends it
5
+ # to a Controller. For example, you can use it to translate the 'space' key
6
+ # from the keyboard and an 'x' button from a controller into a +:jump+
7
+ # command.
8
+ #
9
+ # This class has an internal Hash that translates inputs into commands. For
10
+ # every input, it looks if there is a key associated with that input; it
11
+ # sends a command if such key exists; otherwise, it does nothing.
12
+ #
13
+ # @see RedBird::Controller
14
+ # @author Frederico Linhares
15
+ class InputDevice
16
+ # Defines a {RedBird::Controller} to receives commands from the input.
17
+ attr_writer :controller
18
+
19
+ # @param controller [RedBird::Controller]
20
+ # @author Frederico Linhares
21
+ def initialize(controller)
22
+ @controller = controller
23
+ @keydown_inputs = {}
24
+ @keyup_inputs = {}
25
+ end
26
+
27
+ # Associates a keydown even to a command_name.
28
+ #
29
+ # @param keycode [Integer] use constants under {RedBird::Keycode}.
30
+ # @param command_name [Symbol]
31
+ # @author Frederico Linhares
32
+ def add_keydown(keycode, command_name)
33
+ @keydown_inputs[keycode] = command_name
34
+ end
35
+
36
+ # Associates a keyup even to a command_name.
37
+ #
38
+ # @param keycode [Integer] use constants under {RedBird::Keycode}.
39
+ # @param command_name [Symbol]
40
+ # @author Frederico Linhares
41
+ def add_keyup(keycode, command_name)
42
+ @keyup_inputs[keycode] = command_name
43
+ end
44
+
45
+ # Gets all events that are in the queue, translate then into commands, and
46
+ # send then to the current controller.
47
+ #
48
+ # @param entities [Array<RedBird::Entity>] entities that can receive events
49
+ # from mouse.
50
+ # @author Frederico Linhares
51
+ def exec_events(entities)
52
+ get_events do |type, data|
53
+ case type
54
+ when :key_down then
55
+ @controller.call_command(@keydown_inputs[data])
56
+ when :key_up then
57
+ @controller.call_command(@keyup_inputs[data])
58
+ when :mouse_motion then
59
+ entity = cursor_hover_entity(entities, data[:x], data[:y])
60
+ entity.cursor_hover(data[:x], data[:y]) unless entity.nil?
61
+ when :mouse_button_down then
62
+ entity = cursor_hover_entity(entities, data[:x], data[:y])
63
+ entity.cursor_down(data[:x], data[:y]) unless entity.nil?
64
+ when :mouse_button_up then
65
+ entity = cursor_hover_entity(entities, data[:x], data[:y])
66
+ entity.cursor_up(data[:x], data[:y]) unless entity.nil?
67
+ when :quit_game then
68
+ Engine::quit_game
69
+ end
70
+ end
71
+ end
72
+
73
+ protected
74
+ # This function is called when user move the mouse to se if mouse is hover
75
+ # an entity.
76
+ def cursor_hover_entity(entities, x, y)
77
+ entities.each do |e|
78
+ if(x >= e.pos_x and x <= e.pos_x + e.width and
79
+ y >= e.pos_y and y <= e.pos_y + e.height) then
80
+ return e
81
+ end
82
+ end
83
+ return nil
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,23 @@
1
+ # SPDX-License-Identifier: MIT
2
+ require 'yaml'
3
+
4
+ module RedBird
5
+ class Palette
6
+ # Load information from a YAML file and uses it to create an instance of this
7
+ # class
8
+ #
9
+ # @param tile_file [String] path to the yaml file.
10
+ # @return [RedBird::Palette]
11
+ # @author Frederico Linhares
12
+ def self.from_yml(palette_file)
13
+ data = YAML.load_file(palette_file)
14
+
15
+ # Convert data from YAML into Color instances.
16
+ colors = data.map do |i|
17
+ Color.new(i[0], i[1], i[2], i[3])
18
+ end
19
+
20
+ return self.new(colors)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,95 @@
1
+ # SPDX-License-Identifier: MIT
2
+ require_relative 'entity'
3
+
4
+ module RedBird
5
+ # The {RedBird::Entity} has an absolute position on the screen. Use this
6
+ # class if you want an entity that has a position relative to a scenario
7
+ # ({RedBird::TileMap}).
8
+ #
9
+ # @author Frederico Linhares
10
+ class RelativeEntity < Entity
11
+ # @return [RedBird::Rect]
12
+ attr_reader :collision_box
13
+
14
+ # @param relative_pos_x [Integer] position in the scenario
15
+ # @param relative_pos_y [Integer] position in the scenario
16
+ # @param width [Integer]
17
+ # @param height [Integer]
18
+ # @author Frederico Linhares
19
+ def initialize(relative_pos_x, relative_pos_y, width, height)
20
+ super()
21
+
22
+ @priority = 1
23
+
24
+ @collision_box = RedBird::Rect.new(
25
+ relative_pos_x, relative_pos_y, width, height)
26
+ end
27
+
28
+ # Define which scenario to use as a reference for every
29
+ # {RedBird::RelativeEntity}.
30
+ #
31
+ # @param scenario [RedBird::TileMap]
32
+ # @author Frederico Linhares
33
+ def self.scenario=(scenario)
34
+ @@scenario = scenario
35
+ end
36
+
37
+ # @return [RedBird::TileMap]
38
+ # @author Frederico Linhares
39
+ def self.scenario
40
+ return @@scenario
41
+ end
42
+
43
+ # @return [Integer] position in the scenario
44
+ # @author Frederico Linhares
45
+ def relative_pos_x
46
+ return @collision_box.x
47
+ end
48
+
49
+ # @return [Integer] position in the scenario
50
+ # @author Frederico Linhares
51
+ def relative_pos_y
52
+ return @collision_box.y
53
+ end
54
+
55
+ # @param x [Integer] position in the scenario
56
+ # @author Frederico Linhares
57
+ def relative_pos_x=(x)
58
+ @collision_box.x = x
59
+ end
60
+
61
+ # @param y [Integer] position in the scenario
62
+ # @author Frederico Linhares
63
+ def relative_pos_y=(y)
64
+ @collision_box.y = y
65
+ end
66
+
67
+ # Gets absolute position (position in the screen).
68
+ #
69
+ # @return [Float] position in the screen
70
+ # @author Frederico Linhares
71
+ def pos_x
72
+ @collision_box.x - @@scenario.hor_offset + @@scenario.pos_x
73
+ end
74
+
75
+ # Gets absolute position (position in the screen).
76
+ #
77
+ # @return [Float] position in the screen
78
+ # @author Frederico Linhares
79
+ def pos_y
80
+ @collision_box.y - @@scenario.ver_offset + @@scenario.pos_y
81
+ end
82
+
83
+ # @return [Integer]
84
+ # @author Frederico Linhares
85
+ def width
86
+ @collision_box.width
87
+ end
88
+
89
+ # @return [Integer]
90
+ # @author Frederico Linhares
91
+ def height
92
+ @collision_box.height
93
+ end
94
+ end
95
+ end