Unity入門 - 簡単パターゴルフ -

最近、プライベートでゴルフにハマっているので
Unityで簡単なパターゴルフを作って見ました。

ゴルフはドライバーもアイアンも重要ですが、やっぱりパターが一番重要!!

今回はTerrain Engine(地形エンジン)を使ってみました。

よければ1回でもプレイしてみてください!

《操作方法》
・スペースでパワーを溜める
・[Back]ボタンでTITLEへ
・[Retry]ボタンで再度プレイ
・ステージをクリアすると次のステージが解放されます

960×600のサイズで作ったので、閲覧している画面サイズによっては
スクロースしないと出来ないかもしれません。

Unity入門 - Photon Realtimeとの連携 -

最近のスマホ向けソーシャルゲームは、マルチプレイが主流になってきており
オンラインマルチゲームを作りたいと思ったときの選択のひとつとして
「Photon Realtime」の利用が挙げられます。

Photon Realtimeとは

PCやAndroid, iPhoneでリアルタイム通信を簡単に実装できるネットワークエンジン。
Unityをはじめとする主要プラットフォームに対応。
オンラインゲームによくあるチャットシステム、MMOゲームを作るために必要なネットワーク機能やサーバ機能を提供。
無料アカウントでは同時接続ユーザー数20まで対応。

Photon Realtimeの導入

Photon Realtimeサービスへの登録

使用するためにはアカウントを作る必要がある。
アカウント作成は無料で、フリーのメアドを使用できる。

ここから登録 -> Photon Realtime

f:id:hiro1986:20150623022036p:plain

メールアドレスを入力して「新規登録」ボタンをクリック。
届いたメールから本登録。

サインアップが完了したら、「ダッシュボード」->「Realtime」を選択。
アプリケーションIDを確認。
アプリケーションIDは、後ほどUnity側で設定が必要です。

Photon Unity NetworkingをAssetStoreからインポート

AssetStoreで「photon」と検索すると、「Photon Unity Networking Free」という
アセットがあるので、これをダウンロード。

f:id:hiro1986:20150623022659p:plain

PUN WizardでアプリケーションIDを設定

「Window」->「Photon Unity Networking」->「PUN Wizard」

f:id:hiro1986:20150623023152p:plain

「Setup Project」をクリック

f:id:hiro1986:20150623023336p:plain

アプリケーションIDを入力

Build SettingsにSceneを登録

f:id:hiro1986:20150623023619p:plain

「DemoWorker-Scene」「DemoWorkerGame-Scene」をそれぞれ登録しておく。

Unity上で「DemoWorker-Scene」を起動してみる

起動すると下記のようなロビー画面が表示される。

f:id:hiro1986:20150623023905p:plain

すべてデフォルト設定で問題ないので「Create Room」ボタンを押すと
ヘルメットをかぶった作業員が現れます。

f:id:hiro1986:20150623024026p:plain

WebPlayerプラットフォームとしてBuildする

「File」->「Build Settings」->「Build and Run」
でBuildして、ブラウザ上で同じ部屋に入ってみる。

すると先ほどの作業員の上に、ブラウザから入った作業員が現れます。(笑)

f:id:hiro1986:20150623024533p:plain

Unityとブラウザで色々動かしみる

Unity上と、ブラウザ上でウィンドウを並べるとリアルタイムで同期されることが分かります。

f:id:hiro1986:20150623025049p:plain

左下のチャット機能もしっかり動いてました。

次回はPhoton Realtimeを使って簡単なゲーム性のあるものを作ってみたいです。
すべて無料で試せてかつ、難しい設定はいらないので、軽く触ってみると面白いと思います!

chomeのデフォルト設定でUnityWebPlayerが起動しなくなった

chomeをアップデートしたらUnityWebPlayerが起動しなくなった。

こんな画面がでる。
f:id:hiro1986:20150623014732p:plain

確かにFirefox, Safari, IEでは問題なく再生できる。
調べてみたら、2015年4月14日から配信が開始されたChromeのバージョン42では
NPAPIが無効化されたことによりWebPlayerが起動出来なくなっているらしい。

