スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[Ruby]パズル,ぬるぬる動くようになりました

先日ソース貼り付けたパズルですが,「スライドするときアニメがほしい」だの「マウスで全作業やりたい」だのサークルの後輩からやいのやいの言われたので,その機能をつけました.

で,もう一度ソース晒し.もうちょっときれいなコードを描きたいなぁ.
遊ぶ人は320×480の画像を用意して遊んでください.
もうしばらくしたら,画像とBGMとSEつけてもうちょっとタイトルの見栄えをよくしたものをソースごとまとめて配布できる予定です.

require 'dxruby'

# それぞれウインドウ横幅,縦幅,タイトル
Window.width = 320
Window.height = 480
Window.caption = "Slide Puzzle"

# パズルゲーム本体
class Puzzle
def initialize(mode)
@mode = mode # 難易度=縦横の分割数
@last = @mode ** 2 - 1 # 全ピース配列の末尾の位置
@image = Image.loadToArray("img/#{@mode}.jpg", @mode, @mode) # 分割数×分割数のピースに分解された画像データが入った配列
@piece = Array.new(@mode ** 2) # ピースの順番が納められた配列
for i in 0..(@mode ** 2 - 1)
@piece[i] = i
end
@black = Image.new(@image[0].width, @image[0].height, [0, 0, 0])
shuffle
end

# 外部から画像オブジェクトとピースの情報と末尾の位置を読み取りだけできるように
attr_reader :image, :piece, :last, :before, :after, :black

# クリック時の処理
def click(x, y)
i = @piece.index(@last)
if (((i % @mode) - x).abs == 1 and (i / @mode) == y) or (((i / @mode) - y).abs == 1 and (i % @mode) == x)
@piece[x + y * @mode], @piece[i] = @piece[i], @piece[x + y * @mode]
@after, @before = x + y * @mode, i
return true if @sh
end
end

# ピースをシャッフルする
# シャッフルする回数は,縦・横のピース数×400(適当)
def shuffle
@sh = false
(@mode * 1000).times do
click(rand(@mode), rand(@mode))
end
@sh = true
end

# ↑キーが押されたときの処理
def keyUp
i = @piece.index(@last)
unless ((@last - @mode + 1)..@last).include?(i)
@piece[i], @piece[i + @mode] = @piece[i + @mode], @piece[i]
@before, @after = i, i + @mode
return true
end
end

# ↓キーが押されたときの処理
def keyDown
i = @piece.index(@last)
if i >= @mode
@piece[i], @piece[i - @mode] = @piece[i - @mode], @piece[i]
@before, @after = i, i - @mode
return true
end
end

# →キーが押されたときの処理
def keyRight
i = @piece.index(@last)
unless i % @mode == 0
@piece[i], @piece[i - 1] = @piece[i - 1], @piece[i]
@before, @after = i, i - 1
return true
end
end

# ←キーが押されたときの処理
def keyLeft
i = @piece.index(@last)
unless i % @mode == (@mode - 1)
@piece[i], @piece[i + 1] = @piece[i + 1], @piece[i]
@before, @after = i, i + 1
return true
end
end
end

# メニュー画面用のデータ.
menu_mode = true
title = Font.new(80)
title_size1 = title.getWidth("Slide")
title_size2 = title.getWidth("Puzzle")
menu_f = Font.new(40)
menu = ["Easy", "Normal", "Hard", "Exit"]
cursor_id = 0

# ゲーム時に必要な変数
# どうも,Window.loop外で一度宣言する必要あり?
mode = puz = check = bb = nil

# アニメーション用カウンター
ani_count = speed_w = speed_h = 0

# クリアフラグ.最初はクリアしてないので偽.
# キープッシュフラグ.最初は押してないので偽.
clear = pushed = false

# プログラム本体
Window.loop do
# ==============================================================================================================
# メニュー画面.ここで難易度選択を行う
# ==============================================================================================================

# タイトルを表示.
# メニューは,カーソルIDと示しているメニューは白で,それ以外は灰色で表示
if menu_mode
Window.drawFont(Window.width / 2 - title_size1 / 2, 10, "Slide", title)
Window.drawFont(Window.width / 2 - title_size2 / 2, 70, "Puzzle", title)
for i in 0..3
if cursor_id % 4 == i
Window.drawFont(110, 200 + i * 50, menu[i], menu_f)
else
Window.drawFont(110, 200 + i * 50, menu[i], menu_f, :color=>[150, 150, 150])
end
end

# マウスカーソルがメニュー画面の項目上にあるとき,メニューカーソルの位置をマウスカーソルに合わせる
if (110..(110 + title_size2)).include?(Input.mousePosX) and (200..400).include?(Input.mousePosY)
case (Input.mousePosY - 200)
when 0..49
unless cursor_id == 0
cursor_id = 0
end
when 50..99
unless cursor_id == 1
cursor_id = 1
end
when 100..149
unless cursor_id == 2
cursor_id = 2
end
when 150..200
unless cursor_id == 3
cursor_id = 3
end
end
end

