ぷらこあ

ゆるふわゲームクリエイター / イベントオーガナイザーを目指してます

もし俺の妹がUnity起動時に2Dプロジェクトを作ろうとして間違えて3Dを選択してしまったら

Unityは起動時に表示されるモーダルから新規のプロダクトを作れます
ここで2Dゲーム用のプロダクトか3Dゲーム用のプロダクトか選択できますが
どういう差分があるのかしっかり把握していなかったのでメモ
(なお妹は出てきません)

f:id:lycoris102:20160327221755p:plain

2Dゲームを作ろうとして間違えて3Dゲームを選択したら...

  • 下は3Dを選択した時に最初に表示される画面 (シーン/ゲーム/ヒエラルキー)
    • これを2Dを選択した時の状態にしたい!
    • (ちなみにバージョンはUnity5.3.4f1で試しています / 今後変更になる可能性はあり)

f:id:lycoris102:20160327221801p:plain

とりあえずここを読めば解決

docs.unity3d.com

(1) 頑張って直す

1. Default Behavior Mode を2Dに切り替える

  • Edit > Project Settings > Editor メニュー
  • Default Behavior Mode: Mode を2Dに変更
  • 2Dに変更することで以下の恩恵を受けることが出来る
    • プロジェクトにインポートする画像のTextureTypeがdefaultでSpriteになる

f:id:lycoris102:20160327221804p:plain f:id:lycoris102:20160327221805p:plain

2. シーンビューの2Dを有効にする

  • xy平面での表示に切り替わり、右上のガイドが非表示になる

f:id:lycoris102:20160327221824g:plain

3. Directional Lightを削除する

  • Hierarchyビューから削除する

f:id:lycoris102:20160327221811p:plain

4. カメラの位置を移動する

  • カメラ位置が (0, 1, –10) になっているので (0, 0, –10) に移動する

f:id:lycoris102:20160327221818p:plain

5. カメラの設定を変更

  • MainCameraを選択
  • Inspector の Camera コンポーネントにおいて以下を変更
    • Projection を perspective (透視投影) から orthographic (平行投影) へ

f:id:lycoris102:20160327221842g:plain

6. Lighting (GI) の設定を削除

  • Window > Lighting
  • Skybox を none に指定
  • Precomputed Realtime GI のチェックを外す
  • Baked GI のチェックを外す
  • 最下部の Auto のチェックを外す

f:id:lycoris102:20160327221900g:plain

これでOK

f:id:lycoris102:20160327221826p:plain

(2) プロダクトを作り直す

これが一番早いと思います!

(3) DefaultBehaviorModeを切り替えてシーン再生成 (20160327_追記)

f:id:lycoris102:20160327232833g:plain

(Unityの立ち上げなんだかんだで時間掛かるし
Asset Packagesで指定したAsset群インポートし直すの面倒だし...)

これが一番早いと思います!!

楽天声優ハッカソン成果物「仕返しスナイパー★」

楽天声優ハッカソンに参加しました

rakutenwebservice.doorkeeper.jp

  • 2/27(土), 28(日) の2日間、二子玉川にある楽天クリムゾンハウスにて
  • 今回は会社のゲームジャム部のメンバー4人でチームを組み参加しました

成果物「仕返しスナイパー★」

動画

youtu.be

ハッカソン終了時点での成果物です

概要

  • ハコスコを使ったゆるふわ系VRスナイプゲーム
  • あなたは「仕返し屋」となって依頼人の代わりに仕返しをします。
  • 依頼人の声を頼りにターゲットロックオン!
    • 依頼人によっては曖昧なヒントを出すことも…?

開発過程について

環境

  • 今回は25チーム参加し、各チーム毎に会議室が割り当てられました
    • チームによってはアニメを見たり体操したりしてた
  • また前面ホワイトボード/プロジェクター使用可というのが素敵でした
    • イデア書いたり、タスクや成果物映して進捗確認したり…

f:id:lycoris102:20160304012534j:plain:w400

▲マック食べてる

役割分担

  • @mustankatti : 何でも屋さん、ボクセル/BGMの作成、ヒント周りの実装
  • @ekimemoxtsu : 主にボクセル/デザイン周り、および声のディレクション
  • @akihiro_0228 : セリフ(台本)の作成、音声データの切り分け、発表用の資料作成
  • @lycoris102 (自分) : 主にゲームロジックの実装を担当 (Unity)

