1週間ゲームジャムの準備をした

事前にインストール
  • 「Camera Play」 主に画面揺らすのに使う
  • 「DoTween」 簡単なアニメーションするのに使う
  • 「Hyperbit Arsenal」 爆発演出に使う
  • 「G2U」 データ管理に使うかも
  • 「Fungus」 ちょっとしたストーリーを挟むのに最適
  • 「UniRx」 「〇〇したら(になったら)◾️◾️する」処理をうまく書ける(理解してない)
  • 「Zenject」 クラス間の依存関係をスッキリさせるのに利用する(理解してない)
  • 「Photon Unity Networking Free」 リアルタイム通信のゲーム用ライブラリ
  • 「Modern UI Pack」 おしゃれなUIのPrefabが詰まってる
  • 「TextMesh Pro」リッチなテキストを作る
  • 「Post-processing」画面全体に適用するお手軽演出
  • 「UnityRoomTweet」unityroom専用のツイート投稿
  • 「unity-simple-ranking」オンラインランキング機能
  • 「ShaderSketches」シェーダーお絵描き 特別な演出を入れる時使う
  • 「SimpleAnimation」アニメーションスクリプト
  • 「PhotonRx」PhotonをRxで記述しやすくする
  • 「TypefaceAnimator」少しの操作でテキストアニメーションをつける

APIキー等の設定も事前に終わらせておいた。 使用経験ない「Modern UI Pack」「PhotonRx」「TypefaceAnimator」、
使い方がちょっと変わった「Post-processing」は前日に素振り。

事前にスクリプティング

どのゲームにも必要になりそうなものだけを準備(音の再生とか)

事前に素材用意
事前にビルド
  • 色々アセット入れていると、エディターだと動くがWebGLだと死んでるケースがある
  • ので、上記のAssetを入れてWebGLビルド通るか確認
  • 通らない場合はバージョンダウンや、エラーを吐くアセットの除外を検討
チーム開発準備

今回初の複数人参加です。

  • タスク管理 Trello準備 作業の受け渡しを考えてリスト作っておいた
  • メンバーの担当範囲をどうするか考えておく

ArialフォントのTextコンポーネントを洗い出すエディタ拡張【Unity】

f:id:coffee_ryo:20180830201509p:plain

概要

WebGLで、デフォルトフォントのArialを使うと日本語が出ない問題がある

qiita.com

Arialを使っているTextコンポーネントの洗い出しがめんどくさい
特に開発終盤になりオブジェクトが増えてきた時。

洗い出しをするエディタ拡張を作る。

動作確認したUnityバージョン

version 2018.2.0f2

使い方

  1. 後述のソースコードを、「Assets/Editor」フォルダに入れる。「Editor」フォルダがない場合はフォルダを作成する。

  2. メニュー上部の「Tools/Arialフォント洗い出し」をクリック

f:id:coffee_ryo:20180830201646p:plain

ソース

FinderTextHavingArialFont.cs

using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

namespace CoffeeR{

    /// <summary>
    /// Arialフォントを洗い出すエディタ拡張クラス
    /// </summary>
    public class FinderTextHavingArialFont{

        [MenuItem("Tools/Arialフォント洗い出し")]
        static void Exec (){

            // シーン中にある、テキストコンポーネント全て取得
            var textComponents = UnityEngine.Resources.FindObjectsOfTypeAll( typeof( Text ) ) as Text[];

            // Arialな奴の取得
            var textsWithArial = textComponents
                            .Where(obj => obj.font.name == "Arial");

            // 該当しなければダイアログを出して終了
            if(textsWithArial.Count() == 0){
                FinderTextHavingArialFont.DrawDialog("問題なし","編集中シーンでフォントがArialのTextはありませんでした。");
                return;
            }

            // 該当するものがあれば、パスを記録していく。
            var explain = "編集中シーンでフォントがArialのTextが見つかりました。";
            foreach(var text in textsWithArial){
                explain += "\n" + GetHierarchyPath(text.gameObject.transform);
            }

            // 該当するオブジェクトのパスをダイアログに表示
            FinderTextHavingArialFont.DrawDialog("問題あり", explain);

            return;
        }

