20190927のUnityに関する記事は4件です。

[Unity]SerializeReferenceの使い方がわからんかったので無理やり使えるようにしてみた

Interfaceをやっとシリアライズできる神機能が追加されたらしいですね

2019.3.0b4

ヒャアがまんできねぇシリアライズだ!

Obj.cs
public class Obj : MonoBehaviour
{
    [SerializeReference]
    public SomeInterface なんかのインターフェース;
}
Interface.cs
public interface SomeInterface
{
    void NumberChange();
    int Number { get; }
}

[Serializable]
public class SomeImplementType1 : SomeInterface
{

    [SerializeField]
    private int EditableNumber = 0;

    private readonly int ConstantNumber = 8;

    public int Number => EditableNumber + ConstantNumber;

    public void NumberChange()
    {
        EditableNumber++;
    }
}

[Serializable]
public class SomeImplementType2 : SomeInterface
{
    [SerializeField]
    private int EditableNumber = 0;
    [SerializeField]
    private byte EditableNumber_Byte = 0;

    public int Number => EditableNumber + EditableNumber_Byte;

    public void NumberChange()
    {
        EditableNumber = 0;
        EditableNumber_Byte = 0;

    }
}

interfaceda.gif

なんやこれは???????????????????????????????????????????

クリックしても右クリックしても何も起こらないのでわけがわからず
一応表示はされているのだからシリアライズはされているのだろうと踏んで
エディター拡張で無理やり使えるようにした

PermissionAttribute.cs
using System;
using UnityEngine;

[System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class PermissionAttribute : PropertyAttribute
{
    public readonly Type[] Types;

    public PermissionAttribute(params Type[] types)
    {
        Types = types;
    }
}
using System.Linq;
using UnityEngine;
using UnityEditor;
using System;

[CustomPropertyDrawer(typeof(PermissionAttribute))]
public class SerializeReferenceDrawer : PropertyDrawer
{

    private int ActivateTypeIndex;
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var permission = attribute as PermissionAttribute;
        EditorGUI.BeginChangeCheck();
        //fieldInfoはリフレクションのFieldInfo、基底クラスのPropertyDrawerが描画しているPropertyが入っている
        var targetProperty = fieldInfo.GetValue(property.serializedObject.targetObject);
        //Popup用に高さを調整、調整しないとプロパティが触れなくなる
        position.height = 16;
        var popUpTypeText = permission.Types.Select(type => type.ToString()).ToArray();
        var targetObject = property.serializedObject.targetObject;
        if (targetProperty == null)
        {
            ActivateTypeIndex = EditorGUI.Popup(position, ActivateTypeIndex, popUpTypeText);
            var instance = Activator.CreateInstance(permission.Types[ActivateTypeIndex]);
            fieldInfo.SetValue(targetObject, instance);
        }
        else
        {
            ActivateTypeIndex = EditorGUI.Popup(position, Array.IndexOf(permission.Types, targetProperty.GetType()), popUpTypeText);
            if (targetProperty.GetType() != permission.Types[ActivateTypeIndex])
            {
                var instance = Activator.CreateInstance(permission.Types[ActivateTypeIndex]);
                fieldInfo.SetValue(targetObject, instance);
            }
        }
        //Popupでかさが増えた分を描画をしたへずらす
        position.y += 16;
        position.height = EditorGUI.GetPropertyHeight(property, true) + 14;
        EditorGUI.PropertyField(position, property, label, true);
        property.serializedObject.ApplyModifiedProperties();
        EditorGUI.EndChangeCheck();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUI.GetPropertyHeight(property, label, true) + base.GetPropertyHeight(property, label);
    }
}

使う側

Obj.cs
using UnityEngine;
using UnityEngine.UI;

public class Obj : MonoBehaviour
{
    [SerializeField]
    private Button Button;
    //使いたいものを型で指定する
    [SerializeReference, Permission(typeof(SomeImplementType1), typeof(SomeImplementType2))]
    public SomeInterface なんかのインターフェース;


    private void Awake()
    {
        Button.onClick.AddListener(() =>
        {
            なんかのインターフェース.NumberChange();
            Button.GetComponentInChildren<Text>().text = なんかのインターフェース.Number.ToString();
        });
    }
}

やったぜ

interfacedada.gif

Type1はインクリメントしてType2はリセットする挙動
Unityを再起動してもプレイしても値が残っているので使えそうです
Activatorを使っているせいか、↓は0が代入されてましたがこれは自分のコードの問題でしょうし

private readonly int ConstantNumber = 8;

挙動を変えたりいろいろ捗りそうです

違うそうじゃない

いくらなんでもこんな面倒な手順を踏ませるはずはないので
何か見落としていると思うんですが
誰かちゃんとした使い方教えてください
属性はあるけどまだ使えないとかなんでしょうかね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】PUN2でRpcTarget.AllBufferedとかOthersBufferedが仕事してない時に見るメモ

はじめに

ここへたどり着いたということは、
PhotonのRpcTarget.AllとRpcTarget.AllBufferedの違いは分かっているということでしょう。
分かっていない方は以下のブログ推奨です(PUN2の記事ではないですが、内容的には同じです)。
【Unity】僕もPhotonを使いたい #08 RPC() PhotonTargets編

RpcTarget.○○Bufferedを使うと、後からルームに入室した人にもデータを送信してくれます。
が、この情報だけを見てドツボにハマってしまったのでメモ。

Sceneをまたぐときはちょっと特別

単刀直入に言うとここの内容です。
【Unity】僕もPhotonを使いたい #13 isMessageQueueRunning
私はここを見る前に、よっしゃRPC使ったるでー!と先走ってしまい、
いや、Buffered動かないやんけ・・・と、同じ目に遭遇してしまった・・・。