gyazo.com ▲メンバーの作ったボクセル、可愛い!

イデア

  • 事前に何回かメンバーでブレストを実施して大まかな方向性の擦り合わせ
    • A5の紙にアイデアをひたすら書き互いに発表するスタイル
  • コアになった意見は以下の通り
    • VRへのチャレンジ
    • 声が無いと成立しないゲーム
    • 双方向にコミュニケーションする
      • 時間がなくてオミットしたけど音声入力をフックにアクションしたかった
    • 複雑な説明をしなくても、役割から何をしたら良いのか分かる
      • スナイパー = 照準を合わせて撃つ
  • そこから各メンバーの出来ること(ボクセル)から大まかな世界観が決まる感じに

タスク管理

  • Googleスプレッドシートを使用しました
    • ハッカソン/ゲームジャムレベルなら一覧性を持てて使いやすい
      • レビューや確認などの複雑なステータスを持つ必要が無い
      • 都度コメント残せたりするのも良い
    • 以下の様に段階を分けて目標設定
      • α: ゲームのメイン箇所が動作する (〜1日目 19:00)
      • β:一連のゲームサイクルが体験出来る (〜2日 朝9:00)
      • 最終発表: クオリティアップ (〜2日目 15:00(開発終了))
    • 「データの検証」で予めプルダウンを作成しつつ「条件付き書式」で色を付けると可読性高まる!

gyazo.com

声優さんレコーディング

  • 16時-深夜2時 / 朝6時-14時の間が声優さんの収録可能時刻でした

    • チーム毎に30分の枠を3回まで予約する感じのシステム
    • とてもハードだと思う… 本当にお疲れ様です、ありがとうございました!
  • 今回、自分たちのチームは菅沼千紗さんにお願いしました!

    • (3役 * (服パーツ + 靴パーツ + アクセサリー + 成功 + 失敗 + 相づち) + タイトルコール) くらいのボリューム感
      • 役1: 内気な女子高生
        • 「焼きそばパン…割りこまれて買えなかったの…。仕返し…して…?」
      • 役2: 明るい小学生
        • 「ラジコンで遊んでたんだけど、ちょっと目を話した隙に盗まれちゃったんだ!取り返したいんだ!お願い!」
      • 役3: 純粋無垢な幼女
        • 「あのね…?お母さんを困らせる人がいるの。お願い、お母さんを守って!」
  • 自分は声優さん(声)に詳しくないのでディレクションは他のメンバーにお任せしてしまった…

    • 自分はもう何が来ても満足しちゃいそうだった…
      • ただ依頼側もある程度の指標を持って行かないと相手も自信持ってやれない
      • 自分たちは台本と設定を持って行ったけど、「このキャラで!」と動画を見せたチームもあったみたい
    • もう目の前で可愛らしい声が聞けただけで満足でした…!!

Unity実装(使用アセット紹介)

  • 今回もUnityさんからバウチャーカード$50分頂きました!

SimpliCity Starter Kit

https://www.assetstore.unity3d.com/jp/#!/content/38284

  • MagicaVoxel とシナジーのある舞台のモデルを探して一目惚れして購入
  • 1から組み立てるのは大変なのでサンプルシーンを切り貼りしてステージを作成

LC VR Kit EX

https://www.assetstore.unity3d.com/jp/#!/content/42848

  • 一度自前でジャイロによる見回し実装をしたけどガタガタして気持ち悪い感じに
    • 最終的には自分の所持するAndroid端末だけおかしかったっぽい
    • お金の力で解決することにしました!!!
  • サンプルシーンおよびドキュメントがある程度整っているのが良い
  • 単眼/双眼、それぞれのケースでも対応出来るのもいい感じ
  • シューティング部分に関してもそれっぽい実装がサンプルにある
    • けど自前で調整したかったので結局、カメラからRaycast飛ばすような感じに…

Easy Masking Transition

https://www.assetstore.unity3d.com/jp/#!/content/8734

  • 以前買ったトランジション(画面切り替え演出)アセット
  • デフォルトのパターンテクスチャが充実してて演出的には最高
    • (要検証) これ端末ビルドして使用するとかなり重たい気がするのだけど気のせいかな…