        static void DrawDialog(string title, string text){
            EditorUtility.DisplayDialog(
                    title,
                    text,
                    "OK"
            );
        }

        static string GetHierarchyPath(Transform self){
            string path = self.gameObject.name;
            Transform parent = self.parent;
            while (parent != null){
                path = parent.name + "/" + path;
                parent = parent.parent;
            }
            return path;
        }
    }
}

備考

tsubakit1.hateblo.jp

  • Unity1週間ゲームジャム向けに作りました。開発終盤なんかのチェックに使うのが良いかと思います。

System.Void Zenject.InjectAttribute::.ctor()' that does not exist・・・みたいなエラーが出てWebGLビルドに失敗した話【Unity Zenject】

概要

こんなエラーが出てなんだかビルドに失敗

attempting to call method 'System.Void Zenject.InjectAttribute::.ctor()' that does not exist

UnityとかZenjectのバージョンは忘れた(大事な所なのに!!)

対応方法

ググるとZenjectでバグが起きていた模様。 Zenjectを最新版に更新した。

github.com

1週間ゲームジャム参加の心得メモ

概要

1週間ゲームジャムの開催が近づいてきた。 開発中迷わないようにするため、これまで参加してきた時に得られた気づきを備忘録としてまとめておく。

参加する上での目標設定

  • 順位でTOP6入りを目指す
  • 新しい表現方法を習得する
  • これまで作ったことのないジャンルの設計を習得する
  • 特殊なゲームギミックを実験(面白いか、面白くないのか)
  • とにかく完成させて友達や他開発者とわいわい

どのように&どんなゲームを作るかが変わってくる。
「いろんな人に見てもらえる機会」を使って実現できるものを設定すると良さみ。
自分の場合大抵、TOP6入り&友達とわいわいするのを目標。

企画は初日に決める

初日に決めておくと、残りの6日間を実装に回せる。
頭の中にあるイメージをラクガキで残しておく。
テキストだけだとイメージするのが難しい。

土曜に企画立てて作った利用規約ゲームもあるが、全然作り込めなかった。

土曜日にはプレイ可能なBuildを1つ用意する

日曜日は予備日と思っておく。 だいたい遅延するのでやっぱり日曜日使っちゃうけど。

作る内容に優先順位をつける

  • キャラクターを動かす→必須
  • SNSシェア機能→余裕があれば

みたいなリストを作っておく。時間的に厳しい場面がどうしても出てくるから。
作らない勇気、大事。

機能追加かバランス調整か迷ったらバランス調整を優先する

新しいルールや機能は、ミステリー小説の登場人物を1人増やすようなもの。
開発後半で悩んだらバランス調整優先。

終わった後にブログを書く

事故った経験を忘れないようにしておく。 ライブラリ使おうとしたら〇〇でハマった、とか。 他の人の役に立ったり、1年後の自分が同じことでハマった時に役立つ。

積極的に告知しておく

Unityroom外からの流入を作る。主にTwitter。 頑張って作ったけど、プレイしてもらえたいのは結構悲しいから。 TOP6入りしている人はTwitterで話題になっているのが多い印象。

進捗報告用に動画編集できるようにしておく

Twitterで告知する際はスクショだけだとゲームの面白さが伝わらない。 ので、gifや動画を投稿することを推奨。

他開発者のモチベーションをあげる

面白そうだなと思ったゲームには、Twitter上でいいねをつけておく。
Twitterのいいねは、ゲームジャムにおいて大変良いモチベーションになる。
なんかハマっている時は、自分ができる範囲で協力する。
通信対戦のデバッグとか結構しんどい。

新しい技術はあまり入れない(人によりけり)

入れすぎるとゲーム開発の進捗が上がらない。

こだわらない部分を決める

  • UIのボタン→デフォルトのままで良い
  • 設計→神クラスになっても良い
  • 音楽→自作したい気持ちを抑えて素材サイト様のものを使わせていただく

夢のない話かもしれないが、やらない勇気が完成を導く。

少ないプレイ時間で満足できるようにする

200作品近く投稿される。
プレイ時間が長いとクリア前に他ゲームに遷移してしまう。

操作内容を理解させる

ゲームのファーストビューで見せたり、1プレイ目で操作を説明するとか。
操作がわからなくて離脱してしまうことがしばしばある。