上記のリンク先と少しだけ違うのが、PUN2では

PhotonNetwork.IsMessageQueueRunning

IsのIが大文字になってます。

最後に

内容の無い記事になっていますが、
載せたリンク先はPUN2のワードで検索をかけると出会えない可能性があるので、
PUN2を使っている人が検索をかけそうなワードを散りばめているつもりです。
というのは建前で、忘れたころの自分が検索かけそうなワードを散りばめています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityでチーム開発 流れやルールなど

はじめに

株式会社テクロスでエンジニアとしてアルバイトしてる大学生です。

アルバイトでUnityでのチーム開発を何度か行ったのですが、知見を文書化してなかったのでまとめてみようと思います。
似たような記事もあったけど全体的にまとまってはなかったりしたので、全体感持ちやすいように今回簡単にまとめてみました。

今回はUnityとGitHubを使ってチーム開発を行います。(この記事は初心者の方向けです)

チーム開発の流れ

簡単にざっくり言うと
Unityでプロジェクト作成→GitHubにレポジトリを作る→皆でcloneして開発
って流れになると思います。(当たり前か)

以下で各フェーズでの具体的な手法とルールについて確認していきます。

Unityでプロジェクト作成してGithubにレポジトリを作る

これはこちらのサイトがまとまってて非常に良い。
この記事の流れ通りに設定すればオーケーだと思う。
Unityプロジェクトだと.gitignoreも自動で作ってくれるので便利ですね、UnityとGitHub親和性高い。

レポジトリができたらREADMEにチーム開発のルール等まとめておくといいかと思います。具体的には、

  • Unityのバージョン
  • 最初の環境構築の流れを簡単にまとめる
  • コードの書き方でルール等あればまとめる

ぐらいですかね

  1. このリポジトリを各々forkする
  2. forkしたリポジトリをcloneする (clone したいディレクトリまでローカルで移動して"git clone http~")
  3. ローカルで作業用branchを作成 (git checkout -b (適当なブランチ名))
  4. 編集したらcommitしておく (git add ファイル名) (git commit -m "コメント")
  5. GitHubにpushする (git push (先) (元))
  6. pushしたらプルリク送る https://qiita.com/syougun360/items/013229aeddec08121474

これはUnityじゃない別のプロジェクトですけどこんな感じで書いてます。(Git初心者が多かったのでだいぶ分かりやすく書いてるけど)

コーディング規約は基本的にリーダブルコード様に従ってます。https://qiita.com/Kenya/items/faec4cc374edd5ffbba6
細かいですけど関数はスネークケース、グローバル変数はキャメルケースにするとかいうルールも決めてました。
コーディングルールはその程度決めておけばいいと思います。基本的にはリーダブルコードに則って、キャメルケース等の使い方を統一する程度で。

いざ開発

ここまできたらあとは開発するだけなんですが、複数人で同じプロジェクトをいじる時は絶対に図を作る必要があります。
完成のイメージ図、画面遷移図、シーケンス図、クラス図等必要です。皆の頭の中のイメージを統一させるためと、誰がどの作業をしているのか見やすいようにです。

どの図がどんなものかはこちらのページによくまとまってるのでご覧ください。

そもそもクラスが何かとかよく分かってない人はドラゴンボールで学ぶオブジェクト指向 改が分かりやすいです。

この図を作るのは難しいので何回も作って慣れるしかないと思います。図の作り方まとめてくれてるサイトいっぱいあるので、頑張りましょう!!

図も完成したらいよいよコードを書いて開発していくだけです!!
誰がコードレビューするのか等もルール決めしておくといいかもしれないですね。

おわりに

エンジニア初心者なので上手くまとめられてるか、間違ってないか不安です。間違ってたら教えてください。
また何か思い出したら追記します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】ボタンで複数のパネルの開閉を制御

ちょっと詰まったのでメモです。

目標

  • ボタンとパネルは1対1対応しており、ボタンを押すとそれに対応したパネルが開閉(SetActive() で表示/非表示)する
  • ボタン・パネルの数は問わない
  • 同時に開くパネルは1つまで

(下のスクショは btnL をクリックして pnlL だけを表示させたもの)

スクリーンショット 2019-09-27 18.06.53.png

ソースコード

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

public class PanelController : MonoBehaviour
{
    public GameObject buttonRoot;
    public GameObject panelRoot;
    List<GameObject> buttons = new List<GameObject>();
    List<GameObject> panels = new List<GameObject>();

    void Start() {
        foreach (Transform button in buttonRoot.transform) {
            buttons.Add(button.gameObject);
        }

        foreach (Transform panels in panelRoot.transform) {
            panels.Add(panels.gameObject);
        }
    }

    public void TogglePanel() {
        GameObject pushedBtn = this.gameObject;
        int c = buttons.Count;

        for (int i = 0; i < c; i++) {
            if (buttons[i] == pushedBtn) {
                panels[i].SetActive(!palens[i].activeSelf);
            } else {
                palens[i].SetActive(false);
            }
        }
    }
}

Start() 内の foreach でボタンオブジェクトとパネルオブジェクトをすべて取得し、
TogglePanel() 内の for ですべてのパネルに対し開閉を行なっています。

Unity側の設定

  1. ボタンオブジェクトすべてに PanelController.cs を追加
  2. Panel Controller コンポーネントの2変数にオブジェクトを指定
  3. すべてのボタンオブジェクトの Button コンポーネントの OnClick+ をクリックし、オブジェクトは自分自身、関数は PanelController.TogglePanel を選択
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む