Android Speech TTS

https://www.assetstore.unity3d.com/jp/#!/content/45168

  • 買ったけど!結局使ってない!!
  • Android側の機能(音声認識/TTS)へのアクセスプラグイン
  • もう少し余裕があれば「コミュニケーションをする」アプリにしたかった…
    • 「ヒント教えて?」「赤い服を着ていたような気がする」

Unity実装(雑感)

  • 結構愚直で泥臭い実装してしまったので特に書くことないけど1点だけ…

マルチシーンエディティングの便利さを痛感

  • Unity5.3から入ったマルチシーンエディティング、良いです!
    • アセットのサンプルシーンから必要な要素だけmainシーンに持って来たり
    • mainシーンに重ねてUIシーンを表示するアプローチいい感じです!
      • 今まではSetActiveで管理してたけどなんだかんだで1シーンでmainゲームとresultUIどっちも管理するの面倒
using UnityEngine.SceneManagement;

# 現在のシーンの読み込みを破棄して新しいシーンを読み込み
SceneManager.LoadScene("main", LoadSceneMode.Single);

# 現在のシーンを破棄しないで新しいシーンを読み込み
SceneManager.LoadScene("result", LoadSceneMode.Additive);

感想

自分のチーム/成果物について

素敵なメンバーに囲まれて作業出来て幸せでした!

  • このメンバーだから作れるものが出来たと思う

完成度に関してはかなりトップのほうだと自負出来る!

  • 一通り遊べるゲームループは実装出来た
    • 一人でやるとタイトルやリザルト周りは手が回らないことが多い…
  • BGM/SE等の演出面のサポート (ゲームとしての歯抜けがあまり無い)
    • 審査員の稲川さんからもご指摘あった通り、倒した時のフィードバックだっけ妥協せず実装しておけば良かった…

発表に関して

試遊会のロケーションをもう少し想像して挑めば良かった…

  • 25チームがそんなに広くないスペースで音系のアプリをデモする恐怖
    • 「声優の声が聞こえない!(聴こえにくい)」
    • イヤホンをローソンで買ってくれば良かったとちょっと後悔している
    • 会議室でそのまま実施するという手段もあったかなと思いつつ

もう少し発表に視点を向けた準備をするべきだった

  • 今回は試遊会があったから良かったけど、無かったら何も伝わらなかった
    • 特にVR系のアプリはプレゼン手段を予め考えないと本当にしんどい
  • 工夫したコアバリューを伝えられるように私はなりたい
    • メンバーが工夫した努力の汲み取りを発表者は怠ってはいけない

デモについて

  • twitter上とかで色々話題になってる話題になってる事柄
    • 「自己紹介するな、デモをしろ!」の話
  • 自分個人の見解として運営側と審査員側で齟齬があったと感じています
    • 「プレゼン用の資料(スライド)を作ってください」という指示があった認識でいる
    • その前提を知らずに「デモを評価するぜ!」はちょっと可哀想だったなと思った…
      • 自己紹介はともかく、発表のコツみたいなのを (主に学生さんに) お伝えしても良かったとは思う
  • 自チームはゲームサイクルが1〜2分だったのでデモ基準で伝えようと決めていました
    • あくまで動くものを見せたい (見せないと伝わらない) と思っていた
    • 自分たちが伝えたいものに合わせて、発表内容(手段)を工夫すれば良い
      • でも中間発表の寸劇は完全に滑りましたごめんなさいもうしません

全体的に

  • 運営の皆様、参加者の皆様、そして声優の皆様、ありがとうございました!
  • 楽しかったです!
    • 色々話題になっているけど、やっぱりハッカソンやゲームジャムの醍醐味は「短期間で自分の作りたいもの作れること」そして「他のチームの価値観に触れること」にあると思っています
    • 多種多様な「声」 に対する解釈を知れて、面白かったです!
    • 次回もあれば、是非参加したいですぞ!

1月社内ゲームジャムの成果物「Bound×Boundary」

社内ゲームジャム成果物「Bound×Boundary」

概要

  • GGJ(グローバルゲームジャム)に参加したかったのだけど金曜日に外せない用事があって代わりに土日で社内ゲームジャムをやった
  • 今回の成果物は2人プレイの引っ張りゲー
  • RITUAL(GGJテーマ)要素は何も無い…. でもコレは儀式だと言い張るよ!

ゲーム説明

スクリーンショット

資料

www.slideshare.net

システム

  • 2人で遊ぶ
  • プレイヤーは円を引っ張って離すことで円を動かすことが出来る
  • 円は引っ張った距離に応じて勢いが増す
  • 円は移動際に軌跡を描く
  • 停止したらプレイヤー交代する
  • 片方のプレイヤーはもう片方のプレイヤーの軌跡が壁のような扱いになる

目的

  • 正直、このゲームの「目的」は残念ながらブレブレ
  • (現状で特にスコアやゴールを設けていない)
  • 最初は資料にもある通り、協力ゲーを目指していた
    • 先に進む/ライフを維持する/味方を妨害しないのジレンマをテクニックで解決する
  • 最終的にはPvPのゲームにして「相手を妨害する」「自分のスコアを稼ぐ」を両立させるのが良いかなとか考えている

実装について

UnityにおけるXZ平面の2Dゲーム

  • 俯瞰型のボードゲームタワーディフェンス等のゲームは奥行きが地面/床である(XZ平面)
  • それに対してUnityにおける「2D」の基本的な定義はXY平面を指す
    • すなわち画面の下部に対して重力が働く一般的な横スクロールアクションゲームのイメージ
    • なので跳ね返り等の物理判定を入れるためにRigidbody2Dをアタッチすると画面下部に落ちて行く
  • 主な対応方法として、3D実装/Rigidbodyを使用しつつ、カメラ向きを変更する方法がメジャーな認識
  • 今回は少し変わったアプローチとして「Rigidbody2Dを使用しつつ、重力を0にしつつ、一部の物理挙動をコードでカバーする」というものを取った
    • 今思えば、3Dで実装すれば良かったと後悔している….

Unityにおける重力量

  • “Edit” -> “ProjectSettings” -> “Physics2D” を開く

f:id:lycoris102:20160209202308p:plain

  • 上部にある “Gravity” の項目で重力加速度を設定出来る
    • デフォルトでy軸方向に対して “-9.81” が指定されている
      • 月面のゲームを作りたければ意図的にここの値を下げても良い
      • もしくはアタッチした Rigidbody2D の “GravityScale” を調整すると良いだろう

f:id:lycoris102:20160209202343p:plain

  • 今回は (何を思ったのか) Gravity の指定を (0, 0) にした
    • つまり無重力となり、主に以下のような現象が起こる
      • 摩擦が働かずに減速しない
      • 物質にぶつかっても反発しない
  • すなわち、これらの現象を自前で用意する必要がある
    • この時点で諦めておけば良かったのだが、とある事情により突き進むことに
  • 以下のようなコードをプレイヤーにアタッチすることで減速/反発させるようにした
    • XXX 反発のコードが雑すぎて情けないけど自戒の意を込めて晒す (反射ベクトル使おう…)
    IEnumerator Deceleration() {
        while (true) {
            if (this.GetComponent<Rigidbody2D>().IsSleeping() == false) {
                this.GetComponent<Rigidbody2D>().velocity = new Vector2(
                    this.GetComponent<Rigidbody2D>().velocity.x * friction,
                    this.GetComponent<Rigidbody2D>().velocity.y * friction
                );
            }
            yield return null;
        }
    }

    void OnCollisionEnter2D(Collision2D coll) {
        if (this.GetComponent<Rigidbody2D>().IsSleeping() == false) {
            for (int i = 0; i < coll.contacts.Length; i++) {
                Bound(coll.contacts[i].point);
            }
        }
    }

    // XXX 反射ベクトルを使おう
    void Bound(Vector2 hitPoint) {
        if (System.Math.Abs(hitPoint.x - this.transform.localPosition.x) < 0.1f) {
            this.GetComponent<Rigidbody2D>().velocity = new Vector2(
                this.GetComponent<Rigidbody2D>().velocity.x,
                this.GetComponent<Rigidbody2D>().velocity.y * -1
            );
        }
        if (System.Math.Abs(hitPoint.y - this.transform.localPosition.y) < 0.1f) {
            this.GetComponent<Rigidbody2D>().velocity = new Vector2(
                this.GetComponent<Rigidbody2D>().velocity.x * -1,
                this.GetComponent<Rigidbody2D>().velocity.y
            );
        }
    }