後、開発者ではない身近な友人にプレイしてもらうと良い。 プレイ中の視線の動きやコントローラー/キーボード/マウスの動かし方を見ていれば、理解できているかどうかがわかる。
※開発者はゲームプレイがうますぎるので、難しい操作でも難なくプレイできてしまう。

必要なライブラリは事前にプロジェクトに入れておく

どうせやる作業は事前にやっておく。 自分の場合はUniRx,Zenject,DoTween, Fungus, TextMeshPro

よく使う素材サイトのurlをメモっておく

上記に同じ。ライセンスに気をつける。
あまり注目されないから問題ないだろう。。。とか思っていると、ツイッターでバズった時に死ぬ。

週半ばでWebGLビルドして動作確認する

WebGLのバグ対策。実はこのアセット死んでるとかある。

UnityRoomさんのゲームジャム説明ページをよく見ておく

Unityのバージョンについての注意事項とか書いてある。
後、開発する上でのお役立ち情報とかキャンペーン情報が掲載されていることも。

クソゲーだった時作り直すかどうかの判断

結構難しい問題だと思う。

  • 変えずに完成させる→モチベーションがしんどい。
  • 切り替えて完成させる→スケジュールがしんどい。

自分の場合は開始2日目まで内容の大幅変更を許容。
それ以降は作りこみが間に合わなそうなのでクソゲーだったとしても作りきる。
実は他の人が遊んだら新しい遊び方が発見されて神ゲーになる可能性もある。

クソゲーを受け入れられる人間になる

半年後にリベンジとして、より面白いものを作れば良い。焦らない!

(社会人)有給を1ヶ月前に申請しておく

残業は作業時間だけでなく開発モチベーションを削る。
社会人&マジでやる人は社内の根回しから行わなければならない。

スーパーアーマーの実装メモ【Unity】

f:id:coffee_ryo:20180730165929g:plain

仕様
  • 対象はキャラクター
  • オブジェクト衝突時にダメージを受ける
  • 一度ダメージを受けるとしばらくスーパーアーマー状態
  • スーパーアーマー中はダメージを受けない
  • 時間の経過でスーパーアーマーは解除される
  • スーパーアーマー中キャラを点滅
Unityバージョン

2018.1.0f2 Personal ※UniRx使う

クラス図

f:id:coffee_ryo:20180730152655p:plain

  • ReactivePropertyを使って、スーパーアーマーである時間を設定
  • ダメージを与えるコンポーネントで、スーパーアーマー残り時間が0よりも大きければ攻撃しない
  • スーパーアーマー中は、rendererコンポーネントのenableの値を1フレーム置きに更新する
ダメージ処理のフローチャート

f:id:coffee_ryo:20180730165354p:plain

コード

IStatus ステータスのinterface ※ここinterfaceにしておけば、ダメージ処理が簡潔に書けると思ってる

using UniRx;

public interface IStatus{
    ReactiveProperty<float> TimeSuperArmor{get; set;}
}

PlayerStatus ステータスの実装 キャラクターオブジェクトにアタッチする

using UnityEngine;
using UniRx;

public class PlayerStatus : MonoBehaviour , IStatus{

    public ReactiveProperty<float> TimeSuperArmor{get; set;}

    void Awake (){
        TimeSuperArmor = new ReactiveProperty<float>();
    }
}

SuperArmorTimeUpdater 経過時間をinputとして、スーパーアーマーの残り時間を減らしていく キャラクターオブジェクトにアタッチする

using UnityEngine;
using UniRx;
using UniRx.Triggers;

public class SuperArmorTimeUpdater : MonoBehaviour {
    IStatus status;

    void Start () {
        status = this.GetComponent<IStatus>();

        this.UpdateAsObservable()
        .Where(x => status.TimeSuperArmor.Value > 0)
        .Subscribe(x => {
            status.TimeSuperArmor.Value -= Time.deltaTime;
        });
    }
}

SuperArmorBlinker スーパーアーマー中にレンダラー(キャラクター画像に当たる)を点滅させる キャラクターオブジェクトにアタッチする

using UnityEngine;
using UniRx;
using UniRx.Triggers;

