Unityでストップウォッチを作る その1 基本機能

Pocket

はじめに

しばらく何も開発ネタを書いていなかったので、Unityを使って簡単なBigStopWatch風のストップウォッチをチュートリアル形式で作っていこうと思います。

Unityというと3Dが得意なのは間違いないですが、2Dものを作るときにもエディタ上で逐一確認しながら作れるので非常に便利です。このチュートリアルでは使いませんが、NGUIとかUni2Dとか他にもいろいろ2D用のアセットがAsset Storeにありますので工夫をすれば2Dゲームもちゃんと作れます。

本屋さんに行くとUnityの入門書がまた最近増えているのを見かけますが、だいたいどれも、無料のアセットを使ってゲームを作ろう的な内容だったりするので(当たり前ですが)ここでは違うアプローチで、外部アセットはいっさい使わず素材ゼロの状態から2Dツールアプリ作っていこうと思います。実際、BigStopWatchはアイコン以外のリソースは全く使っていません。

いちおう対象は、Unityの入門書1冊くらいは読み終えてUnityの基本的な使い方が分かっている方を想定しています。Unityのインストールの仕方のような初歩の初歩からは解説しませんが、出来るだけ手順は飛ばさない様にするつもりです。

たぶん、全部で10回くらいに分けて投稿する予定です。もし、「ここのコードはこうした方が良い」とか「ここの部分がよくわからない」といったところなどがありましたらコメントをいただければ幸いです。大部分はもう書き終わってはいますが、ご意見があれば少々修正しながら公開していこうかなと思っております。

Unityのバージョンは4.2を使用しています。

プロジェクトの作成と設定

それでは早速Unityで新規にプロジェクトを作ってください。

プロジェクトが開いたらMain Cameraだけが置いてあるシーンが出来ていると思いますので、とりあえず「Main」というシーン名で保存しておきましょう。

ここではiPhoneの横画面向けに作っていきますので、開発しやすい設定をしておきます。

「Build Settings」でiOSにSwitch Platformしてください(今はUnity iOSは無料ですのでユーザー登録さえしておけば最初から選べる様になっているかと思います)。また、横向きのレイアウト固定にしますので、「Player Settings」の「Resolution and Presentation」の「Default Orientation」をAuto Rotationにして、「Landscape Right」と「Landscape Left」にチェックを入れてください。これでiOSでビルドして試すときにも横向きに表示されます。

unitysw_1_0.png

エディターの再生時に使うGameウィンドウのアスペクト比の設定を「iPhone Wide」または「iPhone 4G Wide」にします。お使いのディスプレイの大きさによって全体が見える方を選んでください。基本的にはiPhone4の画面サイズでレイアウトをして、iPhone5の横長の画面サイズにしても問題ないような作り方にしようと思います。iPadを考えると画面比率的には横幅が狭くなってしまうのですが、それは気にしない事にします。

unitysw_1_0_1.png

とりあえずiPhone向けの設定をしましたが、以後このチュートリアルの中では特にビルドしたりなどの記述はしないつもりです。モバイル実機で動かしたい方は、ご自身で適当にビルドして試してください。Androidで動かしたい方はAndroid向けの設定をしておいても良いと思います。

では、ここからはシーンを編集していきましょう。

カメラの設定

既にシーンに置いてある「Main Camera」オブジェクトのパラメータをインスペクタで以下のように変更してください。

・Position > X = 0 / Y = 0 / Z = 0
・Clear Flags > Solid Color
・Background > 黒
・Projection > Orthographic
・size > 160
・Clipping Planes > Near = -1 / Far = 1

unitysw_1_1.png

2Dモノしか描画させないのでOrthographicにして遠近感を無くし、Unity上での縦の長さをiPhoneの横幅のサイズと同じ320と一致させたいのでSizeを160にしています。

Backgroundの色は別に何色でもいいのですが、とりあえずBigStopWatchと同じ黒にしてあります。

オブジェクトは基本的にZを0の位置に置いて、そんなに前後は使わないつもりですので、カメラの表示範囲を-1〜1にしています。

タイム表示をするテキストを作成

ストップウォッチのタイム表示をするテキストを作成しましょう。

新規にゲームオブジェクトをシーンに作成して「Root」と名前を変更し、Positionを「X=0 / Y=0 / Z=0」にしてください。このオブジェクトは以降、時間表示をするオブジェクトの親にします。

メニューから「GameObject / Create Other / 3DText」を選択してオブジェクトを作成し、「Root」オブジェクトの子に移動します。名前は「TimeText」に変更してください。これもPositionを「X=0 / Y=0 / Z=0」にしてください。

「TimeText」のTextMeshのインスペクタで以下のように変更してください。

・Character Size > 4
・Anchor > middle center
・Alignment > center
・Font Size > 100

unitysw_1_2.png

TextMeshの文字がテクスチャに描画される大きさはFont Sizeで決まり、Character Sizeでメッシュの大きさを調整できます。カメラが表示するスケールを非Retinaの解像度と一致させてRetinaで表示する事を考えると、Character Sizeは4くらいがちょうど良い解像度になると思います。

