road_to_rubykaigi 0.1.0 → 0.2.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 +4 -4
- data/.standard.yml +11 -0
- data/CHANGELOG.md +6 -0
- data/README.md +15 -1
- data/Rakefile +1 -0
- data/lib/road_to_rubykaigi/audio/audio_engine.rb +70 -0
- data/lib/road_to_rubykaigi/audio/oscillator.rb +159 -0
- data/lib/road_to_rubykaigi/audio/sequencer.rb +263 -0
- data/lib/road_to_rubykaigi/audio/wav/attack_01.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/attack_02.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/attack_03.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/attack_04.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/attack_05.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/bonus.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/crouch.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/defeat.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/game_over.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/jump.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/laptop.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/stun.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/walk_01.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav/walk_02.wav +0 -0
- data/lib/road_to_rubykaigi/audio/wav_source.rb +55 -0
- data/lib/road_to_rubykaigi/event_dispatcher.rb +122 -0
- data/lib/road_to_rubykaigi/fireworks.rb +4 -4
- data/lib/road_to_rubykaigi/game.rb +49 -60
- data/lib/road_to_rubykaigi/graphics/demo-map.txt +30 -0
- data/lib/road_to_rubykaigi/graphics/demo-mask.txt +30 -0
- data/lib/road_to_rubykaigi/graphics/map.rb +6 -1
- data/lib/road_to_rubykaigi/graphics/mask.rb +7 -1
- data/lib/road_to_rubykaigi/graphics/player.rb +56 -65
- data/lib/road_to_rubykaigi/graphics/player.txt +26 -0
- data/lib/road_to_rubykaigi/manager/audio_manager.rb +81 -0
- data/lib/road_to_rubykaigi/manager/collision_manager.rb +23 -108
- data/lib/road_to_rubykaigi/manager/drawing_manager.rb +7 -6
- data/lib/road_to_rubykaigi/manager/game_manager.rb +50 -13
- data/lib/road_to_rubykaigi/manager/physics_engine.rb +21 -0
- data/lib/road_to_rubykaigi/manager/update_manager.rb +15 -12
- data/lib/road_to_rubykaigi/map.rb +1 -15
- data/lib/road_to_rubykaigi/score_board.rb +18 -1
- data/lib/road_to_rubykaigi/sprite/attack.rb +13 -6
- data/lib/road_to_rubykaigi/sprite/bonus.rb +16 -0
- data/lib/road_to_rubykaigi/sprite/deadline.rb +3 -3
- data/lib/road_to_rubykaigi/sprite/enemy.rb +12 -8
- data/lib/road_to_rubykaigi/sprite/player.rb +110 -29
- data/lib/road_to_rubykaigi/version.rb +1 -1
- data/lib/road_to_rubykaigi.rb +20 -4
- metadata +55 -3
@@ -8,13 +8,17 @@ module RoadToRubykaigi
|
|
8
8
|
WALK_MAX_SPEED = 20.0
|
9
9
|
WALK_FRICTION = 1.0
|
10
10
|
|
11
|
+
INITIAL_X = 10
|
11
12
|
BASE_Y = 26
|
13
|
+
BASE_HEIGHT = 3
|
12
14
|
JUMP_INITIAL_VELOCITY = -40.0
|
13
15
|
JUMP_GRAVITY = 80.0
|
14
16
|
|
17
|
+
ATTACK_COOLDOWN_SECOND = 0.1
|
15
18
|
KEY_INPUT_THRESHOLD = 0.5
|
16
|
-
ANIMETION_FRAME_SECOND = 0.
|
19
|
+
ANIMETION_FRAME_SECOND = 0.25
|
17
20
|
STUN_SECOND = 2.0
|
21
|
+
CROUCH_SECOND = 1.0
|
18
22
|
|
19
23
|
RIGHT = 1
|
20
24
|
LEFT = -1
|
@@ -28,25 +32,40 @@ module RoadToRubykaigi
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def jump
|
31
|
-
unless jumping?
|
35
|
+
unless jumping? || crouching?
|
32
36
|
@jumping = true
|
33
37
|
@vy = JUMP_INITIAL_VELOCITY
|
38
|
+
Manager::AudioManager.instance.jump
|
34
39
|
end
|
35
40
|
end
|
36
41
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# Not change stompable since stompable will not change from true
|
42
|
+
def crouch
|
43
|
+
unless jumping? || crouching?
|
44
|
+
@crouching_until = Time.now + CROUCH_SECOND
|
45
|
+
end
|
42
46
|
end
|
43
47
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def crouching?
|
49
|
+
@crouching_until && Time.now < @crouching_until
|
50
|
+
end
|
51
|
+
|
52
|
+
def can_attack!
|
53
|
+
@attack_mode = true
|
54
|
+
end
|
55
|
+
|
56
|
+
def can_attack?(attacks)
|
57
|
+
@attack_mode && attacks.remain_attack? && (Time.now - @last_attack_time >= ATTACK_COOLDOWN_SECOND)
|
58
|
+
end
|
59
|
+
|
60
|
+
def attack(attacks)
|
61
|
+
attacks.add(self)
|
62
|
+
@last_attack_time = Time.now
|
63
|
+
end
|
64
|
+
|
65
|
+
def attack_position
|
66
|
+
x_position = current_direction == RIGHT ? x + width : x - 2
|
67
|
+
y_position = crouching? ? y + 2 : y + 1
|
68
|
+
[x_position, y_position]
|
50
69
|
end
|
51
70
|
|
52
71
|
def stun
|
@@ -62,27 +81,55 @@ module RoadToRubykaigi
|
|
62
81
|
end
|
63
82
|
|
64
83
|
def update
|
65
|
-
return
|
84
|
+
return if stunned?
|
66
85
|
|
67
86
|
now = Time.now
|
87
|
+
standup
|
68
88
|
if (now - @animetion_updated_time) >= ANIMETION_FRAME_SECOND
|
69
89
|
@walking_frame = (@walking_frame + 1) % current_character.size
|
70
90
|
@animetion_updated_time = now
|
71
91
|
end
|
92
|
+
if jumping?
|
93
|
+
@stompable = @vy.positive? || (@y == BASE_Y && @vy.zero?) # stompable also when the moment just land
|
94
|
+
if @vy.zero?
|
95
|
+
@jumping = false
|
96
|
+
end
|
97
|
+
else
|
98
|
+
@stompable = false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def fall_if_ground_is_passable(map)
|
103
|
+
foot_y = @y + BASE_HEIGHT
|
104
|
+
center_x = @x + width / 2.0
|
105
|
+
if map.passable_at?(center_x, foot_y + 1)
|
106
|
+
fall
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def land_unless_ground_is_passable(map)
|
111
|
+
foot_y = @y + BASE_HEIGHT
|
112
|
+
(x...(x + width)).each do |col|
|
113
|
+
unless map.passable_at?(col, foot_y)
|
114
|
+
break land(foot_y)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
72
118
|
|
119
|
+
def simulate_physics
|
120
|
+
return @coordinate_updated_time = Time.now if stunned?
|
121
|
+
|
122
|
+
now = Time.now
|
73
123
|
elapsed_time = now - @coordinate_updated_time
|
74
124
|
@coordinate_updated_time = now
|
75
125
|
if jumping?
|
76
126
|
@vy += JUMP_GRAVITY * elapsed_time
|
77
127
|
@y += @vy * elapsed_time
|
78
|
-
@stompable = @vy.positive?
|
79
128
|
if @y >= BASE_Y
|
80
129
|
@y = BASE_Y
|
81
130
|
@vy = 0
|
82
|
-
@jumping = false
|
83
131
|
end
|
84
132
|
else
|
85
|
-
@stompable = false
|
86
133
|
if current_direction == RIGHT
|
87
134
|
@vx -= friction * elapsed_time
|
88
135
|
@vx = [@vx, 0].max # vx must be positive
|
@@ -92,7 +139,6 @@ module RoadToRubykaigi
|
|
92
139
|
end
|
93
140
|
end
|
94
141
|
@x += @vx * elapsed_time
|
95
|
-
|
96
142
|
@x = @x.round.to_i
|
97
143
|
@y = @y.round.to_i
|
98
144
|
end
|
@@ -100,7 +146,7 @@ module RoadToRubykaigi
|
|
100
146
|
def build_buffer(offset_x:)
|
101
147
|
buffer = Array.new(Map::VIEWPORT_HEIGHT) { Array.new(Map::VIEWPORT_WIDTH) { "" } }
|
102
148
|
relative_x = @x - offset_x - 1
|
103
|
-
relative_y = @y - 1
|
149
|
+
relative_y = @y + (BASE_HEIGHT - height) - 1
|
104
150
|
current_character[@walking_frame].each_with_index do |row, i|
|
105
151
|
row.each_with_index do |character, j|
|
106
152
|
buffer[relative_y+i][relative_x+j] = character
|
@@ -122,27 +168,36 @@ module RoadToRubykaigi
|
|
122
168
|
end
|
123
169
|
|
124
170
|
def width
|
125
|
-
@width ||= current_character.first.map(&:size).max
|
171
|
+
@width[@attack_mode] ||= current_character.first.map(&:size).max
|
126
172
|
end
|
127
173
|
|
128
174
|
def height
|
129
|
-
@height ||= current_character.first.size
|
175
|
+
@height[crouching?] ||= current_character.first.size
|
176
|
+
end
|
177
|
+
|
178
|
+
def current_direction
|
179
|
+
(@vx >= 0) ? RIGHT : LEFT
|
130
180
|
end
|
131
181
|
|
132
182
|
private
|
133
183
|
|
134
|
-
def initialize
|
135
|
-
@x =
|
136
|
-
@y =
|
184
|
+
def initialize
|
185
|
+
@x = INITIAL_X
|
186
|
+
@y = BASE_Y
|
137
187
|
@vx = 0.0
|
138
188
|
@vy = 0.0
|
189
|
+
@width ||= {}
|
190
|
+
@height ||= {}
|
139
191
|
@walking_frame = 0
|
140
192
|
@coordinate_updated_time = Time.now
|
141
193
|
@animetion_updated_time = Time.now
|
142
194
|
@key_input_time = Time.now
|
143
195
|
@jumping = false
|
196
|
+
@crouching_until = nil
|
144
197
|
@stompable = false
|
145
198
|
@stunned_until = Time.now
|
199
|
+
@attack_mode = false
|
200
|
+
@last_attack_time = Time.now
|
146
201
|
end
|
147
202
|
|
148
203
|
def move(dx)
|
@@ -151,11 +206,41 @@ module RoadToRubykaigi
|
|
151
206
|
end
|
152
207
|
@vx += WALK_ACCEL * dx
|
153
208
|
@vx = @vx.clamp(-WALK_MAX_SPEED, WALK_MAX_SPEED)
|
209
|
+
Manager::AudioManager.instance.walk
|
210
|
+
end
|
211
|
+
|
212
|
+
def fall
|
213
|
+
unless @jumping
|
214
|
+
@jumping = true
|
215
|
+
@vy = 0
|
216
|
+
@stompable = true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def land(land_y)
|
221
|
+
@y = land_y - BASE_HEIGHT
|
222
|
+
@vy = 0
|
223
|
+
@jumping = false
|
224
|
+
# Not change stompable since stompable will not change from true
|
225
|
+
end
|
226
|
+
|
227
|
+
def standup
|
228
|
+
if @crouching_until && Time.now > @crouching_until
|
229
|
+
@crouching_until = nil
|
230
|
+
# Standup with jumping
|
231
|
+
@y -= 1
|
232
|
+
@jumping = true
|
233
|
+
@vy = -0.1 # Avoid 0 to keep @jumping true for 1 frame
|
234
|
+
Manager::AudioManager.instance.jump
|
235
|
+
end
|
154
236
|
end
|
155
237
|
|
156
238
|
def current_character
|
239
|
+
posture = crouching? ? :crouching : :standup
|
157
240
|
status = stunned? ? :stunned : :normal
|
158
|
-
Graphics::Player.character(
|
241
|
+
Graphics::Player.character(
|
242
|
+
posture: posture, status: status, direction: current_direction, attack_mode: @attack_mode
|
243
|
+
)
|
159
244
|
end
|
160
245
|
|
161
246
|
def jumping?
|
@@ -169,10 +254,6 @@ module RoadToRubykaigi
|
|
169
254
|
WALK_FRICTION
|
170
255
|
end
|
171
256
|
end
|
172
|
-
|
173
|
-
def current_direction
|
174
|
-
(@vx >= 0) ? RIGHT : LEFT
|
175
|
-
end
|
176
257
|
end
|
177
258
|
end
|
178
259
|
end
|
data/lib/road_to_rubykaigi.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
require_relative "road_to_rubykaigi/version"
|
2
2
|
require_relative "road_to_rubykaigi/ansi"
|
3
|
+
require_relative "road_to_rubykaigi/audio/audio_engine"
|
4
|
+
require_relative "road_to_rubykaigi/audio/oscillator"
|
5
|
+
require_relative "road_to_rubykaigi/audio/sequencer"
|
6
|
+
require_relative "road_to_rubykaigi/audio/wav_source"
|
7
|
+
require_relative "road_to_rubykaigi/event_dispatcher"
|
3
8
|
require_relative "road_to_rubykaigi/fireworks"
|
4
9
|
require_relative "road_to_rubykaigi/game"
|
5
10
|
require_relative "road_to_rubykaigi/map"
|
6
11
|
require_relative "road_to_rubykaigi/opening_screen"
|
7
12
|
require_relative "road_to_rubykaigi/score_board"
|
13
|
+
require_relative "road_to_rubykaigi/manager/audio_manager"
|
8
14
|
require_relative "road_to_rubykaigi/manager/collision_manager"
|
9
15
|
require_relative "road_to_rubykaigi/manager/drawing_manager"
|
10
16
|
require_relative "road_to_rubykaigi/manager/game_manager"
|
17
|
+
require_relative "road_to_rubykaigi/manager/physics_engine"
|
11
18
|
require_relative "road_to_rubykaigi/manager/update_manager"
|
12
19
|
require_relative "road_to_rubykaigi/sprite/sprite"
|
13
20
|
require_relative "road_to_rubykaigi/sprite/attack"
|
@@ -24,16 +31,25 @@ require "io/console"
|
|
24
31
|
|
25
32
|
module RoadToRubykaigi
|
26
33
|
class Error < StandardError; end
|
27
|
-
END_POSITION = Map
|
34
|
+
END_POSITION = Map::VIEWPORT_HEIGHT + 2
|
28
35
|
|
29
|
-
def self.start
|
36
|
+
def self.start(game_mode = :normal)
|
30
37
|
ANSI.cursor_off
|
31
38
|
at_exit do
|
32
39
|
print "\e[#{END_POSITION};1H"
|
33
40
|
ANSI.cursor_on
|
34
41
|
end
|
35
42
|
|
36
|
-
|
43
|
+
@game_mode = game_mode
|
44
|
+
if demo?
|
45
|
+
Game.new.run
|
46
|
+
else
|
47
|
+
OpeningScreen.new.display && Game.new.run
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.demo?
|
52
|
+
@game_mode != :normal
|
37
53
|
end
|
38
54
|
|
39
55
|
def self.debug
|
@@ -41,6 +57,6 @@ module RoadToRubykaigi
|
|
41
57
|
end
|
42
58
|
|
43
59
|
def self.debug_add(string)
|
44
|
-
|
60
|
+
debug << "\e[#{END_POSITION+debug.size};1H" + string
|
45
61
|
end
|
46
62
|
end
|
metadata
CHANGED
@@ -1,14 +1,42 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: road_to_rubykaigi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- makicamel
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
11
|
-
dependencies:
|
10
|
+
date: 2025-04-15 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: ffi-portaudio
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: wavefile
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
12
40
|
description: Road to RubyKaigi is a Ruby gem that delivers a nostalgic, text-based
|
13
41
|
action game experience. Dodge obstacles, overcome bugs, and beat the deadline to
|
14
42
|
reach RubyKaigi. All in your terminal.
|
@@ -29,8 +57,29 @@ files:
|
|
29
57
|
- bin/road_to_rubykaigi
|
30
58
|
- lib/road_to_rubykaigi.rb
|
31
59
|
- lib/road_to_rubykaigi/ansi.rb
|
60
|
+
- lib/road_to_rubykaigi/audio/audio_engine.rb
|
61
|
+
- lib/road_to_rubykaigi/audio/oscillator.rb
|
62
|
+
- lib/road_to_rubykaigi/audio/sequencer.rb
|
63
|
+
- lib/road_to_rubykaigi/audio/wav/attack_01.wav
|
64
|
+
- lib/road_to_rubykaigi/audio/wav/attack_02.wav
|
65
|
+
- lib/road_to_rubykaigi/audio/wav/attack_03.wav
|
66
|
+
- lib/road_to_rubykaigi/audio/wav/attack_04.wav
|
67
|
+
- lib/road_to_rubykaigi/audio/wav/attack_05.wav
|
68
|
+
- lib/road_to_rubykaigi/audio/wav/bonus.wav
|
69
|
+
- lib/road_to_rubykaigi/audio/wav/crouch.wav
|
70
|
+
- lib/road_to_rubykaigi/audio/wav/defeat.wav
|
71
|
+
- lib/road_to_rubykaigi/audio/wav/game_over.wav
|
72
|
+
- lib/road_to_rubykaigi/audio/wav/jump.wav
|
73
|
+
- lib/road_to_rubykaigi/audio/wav/laptop.wav
|
74
|
+
- lib/road_to_rubykaigi/audio/wav/stun.wav
|
75
|
+
- lib/road_to_rubykaigi/audio/wav/walk_01.wav
|
76
|
+
- lib/road_to_rubykaigi/audio/wav/walk_02.wav
|
77
|
+
- lib/road_to_rubykaigi/audio/wav_source.rb
|
78
|
+
- lib/road_to_rubykaigi/event_dispatcher.rb
|
32
79
|
- lib/road_to_rubykaigi/fireworks.rb
|
33
80
|
- lib/road_to_rubykaigi/game.rb
|
81
|
+
- lib/road_to_rubykaigi/graphics/demo-map.txt
|
82
|
+
- lib/road_to_rubykaigi/graphics/demo-mask.txt
|
34
83
|
- lib/road_to_rubykaigi/graphics/fireworks.rb
|
35
84
|
- lib/road_to_rubykaigi/graphics/fireworks.txt
|
36
85
|
- lib/road_to_rubykaigi/graphics/map.rb
|
@@ -38,9 +87,12 @@ files:
|
|
38
87
|
- lib/road_to_rubykaigi/graphics/mask.rb
|
39
88
|
- lib/road_to_rubykaigi/graphics/mask.txt
|
40
89
|
- lib/road_to_rubykaigi/graphics/player.rb
|
90
|
+
- lib/road_to_rubykaigi/graphics/player.txt
|
91
|
+
- lib/road_to_rubykaigi/manager/audio_manager.rb
|
41
92
|
- lib/road_to_rubykaigi/manager/collision_manager.rb
|
42
93
|
- lib/road_to_rubykaigi/manager/drawing_manager.rb
|
43
94
|
- lib/road_to_rubykaigi/manager/game_manager.rb
|
95
|
+
- lib/road_to_rubykaigi/manager/physics_engine.rb
|
44
96
|
- lib/road_to_rubykaigi/manager/update_manager.rb
|
45
97
|
- lib/road_to_rubykaigi/map.rb
|
46
98
|
- lib/road_to_rubykaigi/opening_screen.rb
|