追記(20160211)

  • 反射ベクトル、すごい簡単に求められます!
    • collison から法線が取得可能
    • veclocityと法線を Vector2.Refrect に通せば反射ベクトルが取得可能
    void OnCollisionEnter2D(Collision2D coll) {
        if (this.GetComponent<Rigidbody2D>().IsSleeping() == false) {
            for (int i = 0; i < coll.contacts.Length; i++) {
                Vector2 refrectVec = Vector2.Reflect(this.GetComponent<Rigidbody2D>().velocity, coll.contacts[0].normal);
                this.GetComponent<Rigidbody2D>().velocity = refrectVec;
            }
        }
    }

軌跡の描画

// 線として結びつけたい座標の配列を作成
List<Vector2> linePoints = new List<Vector2>() { this.transform.localPosition, targetPosition };

// 第一引数にHierarchyに表示されるName
// 第二引数に座標
// 第三引数にテクスチャ
// 第四引数に線の大きさ(太さ)
// 第五引数に線の連続性の指定 (未指定可)
VectorLine line new VectorLine("LineName", linePoints, texture, 1.0f, LineType.Continuous);
line.Draw();
  • line.collider = true; するだけで描画した線に対してColliderを生成することが出来る
  • (がuGUIを使用し始めたバージョンからWorld座標/Screen座標を考慮する必要がありそのまま使用するのはもしかしたら少し面倒かもしれない…)
  • 今回は線とコライダの位置がずれてしまったので自前でコライダを別途用意することにした
    • (コライダ機能を使いたくてRigidbody2D貫き通したのに、完全に本末転倒な感じだった)

軌跡に対する跳ね返りの実装

  • EdgeCollider2D (指定した座標間に対してコライダを生成) をスクリプト側で操作する
  • 衝突したときに座標を追加し、静止時に有効にしてあげる
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class PlayerLocusLineCollider : MonoBehaviour {

    [SerializeField] EdgeCollider2D lineCollider;

    private List<Vector2> lineColliderPoints = new List<Vector2>();

    public void Set(Vector2 position) {
        lineColliderPoints.Add(position);
    }

    public void UpdateCollider() {
        lineCollider.enabled = true;
        lineCollider.points = lineColliderPoints.ToArray();
    }

    public void Reset() {
        lineColliderPoints = new List<Vector2>();
        lineCollider.enabled = false;
    }

    void OnCollisionEnter2D(Collision2D coll) {
        Set(this.transform.localPosition);
    }
}

iTween

using UnityEngine;
using System.Collections;

public class StageWall : MonoBehaviour {

    void OnCollisionEnter2D(Collision2D coll) {
        if (coll.gameObject.tag == "Player") {
            this.GetComponent<BoxCollider2D>().enabled = false;
            iTween.ValueTo(gameObject, iTween.Hash(
                "from", 1.0f,
                "to", 0.0f,
                "time", 0.5f,
                "onupdate", "Fadeout",
                "oncomplete", "Delte"
            ));
        }
    }

    void Delete() {
        Destroy(this.gameObject);
    }

    void Fadeout(float alpha) {
        Color currentColor = this.GetComponent<SpriteRenderer>().color;
        this.GetComponent<SpriteRenderer>().color = new Color(
            currentColor.r,
            currentColor.g,
            currentColor.b,
            alpha
        );
    }
}

スクリプト構成

  • 今までは割と一つのクラスにメソッドを詰め込みがちだったが役割に応じてスクリプトを分割した
    • 可読性が上がって良い
  • ちなみにきっかけはテラシュールブログさんの以下の記事
    • UnityのサンプルプロジェクトTank!がrole毎にスクリプトを分割していて独立して動くため、流用性があって良いという話

tsubakit1.hateblo.jp

// 今までは Player.cs に全ての挙動を詰め込みがちだった
├── Player
│   ├── Player.cs                       // ステータス管理・イベント発火
│   ├── PlayerAuxiliaryLine.cs          // 引っ張る時の補助線描画
│   ├── PlayerLocusLine.cs              // 移動時の軌跡の描画
│   ├── PlayerLocusLineCollider.cs      // 軌跡のコライダの管理
│   └── PlayerMove.cs                   // 移動

次回

rakutenwebservice.doorkeeper.jp