PuyoPuyoChap14
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[目次へもどる>PuyoPuyo]]
* 横に動かそう [#fbb6538a]
#contents
入力を処理する準備が整ったのでコントロールブロックを横に...
** 冷静に考察 [#yd069676]
ここで,横に移動するために冷静な考察を行う.
コントロールブロックはキー入力によって任意のタイミングで...
このとき,移動先にすでにブロックが存在するときは移動でき...
が,少し重なる程度ならばすでに存在するブロックの上に乗る...
ここで問題になるのが,現在のブロックの落下処理は1マスごと...
そこで今回はいっそのことすでに表示されているブロックとコ...
今のブロックのクラスであるBlockには共通の機能のみを残し,...
#sh(ruby){{
class Block
attr_accessor :color, :row, :line
attr_reader :draw_pos
def initialize(col, block_s)
@color = col
@row = -1
@line = -1
@block_s = block_s
@draw_pos = [0,0]
end
def inspect
sprintf("|(%2d,%2d):%s|",@row,@line,@color.to_s)
end
def to_s
sprintf("|(%2d,%2d):%s|",@row,@line,@color.to_s)
end
def get_color(alpha = 255)
case @color
when :r
StarRuby::Color.new(255,128,128,alpha)
when :g
StarRuby::Color.new(128,255,128,alpha)
when :b
StarRuby::Color.new(128,128,255,alpha)
when :y
StarRuby::Color.new(255,255,128,alpha)
when :p
StarRuby::Color.new(255,128,255,alpha)
end
end
def update
@draw_pos[0] = @row * @block_s
@draw_pos[1] = @line * @block_s
end
def draw(ox,oy,alpha=255)
x = ox + @draw_pos[0]
y = oy - @draw_pos[1]
screen = GameMain.screen
screen.render_rect(x, y, @block_s, @block_s, get_colo...
end
end
}}
#sh(ruby){{
class StableBlock < Block
def initialize(col, block_s)
super
init_animation
end
def init_animation
@move_x = nil
@move_y = nil
@collapse = nil
@draw_pos = [0,0]
end
def set_move_x(from, to, speed)
@move_x = {
:from => from,
:to => to,
:speed => speed,
:counter => 0
}
end
def set_move_y(from, to, speed)
@move_y = {
:from => from,
:to => to,
:speed => speed,
:counter => 0
}
end
def set_collapse(time)
@collapse = {
:time => time,
:counter => time
}
end
def update_move(param)
return nil unless param
pos = param[:from] + param[:counter] + param[:speed]
param[:counter] += param[:speed]
if param[:speed] > 0
(pos = param[:to]; yield) if pos > param[:to]
else
(pos = param[:to]; yield) if pos < param[:to]
end
return pos
end
def update_collapse
return unless @collapse
if @collapse[:counter] == 0
@collapse = nil
else
@collapse[:counter] -= 1
end
end
def update
# update move_x move_y
x = update_move(@move_x){@move_x = nil}
y = update_move(@move_y){@move_y = nil}
@draw_pos[0] = x ? x : @row * @block_s
@draw_pos[1] = y ? y : @line * @block_s
# update collapse
update_collapse
end
def move_x?; !@move_x.nil?; end
def move_y?; !@move_y.nil?; end
def move?; move_x? || move_y?; end
def collapse?; !@collapse.nil?; end
def animation?; move? || collapse?; end
def reasonable_collapse?
return false unless @collapse
@collapse[:counter] >= @collapse[:time] / 5
end
def draw(ox,oy)
if @collapse
alpha = @collapse[:counter] * 255 / @collapse[:time]
else
alpha = 255
end
super(ox, oy, alpha)
end
end
}}
#sh(ruby){{
# row : base on @row [ draw_pos < row ]
# line : base on @draw_pos[1] [ draw_pos > line ]
class FreeBlock < Block
def initialize(col, block_s)
super
init_animation
end
def init_animation
@move_x = nil
end
def line=(line)
@draw_pos[1] = line * @block_s
@line = line
end
def set_move_x(from, to, speed)
@move_x = {
:from => from,
:to => to,
:speed => speed,
:counter => 0
}
end
def update_move(param)
return nil unless param
pos = param[:from] + param[:counter] + param[:speed]
param[:counter] += param[:speed]
if param[:speed] > 0
(pos = param[:to]; yield) if pos > param[:to]
else
(pos = param[:to]; yield) if pos < param[:to]
end
return pos
end
def update
# update move_x
x = update_move(@move_x){@move_x = nil}
@draw_pos[0] = x ? x : @row * @block_s
# update line
@line = (@draw_pos[1].truncate + @block_s / 2) / @blo...
end
def move_x?; !@move_x.nil?; end
def move?; move_x?; end
def animation?; move?; end
def convert_stable
sb = StableBlock.new(@color, @block_s)
sb.row = @row
sb.line = @line
sb
end
end
}}
ステーブルブロックとフリーブロックの主な違いはy座標の扱い...
ステーブルブロックはlineの値を主としてy座標を決定している.
一方フリーブロックではy座標を主としてlineの値を決定してい...
また,着地したときにフリーブロックをステーブルブロックに...
ついでにブロック自身もブロックサイズを保持するようにした.
** フィールドと落下処理 [#kc9ab194]
Fieldクラスではステーブルブロックとフリーブロックの生成,...
#sh(ruby){{
def set(r,l,col)
if @table[r][l]
@active_blocks.delete @table[r][l]
end
block = StableBlock.new(col, @block_s)
block.row = r
block.line = l
@table[r][l] = block
@active_blocks.push block
end
def start_control_block(colors)
pivot = FreeBlock.new(colors.sample, @block_s)
belong = FreeBlock.new(colors.sample, @block_s)
@ctrl_block.set(pivot, belong, 80)
@ctrl_block.start
end
def update_control_block_move_y(iff)
fall_y = @ctrl_block.can_falldown?(@table, @block_s)
Debug.print fall_y
if fall_y > 0 # fall
@ctrl_block.falldown(fall_y > 0.8 ? 0.8 : fall_y) #...
elsif fall_y < 0 # dent
@ctrl_block.fix_dent(-fall_y)
else # postpone or land
if @ctrl_block.postpone?
@ctrl_block.update_postpone
else
control_block_land
return false
end
end
return true
end
end
}}
update_control_block_move_yメソッドではコントロールブロッ...
can_fall?メソッドを詳しく見てみよう.
#sh(ruby){{
class ControlBlock
def can_falldown?(table, block_s)
fall_ys = blocks.group_by{|block| block.row}.map{|row...
min_y = blks.min_by{|blk| blk.draw_pos[1]}.draw_pos...
min_y - table[row].size * block_s
}
# fall_ys == 0 : can not fall
# > 0 : fall y
# < 0 : dent y
return fall_ys.min
end
def falldown(y)
blocks.each do |block|
block.draw_pos[1] -= y
end
end
end
}}
まず列ごとにコントロールブロックを分類し,各グループにつ...
あとはフィールド側の処理で,1フレームに移動できる距離に制...
** 横に動かす [#ja95dbe4]
まずは入力があったときにブロックを横に動かすことが可能か...
#sh(ruby){{
class ControlBlock
def can_move_row?(imr, table, row_s)
return false if imr == 0 # no move
blocks.group_by{|block| block.line}.each do |line, bl...
if imr > 0 # move right
row = blks.max_by{|blk| blk.row}.row
return false if row >= row_s - 1
return false if table[row + 1][line]
else # move left
row = blks.min_by{|blk| blk.row}.row
return false if row <= 0
return false if table[row - 1][line]
end
end
return true
end
def move_row(imr, speed, block_s)
blocks.each do |block|
x1 = block.row * block_s
x2 = x1 + imr * block_s
block.set_move_x(x1, x2, imr * speed)
block.row += imr
end
end
end
}}
引数imrは右移動が入力されれば1が,左なら-1,それいがいな...
さて,横移動なので今度は行についてブロックをグループ分け...
そしてそれぞれのグループについて移動方向によって最も小さ...
実際に移動するmove_rowメソッドは単純にアニメーションをセ...
ここで,ポイントとなる部分を見てみよう.
#sh(ruby){{
class FreeBlock < Block
def update
# update move_x
x = update_move(@move_x){@move_x = nil}
@draw_pos[0] = x ? x : @row * @block_s
# update line
@line = (@draw_pos[1].truncate + @block_s / 2) / @blo...
end
end
}}
フリーブロックの更新処理中に,
@draw_pos[1]に基づいて@lineを更新している部分がある.
これによればフリーブロックの行は
(描画位置+ブロックサイズの半分)/ブロックサイズ
である.
つまり,ブロックサイズの半分まで描画位置が下がっても,属...
これによりcan_move_row?はブロックの位置が少し下がってもtr...
この状態で移動すればブロックは少しめり込む事になるが,落...
最初に想定した仕様通りの動きをすることになる.
最後にフィールド側の横移動の処理をのせておく.
#sh(ruby){{
class Field
def update_control_block_move_x(imr)
return true if @ctrl_block.move_x?
return false unless @ctrl_block.can_move_row?(imr,@ta...
@ctrl_block.move_row(imr, 4, @block_s)
return true
end
end
}}
** 実行 [#r26ea71d]
#media(PuyoPuyoChap14/PuyoPuyoChap14.flv);
回転はできないがとりあえず横に動かせる.また,少し下に下...
ちなみに上に表示されている数字は,ブロックが落下可能な距...
すなわちcan_fall?メソッドの戻り値である.
終了行:
[[目次へもどる>PuyoPuyo]]
* 横に動かそう [#fbb6538a]
#contents
入力を処理する準備が整ったのでコントロールブロックを横に...
** 冷静に考察 [#yd069676]
ここで,横に移動するために冷静な考察を行う.
コントロールブロックはキー入力によって任意のタイミングで...
このとき,移動先にすでにブロックが存在するときは移動でき...
が,少し重なる程度ならばすでに存在するブロックの上に乗る...
ここで問題になるのが,現在のブロックの落下処理は1マスごと...
そこで今回はいっそのことすでに表示されているブロックとコ...
今のブロックのクラスであるBlockには共通の機能のみを残し,...
#sh(ruby){{
class Block
attr_accessor :color, :row, :line
attr_reader :draw_pos
def initialize(col, block_s)
@color = col
@row = -1
@line = -1
@block_s = block_s
@draw_pos = [0,0]
end
def inspect
sprintf("|(%2d,%2d):%s|",@row,@line,@color.to_s)
end
def to_s
sprintf("|(%2d,%2d):%s|",@row,@line,@color.to_s)
end
def get_color(alpha = 255)
case @color
when :r
StarRuby::Color.new(255,128,128,alpha)
when :g
StarRuby::Color.new(128,255,128,alpha)
when :b
StarRuby::Color.new(128,128,255,alpha)
when :y
StarRuby::Color.new(255,255,128,alpha)
when :p
StarRuby::Color.new(255,128,255,alpha)
end
end
def update
@draw_pos[0] = @row * @block_s
@draw_pos[1] = @line * @block_s
end
def draw(ox,oy,alpha=255)
x = ox + @draw_pos[0]
y = oy - @draw_pos[1]
screen = GameMain.screen
screen.render_rect(x, y, @block_s, @block_s, get_colo...
end
end
}}
#sh(ruby){{
class StableBlock < Block
def initialize(col, block_s)
super
init_animation
end
def init_animation
@move_x = nil
@move_y = nil
@collapse = nil
@draw_pos = [0,0]
end
def set_move_x(from, to, speed)
@move_x = {
:from => from,
:to => to,
:speed => speed,
:counter => 0
}
end
def set_move_y(from, to, speed)
@move_y = {
:from => from,
:to => to,
:speed => speed,
:counter => 0
}
end
def set_collapse(time)
@collapse = {
:time => time,
:counter => time
}
end
def update_move(param)
return nil unless param
pos = param[:from] + param[:counter] + param[:speed]
param[:counter] += param[:speed]
if param[:speed] > 0
(pos = param[:to]; yield) if pos > param[:to]
else
(pos = param[:to]; yield) if pos < param[:to]
end
return pos
end
def update_collapse
return unless @collapse
if @collapse[:counter] == 0
@collapse = nil
else
@collapse[:counter] -= 1
end
end
def update
# update move_x move_y
x = update_move(@move_x){@move_x = nil}
y = update_move(@move_y){@move_y = nil}
@draw_pos[0] = x ? x : @row * @block_s
@draw_pos[1] = y ? y : @line * @block_s
# update collapse
update_collapse
end
def move_x?; !@move_x.nil?; end
def move_y?; !@move_y.nil?; end
def move?; move_x? || move_y?; end
def collapse?; !@collapse.nil?; end
def animation?; move? || collapse?; end
def reasonable_collapse?
return false unless @collapse
@collapse[:counter] >= @collapse[:time] / 5
end
def draw(ox,oy)
if @collapse
alpha = @collapse[:counter] * 255 / @collapse[:time]
else
alpha = 255
end
super(ox, oy, alpha)
end
end
}}
#sh(ruby){{
# row : base on @row [ draw_pos < row ]
# line : base on @draw_pos[1] [ draw_pos > line ]
class FreeBlock < Block
def initialize(col, block_s)
super
init_animation
end
def init_animation
@move_x = nil
end
def line=(line)
@draw_pos[1] = line * @block_s
@line = line
end
def set_move_x(from, to, speed)
@move_x = {
:from => from,
:to => to,
:speed => speed,
:counter => 0
}
end
def update_move(param)
return nil unless param
pos = param[:from] + param[:counter] + param[:speed]
param[:counter] += param[:speed]
if param[:speed] > 0
(pos = param[:to]; yield) if pos > param[:to]
else
(pos = param[:to]; yield) if pos < param[:to]
end
return pos
end
def update
# update move_x
x = update_move(@move_x){@move_x = nil}
@draw_pos[0] = x ? x : @row * @block_s
# update line
@line = (@draw_pos[1].truncate + @block_s / 2) / @blo...
end
def move_x?; !@move_x.nil?; end
def move?; move_x?; end
def animation?; move?; end
def convert_stable
sb = StableBlock.new(@color, @block_s)
sb.row = @row
sb.line = @line
sb
end
end
}}
ステーブルブロックとフリーブロックの主な違いはy座標の扱い...
ステーブルブロックはlineの値を主としてy座標を決定している.
一方フリーブロックではy座標を主としてlineの値を決定してい...
また,着地したときにフリーブロックをステーブルブロックに...
ついでにブロック自身もブロックサイズを保持するようにした.
** フィールドと落下処理 [#kc9ab194]
Fieldクラスではステーブルブロックとフリーブロックの生成,...
#sh(ruby){{
def set(r,l,col)
if @table[r][l]
@active_blocks.delete @table[r][l]
end
block = StableBlock.new(col, @block_s)
block.row = r
block.line = l
@table[r][l] = block
@active_blocks.push block
end
def start_control_block(colors)
pivot = FreeBlock.new(colors.sample, @block_s)
belong = FreeBlock.new(colors.sample, @block_s)
@ctrl_block.set(pivot, belong, 80)
@ctrl_block.start
end
def update_control_block_move_y(iff)
fall_y = @ctrl_block.can_falldown?(@table, @block_s)
Debug.print fall_y
if fall_y > 0 # fall
@ctrl_block.falldown(fall_y > 0.8 ? 0.8 : fall_y) #...
elsif fall_y < 0 # dent
@ctrl_block.fix_dent(-fall_y)
else # postpone or land
if @ctrl_block.postpone?
@ctrl_block.update_postpone
else
control_block_land
return false
end
end
return true
end
end
}}
update_control_block_move_yメソッドではコントロールブロッ...
can_fall?メソッドを詳しく見てみよう.
#sh(ruby){{
class ControlBlock
def can_falldown?(table, block_s)
fall_ys = blocks.group_by{|block| block.row}.map{|row...
min_y = blks.min_by{|blk| blk.draw_pos[1]}.draw_pos...
min_y - table[row].size * block_s
}
# fall_ys == 0 : can not fall
# > 0 : fall y
# < 0 : dent y
return fall_ys.min
end
def falldown(y)
blocks.each do |block|
block.draw_pos[1] -= y
end
end
end
}}
まず列ごとにコントロールブロックを分類し,各グループにつ...
あとはフィールド側の処理で,1フレームに移動できる距離に制...
** 横に動かす [#ja95dbe4]
まずは入力があったときにブロックを横に動かすことが可能か...
#sh(ruby){{
class ControlBlock
def can_move_row?(imr, table, row_s)
return false if imr == 0 # no move
blocks.group_by{|block| block.line}.each do |line, bl...
if imr > 0 # move right
row = blks.max_by{|blk| blk.row}.row
return false if row >= row_s - 1
return false if table[row + 1][line]
else # move left
row = blks.min_by{|blk| blk.row}.row
return false if row <= 0
return false if table[row - 1][line]
end
end
return true
end
def move_row(imr, speed, block_s)
blocks.each do |block|
x1 = block.row * block_s
x2 = x1 + imr * block_s
block.set_move_x(x1, x2, imr * speed)
block.row += imr
end
end
end
}}
引数imrは右移動が入力されれば1が,左なら-1,それいがいな...
さて,横移動なので今度は行についてブロックをグループ分け...
そしてそれぞれのグループについて移動方向によって最も小さ...
実際に移動するmove_rowメソッドは単純にアニメーションをセ...
ここで,ポイントとなる部分を見てみよう.
#sh(ruby){{
class FreeBlock < Block
def update
# update move_x
x = update_move(@move_x){@move_x = nil}
@draw_pos[0] = x ? x : @row * @block_s
# update line
@line = (@draw_pos[1].truncate + @block_s / 2) / @blo...
end
end
}}
フリーブロックの更新処理中に,
@draw_pos[1]に基づいて@lineを更新している部分がある.
これによればフリーブロックの行は
(描画位置+ブロックサイズの半分)/ブロックサイズ
である.
つまり,ブロックサイズの半分まで描画位置が下がっても,属...
これによりcan_move_row?はブロックの位置が少し下がってもtr...
この状態で移動すればブロックは少しめり込む事になるが,落...
最初に想定した仕様通りの動きをすることになる.
最後にフィールド側の横移動の処理をのせておく.
#sh(ruby){{
class Field
def update_control_block_move_x(imr)
return true if @ctrl_block.move_x?
return false unless @ctrl_block.can_move_row?(imr,@ta...
@ctrl_block.move_row(imr, 4, @block_s)
return true
end
end
}}
** 実行 [#r26ea71d]
#media(PuyoPuyoChap14/PuyoPuyoChap14.flv);
回転はできないがとりあえず横に動かせる.また,少し下に下...
ちなみに上に表示されている数字は,ブロックが落下可能な距...
すなわちcan_fall?メソッドの戻り値である.
ページ名: