ポンクソフト

jQuery UI Sortableで1ラインオセロゲーム - jQuery入門

前ページ jQuery入門 TOP 次ページ

目次

  1. jQuery入門
  2. jQueryのインストール・簡単な使い方
  3. クイズゲームの作り方
  4. 秘密の暗号を作ってみよう(たぬき暗号)
  5. アクションゲームを作ってみよう(ぬりかべ)
  6. 画像を使ったジグソーパズルを作ってみよう
  7. もぐらたたきっぽいゲーム
  8. ドラッグ可能なポップアップウインドウを作ろう
  9. jQuery UI Sortableで1ラインオセロゲーム
  10. ブラウザ全体をブロックしてみる
  11. Geolocation APIを使って都道府県のセレクトボックスを現在地に近い順にソートする
  12. 発生したイベントの状態を保持・保存する6つのパターン
  13. Ajaxを利用したシンプルなイメージギャラリーを作ってみる
  14. テーブルにページ送り(ページング)を実装してみる
  15. jQuery UI Draggableを使って付箋(sticky)を作ってみる
  16. カラムでソートできるテーブルを自作してみる
  17. テーブルを使ったシンプルなドット絵エディタを作ってみる
  18. iPhoneのようにマウスではじいてスクロール(フリックスクロール)を実装してみる
  19. テキストフィールドの数値をマウスの上下移動で増減する
  20. iPhoneのように大きい画像の表示領域をマウスのドラッグで移動してみる
  21. iPhoneのように画像をダブルクリックした地点を中心に拡大縮小する
  22. リアルタイムプレビュー付きのHTMLエディタを作ろう
  23. 保存できる付箋を作ってみる(Cookie、localStorage)

1ラインオセロ

jQuery入門の第9回目は、jQuery UIを使ってみます。jQuery UIは、jQuery要素に対してドラッグ&ドロップ・リサイズ・選択などの基本機能、さらにダイアログ・タブ・スライダーと言った多様なUIを追加してくれるプラグインです。その中で今回は、要素をドラッグして並び替えを可能にする「Sortable」の機能を使ってみましょう。作るものはオセロ・・・はソースが長くなるので1行だけのオセロゲームです。

実行結果

コマをドラッグして移動すると、普通のオセロのようにコマが裏返ります。決められた手数以内で全てのコマを黒くするとクリアです。全5面でだんだん難しくなります。

1ラインオセロのソース

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
<title>1ラインオセロ</title>
<script>
$(function() {
  var round = 0;
  var remain;
  var field = [
    [1, "●○●○○"],
    [1, "●○○○●○●"],
    [2, "●○●○●○●○●"],
    [2, "●○●●○●●●○"],
    [2, "●●○●●○○●●●○●○●●"]
  ];

  // 面の開始
  function start() {
    remain = field[round][0];
    $('#field')
    .html($.map(field[round][1].split(''), function(i) {
      return '<div>' + i + '</div>';
    }).join(''));

    $('#round').text(round + 1);
    $('#remain').text(remain);
  }
  start();

  $('#field').sortable({
    axis: 'x',
    update: function(e, u) {
      // 裏返す
      var color = u.item.text();
      $.each(['prev', 'next'], function(i, dir) {
        var rev = false;
        (function (item) {
          if (item.length < 1) return;
          if (item.text() == color) rev = true;
          else arguments.callee(item[dir]());
          if (rev) item.text(color);
        })(u.item[dir]());
      });

      // クリアチェック
      $('#remain').text(--remain);
      if (!$('#field div').is(':contains("○")')) {
        if (++round >= field.length) {
          alert("オールクリア!");
        } else {
          alert("クリア!");
          start();
        }
      }

      // ゲームオーバーチェック
      if (remain <= 0) {
        $('#field').sortable('destroy');
        alert("ゲームオーバー");
      }
    }
  });
});
</script>
<style>
div {
  float: left;
  cursor: pointer;
}
</style>
</head>
<body>
<p>全て●にせよ! 第<span id="round"></span>面 残り<span id="remain"></span>手</p>
<div id="field"></div>
</body>
</html>

プログラムの解説

<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
GoogleでホスティングされているjQuery UIのバージョン1.7.1を読み込んでいます。

変数定義

var round = 0;
現在の面数です(実際の面数は+1される)。
var remain;
残り手数です。これが0になるとゲームオーバーです。
var field = [
  [1, "●○●○○"],
  [1, "●○○○●○●"],
  [2, "●○●○●○●○●"],
  [2, "●○●●○●●●○"],
  [2, "●●○●●○○●●●○●○●●"]
];
各面の配置データ配列です。上から順に1~5面のデータで、それぞれの要素がさらに配列になっており、最初の要素が手数、次の要素が実際の配置データです。

コマ表示

$('#field')
.html($.map(field[round][1].split(''), function(i) {
  return '<div>' + i + '</div>';
}).join(''));
配列fieldから画面にコマを書き出している部分です。コマの並びの文字列を1文字ずつdivで囲っています。$.mapはオブジェクトや配列の要素それぞれについて指定した関数を実行するjQueryのユーティリティ関数です。