chomeを起動してURLバーに下記を入力。

chrome://flags/#enable-npapi

NPAPIを有効にするを選択し

f:id:hiro1986:20150623015012p:plain

chomeを再起動。

問題なくUnityWebPlayerが起動された!

access_logをawkコマンドで解析

いつもawkの使い方を忘れてしまうのでメモ。

access.log (sample)

192.168.0.1 - - [1/Apr/2015:00:00:00 +0900] "GET /hoge_1.html HTTP/1.1" 200 1234 "https://www.google.co.jp/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"
192.168.0.1 - - [1/Apr/2015:00:00:00 +0900] "GET /hoge_2.html HTTP/1.1" 200 1234 "https://www.google.co.jp/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"
192.168.0.1 - - [1/Apr/2015:00:00:00 +0900] "GET /hoge_2.html HTTP/1.1" 200 1234 "https://www.google.co.jp/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"
192.168.0.1 - - [1/Apr/2015:00:00:00 +0900] "GET /hoge_1.html HTTP/1.1" 200 1234 "https://www.google.co.jp/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"
192.168.0.1 - - [1/Apr/2015:00:00:00 +0900] "GET /hoge_3.html HTTP/1.1" 200 1234 "https://www.google.co.jp/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"
192.168.0.1 - - [1/Apr/2015:00:00:00 +0900] "GET /hoge_1.html HTTP/1.1" 200 1234 "https://www.google.co.jp/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"

このサンプルaccess_logからアクセス数順に集計したいとき

cat access.log | awk '{ print $7 }'

/hoge_1.html
/hoge_2.html
/hoge_2.html
/hoge_1.html
/hoge_3.html
/hoge_1.html

awkコマンドはデフォルトでは半角空白をフィールドの区切りに用いる。
"(ダブルクォーテーション)で区切って下記のようにも出来る。

cat access.log | awk -F '"' '{ print $2 }' | awk '{print $2}'

/hoge_1.html
/hoge_2.html
/hoge_2.html
/hoge_1.html
/hoge_3.html
/hoge_1.html

ここからsortコマンドで抽出した文字列を並び替える

cat access.log | awk '{ print $7 }' | sort

/hoge_1.html
/hoge_1.html
/hoge_1.html
/hoge_2.html
/hoge_2.html
/hoge_3.html

そして最後に uniq -c でユニークにして件数を表示する

cat access.log | awk '{ print $7 }' | sort | uniq -c

   3 /hoge_1.html
   2 /hoge_2.html
   1 /hoge_3.html

※ 今回のサンプルaccess_logからuser_agentを抽出したい場合は
下記のコマンドで抽出できる

cat access.log | awk -F '"' '{ print $6 }' | sort | uniq -c

   6 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36


あまり普段使わないので忘れがちですが、awkのみの書籍もあるくらいなので
もっと勉強しなくてはと思う今日この頃。

Unity入門 - ユニティちゃん立体迷路 -

Unity4から追加された「Mecanim」を触ってみたかったので
ユニティちゃんの3Dモデルを使った立体迷路を作ってみました!

ユニティちゃん立体迷路の概要
・矢印キーでユニティちゃんを操作
・制限時間内に赤いCubeに触れるとクリア
・制限時間が0になるとゲームオーバー
・スペースキーを押して、迷路のSizeを指定して「Restart」を押すとSizeを変更し再スタート
・迷路のSizeが大きいほどクリア時のスコアが高くなる
・迷路のブロックはランダム生成

WebPlayer

Unity入門 - ツムツム風 ラブライブ 2Dパズルゲーム -

ツムツムが流行って結構経ちますが、今回はツムツム風のラブライブパズルゲームを作ってみました!

まずはunityの2Dの勉強として、unityが提供している「シューティングゲームチュートリアル」を
一通りやってみて、それをベースに作成しました。