このエントリーの頭でも宣言した通り外部アセットはいっさい使わずに行くのでフォントはそのままArialを使っていきますが、あまりかっこいいフォントではないので、気に入らない人はネットに転がっているフリーのフォントに差し替えてみると良いと思います。iOSに搭載されているいろいろなフォントを自由に使いたい場合には、Unity内部の機能ではなくプラグインを使ってiOSネイティブの機能でテクスチャに書き込まないといけないのですが、それはこのチュートリアルでは解説しません。

Stopwatchクラスの作成

ストップウォッチの基本機能を実装したStopwatchクラスを作成します。

メニューの「Asset / Create / C# Script」で「Stopwatch.cs」という新規スクリプトを作成してください。後々アセットが増えてきたときの事も考えて、「Script」というフォルダを作成し「Stopwatch.cs」を中に入れて整理しておいてください。

Stopwatch.csに記述するコードは以下になります。

//
// Stopwatch.cs
//
using UnityEngine;
using System;
using System.Collections;
public class Stopwatch : MonoBehaviour {
    
    enum StopwatchState {
        Zero,
        Play,
        Pause
    }
    public TextMesh timeText;
    StopwatchState state = StopwatchState.Zero;
    TimeSpan lastStopTimeSpan;
    DateTime startDateTime;
    void Update () {
        if (Input.GetMouseButtonDown(0)) {
            ChangeState();
        }
        UpdateTime();
    }
    void ChangeState() {
        if (state == StopwatchState.Pause) {
            lastStopTimeSpan = new TimeSpan(0);
            startDateTime = DateTime.UtcNow;
            state = StopwatchState.Zero;
        } else if (state == StopwatchState.Play) {
            TimeSpan ts = DateTime.UtcNow - startDateTime;
            lastStopTimeSpan = ts + lastStopTimeSpan;
            state = StopwatchState.Pause;
        } else {
            startDateTime = DateTime.UtcNow;
            state = StopwatchState.Play;
        }
    }
    void UpdateTime() {
        TimeSpan currentTs;
        if (state == StopwatchState.Play) {
            TimeSpan ts = DateTime.UtcNow - startDateTime;
            currentTs = ts + lastStopTimeSpan;
        } else {
            currentTs = lastStopTimeSpan;
        }
        if (timeText != null) {
            timeText.text = ConvertTimeSpanToString(currentTs);
        }
    }
    static public string ConvertTimeSpanToString(TimeSpan ts) {
        if (ts.Hours > 0 || ts.Days > 0) {
            return string.Format("{0}:{1:D2}:{2:D2}.{3}", ts.Days * 24 + ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds.ToString("000").Substring(0, 2));
        } else {
            return string.Format("{0}:{1:D2}.{2}", ts.Minutes, ts.Seconds, ts.Milliseconds.ToString("000").Substring(0, 2));
        }
    }
}

上記のコードをコピーしたら、シーンに「Stopwatch」という名前でゲームオブジェクトを作成し、Componentに追加してください。その「Stopwatch」オブジェクトの「timeText」プロパティに先ほど作成した「TimeText」オブジェクトをアサインします。

unitysw_1_6.png

この状態でストップウォッチとして機能するようになっているはずです。Unityを再生して画面上をタップ or クリックすると、「再生」→「停止」→「ゼロにリセット」→「再生」→…と動きます。

Stopwatchクラスの解説

Stopwatchクラスに関して、いくつかポイントとなる所を解説していきます。

ストップウォッチの状態を「StopwatchState」というenumで作りました。画面をクリックしたら、状態が「Zero」「Play」「Pause」を順に切り替わる様な動作にしています。拙作のBigStopWatchではもうちょっといろんな機能があって状態の種類も多いのですが、このチュートリアルではそんなに多機能にはしないので、この3種類だけ使います。

時間の管理にはDateTimeとTimeSpanを使っています。DateTimeは時刻を、TimeSpanは時間間隔をそれぞれ表す構造体です。

詳しいリファレンスはこちら
DateTime 構造体
TimeSpan 構造体

Unityで時間というと、よく使われるTimeクラスがありますが、これはアプリが起動してからの時間でしかもアプリが停止中は時間が加算されないので、今回のようなストップウォッチの計測時間を記録するのには使えません。ですので、ストップウォッチの経過時間を計るために、実時間を表すDateTimeを使って取得しています。

計測時間がゼロのときの表示タイムはうむをいわさず0分0秒です。

画面をタップして計測を開始し始めたら、そのタップしたときの時刻を記録しておいて、現在の時間との差分を計算してタイム表示しています。

一時停止してから計測を再開する場合には、再開時点での表示タイムと、再開したタイミングの時刻からの現在までの差分を足します。今のコードではそのような積算の機能はないのですが、チュートリアルの後半で実装する予定です。

ちなみに、時刻の取得にはDateTime.NowではなくDateTime.UtcNowを使っています。DateTime.Nowだと、デバイスのタイムゾーンを計測途中に変えたりした場合に時間のずれが発生してしまうので、UTCにしておく事でそのような設定変更によるずれが起きないようにしています。

今回のWebPlayerビルド

今回は以上です。次回はメッシュやテクスチャの作成を出来るようにしたいと思います。

次へ

Unityでストップウォッチを作る その1 基本機能」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です