Unityでつむつ○みたいなパズルゲーム

ayumegu(プログラマー)
よろしくお願いします。

どうもあゆめぐです、昨日はcocosの勉強をしましたが、あまりにも進まずいらっとしてしまったので気分転換にさくっとunityでつくってみました。作業時間は3時間くらいのシンプルなものです。

ラインのディ○ニーのつむつ○みたいなのをつくってみました。 ルールは3つ以上つなぐと消える。それだけ。基盤部分しか作っていません。

WebPlayerでビルドしたものです。
スマホ用なので、本来は画面の両端は表示されないはずです・・・
つくったもの

ねこの画像はこちらから借りましたことらのイラスト工房

はい、線は相変わらずLineRendererなのでなんか変ですw
私細かいことは気にしないタイプなのw

ちなみにゲーム中のDrawCall数は最大3です。

ソース

リファクタリングなどしていない汚いソースですが。
今回はソースはこれですべてです。なんと短い!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
var countDownObj:GameObject; // カウントダウンテキスト
var mainCamera:GameObject;      // カメラ

var gameStatus:int; // ゲームステータス 0:wait 1:play

var clickStartObject:GameObject;    // クリックし始めたオブジェクト
var prevObject:GameObject;          // 前のオブジェクト
var removeObjectList:Array;         // 削除するオブジェクトのリスト
var lineObject:GameObject;          // LineRendererオブジェクト

function Start () {
  init();
}

function Update () {
  if(gameStatus == 1){
      if(Input.GetMouseButton(0) && clickStartObject == null){
          removeObjectList = new Array();

          var hit:RaycastHit2D =Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
          if (hit.collider != null) {
              if(hit.collider.gameObject.name.IndexOf("Chara") != -1){
                  clickStartObject = hit.collider.gameObject;
                  prevObject = clickStartObject;
                  removeObjectList.push(prevObject); // 削除候補のリストに追加
                  // 選択されたものは色を半透明に
                  var charaTexture:tk2dSprite = prevObject.GetComponent(tk2dSprite);
                  charaTexture.color.a = 0.5;
              }
          }
      }else if(clickStartObject && Input.GetMouseButtonUp(0)){
          if(lineObject != null){
              Destroy(lineObject);   // linerendererオブジェクト削除
          }
          // 3個以上つながっていたら消す
          if(removeObjectList.length >= 3){
              var dropCount:int = removeObjectList.length;
              for(var i:int = 0; i < removeObjectList.length; i++){
                  Destroy(removeObjectList[i]);
              }
              removeObjectList = new Array();
              dropChara(dropCount);
          }else{
              // 3個以上つながっていない場合は色を通常に戻す
              for(i = 0; i < removeObjectList.length; i++){
                  var obj:GameObject = removeObjectList[i];
                  obj.GetComponent(tk2dSprite).color.a = 1;
              }
          }
          prevObject = clickStartObject = null;
          clickStartObject = null;
      }else if(clickStartObject){
          hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
          if (hit.collider != null) {
              if(hit.collider.gameObject.name == prevObject.name){
                  if(prevObject != hit.collider.gameObject){

                      var dist:float = Vector2.Distance(prevObject.transform.position,  hit.collider.gameObject.transform.position);
                      // 前のオブジェクトとの距離が一定範囲以下の場合つながっているとする
                      if(dist <= 1.5){
                          var idExistNo:int = -1;
                          // 既に追加されたオブジェクトではないかチェック
                          for(i = 0; i < removeObjectList.length; i++){
                              obj = removeObjectList[i];
                              if(obj == hit.collider.gameObject){
                                  idExistNo = i;
                              }
                          }
                          
                          if(idExistNo == -1){
                              // 既に追加されていないオブジェクトであれば追加する
                              prevObject = hit.collider.gameObject;
                              charaTexture = prevObject.GetComponent(tk2dSprite);
                              charaTexture.color.a = 0.5;
                              
                              removeObjectList.push(prevObject);
                              
                          }else{
                              // 既に追加されているオブジェクトの場合、そこまで線を戻す
                              for(i = idExistNo + 1; i < removeObjectList.length; i++){
                                  obj = removeObjectList[i];
                                  obj.GetComponent(tk2dSprite).color.a = 1;
                              }
                              removeObjectList.splice(idExistNo + 1, removeObjectList.length - idExistNo - 1);
                              prevObject = removeObjectList[removeObjectList.length - 1];
                          }
                          
                          if(lineObject != null){
                              Destroy(lineObject);
                          }
                              
                          lineObject = Instantiate(Resources.Load("Prefabs/LineRenderer"));
                          var lineRenderer:LineRenderer = lineObject.GetComponent(LineRenderer);
                          lineRenderer.SetVertexCount(removeObjectList.length);
                          lineRenderer.SetWidth(0.1,0.1);
                      
                          for(i = 0; i < removeObjectList.length; i++){
                              obj = removeObjectList[i];
                              lineRenderer.SetPosition(i, obj.transform.position);
                          }
                      }
                  }
              }
          }
      }
  }
}