ツムツム風のラブライブパズルゲームの概要
スクリプトC#で作成
・2Dモードで作成
・パズルを3つ繋げてクリックすると消える
・1パズルごとに100点加算
・3000点に達するとクリア
・リセットボタンを押すとリスタートできる

WebPlayer

手順

1. キャラのスプライトシートを作成
 block_sprite_[0-8] という名前でスライスする

2. Prefabsにブロックを作成
 Sprite Renderer, Crcle Collider 2D, Rigidbody 2D コンポーネントを追加

3. ブロックが外に出ないように、上下左右に枠を作成
 Sprite Renderer,Box Collider 2D コンポーネントを追加

4. クリア用のGUITextを作成

5. スコア用のGUITextを作成

6. リセットボタン用のGUITextureを作成

7, ブロック操作、画面操作、スコア管理、リセットボタン管理のスクリプトを作成して、それぞれにコンポーネント追加

作成したスクリプト

ブロック操作
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class BlockManager : MonoBehaviour {

	// blockプレハブを設定
	public GameObject block;

	// テクスチャを指定
	public Sprite[] blockSprites;

	// 初期の出現ブロック数
	public int block_num = 50;

	// 出現するx軸の範囲
	public float drop_pos_range_x = 2.0f;

	// 出現するy軸の範囲
	public float drop_pos_y = 1.5f;

	// 直前にクリックしたブロック
	private GameObject firstBlock;

	// 直前にクリックしたブロック
	private GameObject lastBlock;

	// 現在のブロック名
	private string currentName;

	// 削除するブロックリスト
	List<GameObject> removeBlockList = new List<GameObject>();

	// スコア
	public int point = 100;

	// クリアスコア
	public int clear_point = 3000;

	// Use this for initialization
	void Start () {
		//playSound.PlaySe00 ();
		DropBlock (block_num);
	}
	
	// Update is called once per frame
	void Update () {
		//removeBlockList = new List<GameObject>();
		if (Input.GetMouseButton (0) && firstBlock == null) {
			OnClickFirst ();
		} else if (Input.GetMouseButton (0) && firstBlock) {
			OnClicking ();
		} else if (Input.GetMouseButtonUp(0) && firstBlock) {
			OnClickEnd ();
		}
	}

	// ブロックを出現させる
	private void DropBlock(int count){
	
		for (int i = 0; i < count; i++) {
			// ポジションを取得
			Vector3 position = block.transform.position;
			position.x = Random.Range(position.x - drop_pos_range_x, position.x + drop_pos_range_x);
			position.y = drop_pos_y;

			// テクスチャの変更
			int spriteId = Random.Range(0, 8);
			block.name = "block_sprite_" + spriteId;
			SpriteRenderer spriteObj = block.GetComponent<SpriteRenderer>();
			spriteObj.sprite = blockSprites[spriteId];

			Instantiate (block, position, block.transform.rotation);
		}
	}

	// クリックした時の処理
	private void OnClickFirst(){
		// クリックしたオブジェクト取得
		RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
		if (hit.collider != null) {
			//Debug.Log (hit.collider.gameObject.name);
			GameObject hitObj = hit.collider.gameObject;

			// オブジェクト名を前方一致で判定
			string stTarget = hitObj.name;
			if (stTarget.StartsWith("block_sprite_")) {
				firstBlock  = hitObj;
				lastBlock   = hitObj;
				currentName = hitObj.name;

				// 削除対象のオブジェクトを格納
				removeBlockList = new List<GameObject>();
				removeBlockList.Add (hitObj);
			}
		}
	}

	// クリックしている途中の処理
	private void OnClicking(){
		// クリックしたオブジェクト取得
		RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
		if (hit.collider != null) {
			GameObject hitObj = hit.collider.gameObject;

			// 同じブロックをクリックしている時
			if (hitObj.name == currentName && lastBlock != hitObj) {
				float distance = Vector2.Distance(hitObj.transform.position, lastBlock.transform.position);
				if (distance < 1.0f) {
					// 削除対象のオブジェクトを格納
					lastBlock = hitObj;
					removeBlockList.Add (hitObj);
				}
			}
		}
	}

	// クリックをはなした時の処理
	private void OnClickEnd(){
		int remove_cnt = removeBlockList.Count;
		Debug.Log ("Remove Count => " + remove_cnt);
		if (remove_cnt >= 3) {
			for (int i = 0; i < remove_cnt; i++) {
				Destroy (removeBlockList[i]);
			}

			// スコアの加算
			FindObjectOfType<Score>().AddPoint(point * remove_cnt);

			// クリア判定
			int currentPoint = FindObjectOfType<Score> ().GetPoint ();
			if (currentPoint >= clear_point) {
				FindObjectOfType<Manager>().GameClear();
			}

			// ボール新たに生成
			DropBlock (remove_cnt);
		}
		firstBlock = null;
		lastBlock  = null;
	}
}
画面操作
using UnityEngine;
using System.Collections;

