Class: RoadToRubykaigi::Sprite::Player

Inherits:
Object
  • Object
show all
Defined in:
lib/road_to_rubykaigi/sprite/player.rb

Constant Summary collapse

WALK_ACCEL =
15.0
WALK_MAX_SPEED =
20.0
WALK_FRICTION =
1.0
RUNNING_SPEED_THRESHOLD =
1.3
RUNNING_SUSTAIN_SECOND =
0.3
INITIAL_X =
{ 2025 => 10, 2026 => 40 }
WARMUP_END_X =
{ 2025 => 18, 2026 => 48 }
WARMUP_SPEED_RATIO_CAP =
1.0
BASE_Y =
26
INITIAL_Y =
{ 2025 => BASE_Y, 2026 => 15 }
BASE_HEIGHT =
3
JUMP_INITIAL_VELOCITY =
-40.0
JUMP_GRAVITY =
80.0
ATTACK_COOLDOWN_SECOND =
0.1
KEY_INPUT_THRESHOLD =
0.5
ANIMETION_FRAME_SECOND =
0.25
STUN_SECOND =
2.0
CROUCH_SECOND =
1.0
RIGHT =
1
LEFT =
-1

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#vyObject

Returns the value of attribute vy.



5
6
7
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 5

def vy
  @vy
end

#xObject (readonly)

Returns the value of attribute x.



4
5
6
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 4

def x
  @x
end

#yObject (readonly)

Returns the value of attribute y.



4
5
6
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 4

def y
  @y
end

Instance Method Details

#attack(attacks) ⇒ Object



76
77
78
79
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 76

def attack(attacks)
  attacks.add(self)
  @last_attack_time = Time.now
end

#attack_positionObject



81
82
83
84
85
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 81

def attack_position
  x_position = current_direction == RIGHT ? x + width : x - 2
  y_position = crouching? ? y + 2 : y + 1
  [x_position, y_position]
end

#bounding_boxObject



182
183
184
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 182

def bounding_box
  { x: @x, y: @y, width: width, height: height }
end

#build_buffer(offset_x:) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 162

def build_buffer(offset_x:)
  buffer = Array.new(Map::VIEWPORT_HEIGHT) { Array.new(Map::VIEWPORT_WIDTH) { "" } }
  relative_x = @x - offset_x - 1
  relative_y = @y + (BASE_HEIGHT - height) - 1
  current_character[@walking_frame].each_with_index do |row, i|
    row.each_with_index do |character, j|
      buffer[relative_y+i][relative_x+j] = character
    end
  end
  buffer
end

#can_attack!Object



68
69
70
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 68

def can_attack!
  @attack_mode = true
end

#can_attack?(attacks) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 72

def can_attack?(attacks)
  @attack_mode && attacks.remain_attack? && (Time.now - @last_attack_time >= ATTACK_COOLDOWN_SECOND)
end

#crouchObject



58
59
60
61
62
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 58

def crouch
  unless jumping? || crouching?
    @crouching_until = Time.now + CROUCH_SECOND
  end
end

#crouching?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 64

def crouching?
  @crouching_until && Time.now < @crouching_until
end

#current_directionObject



194
195
196
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 194

def current_direction
  (@vx >= 0) ? RIGHT : LEFT
end

#enforce_boundary(map, offset_x:) ⇒ Object



174
175
176
177
178
179
180
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 174

def enforce_boundary(map, offset_x:)
  @x, @y = map.clamp_position(
    dx: @vx.round.clamp(-1, 1) * -1,
    dy: @vy.round.clamp(-1, 1) * -1,
    **bounding_box
  )
end

#fall_if_ground_is_passable(map) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 118

def fall_if_ground_is_passable(map)
  foot_y = @y + BASE_HEIGHT
  center_x = @x + width / 2.0
  if map.passable_at?(center_x, foot_y + 1)
    fall
  end
end

#heightObject



190
191
192
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 190

def height
  @height[crouching?] ||= current_character.first.size
end

#jumpObject



50
51
52
53
54
55
56
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 50

def jump
  unless jumping? || crouching?
    @jumping = true
    @vy = JUMP_INITIAL_VELOCITY
    Manager::AudioManager.instance.jump
  end
end

#land_unless_ground_is_passable(map) ⇒ Object



126
127
128
129
130
131
132
133
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 126

def land_unless_ground_is_passable(map)
  foot_y = @y + BASE_HEIGHT
  (x...(x + width)).each do |col|
    unless map.passable_at?(col, foot_y)
      break land(foot_y)
    end
  end
end

#left(speed_ratio = 1.0) ⇒ Object



35
36
37
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 35

def left(speed_ratio = 1.0)
  move(in_warmup? ? RIGHT : LEFT, speed_ratio)
end

#right(speed_ratio = 1.0) ⇒ Object



31
32
33
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 31

def right(speed_ratio = 1.0)
  move(RIGHT, speed_ratio)
end

#simulate_physicsObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 135

def simulate_physics
  return @coordinate_updated_time = Time.now if stunned?

  now = Time.now
  elapsed_time = now - @coordinate_updated_time
  @coordinate_updated_time = now
  if jumping?
    @vy += JUMP_GRAVITY * elapsed_time
    @y += @vy * elapsed_time
    if @y >= BASE_Y
      @y = BASE_Y
      @vy = 0
    end
  else
    if current_direction == RIGHT
      @vx -= friction * elapsed_time
      @vx = [@vx, 0].max # vx must be positive
    else
      @vx += friction * elapsed_time
      @vx = [@vx, 0].min # vx must be negative
    end
  end
  @x += @vx * elapsed_time
  @x = @x.round.to_i
  @y = @y.round.to_i
end

#stompable?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 95

def stompable?
  @stompable
end

#stopObject



44
45
46
47
48
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 44

def stop
  @vx = 0
  @last_speed_ratio = 1.0
  @fast_speed_since = nil
end

#stunObject



87
88
89
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 87

def stun
  @stunned_until = Time.now + STUN_SECOND
end

#stunned?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 91

def stunned?
  Time.now < @stunned_until
end

#updateObject



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 99

def update
  return if stunned?

  now = Time.now
  standup
  if (now - @animetion_updated_time) >= ANIMETION_FRAME_SECOND
    @walking_frame = (@walking_frame + 1) % current_character.size
    @animetion_updated_time = now
  end
  if jumping?
    @stompable = @vy.positive? || (@y == BASE_Y && @vy.zero?) # stompable also when the moment just land
    if @vy.zero?
      @jumping = false
    end
  else
    @stompable = false
  end
end

#walk(action) ⇒ Object

Parameters:



40
41
42
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 40

def walk(action)
  action.right? ? right(action.speed_ratio) : left(action.speed_ratio)
end

#widthObject



186
187
188
# File 'lib/road_to_rubykaigi/sprite/player.rb', line 186

def width
  @width[@attack_mode] ||= current_character.first.map(&:size).max
end