private function init(){
  countDownObj.SetActive(false);
  gameStatus = 0;
  
  dropChara(40);
  countDown();
}

// キャラクターをcountの数だけ上から落とす
private function dropChara(count:int){
  for(var i:int = 0; i < count; i++){
      var chara:GameObject =  Instantiate(Resources.Load("Prefabs/Chara"));
      chara.transform.position.x = Random.Range(-2.0, 2.0);
      yield WaitForSeconds(0.05);
      var charaTexture:tk2dSprite = chara.GetComponent(tk2dSprite);
      var spriteId:int = Random.Range(0,5);
      chara.name = "Chara" + spriteId;
      charaTexture.spriteId = spriteId;
  }
}

// カウントダウンアニメーション
private function countDown(){
  var countDownText:tk2dTextMesh = countDownObj.GetComponent(tk2dTextMesh);
  countDownObj.SetActive(true);
  countDownText.text = 3 + "";
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.2,"y", 1.2, "delay", 0, "time", 0.3, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 0.8,"y", 0.8, "delay", 0.3, "time", 0.3, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.0,"y", 1.0, "delay", 0.3, "time", 0.3, "easeType", "easeInOutQuad"));
  yield WaitForSeconds(1);
  countDownText.text = 2 + "";
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.2,"y", 1.2, "delay", 0, "time", 0.3, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 0.8,"y", 0.8, "delay", 0.3, "time", 0.3, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.0,"y", 1.0, "delay", 0.3, "time", 0.3, "easeType", "easeInOutQuad"));
  yield WaitForSeconds(1);
  countDownText.text = 1 + "";
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.2,"y", 1.2, "delay", 0, "time", 0.3, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 0.8,"y", 0.8, "delay", 0.3, "time", 0.3, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.0,"y", 1.0, "delay", 0.3, "time", 0.3, "easeType", "easeInOutQuad"));
  yield WaitForSeconds(1);
  countDownText.text = "Start";
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 1.4,"y", 1.4, "delay", 0, "time", 0.5, "easeType", "easeInOutQuad"));
  iTween.ScaleTo(countDownObj, iTween.Hash("x", 0,"y", 0, "delay", 0.5, "time", 0.5, "easeType", "easeInOutQuad"));
  yield WaitForSeconds(1);
  countDownObj.SetActive(false);
  
  gameStatus = 1;
}

それほど難しいことはしていないです。 注意する点は2カ所

  • 一度通った線のオブジェクトにあたったときは線を戻すように処理すること
  • 線がつながるという判定はColliderのあたり判定ではなく、シンプルに2つのオブジェクトの距離を算出し、一定距離以下だったら線をつなぐようにする。これは、隙間ができるため必ず隣接しているとは限らないからです。

あとはRayは毎updateで飛ばす必要ないので何回かに一回にすれば判定はもう少し軽くできそうです。(やってないけどw)

UI操作まわり

猫 

2D ToolkitのspriteにCircle Collider2DとRigidbody2Dを追加
バウンドするようにpysics2d Materialの設定をBounsiness0.5にしてRigidbody2dに追加
ソースからインスタンス化するのでRecources/Prefabs/配下にプレハブとして登録

2D ToolkitのspriteにBox Collider2Dを追加

使用Asset紹介

今回使用しているAssetです

  • iTween(無料) : 定番のアニメーションのAsset。簡単に使える!

  • 2D Toolkit($65) : 私NGUIも購入しているのですが、私は2dToolkitが好きです。NGUI使い方覚えるまでが大変で・・・。

今回の感想

cocos2d-x 3.0が大変!
2.0系の本と結構違うから、いちいち調べて悩んで;w;心が折れました。
ちょっとタッチイベントやって、シーン移動したりしただけでもう疲れました^^
でもやらないことにはできるようにならないもんね・・・。
早く本でないかな〜

あとあと、ついにiPhoneデベロッパプログラムに登録しました〜買いました。
ipodtouchなんだけどね・・・