red_bird 0.1.1

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 (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,33 @@
1
+ // SPDX-License-Identifier: MIT
2
+ #ifndef RED_BIRD_TEXTURE_H
3
+ #define RED_BIRD_TEXTURE_H 1
4
+
5
+ #include "main.h"
6
+
7
+ extern VALUE bird_cTexture;
8
+
9
+ struct bird_texture_data
10
+ {
11
+ SDL_Texture *data;
12
+ int width, height;
13
+ };
14
+
15
+ VALUE
16
+ bird_alloc_texture(VALUE klass);
17
+
18
+ VALUE
19
+ bird_cTexture_initialize(VALUE self, VALUE file_path, VALUE palette);
20
+
21
+ VALUE
22
+ bird_cTexture_width(VALUE self);
23
+
24
+ VALUE
25
+ bird_cTexture_height(VALUE self);
26
+
27
+ struct bird_texture_data*
28
+ bird_cTexture_get_data(VALUE self);
29
+
30
+ void
31
+ Init_red_bird_texture(void);
32
+
33
+ #endif /* RED_BIRD_TEXTURE_H */
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: MIT
2
+ #include "texture_imp.hpp"
3
+
4
+ #include <charconv>
5
+ #include <fstream>
6
+ #include <string>
7
+
8
+ SDL_bool
9
+ bird_cTexture_PGM_load(
10
+ struct bird_cTexture_PGM *pgm_img, const char *file_path)
11
+ {
12
+ int wh_pos;
13
+ std::string line;
14
+ std::ifstream file(file_path);
15
+
16
+ if(!file) return SDL_FALSE;
17
+
18
+ // Read file magic.
19
+ std::getline(file, line);
20
+ if(line != "P5") return SDL_FALSE;
21
+
22
+ // Read file comment.
23
+ std::getline(file, line);
24
+
25
+ // Read file width and height.
26
+ std::getline(file, line);
27
+ wh_pos = line.find(" ");
28
+ std::from_chars(line.data(), line.data() + wh_pos, pgm_img->width);
29
+ std::from_chars(
30
+ line.data() + wh_pos + 1, line.data() + line.size(), pgm_img->height);
31
+
32
+ // Read file maximum value.
33
+ std::getline(file, line);
34
+ std::from_chars(line.data(), line.data() + line.size(), pgm_img->max_value);
35
+
36
+ // Read file values.
37
+ std::getline(file, line);
38
+ pgm_img->data_size = line.size();
39
+ pgm_img->data = new char[pgm_img->data_size];
40
+ memcpy(pgm_img->data, line.data(), pgm_img->data_size);
41
+
42
+ return SDL_TRUE;
43
+ }
44
+
45
+ void
46
+ bird_cTexture_PGM_unload(bird_cTexture_PGM *pgm_img)
47
+ {
48
+ delete[] pgm_img->data;
49
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+ #ifndef RED_BIRD_TEXTURE_IMP_H
3
+ #define RED_BIRD_TEXTURE_IMP_H 1
4
+
5
+ #ifdef __cplusplus
6
+ extern "C"
7
+ {
8
+ #endif
9
+
10
+ #include "main.h"
11
+
12
+ struct bird_cTexture_PGM
13
+ {
14
+ int width, height, max_value, data_size;
15
+ char *data;
16
+ };
17
+
18
+ SDL_bool
19
+ bird_cTexture_PGM_load(
20
+ struct bird_cTexture_PGM *pgm_img, const char *file_path);
21
+
22
+ void
23
+ bird_cTexture_PGM_unload(struct bird_cTexture_PGM *pgm_img);
24
+
25
+ #ifdef __cplusplus
26
+ }
27
+ #endif
28
+
29
+ #endif /* RED_BIRD_TEXTURE_IMP_H */
@@ -0,0 +1,134 @@
1
+ // SPDX-License-Identifier: MIT
2
+ #include "timer.h"
3
+
4
+ #include "engine.h"
5
+
6
+ /*
7
+ Document-class: RedBird::Timer
8
+
9
+ A Timer controls the speed of execution of a frame; it prevents that a frame
10
+ run too quickly and give you compensation when a frame runs too slow.
11
+
12
+ When creating a new instance, you must define the maximum frame rate that you
13
+ want; then, you should call {#tick} at every frame to get a delta time. The
14
+ delta time is proportional to the frame rate defined during the creation of
15
+ the instance or is higher when the last frame was slower than expected.
16
+
17
+ @author Frederico Linhares
18
+ */
19
+ VALUE bird_cTimer;
20
+
21
+ /*
22
+ Basic functions all Ruby classes need.
23
+ */
24
+
25
+ static void
26
+ bird_free_timer(void* obj)
27
+ {
28
+ struct bird_timer_data *ptr = obj;
29
+
30
+ free(ptr);
31
+ }
32
+
33
+ static size_t
34
+ bird_memsize_timer(const void* obj)
35
+ {
36
+ // TODO
37
+ return 0;
38
+ }
39
+
40
+ static const rb_data_type_t
41
+ bird_timer_type = {
42
+ "red_bird_timer",
43
+ {0, bird_free_timer, bird_memsize_timer,},
44
+ 0, 0,
45
+ RUBY_TYPED_FREE_IMMEDIATELY,
46
+ };
47
+
48
+ static VALUE
49
+ bird_alloc_timer(VALUE klass)
50
+ {
51
+ VALUE obj;
52
+ struct bird_timer_data *ptr;
53
+
54
+ obj = TypedData_Make_Struct(klass, struct bird_timer_data, &bird_timer_type,
55
+ ptr);
56
+
57
+ return obj;
58
+ }
59
+
60
+ /*
61
+ @param max_fps [Integer] the maximum of frames to be rendered per second.
62
+ @author Frederico Linhares
63
+ */
64
+ VALUE
65
+ bird_cTimer_initialize(VALUE self, VALUE max_fps)
66
+ {
67
+ struct bird_timer_data *ptr;
68
+
69
+ if(!engine_initialized)
70
+ rb_raise(rb_eRuntimeError, "%s",
71
+ "can not create a RedBird::Timer instance before "
72
+ "RedBird::Engine is started");
73
+
74
+ RB_INTEGER_TYPE_P(max_fps);
75
+
76
+ TypedData_Get_Struct(self, struct bird_timer_data, &bird_timer_type, ptr);
77
+ ptr->max_frame_duration_ms = 1000 / NUM2INT(max_fps);
78
+ ptr->max_frame_duration_sec = ptr->max_frame_duration_ms/1000.0;
79
+ ptr->frame_start = SDL_GetTicks();
80
+
81
+ return self;
82
+ }
83
+
84
+ /*
85
+ Every time you call this method, it compares the current time with the last
86
+ time it was called; if the amount of time is inferior to the frame duration,
87
+ it waits to ensure the frame has the exact duration expected; otherwise, it
88
+ returns instantly and gives you a delta value that compensates for the extra
89
+ duration of the last frame.
90
+
91
+ @return [Float] represents the amount of time between this frame and the last
92
+ frame, the higher, the higher amount of time has passed.
93
+ @author Frederico Linhares
94
+ */
95
+ VALUE
96
+ bird_cTimer_tick(VALUE self)
97
+ {
98
+ struct bird_timer_data *ptr;
99
+ Uint32 frame_stop;
100
+ Uint32 frame_duration;
101
+ VALUE delta;
102
+
103
+ TypedData_Get_Struct(self, struct bird_timer_data, &bird_timer_type, ptr);
104
+
105
+ frame_stop = SDL_GetTicks();
106
+ frame_duration = frame_stop - ptr->frame_start;
107
+
108
+ // If frame take less time than maximum allowed.
109
+ if(ptr->max_frame_duration_ms > frame_duration)
110
+ {
111
+ SDL_Delay(ptr->max_frame_duration_ms - frame_duration);
112
+ delta = rb_float_new(ptr->max_frame_duration_sec);
113
+ }
114
+ // If frame take too long time.
115
+ else
116
+ {
117
+ // SDL_GetTicks return time im miliseconds, so I need to divide by 1000 to
118
+ // get the time in seconds.
119
+ delta = rb_float_new((double)frame_duration/1000.0);
120
+ }
121
+
122
+ ptr->frame_start = frame_stop;
123
+
124
+ return delta;
125
+ }
126
+
127
+ void
128
+ Init_red_bird_timer(void)
129
+ {
130
+ bird_cTimer = rb_define_class_under(bird_m, "Timer", rb_cData);
131
+ rb_define_alloc_func(bird_cTimer, bird_alloc_timer);
132
+ rb_define_method(bird_cTimer, "initialize", bird_cTimer_initialize, 1);
133
+ rb_define_method(bird_cTimer, "tick", bird_cTimer_tick, 0);
134
+ }
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: MIT
2
+ #ifndef RED_BIRD_TIMER_H
3
+ #define RED_BIRD_TIMER_H 1
4
+
5
+ #include "main.h"
6
+
7
+ extern VALUE bird_cTimer;
8
+
9
+ struct bird_timer_data
10
+ {
11
+ Uint32 frame_start;
12
+ Uint32 max_frame_duration_ms; // in miliseconds
13
+ double max_frame_duration_sec; // in seconds
14
+ };
15
+
16
+ VALUE
17
+ bird_cTimer_initialize(VALUE self, VALUE max_fps);
18
+
19
+ VALUE
20
+ bird_cTimer_tick(VALUE self);
21
+
22
+ void
23
+ Init_red_bird_timer(void);
24
+
25
+ #endif // RED_BIRD_TIMER_H
@@ -0,0 +1,15 @@
1
+ # SPDX-License-Identifier: MIT
2
+ require_relative "red_bird/red_bird"
3
+ require_relative "red_bird/controller"
4
+ require_relative "red_bird/dynamic_sprite"
5
+ require_relative "red_bird/engine"
6
+ require_relative "red_bird/entity"
7
+ require_relative "red_bird/input_device"
8
+ require_relative "red_bird/palette"
9
+ require_relative "red_bird/sprite"
10
+ require_relative "red_bird/version"
11
+
12
+ module RedBird
13
+ class Error < StandardError; end
14
+ # Your code goes here...
15
+ end
@@ -0,0 +1,133 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # This module contains different kinds of animations.
4
+ module Animation
5
+ # Each frame has a sprite and a duration.
6
+ #
7
+ # @!attribute [r] duration
8
+ # @return [Integer] how long this frame lasts.
9
+ # @!attribute [r] sprite
10
+ # @return [RedBird::Sprite] sprite to display in this frame.
11
+ # @see RedBird::Animation::Base
12
+ # @author Frederico Linhares
13
+ class Frame
14
+ attr_reader :duration, :sprite
15
+
16
+ # @param duration [Integer] this animation frame will persist for as many
17
+ # game frames as defined by this value.
18
+ # @param sprite [RedBird::Sprite] sprite to be displayed in this frame.
19
+ # @author Frederico Linhares
20
+ def initialize(duration, sprite)
21
+ @duration = duration
22
+ @sprite = sprite
23
+ end
24
+
25
+ # Create an array of frames and return it. This method must receive an
26
+ # Array.
27
+ #
28
+ # @param frames [Array] each object in it must be an array containing the
29
+ # attributes for each frame returned.
30
+ # @author Frederico Linhares
31
+ def self.sequence(frames)
32
+ return frames.collect { |i| Frame.new(i[0], i[1]) }
33
+ end
34
+ end
35
+
36
+ # Base class for different animations. An animation consists of a sequence
37
+ # of frames, a state to define which one to show and which comes next and
38
+ # an animation method to determine how the frames change.
39
+ #
40
+ # @author Frederico Linhares
41
+ class Base
42
+ # @return [RedBird::Sprite] the sprite for the current stage of the
43
+ # animation.
44
+ attr_reader :current_sprite
45
+
46
+ # @param frames [Array] an array of RedBird::Frame.
47
+ # @author Frederico Linhares
48
+ def initialize(frames)
49
+ @frames = frames
50
+ self.set
51
+ end
52
+
53
+ # Set this animation to the initial state.
54
+ #
55
+ # @author Frederico Linhares
56
+ def reset
57
+ self.set
58
+ end
59
+ end
60
+
61
+ # This animation starts in the first frame and goes through every frame
62
+ # until the last, then it goes back to the first frame and starts again.
63
+ #
64
+ # @author Frederico Linhares
65
+ class Loop < Base
66
+ # This method must be called for every tick. It changes the current
67
+ # displayed sprite.
68
+ def animate
69
+ @current_time += 1
70
+ if @current_time > @frames[@current_frame].duration then
71
+ @current_time -= @frames[@current_frame].duration
72
+ @current_frame += 1
73
+ if @current_frame >= @frames.size then
74
+ @current_frame = 0
75
+ end
76
+ @current_sprite = @frames[@current_frame].sprite
77
+ end
78
+ end
79
+
80
+ protected
81
+ def set
82
+ @current_time = 0
83
+ @current_frame = 0
84
+ @current_sprite = @frames[@current_frame].sprite
85
+ end
86
+ end
87
+
88
+ # This animation starts in the first frame and goes through every frame
89
+ # until the last; then, it moves backward through every frame and starts
90
+ # again.
91
+ #
92
+ # @author Frederico Linhares
93
+ class BackAndForth < Base
94
+ # This method must be called for every tick. It changes the current
95
+ # displayed sprite.
96
+ def animate
97
+ case @direction
98
+ when :forward
99
+ @current_time += 1
100
+ if @current_time > @frames[@current_frame].duration then
101
+ @current_time -= @frames[@current_frame].duration
102
+ @current_frame += 1
103
+ if @current_frame >= @frames.size then
104
+ @direction = :backward
105
+ @current_frame = @frames.size - 2
106
+ end
107
+ @current_sprite = @frames[@current_frame].sprite
108
+ end
109
+ when :backward
110
+ @current_time += 1
111
+ if @current_time > @frames[@current_frame].duration then
112
+ @current_time -= @frames[@current_frame].duration
113
+ @current_frame -= 1
114
+ if @current_frame < 0 then
115
+ @direction = :forward
116
+ @current_frame = 1
117
+ end
118
+ @current_sprite = @frames[@current_frame].sprite
119
+ end
120
+ end
121
+ end
122
+
123
+ protected
124
+ def set
125
+ @direction = :forward
126
+ @current_time = 0
127
+ @current_frame = 0
128
+ @current_sprite = @frames[@current_frame].sprite
129
+ end
130
+ end
131
+
132
+ end
133
+ end
@@ -0,0 +1,61 @@
1
+ # SPDX-License-Identifier: MIT
2
+ module RedBird
3
+ # Because most of the time the tilemap used as the scenario is larger than
4
+ # the screen, you need to choose an entity to use as a reference. A Camera
5
+ # control the scenario offset and makes the position of the scene rendered in
6
+ # the screen be relative to an entity.
7
+ #
8
+ # @author Frederico Linhares
9
+ class Camera
10
+
11
+ # @param focus [RedBird::RelativeEntity] entity to use as reference for the
12
+ # scenario
13
+ # @param scenario [RedBird::TileMap]
14
+ # @author Frederico Linhares
15
+ def initialize(focus, scenario)
16
+ @scenario = scenario
17
+ @max_hor_offset = @scenario.total_width - @scenario.width
18
+ @max_ver_offset = @scenario.total_height - @scenario.height
19
+ self.focus = focus
20
+ end
21
+
22
+ # Change the camere focus.
23
+ #
24
+ # @param focus [RedBird::RelativeEntity]
25
+ # @author Frederico Linhares
26
+ def focus=(focus)
27
+ @focus = focus
28
+ set_center
29
+ end
30
+
31
+ # Updates scenario offset according to entity position.
32
+ #
33
+ # @author Frederico Linhares
34
+ def call
35
+ hor_offset = (@focus.relative_pos_x - @hor_center).to_i
36
+ if hor_offset < 0 then
37
+ @scenario.hor_offset = 0
38
+ elsif hor_offset > @max_hor_offset then
39
+ @scenario.hor_offset = @max_hor_offset
40
+ else
41
+ @scenario.hor_offset = hor_offset
42
+ end
43
+
44
+ ver_offset = (@focus.relative_pos_y - @ver_center).to_i
45
+ if ver_offset < 0 then
46
+ @scenario.ver_offset = 0
47
+ elsif ver_offset > @max_ver_offset then
48
+ @scenario.ver_offset = @max_ver_offset
49
+ else
50
+ @scenario.ver_offset = ver_offset
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def set_center
57
+ @hor_center = @scenario.width / 2 - @focus.width / 2
58
+ @ver_center = @scenario.height / 2 - @focus.height / 2
59
+ end
60
+ end
61
+ end