Get it on Google Play Get it on Google Play Get it on Google Play


Wm뮤 :: 자주 쓰는 USharp 코드

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
전자과 게임프로그래머 (퇴사함)
2022.3.22f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2023. 1. 22. 00:30 게임/VRChat

자주 쓰는 U# 코드들이다

 

 

핸들이 손에 잡힌 상태인지

GetComponent<VRC_Pickup>().IsHeld
//주의: GetComponent<VRC_Pickup>().currentHand != VRC_Pickup.PickupHand.None는 오작동하므로 쓰면 안됨

 

왼손으로 잡혀있는지

GetComponent<VRC_Pickup>().currentHand == VRC_Pickup.PickupHand.Left

 

 

 

 

변수동기화

[UdonSynced]
int state = 0;

 

 

 

매뉴얼 동기화 예제

이 코드는 종각역 만들때 썼다

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

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class StageText : UdonSharpBehaviour
{
    [UdonSynced]
    [Multiline]
    public string syncText;

    public Text textUI;


    public void UpdateText(string text)
    {
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        syncText = text;
        RequestSerialization();
    }
    void Update()
    {
        textUI.text = syncText;
    }
}

 

 

 

텔레포트

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

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class Teleport : UdonSharpBehaviour
{
    public Transform teleportTarget;
    public override void Interact()
    {
        Networking.LocalPlayer.TeleportTo(teleportTarget.position, teleportTarget.rotation);
    }
}

 

 

 

 

스크립트 LOD

기본 LOD도 훌륭하지만 이걸 쓰는 이유는 라이팅이나 스크립트 On Off도 용이하기 때문이다

몰론 그렇다고 이거만 쓰진 말고 기본 LOD와 병행해서 쓰자

https://ahzkwid.booth.pm/items/5892835

https://gist.github.com/ahzkwid/6647d3aec625afe96c54bb38b2671c72

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

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class ScriptLOD : UdonSharpBehaviour
{

    public float radius = 20;
    public GameObject[] hqObjects;
    public GameObject[] lqObjects;
#if UNITY_EDITOR
    void OnDrawGizmos()
    {
        Gizmos.DrawWireSphere(transform.position, radius);
    }
#endif
    void Update()
    {
        var active = Vector3.Distance(Networking.LocalPlayer.GetPosition(), transform.position) < radius;
        foreach (var obj in hqObjects)
        {
            obj.SetActive(active);
        }
        foreach (var obj in lqObjects)
        {
            obj.SetActive(!active);
        }
    }
}

 

 

글로벌 토글 스위치

https://gist.github.com/ahzkwid/4ee36e9fb9678b6c07522f4fbd1b931d

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

public class GlobalSwitch : UdonSharpBehaviour
{
    public GameObject[] targets;

    [UdonSynced]
    public bool targetsEnabled=false;
    public override void Interact()
    {
        Networking.SetOwner(Networking.LocalPlayer,gameObject);
        targetsEnabled = !targetsEnabled;
    }
    public void Update()
    {
        foreach (var target in targets)
        {
            target.SetActive(targetEnabled);
        }
    }
}

 

 

 

플레이어가 Trigger 콜라이더 내부인지 체크

콜라이더 레이어는 가급적 Default로 해두자

https://gist.github.com/ahzkwid/2c6a020d9c33af2456239baed64726fb

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

public class PlayerInsideCheck : UdonSharpBehaviour
{
    public GameObject[] gameObjects;
    private void Start()
    {
        foreach (var gameObject in gameObjects)
        {
            gameObject.SetActive(false);
        }
    }

    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        if (player.isLocal)
        {
            foreach (var gameObject in gameObjects)
            {
                gameObject.SetActive(true);
            }
        }
    }
    public override void OnPlayerTriggerExit(VRCPlayerApi player)
    {
        if (player.isLocal)
        {
            foreach (var gameObject in gameObjects)
            {
                gameObject.SetActive(false);
            }
        }
    }
}

 

 

 

 

 

유저출입기록

https://ahzkwid.booth.pm/items/6791634

https://gist.github.com/ahzkwid/4fab060b1d493188b10f545f626ab979


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