# ↑↓キーを押すことで,カーソル位置が移動する
if Input.keyPush?(K_DOWN)
cursor_id += 1
end

if Input.keyPush?(K_UP)
cursor_id -= 1
end

# EnterかZボタンかマウス左を押した時点でのカーソル位置で,ゲームの難易度か終了するかを決定.
if Input.keyPush?(K_RETURN) or Input.keyPush?(K_Z) or Input.mousePush?(M_LBUTTON)
break if cursor_id % 4 == 3 # カーソル位置がExitだった場合,ループを抜けてプログラムを終了させる.
mode = cursor_id % 4 + 3 # それ以外の場合,カーソルID+3を難易度としてパズルクラスを作る.
puz = Puzzle.new(mode)
check = Array.new(puz.piece.length)
puz.piece.each_index {|i| check[i] = i} # 0..ピース末尾までの,完成時の配列の並びを記憶した変数checkの作成
menu_mode = clear = false
ani_count = 0
speed_w = puz.image[0].width / 4
speed_h = puz.image[0].height / 4
end

if Input.keyPush?(K_F12)
mode = 8
puz = Puzzle.new(mode)
check = Array.new(puz.piece.length)
puz.piece.each_index {|i| check[i] = i}
menu_mode = clear = false
ani_count = 0
speed_w = puz.image[0].width / 4
speed_h = puz.image[0].height / 4
end
next
end

# ==============================================================================================================
# ゲーム開始
# ==============================================================================================================

# スクリーンショット機能
if Input.keyPush?(K_F12) == true
if ! File.exist?("screenshot")
Dir.mkdir("screenshot")
end
Window.getScreenShot("screenshot/screenshot" + Time.now.strftime("%Y%m%d_%H%M%S") + ".jpg")
end

# ESCキーでメニュー画面へ
# クリア時,何かボタンを押してもメニュー画面へ
if Input.keyPush?(K_ESCAPE) or (clear and Input.keys.length > 0 and bb == 0) or (clear and Input.mousePush?(M_LBUTTON))
clear = false
menu_mode = true
end

# マウスを押した位置からどのピースをクリックしたかを判定して,クリック処理
if Input.mousePush?(M_LBUTTON) and !clear and !pushed
pushed = puz.click(Input.mousePosX / puz.image[0].width, Input.mousePosY / puz.image[0].height)
end

# ピースがそろっていないとき,配列の末要素(空白ピース)以外を表示
# 配列checkにはピース数と同じ数の配列が入っているためeach_indexでループすればピースすべてを描画できる.
check.each_index do |j|
if puz.piece[j] != (puz.piece.length - 1)
Window.draw(j % mode * puz.image[0].width, j / mode * puz.image[0].height, puz.image[puz.piece[j]])
end
end

# ピースがそろっていたとき,全ピースを表示
# この時点で配列の末要素以外のピースはすべて↑のループで表示されているため,ここで表示するのは配列の末要素のみ
if puz.piece == check
Window.draw(puz.last % mode * puz.image[0].width, puz.last / mode * puz.image[0].height, puz.image[puz.piece[puz.last]])
clear = true
end

# クリア状態でなく,キーかマウスが押された直後以外のとき,十字キーでのピース移動を有効に
if !clear and !pushed
pushed = puz.keyUp if Input.keyPush?(K_UP)
pushed = puz.keyDown if Input.keyPush?(K_DOWN)
pushed = puz.keyLeft if Input.keyPush?(K_LEFT)
pushed = puz.keyRight if Input.keyPush?(K_RIGHT)
end

# ピース移動時のアニメーション処理
if pushed
Window.draw(puz.before % mode * puz.image[0].width, puz.before / mode * puz.image[0].height, puz.black)
Window.draw(puz.after % mode * puz.image[0].width, puz.after / mode * puz.image[0].height, puz.black)
case (puz.before - puz.after)
when -1
Window.draw(puz.after % mode * puz.image[0].width - speed_w * ani_count, puz.before / mode * puz.image[0].height, puz.image[puz.piece[puz.before]])
when 1
Window.draw(puz.after % mode * puz.image[0].width + speed_w * ani_count, puz.before / mode * puz.image[0].height, puz.image[puz.piece[puz.before]])
when -mode
Window.draw(puz.after % mode * puz.image[0].width, puz.after / mode * puz.image[0].height - speed_h * ani_count, puz.image[puz.piece[puz.before]])
when mode
Window.draw(puz.after % mode * puz.image[0].width, puz.after / mode * puz.image[0].height + speed_h * ani_count, puz.image[puz.piece[puz.before]])
end
ani_count += 1
if ani_count == 4
ani_count = 0
pushed = false
end
end

bb = Input.keys.length
end

テーマ : プログラミング - ジャンル : コンピュータ

コメント
コメントの投稿
管理者にだけ表示を許可する

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。