road_to_rubykaigi 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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.standard.yml +18 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +49 -0
- data/Rakefile +10 -0
- data/bin/road_to_rubykaigi +5 -0
- data/lib/road_to_rubykaigi/ansi.rb +22 -0
- data/lib/road_to_rubykaigi/fireworks.rb +63 -0
- data/lib/road_to_rubykaigi/game.rb +97 -0
- data/lib/road_to_rubykaigi/graphics/fireworks.rb +16 -0
- data/lib/road_to_rubykaigi/graphics/fireworks.txt +369 -0
- data/lib/road_to_rubykaigi/graphics/map.rb +11 -0
- data/lib/road_to_rubykaigi/graphics/map.txt +30 -0
- data/lib/road_to_rubykaigi/graphics/mask.rb +11 -0
- data/lib/road_to_rubykaigi/graphics/mask.txt +30 -0
- data/lib/road_to_rubykaigi/graphics/player.rb +81 -0
- data/lib/road_to_rubykaigi/manager/collision_manager.rb +133 -0
- data/lib/road_to_rubykaigi/manager/drawing_manager.rb +48 -0
- data/lib/road_to_rubykaigi/manager/game_manager.rb +55 -0
- data/lib/road_to_rubykaigi/manager/update_manager.rb +27 -0
- data/lib/road_to_rubykaigi/map.rb +120 -0
- data/lib/road_to_rubykaigi/opening_screen.rb +56 -0
- data/lib/road_to_rubykaigi/score_board.rb +17 -0
- data/lib/road_to_rubykaigi/sprite/attack.rb +72 -0
- data/lib/road_to_rubykaigi/sprite/bonus.rb +127 -0
- data/lib/road_to_rubykaigi/sprite/deadline.rb +57 -0
- data/lib/road_to_rubykaigi/sprite/effect.rb +88 -0
- data/lib/road_to_rubykaigi/sprite/enemy.rb +178 -0
- data/lib/road_to_rubykaigi/sprite/player.rb +178 -0
- data/lib/road_to_rubykaigi/sprite/sprite.rb +22 -0
- data/lib/road_to_rubykaigi/version.rb +5 -0
- data/lib/road_to_rubykaigi.rb +46 -0
- data/sig/road_to_rubykaigi.rbs +4 -0
- metadata +82 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
module RoadToRubykaigi
|
2
|
+
module Sprite
|
3
|
+
class Deadline < Sprite
|
4
|
+
DEADLINE_SPEED = 0.3
|
5
|
+
DEADLINE_START_X = 18
|
6
|
+
|
7
|
+
attr_reader :x, :y, :width, :height
|
8
|
+
|
9
|
+
def find
|
10
|
+
yield self || nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def update
|
14
|
+
return unless active?
|
15
|
+
now = Time.now
|
16
|
+
if (now - @last_update) > DEADLINE_SPEED
|
17
|
+
@x += 1
|
18
|
+
@last_update = now
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_buffer(offset_x:)
|
23
|
+
buffer = Array.new(Map::VIEWPORT_HEIGHT) { Array.new(Map::VIEWPORT_WIDTH) { "" } }
|
24
|
+
relative_x = @x - offset_x - 1
|
25
|
+
relative_y = @y - 1
|
26
|
+
@height.times do |i|
|
27
|
+
next if relative_x < 1
|
28
|
+
buffer[relative_y+i][relative_x] = ANSI::RED + "#" + ANSI::DEFAULT_TEXT_COLOR
|
29
|
+
end
|
30
|
+
buffer
|
31
|
+
end
|
32
|
+
|
33
|
+
def bounding_box
|
34
|
+
{ x: @x, y: @y, width: @width, height: @height }
|
35
|
+
end
|
36
|
+
|
37
|
+
def activate(player_x:)
|
38
|
+
@waiting = false if player_x > DEADLINE_START_X
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def initialize(map_height)
|
44
|
+
@x = 2
|
45
|
+
@y = 1
|
46
|
+
@width = 1
|
47
|
+
@height = map_height
|
48
|
+
@last_update = Time.now
|
49
|
+
@waiting = true
|
50
|
+
end
|
51
|
+
|
52
|
+
def active?
|
53
|
+
!@waiting
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module RoadToRubykaigi
|
2
|
+
module Sprite
|
3
|
+
class Effects
|
4
|
+
def update
|
5
|
+
@effects.reject!(&:expired?)
|
6
|
+
end
|
7
|
+
|
8
|
+
def heart(x, y)
|
9
|
+
@effects << HeartEffect.new(x, y)
|
10
|
+
end
|
11
|
+
|
12
|
+
def note(x, y)
|
13
|
+
@effects << NoteEffect.new(x, y)
|
14
|
+
end
|
15
|
+
|
16
|
+
def lightning(x, y)
|
17
|
+
@effects << LightningEffect.new(x, y)
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_buffer(offset_x:)
|
21
|
+
buffer = Array.new(Map::VIEWPORT_HEIGHT) { Array.new(Map::VIEWPORT_WIDTH) { "" } }
|
22
|
+
@effects.each do |effect|
|
23
|
+
bounding_box = effect.bounding_box
|
24
|
+
relative_x = bounding_box[:x] - offset_x - 1
|
25
|
+
relative_y = bounding_box[:y] - 1
|
26
|
+
next if relative_x < 1
|
27
|
+
buffer[relative_y][relative_x] = effect.character
|
28
|
+
end
|
29
|
+
buffer
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_a
|
33
|
+
@effects.to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
@effects = []
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Effect < Sprite
|
44
|
+
def update
|
45
|
+
elapsed = Time.now - @start_time
|
46
|
+
@y = (@y - elapsed).to_i
|
47
|
+
end
|
48
|
+
|
49
|
+
def character
|
50
|
+
self.class::SYMBOL
|
51
|
+
end
|
52
|
+
|
53
|
+
def expired?
|
54
|
+
(Time.now - @start_time) >= self.class::DURATION
|
55
|
+
end
|
56
|
+
|
57
|
+
def bounding_box
|
58
|
+
{ x: @x, y: @y, width: 1, height: 1 }
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def initialize(x, y)
|
64
|
+
@x = x
|
65
|
+
@y = y
|
66
|
+
@start_time = Time.now
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class HeartEffect < Effect
|
71
|
+
DURATION = 1.0
|
72
|
+
SYMBOL = ANSI::RED + "♥" + ANSI::DEFAULT_TEXT_COLOR
|
73
|
+
end
|
74
|
+
|
75
|
+
class NoteEffect < Effect
|
76
|
+
DURATION = 1.0
|
77
|
+
SYMBOL = ANSI::BLUE + "♪" + ANSI::DEFAULT_TEXT_COLOR
|
78
|
+
end
|
79
|
+
|
80
|
+
class LightningEffect < Effect
|
81
|
+
DURATION = 0.3
|
82
|
+
SYMBOL = ANSI::YELLOW + "⚡︎" + ANSI::DEFAULT_TEXT_COLOR
|
83
|
+
|
84
|
+
def update
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module RoadToRubykaigi
|
4
|
+
module Sprite
|
5
|
+
class Enemies
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@enemies, :to_a, :find, :delete, :each
|
8
|
+
ENEMIES_DATA = {
|
9
|
+
FixedPatrol: [
|
10
|
+
{ x: 55, y: 6, left_bound: 0, right_bound: 0, speed: 0, character: :ladybug },
|
11
|
+
{ x: 125, y: 8, left_bound: 0, right_bound: 0, speed: 0, character: :ladybug },
|
12
|
+
{ x: 293, y: 23, left_bound: 0, right_bound: 0, speed: 0, character: :spider },
|
13
|
+
],
|
14
|
+
HorizontalPatrol: [
|
15
|
+
{ x: 123, y: 26, left_bound: 114, right_bound: 123, speed: 1.5, character: :bee },
|
16
|
+
{ x: 171, y: 26, left_bound: 162, right_bound: 171, speed: 1.5, character: :bee },
|
17
|
+
{ x: 278, y: 15, left_bound: 270, right_bound: 278, speed: 1.5, character: :bug },
|
18
|
+
{ x: 291, y: 15, left_bound: 283, right_bound: 291, speed: 1.5, character: :bug },
|
19
|
+
{ x: 302, y: 15, left_bound: 297, right_bound: 302, speed: 1.5, character: :bug },
|
20
|
+
],
|
21
|
+
ScreenEntryPatrol: [
|
22
|
+
{ x: 63, y: 27, left_bound: 0, right_bound: 63, speed: 4.0, character: :bug },
|
23
|
+
{ x: 76, y: 27, left_bound: 0, right_bound: 76, speed: 4.0, character: :bug },
|
24
|
+
{ x: 87, y: 27, left_bound: 0, right_bound: 76, speed: 4.0, character: :bug },
|
25
|
+
{ x: 221, y: 23, left_bound: 0, right_bound: 151, speed: 6.0, character: :bee },
|
26
|
+
{ x: 240, y: 19, left_bound: 0, right_bound: 170, speed: 6.0, character: :bee },
|
27
|
+
{ x: 256, y: 16, left_bound: 0, right_bound: 186, speed: 6.0, character: :bee },
|
28
|
+
],
|
29
|
+
}
|
30
|
+
|
31
|
+
def build_buffer(offset_x:)
|
32
|
+
buffer = Array.new(Map::VIEWPORT_HEIGHT) { Array.new(Map::VIEWPORT_WIDTH) { "" } }
|
33
|
+
@enemies.each do |enemy|
|
34
|
+
bounding_box = enemy.bounding_box
|
35
|
+
relative_x = bounding_box[:x] - offset_x - 1
|
36
|
+
relative_y = bounding_box[:y] - 1
|
37
|
+
next if relative_x < 1
|
38
|
+
enemy.characters.each_with_index do |character, j|
|
39
|
+
next if relative_x + j >= Map::VIEWPORT_WIDTH - 1
|
40
|
+
buffer[relative_y][relative_x+j] = character
|
41
|
+
end
|
42
|
+
end
|
43
|
+
buffer
|
44
|
+
end
|
45
|
+
|
46
|
+
def update
|
47
|
+
if activated?
|
48
|
+
@enemies.each(&:update)
|
49
|
+
else
|
50
|
+
@enemies.each(&:reset_last_update_time)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def activate
|
55
|
+
@waiting = false
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def initialize
|
61
|
+
@enemies = ENEMIES_DATA.map do |key, enemies|
|
62
|
+
strategy = RoadToRubykaigi::Sprite.const_get("#{key}Strategy")
|
63
|
+
enemies.map do |enemy|
|
64
|
+
Enemy.new(
|
65
|
+
enemy[:x],
|
66
|
+
enemy[:y],
|
67
|
+
enemy[:character],
|
68
|
+
strategy.new(
|
69
|
+
left_bound: enemy[:left_bound],
|
70
|
+
right_bound: enemy[:right_bound],
|
71
|
+
speed: enemy[:speed],
|
72
|
+
),
|
73
|
+
)
|
74
|
+
end
|
75
|
+
end.flatten
|
76
|
+
@waiting = true
|
77
|
+
end
|
78
|
+
|
79
|
+
def activated?
|
80
|
+
!@waiting
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Enemy < Sprite
|
85
|
+
CHARACTER = {
|
86
|
+
bee: "🐝",
|
87
|
+
bug: "🐛",
|
88
|
+
ladybug: "🐞",
|
89
|
+
spider: "🕷️",
|
90
|
+
}
|
91
|
+
RIGHT = 1
|
92
|
+
LEFT = -1
|
93
|
+
attr_accessor :x
|
94
|
+
attr_reader :y, :direction
|
95
|
+
|
96
|
+
def bounding_box
|
97
|
+
{ x: @x, y: @y, width: width, height: height }
|
98
|
+
end
|
99
|
+
|
100
|
+
def characters
|
101
|
+
super { [CHARACTER[@character]] }
|
102
|
+
end
|
103
|
+
|
104
|
+
def update
|
105
|
+
elapsed_time = Time.now - @last_update_time
|
106
|
+
@last_update_time = Time.now
|
107
|
+
@strategy.update(self, elapsed_time)
|
108
|
+
end
|
109
|
+
|
110
|
+
def reset_last_update_time
|
111
|
+
@last_update_time = Time.now
|
112
|
+
end
|
113
|
+
|
114
|
+
def width
|
115
|
+
2
|
116
|
+
end
|
117
|
+
|
118
|
+
def height
|
119
|
+
1
|
120
|
+
end
|
121
|
+
|
122
|
+
def reverse_direction
|
123
|
+
@direction *= -1
|
124
|
+
end
|
125
|
+
|
126
|
+
def activate_with_offset(offset_x)
|
127
|
+
if !@active && @x <= (offset_x + Map::VIEWPORT_WIDTH)
|
128
|
+
@active = true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def active?
|
133
|
+
@active
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def initialize(x, y, character, strategy)
|
139
|
+
@x = x
|
140
|
+
@y = y
|
141
|
+
@character = character
|
142
|
+
@direction = LEFT
|
143
|
+
@strategy = strategy
|
144
|
+
@active = !strategy.is_a?(ScreenEntryPatrolStrategy)
|
145
|
+
@last_update_time = Time.now
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class PatrolStrategy
|
150
|
+
def initialize(left_bound:, right_bound:, speed:)
|
151
|
+
@left_bound = left_bound
|
152
|
+
@right_bound = right_bound
|
153
|
+
@speed = speed
|
154
|
+
end
|
155
|
+
|
156
|
+
def update(enemy, elapsed_time)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class FixedPatrolStrategy < PatrolStrategy
|
161
|
+
end
|
162
|
+
|
163
|
+
class HorizontalPatrolStrategy < PatrolStrategy
|
164
|
+
def update(enemy, elapsed_time)
|
165
|
+
enemy.x += @speed * elapsed_time * enemy.direction
|
166
|
+
enemy.x = enemy.x.clamp(@left_bound, @right_bound)
|
167
|
+
enemy.reverse_direction if enemy.x == @left_bound || enemy.x == @right_bound
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class ScreenEntryPatrolStrategy < PatrolStrategy
|
172
|
+
def update(enemy, elapsed_time)
|
173
|
+
return unless enemy.active?
|
174
|
+
enemy.x += @speed * elapsed_time * enemy.direction
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module RoadToRubykaigi
|
2
|
+
module Sprite
|
3
|
+
class Player
|
4
|
+
attr_reader :x, :y
|
5
|
+
attr_accessor :vy
|
6
|
+
|
7
|
+
WALK_ACCEL = 15.0
|
8
|
+
WALK_MAX_SPEED = 20.0
|
9
|
+
WALK_FRICTION = 1.0
|
10
|
+
|
11
|
+
BASE_Y = 26
|
12
|
+
JUMP_INITIAL_VELOCITY = -40.0
|
13
|
+
JUMP_GRAVITY = 80.0
|
14
|
+
|
15
|
+
KEY_INPUT_THRESHOLD = 0.5
|
16
|
+
ANIMETION_FRAME_SECOND = 0.5
|
17
|
+
STUN_SECOND = 2.0
|
18
|
+
|
19
|
+
RIGHT = 1
|
20
|
+
LEFT = -1
|
21
|
+
|
22
|
+
def right
|
23
|
+
move(RIGHT)
|
24
|
+
end
|
25
|
+
|
26
|
+
def left
|
27
|
+
move(LEFT)
|
28
|
+
end
|
29
|
+
|
30
|
+
def jump
|
31
|
+
unless jumping?
|
32
|
+
@jumping = true
|
33
|
+
@vy = JUMP_INITIAL_VELOCITY
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def land(land_y)
|
38
|
+
@y = land_y - height
|
39
|
+
@vy = 0
|
40
|
+
@jumping = false
|
41
|
+
# Not change stompable since stompable will not change from true
|
42
|
+
end
|
43
|
+
|
44
|
+
def fall
|
45
|
+
unless @jumping
|
46
|
+
@jumping = true
|
47
|
+
@vy = 0
|
48
|
+
@stompable = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def stun
|
53
|
+
@stunned_until = Time.now + STUN_SECOND
|
54
|
+
end
|
55
|
+
|
56
|
+
def stunned?
|
57
|
+
Time.now < @stunned_until
|
58
|
+
end
|
59
|
+
|
60
|
+
def stompable?
|
61
|
+
@stompable
|
62
|
+
end
|
63
|
+
|
64
|
+
def update
|
65
|
+
return @coordinate_updated_time = Time.now if stunned?
|
66
|
+
|
67
|
+
now = Time.now
|
68
|
+
if (now - @animetion_updated_time) >= ANIMETION_FRAME_SECOND
|
69
|
+
@walking_frame = (@walking_frame + 1) % current_character.size
|
70
|
+
@animetion_updated_time = now
|
71
|
+
end
|
72
|
+
|
73
|
+
elapsed_time = now - @coordinate_updated_time
|
74
|
+
@coordinate_updated_time = now
|
75
|
+
if jumping?
|
76
|
+
@vy += JUMP_GRAVITY * elapsed_time
|
77
|
+
@y += @vy * elapsed_time
|
78
|
+
@stompable = @vy.positive?
|
79
|
+
if @y >= BASE_Y
|
80
|
+
@y = BASE_Y
|
81
|
+
@vy = 0
|
82
|
+
@jumping = false
|
83
|
+
end
|
84
|
+
else
|
85
|
+
@stompable = false
|
86
|
+
if current_direction == RIGHT
|
87
|
+
@vx -= friction * elapsed_time
|
88
|
+
@vx = [@vx, 0].max # vx must be positive
|
89
|
+
else
|
90
|
+
@vx += friction * elapsed_time
|
91
|
+
@vx = [@vx, 0].min # vx must be negative
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@x += @vx * elapsed_time
|
95
|
+
|
96
|
+
@x = @x.round.to_i
|
97
|
+
@y = @y.round.to_i
|
98
|
+
end
|
99
|
+
|
100
|
+
def build_buffer(offset_x:)
|
101
|
+
buffer = Array.new(Map::VIEWPORT_HEIGHT) { Array.new(Map::VIEWPORT_WIDTH) { "" } }
|
102
|
+
relative_x = @x - offset_x - 1
|
103
|
+
relative_y = @y - 1
|
104
|
+
current_character[@walking_frame].each_with_index do |row, i|
|
105
|
+
row.each_with_index do |character, j|
|
106
|
+
buffer[relative_y+i][relative_x+j] = character
|
107
|
+
end
|
108
|
+
end
|
109
|
+
buffer
|
110
|
+
end
|
111
|
+
|
112
|
+
def enforce_boundary(map, offset_x:)
|
113
|
+
@x, @y = map.clamp_position(
|
114
|
+
dx: @vx.round.clamp(-1, 1) * -1,
|
115
|
+
dy: @vy.round.clamp(-1, 1) * -1,
|
116
|
+
**bounding_box
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def bounding_box
|
121
|
+
{ x: @x, y: @y, width: width, height: height }
|
122
|
+
end
|
123
|
+
|
124
|
+
def width
|
125
|
+
@width ||= current_character.first.map(&:size).max
|
126
|
+
end
|
127
|
+
|
128
|
+
def height
|
129
|
+
@height ||= current_character.first.size
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def initialize(x = 10, y = BASE_Y)
|
135
|
+
@x = x
|
136
|
+
@y = y
|
137
|
+
@vx = 0.0
|
138
|
+
@vy = 0.0
|
139
|
+
@walking_frame = 0
|
140
|
+
@coordinate_updated_time = Time.now
|
141
|
+
@animetion_updated_time = Time.now
|
142
|
+
@key_input_time = Time.now
|
143
|
+
@jumping = false
|
144
|
+
@stompable = false
|
145
|
+
@stunned_until = Time.now
|
146
|
+
end
|
147
|
+
|
148
|
+
def move(dx)
|
149
|
+
unless current_direction == dx
|
150
|
+
@vx = 0
|
151
|
+
end
|
152
|
+
@vx += WALK_ACCEL * dx
|
153
|
+
@vx = @vx.clamp(-WALK_MAX_SPEED, WALK_MAX_SPEED)
|
154
|
+
end
|
155
|
+
|
156
|
+
def current_character
|
157
|
+
status = stunned? ? :stunned : :normal
|
158
|
+
Graphics::Player.character(status, current_direction)
|
159
|
+
end
|
160
|
+
|
161
|
+
def jumping?
|
162
|
+
@jumping
|
163
|
+
end
|
164
|
+
|
165
|
+
def friction
|
166
|
+
if (Time.now - @key_input_time) >= KEY_INPUT_THRESHOLD
|
167
|
+
WALK_MAX_SPEED
|
168
|
+
else
|
169
|
+
WALK_FRICTION
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def current_direction
|
174
|
+
(@vx >= 0) ? RIGHT : LEFT
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RoadToRubykaigi
|
2
|
+
module Sprite
|
3
|
+
class Sprite
|
4
|
+
def characters
|
5
|
+
yield.map do |character|
|
6
|
+
fullwidth?(character) ? [character, ANSI::NULL] : character
|
7
|
+
end.flatten
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def fullwidth?(character)
|
13
|
+
code = character.ord
|
14
|
+
(0x1F300..0x1F5FF).cover?(code) ||
|
15
|
+
(0x1F600..0x1F64F).cover?(code) ||
|
16
|
+
(0x1F680..0x1F6FF).cover?(code) ||
|
17
|
+
(0x1F700..0x1F77F).cover?(code) ||
|
18
|
+
code == 0x2615
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative "road_to_rubykaigi/version"
|
2
|
+
require_relative "road_to_rubykaigi/ansi"
|
3
|
+
require_relative "road_to_rubykaigi/fireworks"
|
4
|
+
require_relative "road_to_rubykaigi/game"
|
5
|
+
require_relative "road_to_rubykaigi/map"
|
6
|
+
require_relative "road_to_rubykaigi/opening_screen"
|
7
|
+
require_relative "road_to_rubykaigi/score_board"
|
8
|
+
require_relative "road_to_rubykaigi/manager/collision_manager"
|
9
|
+
require_relative "road_to_rubykaigi/manager/drawing_manager"
|
10
|
+
require_relative "road_to_rubykaigi/manager/game_manager"
|
11
|
+
require_relative "road_to_rubykaigi/manager/update_manager"
|
12
|
+
require_relative "road_to_rubykaigi/sprite/sprite"
|
13
|
+
require_relative "road_to_rubykaigi/sprite/attack"
|
14
|
+
require_relative "road_to_rubykaigi/sprite/bonus"
|
15
|
+
require_relative "road_to_rubykaigi/sprite/deadline"
|
16
|
+
require_relative "road_to_rubykaigi/sprite/effect"
|
17
|
+
require_relative "road_to_rubykaigi/sprite/enemy"
|
18
|
+
require_relative "road_to_rubykaigi/sprite/player"
|
19
|
+
require_relative "road_to_rubykaigi/graphics/fireworks"
|
20
|
+
require_relative "road_to_rubykaigi/graphics/mask"
|
21
|
+
require_relative "road_to_rubykaigi/graphics/map"
|
22
|
+
require_relative "road_to_rubykaigi/graphics/player"
|
23
|
+
require "io/console"
|
24
|
+
|
25
|
+
module RoadToRubykaigi
|
26
|
+
class Error < StandardError; end
|
27
|
+
END_POSITION = Map.new.height + 2
|
28
|
+
|
29
|
+
def self.start
|
30
|
+
ANSI.cursor_off
|
31
|
+
at_exit do
|
32
|
+
print "\e[#{END_POSITION};1H"
|
33
|
+
ANSI.cursor_on
|
34
|
+
end
|
35
|
+
|
36
|
+
OpeningScreen.new.display && Game.new.run
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.debug
|
40
|
+
@debug ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.debug_add(string)
|
44
|
+
@debug << "\e[#{END_POSITION+@debug.size};1H" + string
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: road_to_rubykaigi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- makicamel
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-02-27 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: Road to RubyKaigi is a Ruby gem that delivers a nostalgic, text-based
|
13
|
+
action game experience. Dodge obstacles, overcome bugs, and beat the deadline to
|
14
|
+
reach RubyKaigi. All in your terminal.
|
15
|
+
email:
|
16
|
+
- unright@gmail.com
|
17
|
+
executables:
|
18
|
+
- road_to_rubykaigi
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- ".rspec"
|
23
|
+
- ".standard.yml"
|
24
|
+
- CHANGELOG.md
|
25
|
+
- CODE_OF_CONDUCT.md
|
26
|
+
- LICENSE.txt
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- bin/road_to_rubykaigi
|
30
|
+
- lib/road_to_rubykaigi.rb
|
31
|
+
- lib/road_to_rubykaigi/ansi.rb
|
32
|
+
- lib/road_to_rubykaigi/fireworks.rb
|
33
|
+
- lib/road_to_rubykaigi/game.rb
|
34
|
+
- lib/road_to_rubykaigi/graphics/fireworks.rb
|
35
|
+
- lib/road_to_rubykaigi/graphics/fireworks.txt
|
36
|
+
- lib/road_to_rubykaigi/graphics/map.rb
|
37
|
+
- lib/road_to_rubykaigi/graphics/map.txt
|
38
|
+
- lib/road_to_rubykaigi/graphics/mask.rb
|
39
|
+
- lib/road_to_rubykaigi/graphics/mask.txt
|
40
|
+
- lib/road_to_rubykaigi/graphics/player.rb
|
41
|
+
- lib/road_to_rubykaigi/manager/collision_manager.rb
|
42
|
+
- lib/road_to_rubykaigi/manager/drawing_manager.rb
|
43
|
+
- lib/road_to_rubykaigi/manager/game_manager.rb
|
44
|
+
- lib/road_to_rubykaigi/manager/update_manager.rb
|
45
|
+
- lib/road_to_rubykaigi/map.rb
|
46
|
+
- lib/road_to_rubykaigi/opening_screen.rb
|
47
|
+
- lib/road_to_rubykaigi/score_board.rb
|
48
|
+
- lib/road_to_rubykaigi/sprite/attack.rb
|
49
|
+
- lib/road_to_rubykaigi/sprite/bonus.rb
|
50
|
+
- lib/road_to_rubykaigi/sprite/deadline.rb
|
51
|
+
- lib/road_to_rubykaigi/sprite/effect.rb
|
52
|
+
- lib/road_to_rubykaigi/sprite/enemy.rb
|
53
|
+
- lib/road_to_rubykaigi/sprite/player.rb
|
54
|
+
- lib/road_to_rubykaigi/sprite/sprite.rb
|
55
|
+
- lib/road_to_rubykaigi/version.rb
|
56
|
+
- sig/road_to_rubykaigi.rbs
|
57
|
+
homepage: https://github.com/makicamel/road_to_rubykaigi
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata:
|
61
|
+
homepage_uri: https://github.com/makicamel/road_to_rubykaigi
|
62
|
+
source_code_uri: https://github.com/makicamel/road_to_rubykaigi
|
63
|
+
changelog_uri: https://github.com/makicamel/road_to_rubykaigi/blob/main/CHANGELOG.md
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 3.4.0
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubygems_version: 3.6.2
|
79
|
+
specification_version: 4
|
80
|
+
summary: A retro ASCII action game where Rubyist overcomes a looming deadline and
|
81
|
+
bugs on your way to RubyKaigi
|
82
|
+
test_files: []
|