並び替え関数

$('#field').sortable({・・・});
この部分で要素の並び替えを設定しています。並び替えの対象になる要素は#field以下の要素全て、つまり先ほどdivで囲った○,●文字全てです。引数のハッシュで並び替え動作の設定を行ないます。
axis: 'x',
ドラッグを横方向のみに制限しています。
update: function(e, u) {・・・}
ドラッグが完了して、実際に要素が並び替えられたときに呼ばれる関数を設定します。要素が並び替えられないときは関数が呼ばれないので注意してください。引数のeはイベントオブジェクト、uは各種オプションですが、今回使っているのはドラッグされた要素を表すu.itemだけです。

コマを裏返す

コマをドラッグしてボタンを離したときにコマを裏返す処理が実行されるわけですが、結構面倒な処理なので今回は再帰を使ってなるべくシンプルに実装してみました。
var color = u.item.text();
まず最初に裏返すときのチェック用に、ドラッグされた要素のテキスト(●か○)を保存します。
$.each(['prev', 'next'], function(i, dir) {・・・}
$.eachもjQueryのユーティリティ関数で、第1引数で指定したオブジェクトや配列のそれぞれの要素に対して関数を実行します。引数iには配列のインデックス、dirには値が入ります。
(function (item) {・・・})(u.item[dir]());
JavaScriptの独特な書き方です。「function(i) {・・・}(x)」という書き方で、匿名関数を定義して、さらに実引数xで実行までを行なうのです。ここでは実引数「u.item[dir]()」が「item」に代入されて実行されます。「u.item[dir]()」の部分ですが、dirには先ほどの$.eachによって「prev」もしくは「next」の文字が入るので、「u.item['prev']()」か「u.item['next']()」となりますが、JavaScriptのオブジェクトの各メンバはハッシュとしてアクセスすることができます。つまり「u.item.prev()」か「u.item.next()」となるわけです。prev()は要素のひとつ前の兄弟要素、nextは要素のひとつ後の兄弟要素を辿るjQueryのメソッドです。
if (item.length < 1) return;
兄弟要素が存在するときは、要素の長さlengthは「●」か「○」で必ず1になるハズなので、ここの条件が満たされるのは先頭か最後にたどり着いたときです。
if (item.text() == color) rev = true;
先頭か最後にたどり着く前に、置いたコマと同じ色のコマが現れたときは、挟める状態となるのでフラグを立てています。
else arguments.callee(item[dir]());
置いたコマと違う色のコマが現れたときは、裏返される可能性のあるコマですが、とりあえず置いておき次の兄弟要素のコマを再帰によって辿ります。
if (rev) item.text(color);
フラグが立っていたならば、さきほどとりあえず置いておいたコマを裏返します。

クリア・ゲームオーバー

if (!$('#field div').is(':contains("○")')) {・・・}
isは、jQueryの要素に対して、引数で指定したセレクタに合致する要素がひとつでもある場合にtrueになるメソッドです。:containsは、要素のテキストに指定した文字列が含まれているものを選択するセレクタです。ここでは、白丸がひとつも含まれていない場合、ifの条件が満たされ、クリアとなります。
$('#field').sortable('destroy');
ゲームオーバーのとき、並び替えを無効にしています。
前ページ jQuery入門 TOP 次ページ
このエントリーをはてなブックマークに追加 そっか0

このページに関するコメントをどうぞ

お名前:


check_boxes
ソースを使ってもいいですか?
2017/07/12 16:01

k
jQueryで作成した付箋を複数人で同時に編集し共有するシステムを実装するとなると、どのような技術を用いるべきでしょうか?
2017/06/20 23:19

ataru
もぐらたたきに絵を入れるとしたら、どこを変えたらいいのですか?
2016/09/06 14:20

教えてください
クイズゲームの作り方で、2問目、3問目を作っても絶対に
2番が正解になりますよね?

input要素を読み込んでいるので、全て同じ動作になると思うんですが、他の番号を正解にしたい場合どうしたら良いでしょうか?

また、inputにid行ってみましたが、うまく反応しませんでした。
2016/03/07 14:13

まほ
わかりやすく説明していただきありがとうございます!
ところで、
$.each(items, function(i, item) {
make().css(item.css).html(item.html);
});
の部分だけ今ひとつ理解ができなかったのですが
localStorage.stickyに値が入っているときに
①itemsという配列に JSON形式の文字列をjsのオブジェクトとして返し
②それぞれのitemsの要素に対してcss、htmlの要素の中身を入れている

という認識で良いでしょうか?

function(i,item)のところにiが入っていますが、これはどこに影響を与えているのでしょうか?

長々とすみませんがご回答いただければ嬉しいです!
2016/02/17 21:03

ぴよよ
↓ 目次8からHTMLのheadの部分の記述が・・・スミマセン
2016/02/06 01:34

ぴよよ
これまでスムーズにできたのですが、今回わからないです><;
2016/02/06 01:31

UT
わかりやすいですね!感謝します。
2016/01/26 10:02

こっぺぱん
ありがとです
2016/01/19 15:32


ありがとうございます。
2016/01/19 15:32

残りを読む »