public class UserAccessLog : UdonSharpBehaviour
{
    public Text log;
    public Scrollbar scrollbar;
    public Text userCount;
    public Color joinColor=Color.green;
    public Color leaveColor = Color.red;
    int logCount = 0;
    public int logCountMax = 20;
    public void Start()
    {
        log.text = "";
    }
    public override void OnPlayerJoined(VRCPlayerApi player)
    {
        if (Time.time<5)
        {
            if (player.isLocal==false)
            {
                //return;
            }
        }
        Log(true, player);
        UpdateUserCount();
    }

    public void UpdateUserCount()
    {
        userCount.text = VRCPlayerApi.GetPlayerCount().ToString();
    }

    public override void OnPlayerLeft(VRCPlayerApi player)
    {
        Log(false, player);
        SendCustomEventDelayedSeconds(nameof(UpdateUserCount), 1f);
    }
    string ToHtmlStringRGB(Color c)
    {
        int r = (int)(c.r * 255f);
        int g = (int)(c.g * 255f);
        int b = (int)(c.b * 255f);
        return $"#{r:X2}{g:X2}{b:X2}";
}
    public void Log(bool isJoin,VRCPlayerApi player)
    {
        var color = joinColor;
        var joinText = "Join";
        if (isJoin==false)
        {
            color = leaveColor;
            joinText = "Left";
        }
        var time = $"{DateTime.Now.ToString("HH:mm:ss")}";
        //var webColor = $"#{ColorUtility.ToHtmlStringRGB(color)}";
        var webColor = ToHtmlStringRGB(color);
        var text = $"{time} <color={webColor}>{joinText}</color> {player.displayName}";
        if (string.IsNullOrWhiteSpace(log.text)==false)
        {
            text = $"\n{text}";
        }
        if (logCount>= logCountMax)
        {
            int index = log.text.IndexOf('\n'); 
            log.text = log.text.Substring(index + 1);
        }
        log.text += text;
        scrollbar.value=0;


        logCount++;
    }
}

 

 

 

 

자동사이즈의자

https://ahzkwid.booth.pm/items/6795564

https://gist.github.com/ahzkwid/3b847810eff472ee2198a05b94abcadd