public class SuperArmorBlinker : MonoBehaviour {
    IStatus status;
    SpriteRenderer renderer;

    void Start () {
        status = this.GetComponent<IStatus>();
        renderer = this.GetComponent<SpriteRenderer>();

        this.UpdateAsObservable()
        .Where(x => status.TimeSuperArmor.Value > 0)
        .Subscribe(x => {
            renderer.enabled = this.BoolSwitch(renderer.enabled);
        });
        
        // スーパーアーマーが終わったら、レンダラーを必ず有効にしてあげる
        status.TimeSuperArmor
        .Where(time => time <= 0)
        .Subscribe(time => {
            renderer.enabled = true;
        });
    }

    bool BoolSwitch(bool flg){
        if(flg == true){
            return false;
        }else{
            return true;
        }
    }
}

Damager ダメージを与えるコンポーネント なんらかの攻撃を行うオブジェクトにアタッチする

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Damager : MonoBehaviour {

    void OnTriggerEnter2D(Collider2D collider) {

        // ステータスコンポーネントを取得
        var status = collider.gameObject.GetComponent<IStatus>();

        // コンポーネントがなければ、ダメージを与えられないオブジェクトとして処理終わり
        if(status == null){
            Debug.Log("ステータスコンポーネントを持っていないオブジェクトと衝突");
            return;
        }
        
        // スーパーアーマー中であればダメージを与えない
        if(status.TimeSuperArmor.Value > 0){
            Debug.Log("スーパーアーマー中");
            return;
        }

        // ここにダメージ処理記述
        Debug.Log("ダメージを与えた!!");

        // スーパーアーマー状態にする(動作確認用に2.0fにしてます)
        status.TimeSuperArmor.Value  = 2.0f;
    }
}
完成したもの

f:id:coffee_ryo:20180730165929g:plain

未検証事項
  • rendererのenableを切り替えて点滅させるのではなく、シェーダーを使って点滅させた方が実行速度でる?

TextのColorを変更しても反映されず黒になる問題の解消【Unity】

f:id:coffee_ryo:20180725145544p:plain

気づいたらなぜか色変えができなかったので解決方法を備忘しておく。

https://forum.unity.com/threads/ui-text-all-black.407597/

事象が発生したUnityのバージョン

2018.1.0f2 Personal

修正方法

TextコンポーネントのMaterialにFont Materialを入れる

【Unity備忘録】クラス図設計して個人的によかった点

f:id:coffee_ryo:20180715035936p:plain

前提

  • 設計よくわかってない人間、コーダーとかスクリプターとか
  • PlantUMLでクラス図書く
  • ZenjectとUniRx使ってみる
  • 開発で使える期間は1年間と決まっている
  • 個人ゲーム開発

良かった点

予定を立てられる
  • エターなりたくない、ならば、いつ開発終わるの?の自問自答に対して答えられるようにしたい
  • クラス数最低〇〇個みたいなのが見えてくる
  • 技術的に難しそうな箇所の早期発見、早い段階で検証すれば精神的不安も解消
  • 「コーディングだけで最低半年かかる」とか分かれば早期に仕様の削り落としとかにも繋がる
重複コードの発見
  • 似たようなメンバ変数の構成のコンポーネントが出てくる
  • ボタンクリック時とかの処理とか、よく見るとメソッドの引数が違うだけとか
  • 通化しても問題なさそうなところはしていく、コード行数少なければ開発後半の苦しみが減る
  • 行き当たりばったりで開発していると気づきにくいかも
自分が書いたコードがわからなくなる現象の回避
  • 1個のクラスの役割「do」は1つ〜2つ程度でおさまっているか?
  • たくさんあるとシンドイ。プレイヤーの移動&ダッシュ&スーパーアーマー&死亡とかあるとスパゲッティー化
  • 役割が複数あるのは分割する
  • 逆に役割が0のやつとかがあったりする、そういうのは設計段階でなくす
  • クラス図を残しておくと、なんでこれ作ったか思い出すヒントになる

悩みどころ

個人開発でどこまで設計する?
  • 事前に設計したとしても仕様の変更とかが出てきてしまう。今の所見た目やアニメーションに関わる部分は変更が激しそうなためあまり設計してない。
  • クラス図以外では必要なのか?