切り絵が趣味の僕がプログラムや創作物について書き溜めるブログ

絵やモデリングやプログラミングなど僕が作った物について。アニメの感想や心動かされたきっかけなどを書き溜めるブログです。Boothで3Dアバターの販売もしていますhttps://paw.booth.pm/

VRC Udonトランプ自動配布機能付きのコード解説 パート1

こんぱう~~~

"VRC Udonトランプ自動配布機能付き"のコードについて解説いたします。

f:id:kiriesto:20220215195945p:plain

■基本的なUdon Behaverの設定の仕方

[Add Component]からUdon Behavivourを選択。

f:id:kiriesto:20220227095208p:plainProgram SouirceをUdon C# Program Assetにして[New Program]を押下。

f:id:kiriesto:20220227095458p:plain

[Create Script]を押下。

f:id:kiriesto:20220227100115p:plain

SynchronizationをManualに変更して、Program Scriptからスクリプトファイルを開くことができます。私はVScodeを使用するように設定しています。

f:id:kiriesto:20220227101027p:plain

qiita.comスクリプトファイルの説明

dealbuttonとCubeで使用しているスクリプトファイルがどんな風になっているのか説明します。
完成したスクリプトファイルをUnityで適用すると以下のようになります。

dealbutton

f:id:kiriesto:20220227094210p:plain

Cube

f:id:kiriesto:20220227094624p:plain

サンプルコード

 dealbuttonのコード


using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using System;

public class card : UdonSharpBehaviour
{

    [SerializeField] GameObject m_obj;
    [SerializeField] GameObject textObject;
 
    [SerializeField] GameObject playCardCenter;
    Vector3 worldPos_start;
    Quaternion worldRot_start;
    Vector3 worldScale_start;
    public float radius = 1.0f;

    public int temp(int x){//配列の中身をシャッフルする関数
        int i;
        int temp;
        int value1;
        int value2;
        for(i = 0; i <= 10000; i++){
            value1 = UnityEngine.Random.Range(0, x.Length);
            value2 = UnityEngine.Random.Range(0, x.Length);

            temp = x[value1];
            x[value1] = x[value2];
            x[value2] = temp;
        }
        return x;
    }
   
    void Start () {//開始時にカードの配置を取得する
        worldPos_start = m_obj[0].transform.position;
        worldRot_start = m_obj[0].transform.rotation;
        worldScale_start = m_obj[0].transform.lossyScale;
    }