using System.Linq;
using UdonSharp;
using Unity.Mathematics;
using UnityEngine;
using VRC.SDKBase;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class AutoScaleChair : UdonSharpBehaviour
{
    public GameObject VRCChair;
    float defaultHeight = 1.5f;
    Vector3 smallChairOffset = new Vector3(-0.27f, 0.2125f, 0);
    float smallChairScale = 0.5f;

    //[UdonSynced]
    float scale = 1;

    float avatarHeightPre = 1.5f;
    bool isOwner = false;




    // Custom Animation Character (local)
    public bool bonePositionCheck=true;
    public Transform kneeIntersection;
    float sittingTime = 0f;
    //HumanBodyBones[] heightBones = new HumanBodyBones[] { HumanBodyBones.Hips, HumanBodyBones.LeftUpperLeg, HumanBodyBones.RightUpperLeg };
    //HumanBodyBones[] fowardBones = new HumanBodyBones[] { HumanBodyBones.LeftUpperLeg, HumanBodyBones.RightUpperLeg, HumanBodyBones.LeftLowerLeg, HumanBodyBones.RightLowerLeg };
    VRCPlayerApi seatedPlayer = null;
    float lastCheckTime = 0;
    void Update()
    {
        /*
        if (isOwner)
        {
            var height = Networking.LocalPlayer.GetAvatarEyeHeightAsMeters();
            if (avatarHeightPre != height)
            {
                scale = GetScale(Networking.LocalPlayer);
                avatarHeightPre = height;
                //RequestSerialization();
            }
        }
        */

        var time = Time.time;
        if (time<lastCheckTime+0.1f)
        {
            return;
        }
        lastCheckTime = time;



        UpdateScaleChair();
        UpdateOffset();
    }
    void UpdateOffset()
    {
        if (bonePositionCheck==false)
        {
            transform.localPosition = Vector3.zero;
        }
        if (sittingTime + 3f > Time.time)
        {
            return;
        }
        if (seatedPlayer == null)
        {
            return;
        }


        var player = seatedPlayer;
        /*
        var positions = System.Array.ConvertAll(heightBones, bone =>
        {
            var globalPosition = player.GetBonePosition(bone);
            var localPosition = Quaternion.Inverse(transform.rotation) * (globalPosition - transform.position);
            return localPosition;
        });
         */
        var positions = new Vector3[3];
        for (int i = 0; i < positions.Length; i++)
        {
            //var bone = heightBones[i];
            var bone = HumanBodyBones.Hips;
            switch (i)
            {
                case 1:
                    bone = HumanBodyBones.LeftUpperLeg;
                    break;
                case 2:
                    bone = HumanBodyBones.RightUpperLeg;
                    break;
            }
            var globalPosition = player.GetBonePosition(bone);
            var localPosition = Quaternion.Inverse(transform.rotation) * (globalPosition - transform.position);
            positions[i] = localPosition;
        }

        var kneeIntersectionLocalPosition = Quaternion.Inverse(transform.rotation) * (kneeIntersection.position - transform.position);
        //var yMin = positions.Min(position => position.y);

        var yMin = float.MaxValue;
        for (int i = 0; i < positions.Length; i++)
        {
            yMin = Mathf.Min(yMin, positions[i].y);
        }

        var yOffset = yMin - kneeIntersectionLocalPosition.y;
        /*
        if (Mathf.Abs(yOffset)<0.1f)
        {
            //snap
            yOffset = 0;
        }
        */

        {
            var localPosition = VRCChair.transform.localPosition;
            //localPosition.y = Mathf.Lerp(localPosition.y, -yOffset + scale * 0.05f, 0.1f);
            localPosition.y = Mathf.Lerp(localPosition.y, -yOffset + 0.1f, 0.1f);
            VRCChair.transform.localPosition = localPosition;
        }
        
    }

    float GetScale(VRCPlayerApi player)
    {
        //var player = Networking.LocalPlayer;
        var height = player.GetAvatarEyeHeightAsMeters();
        var scale = height / defaultHeight;
        scale = Mathf.Clamp(scale, 0.2f, 5f);

        return scale;
    }
    void UpdateScaleChair(float scale)
    {
        VRCChair.transform.localScale = Vector3.one * scale;
        VRCChair.transform.localPosition = smallChairOffset / smallChairScale * (1f - scale);
    }
    void UpdateScaleChair()
    {
        if (seatedPlayer == null)
        {
            scale = 1;
        }
        else
        {
            scale = GetScale(seatedPlayer);


            if (seatedPlayer.GetAvatarEyeHeightAsMeters() == 0)
            {
                VRCChair.GetComponent<VRCStation>().ExitStation(seatedPlayer);
                seatedPlayer = null;
                scale = 1;
            }
        }
        UpdateScaleChair(scale);
    }
    public override void Interact()
    {
        Networking.LocalPlayer.UseAttachedStation();
        /*
        //Networking.SetOwner(Networking.LocalPlayer, gameObject);
        scale = GetScale(Networking.LocalPlayer);
        //RequestSerialization();
        avatarHeightPre = Networking.LocalPlayer.GetAvatarEyeHeightAsMeters();
        isOwner = true;
        */
        sittingTime = Time.time;
    }
    /*
    public void UpdateSeatedPlayer()
    {
        seatedPlayer = null;
    }
    */

    public override void OnPlayerLeft(VRCPlayerApi player)
    {
        if (seatedPlayer == player)
        {
            seatedPlayer = null;
            //SendCustomEventDelayedSeconds(nameof(UpdateSeatedPlayer), 1f);
        }
    }
    public override void OnStationEntered(VRCPlayerApi player)
    {
        seatedPlayer = player;

        UpdateScaleChair();
        UpdateOffset();
    }
    public override void OnStationExited(VRCPlayerApi player)
    {
        /*
        if (isOwner)
        {
            scale = 1;
            //RequestSerialization();
        }
        isOwner = false;
        */
        seatedPlayer = null;
    }
}

 

 

 

'게임 > VRChat' 카테고리의 다른 글

Booth 선물 방법  (0) 2023.04.14
VRChat 캐릭터 압착되는 문제  (0) 2023.01.01
VRChat OSC  (0) 2022.02.19
posted by 모카쨩

저사양 유저용 블로그 진입