public class Manager : MonoBehaviour {

	private GameObject clear;

	// Use this for initialization
	void Start () {
		clear = GameObject.Find ("Clear GUI");
		clear.SetActive (false);
	}
	
	// Update is called once per frame
	void Update () {
	
	}

	public void GameClear(){
		clear.SetActive (true);
	}
}
スコア管理
using UnityEngine;
using System.Collections;

public class Score : MonoBehaviour {

	public GUIText scoreGUIText;

	private int score;

	// Use this for initialization
	void Start () {
		Initialize ();
	}
	
	// Update is called once per frame
	void Update () {
		scoreGUIText.text = score.ToString ();
	}

	private void Initialize ()
	{
		score = 0;
	}

	public void AddPoint (int point)
	{
		score = score + point;
	}

	public int GetPoint ()
	{
		return score;
	}
}
リセットボタン
using UnityEngine;
using System.Collections;

public class ResetButton : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
		
	void OnMouseDown()
	{
		Application.LoadLevel("Stage");
	}

	void OnMouseUp()
	{
	}
}


ブロック操作の BlockManager.cs が複雑で結構ハマりましたが
なんとか動くところまで実装出来ました。
本家のツムツムのように、時間制限や特別アイテム、フィーバータイムなどがあったら
もっとゲーム性が上がるんですが、次回以降で(笑)

Unity入門 - ブログにWebPlayerを簡単に貼付ける -

今回は、Unityで作成したゲームをブログで簡単に公開する方法を紹介します。

ブログに公開するまでの流れとしては

・作成したゲームをWebPlayerでビルド
・GoogleDriveにアップ
・ブログにiframeタグを埋め込む

作成したゲームをWebPlayerでビルド

1. File > Build Settings を選択

f:id:hiro1986:20150325023121p:plain

2. PayerSettings にて縦横のサイズを指定。(今回は横:400、縦:300にしました)

f:id:hiro1986:20150325023131p:plain

3. Build ボタンを押して、保存先を指定して実行

4. 指定したフォルダにhtmlファイルと、unity3dファイルが出力されます

GoogleDriveにアップ

DropBoxなど別のオンラインストレージサービスを使っても良いですが
場合によっては、有料になる場合もあるので今回はGoogleDriveでの方法を紹介します。
当たり前ですが、AWSやサクラなど公開出来るサーバがある場合は、この項目は省いて結構です。

1. GoogleDriveに公開用のフォルダを作成する

2. 作成したフォルダにhtmlファイルとunity3dファイルを保存

3. 作成したフォルダを共有設定にて「ウェブ上で一般公開」に設定する

4. 共有にしたフォルダのリンクをコピーすると下記になっているはずです。

https://drive.google.com/folderview?id=[識別ID]&usp=sharing

5. 4のリンクを下記のように変更すれば、公開用のリンクが完成です。

https://www.googledrive.com/host/[識別ID]/[フォルダ内のhtmlファイル]

ブログにiframeタグを埋め込む

iframeタグを作成(今回は横:500、縦:400にしました)

<iframe src="[作成した公開用URL]" frameborder="0" scrolling="no" width="500" height="400"></iframe>


作成したiframeタグをブログに貼付ければ、完了です!!