スポンサーサイト

上記の広告は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
スポンサーサイト

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

[Ruby]メニューカーソルをマウスで移動する

先日書いたパズルゲーム,マウスでピースの移動はできるのにメニュー画面が選択できないのは変だと思い,できるようにしてみました.

if (110..(110 + title_size)).include?(Input.mousePosX) and (200..400).include?(Input.mousePosY)
cursor_id = (Input.mousePosY - 200) / 50
end


こんな感じでしょうか.
あとは,EnterかZボタンを押すと決定という部分に,マウスの左クリックをすると決定を追加すれば完成.うーん,シンプル.
マウスでのカーソル移動時も音を出そうとすると,いろいろ面倒でこんなシンプルには書けないんですけどねぇ.

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

[Ruby]8・15・24パズル

最近知ったRubyのゲーム用ライブラリDXRuby

使いやすさと軽い(らしい)ので,これからゲームを作るときはDXRubyを使ってみる予定です.

で,このライブラリをダウンロードしたときにいくつかサンプルがついてきたのですが,その中に8パズルという,まあよくあるイラストをスライドさせて正しい位置に持って行くゲームです.

それを改造して,難易度選択と十字キーでの操作ができるようにしてみました.
へちょいですが.

ソースコピペして,縦480横320の画像を,名前を3.jpg 4.jpg 5.jpg としてimgフォルダの中に入れておけばうごく……はずです.

ツッコミアドバイス罵倒大歓迎です.
あとは,スライド時にアニメーションさせたいけど,どうやったらいいんだろ…….

require 'dxruby'

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

# パズルゲーム本体
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
shuffle
end

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

# クリック時の処理
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]
end
end

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

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

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

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

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

# 何かキーを押した場合,真が返る.仕組みはわからない.
def push?
for i in 0..255
return true if Input.keyPush?(i)
end
false
end

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

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

# クリアフラグ.最初はクリアしてないので偽
clear = false

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

# タイトルを表示.
# メニューは,カーソルIDと示しているメニューは白で,それ以外は灰色で表示
if menu_mode
Window.drawFont(Window.width / 2 - title_size / 2, 50, "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

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

# EnterかZボタンを押した時点でのカーソル位置で,ゲームの難易度か終了するかを決定.
if Input.keyPush?(K_RETURN) or Input.keyPush?(K_Z)
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
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 push?)
clear = false
menu_mode = true
end

# マウスを押した位置からどのピースをクリックしたかを判定して,クリック処理
if Input.mousePush?(M_LBUTTON) and !clear
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

# クリア状態でないとき,十字キーでのピース移動を有効に
unless clear
puz.keyUp if Input.keyPush?(K_UP)
puz.keyDown if Input.keyPush?(K_DOWN)
puz.keyLeft if Input.keyPush?(K_LEFT)
puz.keyRight if Input.keyPush?(K_RIGHT)
end
end

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

[書評]たった3秒のネット術

たった3秒のネット術 (知的生きかた文庫)たった3秒のネット術 (知的生きかた文庫)
(2008/09/19)
中山 真敬

商品詳細を見る


たった3秒のパソコン術のネット版.

確かに知っておいた方がいい知識が多い.

ただ,ネット術とうたい,フリーソフトのダウンロードすら進めている本としては致命的に「足りない」ものがある.

それは,使用するブラウザがインターネットエクスプローラー前提となっていること.別にOperaでもFirefoxでもSafariでもいい.なぜほかのブラウザの存在を書かなかったのか.

インターネットエクスプローラーを使用している人と,他のメジャーブラウザを使っている人の間にこそ,決定的な実力差が出てくるものだと思います.

本書の狙いが読者のネットでの検索能力,作業効率の向上だとしたら,まずインターネットエクスプローラーの使用をやめることを勧めるべきかと.

あと,たった3秒のパソコン術の時にも言いましたが,是非ショートカットの一覧(切り離し可)がほしかった…….

全体的には読みやすく初心者にもお勧めです.

[Ruby]ライフゲームを作ってみた  最終更新日:2009/07/09

ちょっとお勉強と,今作りたいゲームの下準備としてライフゲームを作ってみました.CUIで.

lifegame.zip

ソースとドキュメントも中に入っています.

Rdoc便利だわぁ…….

ソースを以下に書きます.が,長いので読みたい人だけどうぞ.

[[2009/07/09更新]]
入力が面倒だったため、プレイヤーが入力した文字列を元にランダムにセルを設置するモード追加。

続きを読む »

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

[書評]たった3秒のパソコン術

たった3秒のパソコン術 (知的生きかた文庫)たった3秒のパソコン術 (知的生きかた文庫)
(2008/04/21)
中山 真敬

商品詳細を見る


書店で平積みされてたので気になってました。

中身は、ウインドウズとOfficeソフトのショートカット集でした。たしかに、この操作を知っているかどうかで作業効率がかなり違うのは確かです。

ただし、そのショートカットをど忘れしたとき、この本をいちいち開き直すかと思うとちょっとおっくう。
切り離せる一枚のシートにまとまってれば便利だったんですけどね。

自分がどれを知っていて、どれだけ利用できているか、一度読んでみて確認するといいかもしれません。

テーマ : ブックレビュー - ジャンル : 小説・文学

[書評]DEATH NOTE アナザーノート ロサンゼルスBB連続殺

DEATH NOTE アナザーノート ロサンゼルスBB連続殺人事件DEATH NOTE アナザーノート ロサンゼルスBB連続殺人事件
(2006/08/01)
西尾 維新大場 つぐみ

商品詳細を見る


西尾維新が手がけるもう一つのノベライズ作品。

個人的にHOLiCよりこちらの方がおすすめ。実に原作とは違った雰囲気の文体ですが、不思議と違和感は感じませんでした。

ストーリーは、Lとキラが対決するより前、ロサンゼルスで起こった連続殺害事件をLと、原作ではあっさり殺されてしまった元FBIの南空ナオミが解決する、というストーリー。

原作で以前一緒に仕事をしたことがある、というのはこの事件の話だったんですね。

この本の一番の特色は、語り部、というより支店がメロの視点になっている、ということ。この辺でけっこう好みが分かれそうです。私はおもしろかったですが。

あと、Lがやる気をなくしているときキラに殴られ、その反撃としてLが放った技がまさか○○○○だったとは……いや、まあ変な体制だとは思いましたけどね。

全体的に展開がスピーディーであっさり読めるので、濃いミステリーファンには不向きな本かもしれません。

テーマ : ブックレビュー - ジャンル : 小説・文学

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