    public override void Interact()
    {
        int entry_num = textObject.GetComponent<text>().entry_num;//別のオブジェクトから参加人数を獲得
        int i;
        i = (entry_num == 0)? 1:entry_num;
        int user_num = new int[i];//カードを配るプレーヤーの順番を保持する変数

        for(i = 0; i<entry_num; i++){//user_numの初期値
            user_num[i] = i;
        }
        user_num = this.temp(user_num);//カードを配るプレイヤーの順番を入れ替えている

        int trampList = new int {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53};

        trampList = this.temp(trampList);//カードをシャッフル

        // transformを取得
        Transform myTransform = this.transform;
 
        // ワールド座標を基準に、座標を取得
        //Vector3 worldPos = myTransform.position;
        //worldPos.x -= 0.219f;    // ワールド座標を基準にした、x座標が入っている変数
        //worldPos.y += 0.0f;    // ワールド座標を基準にした、y座標が入っている変数
        //worldPos.z -= 1.0f;    // ワールド座標を基準にした、z座標が入っている変数

        if(entry_num == 0){
            for( i = 0; i<trampList.Length; i++){
                Networking.SetOwner(Networking.LocalPlayer, m_obj[i].gameObject);//カードのオーナーリクエストを送信

                m_obj[trampList[i]].transform.rotation = worldRot_start;//カードの設置場所にもどす(位置)
                m_obj[trampList[i]].transform.position = worldPos_start;//カードの設置場所にもどす(角度)
            }
        }else{
            for( i = 0; i<trampList.Length; i++){
                Networking.SetOwner(Networking.LocalPlayer, m_obj[i].gameObject);//カードのオーナーリクエストを送信

                m_obj[trampList[i]].transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);// カードの回転を初期化
                m_obj[trampList[i]].transform.position = playCardCenter.transform.position;// ワールド座標での座標を設定

                var angle = 360/entry_num*(user_num[i%entry_num]);
                var sin = Math.Sin(angle * (Math.PI / 180));
                var cos = Math.Cos(angle * (Math.PI / 180));

                m_obj[trampList[i]].transform.Translate *1;//カードをずらす

Cubeのコード


using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

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

public class text : UdonSharpBehaviour
{
 
 
 
    public GameObject score_object = null; // Textオブジェクト
    [UdonSynced(UdonSyncMode.None)] public int entry_num = 2; // スコア変数
    Text score_text;

    // 初期化
    void Start () {
        // オブジェクトからTextコンポーネントを取得
        score_text = score_object.GetComponent<Text> ();
        // テキストの表示を入れ替える
        score_text.text = "参加人数:" + entry_num;
    }

    public override void Interact()
    {
         var player = Networking.LocalPlayer;
         score_text = score_object.GetComponent<Text> ();

        if (player.IsOwner(this.gameObject))
        {
            CountUp();
        }
        else
        {
            // Owner以外が押したら、Ownerにカウントアップさせるように命令する
            SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, nameof(CountUp));
        }
    }

    public override void OnDeserialization()
    {
        score_text.text = "参加人数:" + entry_num;   // データ表示更新
    }

    public void CountUp()
    {
        entry_num += 1;
        if(entry_num >= 9){
            entry_num = 0;
        }                                 // データ更新
        RequestSerialization();                     // 同期更新
        score_text.text = "参加人数:" + entry_num;   // データ表示更新
    }

}

usingでUdonSharpだったり必要なモノを使えるようにしています。
[SerializeField]を付けることでUnityの画面で値を入力できるようになります。

参考文献:【初心者Unity】[SerializeField]ってなに? | TECH PROjin

Gameobjectは配列という意味になります。
[SerializeField] GameObject m_obj;
はトランプを格納するので54の大きさの配列になります。

 

    Vector3 worldPos_start;
    Quaternion worldRot_start;
    Vector3 worldScale_start;

はトランプの初期の位置、角度、大きさを格納する箱です。

 

public float radius = 1.0f;
トランプを配るときのプレイヤーの距離を調節するためのモノです。
小さいと近くになって、大きくすると遠ざかります。

 

    void Start () {//開始時にカードの配置を取得する
        worldPos_start = m_obj[0].transform.position;
        worldRot_start = m_obj[0].transform.rotation;
        worldScale_start = m_obj[0].transform.lossyScale;
    }

void Start()は開始時に呼び出されるところなのでここで初期値を設定しています。

 

public int temp(int[] x)ではトランプをシャッフルするのに使っています。
・ランダムに二枚のカードを選ぶ
・交換する
この二つの動作を10000回くりかえしてトランプを混ぜたことにしています。

 

 public override void Interact() はこのコードを適応したモノがつかまれたときに呼び出されます。

Networking.SetOwner(Networking.LocalPlayer, m_obj[i].gameObject);//カードのオーナーリクエストを送信
これがないと誰かがトランプを掴んでしまったらトランプの位置を動かすことができません。

*1:float)sin*1.2f*radius,0.2f,(float)cos*1.2f*radius);//カードを配る

                m_obj[trampList[i]].transform.rotation = Quaternion.Euler(0.0f, angle, 0.0f);//カードを立てる

                m_obj[trampList[i]].transform.Translate ( -0.01f * (Mathf.Floor(i/entry_num)-54/entry_num/2)* worldScale_start.x, 0.0f, 0.001f * Mathf.Floor(i/entry_num