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