CoRサンプル集: テトリスのような落ちものパズルゲームのサンプル

テトリスのような落ちものパズルゲームのサンプル。
音楽・画像などの素材は一切使用していないので、コピペだけで移植出来ます。

操作方法
横移動:←→
ソフトドロップ:↓
ハードドロップ:↑
左回転:Z
右回転:X
ホールド:C
プレー:3 (人数:2) クリア:2 評価: 10 (1回)
タグが設定されていません
#============================================================================== # 落下ピースのロジッククラス #============================================================================== class Piece # 読み取り専用のメソッドを定義 # @param piece_type [Symbol] ピース形状を表すシンボル # @param blocks [Array<Array<Symbol|Integer>>] ピースの形状とブロックIDを含む2次元配列 # @param x [Integer] ピースのx座標 # @angle angle [Integer] ピース向き attr_reader :piece_type, :blocks, :x, :angle # 読み取り・書き込みメソッドの両方を定義 # @return [Integer] ピースのy座標 attr_accessor :y # 初期化メソッド # @param piece_type [Symbol] 使用するピース形状を表すシンボル(:I, :O, :Tなど) # @param block_types [Array<Symbol>] ピースを構成するブロックの種類 def initialize(piece_type, block_types) @piece_type = piece_type @angle = 0 @blocks = assign_random_ids(PIECE_BLOCKS[piece_type], block_types) @x = nil @y = nil end # ピースを初期配置にセット def initialize_position @x = (CONFIG[:grid_width] / 2 - @blocks[0].length / 2).floor # 初期位置(中央) @y = 0 # 最初のブロック行の位置までyを補正(ピースの先頭が空白なら上に移動) @blocks.length.times do |y| if @blocks[y].count { |n| n != 0 } > 0 @y -= y break end end end # ピースのブロック(値1)を、指定されたタイプ一覧からランダムに選んで置き換える # @param blocks [Array<Array<Integer>>] ブロック形状 (0,1) # @param types [Array<Symbol>] 使用可能なブロックタイプの一覧 # @return [Array<Array<Symbol|Integer>>] ブロックタイプを反映したピースデータ def assign_random_ids(blocks, types) return blocks.map do |row| row.map { |cell| cell == 1 ? types.sample : 0 } end end # ピースを移動させる(可能であれば) # @param dx [Integer] x方向移動量(-1:左, 1:右) # @param dy [Integer] y方向移動量(-1:上, 1:) # @param grid [Array<Array>] 参照するグリッド def move(dx, dy, grid) if !colliding?(dx, dy, @blocks, grid) @x += dx @y += dy end end # ピースを一番下まで落とす(ハードドロップ) # @param grid [Array<Array>] グリッド def hard_drop(grid) dy = 0 # 衝突しない範囲まで落とす while !colliding?(0, dy + 1, @blocks, grid) dy += 1 end move(0, dy, grid) end # ピースを右回りに90度回転(衝突がなければ反映) # @param grid [Array<Array>] 参照するグリッド def right_rotate(grid) rotated = Extension.rotate_right(@blocks) unless colliding?(0, 0, rotated, grid, false) @blocks = rotated @angle = (@angle + 1) % 4 end end # ピースを左回りに90度回転(衝突がなければ反映) # @param grid [Array<Array>] 参照するグリッド def left_rotate(grid) rotated = Extension.rotate_left(@blocks) unless colliding?(0, 0, rotated, grid, false) @blocks = rotated @angle = (@angle - 1) % 4 end end # ピースを180度回転(衝突がなければ反映) # @param grid [Array<Array>] 参照するグリッド def rotate_180(grid) rotated = Extension.rotate_180(@blocks) unless colliding?(0, 0, rotated, grid, false) @blocks = rotated @angle = (@angle + 2) % 4 end end # ピースの向きをリセット # 当たり判定は無し def reset_rotate case @angle when 1 @blocks = Extension.rotate_left(@blocks) when 2 @blocks = Extension.rotate_180(@blocks) when 3 @blocks = Extension.rotate_right(@blocks) end @angle = 0 end # 移動・回転後に衝突するかどうかを判定する # # @param dx [Integer] x方向移動量 # @param dy [Integer] y方向移動量 # @param test_blocks [Array<Array>] 試験的に使用するピースの形状 # @param grid [Array<Array>] 参照するグリッド # @param up_check [Boolean] 上方向(y<0)の範囲チェックをするか # @return [Boolean] 衝突する場合はtrue def colliding?(dx, dy, test_blocks, grid, up_check = true) test_blocks.each_with_index do |row, iy| row.each_with_index do |block, ix| next if block == 0 new_x = @x + ix + dx new_y = @y + iy + dy if up_check && new_y < 0 return true end if new_x < 0 || new_x >= CONFIG[:grid_width] return true end if new_y >= CONFIG[:grid_height] return true end if new_y >= 0 && grid[new_y][new_x] != 0 return true end end end return false end # 現在のピースをグリッドに固定する # @param grid [Array<Array>] 参照するグリッド # @return [Boolean] 正常に設置できた場合はtrue。配置場所が範囲外の場合はfalse def place(grid) is_ok = true @blocks.each_with_index do |row, iy| row.each_with_index do |block, ix| next if block == 0 place_y = @y + iy place_x = @x + ix if place_x.between?(0, CONFIG[:grid_width] - 1) && place_y.between?(0, CONFIG[:grid_height] - 1) grid[place_y][place_x] = block else is_ok = false end end end return is_ok end end #============================================================================== # 描画関連ユーティリティ関数 #============================================================================== # ピース用スプライトを生成する(最大サイズに合わせて生成) # # @param sprite_name [String] ピース描画用のスプライト名 # @param generation_count [Integer] スプライト生成数 # @return [Array<Sprite>] ピース描画用スプライト配列 def make_piece_sprites(sprite_name, generation_count = nil) # 必要な枚数 generation_count ||= PIECE_BLOCKS.values.map { |shape| shape.flatten.count(1) }.max # 各ピースのブロック数を数える(配列を1次元にして1の数を数える) # ピース描画用スプライトの配置 return Array.new(generation_count) do put_text sprite_name do position *INVISIBLE_PIECE_SPRITE_POSITION text '' end end end # ブロック描画のためにスプライトプロパティを設定する # # @param sprite [Sprite] ブロック描画用のスプライト # @param block_pattern [Symbol] ブロック描画パターン # @param pos_x [Integer] X座標 # @param pos_y [Integer] Y座標 # @return [Sprite] スプライト def set_block_sprite_property(sprite, block_pattern, pos_x = nil, pos_y = nil) pos_x ||= INVISIBLE_PIECE_SPRITE_POSITION[0] pos_y ||= INVISIBLE_PIECE_SPRITE_POSITION[1] sprite.text '■' sprite.position pos_x, pos_y sprite.color BLOCK_PATTERNS.fetch(block_pattern, ERROR_BLOCK_COLOR) sprite.scale 1.0, 1.0 return sprite end # 操作中のピースを描画する # # @param piece [Piece, nil] 描画対象のピース(nil可) # @param piece_sprites [Array<Sprite>] ピース描画用スプライト配列 def draw_piece(piece, piece_sprites) if piece.nil? y_len = 0 x_len = 0 else blocks = piece.blocks y_len = blocks.length x_len = blocks[0].length end count = 0 y_len.times do |y| x_len.times do |x| id = blocks[y][x] next if id == 0 px, py = get_grid_position(piece.x + x, piece.y + y) set_block_sprite_property(piece_sprites[count], id, px, py) count += 1 end end # 未使用のスプライトは非表示に piece_sprites[count...piece_sprites.length].each do |sprite| sprite.text '' sprite.position *INVISIBLE_PIECE_SPRITE_POSITION sprite.color FREE_CELL_COLOR end end # ネクストピースを描画する # # @param next_pieces [Array<Piece>] ネクストピース一覧 # @param next_piece_sprites [Array<Sprite>] ネクストピース描画用スプライト配列 def draw_next_piece(next_pieces, next_piece_sprites) next_piece_count = CONFIG[:next_piece_count] block_size = NEXT_PIECE_CONFIG[:block_size] next_piece_sprite_len = next_piece_sprites[0]&.length || 0 origin_y = NEXT_PIECE_CONFIG[:y] next_piece_count.times do |index| piece_obj = next_pieces[index] next unless piece_obj blocks = piece_obj.blocks origin_x = NEXT_PIECE_CONFIG[:x] block_count = 0 blocks.each_with_index do |row, y| next if row.count { |n| n != 0 } == 0 # ブロックが無い行は飛ばす origin_y += block_size row.each_with_index do |val, x| next if val == 0 px = origin_x + grid_center_offset(x, blocks[0].length, block_size) set_block_sprite_property(next_piece_sprites[index][block_count], val, px, origin_y) block_count += 1 end end origin_y += NEXT_PIECE_CONFIG[:vertical_spacing] # 未使用スプライトは非表示に next_piece_sprites[index][block_count...next_piece_sprite_len].each do |sprite| sprite.text '' sprite.position *INVISIBLE_PIECE_SPRITE_POSITION sprite.color FREE_CELL_COLOR end end end # ホールドしたピースを描画する # # @param piece [Piece, nil] 描画対象のピース(nil可) # @param piece_sprites [Array<Sprite>] ホールドピース描画用スプライト配列 def draw_hold_piece(piece, piece_sprites) return unless CONFIG[:enable_hold] if piece.nil? y_len = 0 x_len = 0 else # 空行を除いたブロック配列を作る blocks = piece.blocks.find_all do |row| row.count { |n| n != 0 } > 0 end y_len = blocks.length x_len = blocks[0].length end block_size = HOLD_CONFIG[:block_size] count = 0 y_len.times do |y| x_len.times do |x| id = blocks[y][x] next if id == 0 px = HOLD_CONFIG[:x] + grid_center_offset(x, x_len, block_size) py = HOLD_CONFIG[:y] + grid_center_offset(y, y_len, block_size) set_block_sprite_property(piece_sprites[count], id, px, py) count += 1 end end # 未使用のスプライトは非表示に piece_sprites[count...piece_sprites.length].each do |sprite| sprite.text '' sprite.position *INVISIBLE_PIECE_SPRITE_POSITION sprite.color FREE_CELL_COLOR end end #============================================================================== # バッグシステムユーティリティ関数 #============================================================================== # バッグを生成する # 全ピースをシャッフル # バッグシステムが無効ならランダムで1つ取得 # # @param types [Array<Symbol>] バッグに格納するピースタイプ一覧 # @return [Array<Symbol>] バッグ def next_bag(types) return CONFIG[:enable_bags] ? types.shuffle : [types.sample] end
投稿者:Material 185033 3 mini 光楼(114) 対象Lv1 公開日:2025年07月19日 20:48:05
プレー内容を公開する

違反を通報する

コメントする

コメントするには、ログインする必要があります。

コメント一覧

Rmakeic1 mini muga(投稿日:2025/07/19 23:10, 履歴)
すばらしいです!普通に遊べるところがすごいです!
プレー履歴
  • Rmakeic1 mini muga: スコア:1350
    (07/19 23:09)

全てのプレー履歴を見る

新着レビュー

レビューはまだ投稿されていません。 作品の感想を作者に伝えるためにレビューを投稿してみませんか?

全てのレビュー

フォロー/シェア

ブログ/Wiki/掲示板で共有する

Rmake内(ブログ/Wiki/掲示板)に貼り付ける場合は以下のタグを利用してください。

リンク

プレイヤー

外部ホームページに貼り付ける

外部ホームページに貼り付ける場合は以下のタグを利用してください。