Created
August 18, 2023 19:03
-
-
Save planaria/421994e86af949bd61f9db56f041e857 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UdonSharp; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using VRC.SDKBase; | |
using VRC.Udon; | |
public class ColliderDisabler : UdonSharpBehaviour | |
{ | |
public UdonBehaviour portal1; | |
public UdonBehaviour portal2; | |
private MeshCollider lastCollider1; | |
private MeshCollider lastCollider2; | |
public Text debug; | |
private void UpdateWallCollider(UdonBehaviour portal, MeshCollider collider) | |
{ | |
var localPlayer = Networking.LocalPlayer; | |
var p1 = localPlayer.GetPosition(); | |
var p2 = localPlayer.GetBonePosition(UnityEngine.HumanBodyBones.Head); | |
var p = (p1 + p2) * 0.5f; | |
var v = p - portal.transform.position; | |
var n = portal.transform.rotation * new Vector3(0.0f, 1.0f, 0.0f); | |
var dot = Vector3.Dot(n, v); | |
var proj = v - n * dot; | |
if (Mathf.Abs(dot) > 2.0f) | |
{ | |
return; | |
} | |
var threshold = 1.0f; | |
if (proj.sqrMagnitude > threshold * threshold) | |
{ | |
return; | |
} | |
collider.enabled = false; | |
} | |
void LateUpdate() | |
{ | |
if (lastCollider1 != null) | |
{ | |
lastCollider1.enabled = true; | |
} | |
if (lastCollider2 != null) | |
{ | |
lastCollider2.enabled = true; | |
} | |
var wallGameObject1 = (GameObject)portal1.GetProgramVariable("wallGameObject"); | |
var wallGameObject2 = (GameObject)portal2.GetProgramVariable("wallGameObject"); | |
MeshCollider collider1 = null; | |
MeshCollider collider2 = null; | |
if (wallGameObject1 != null && wallGameObject2 != null) | |
{ | |
collider1 = (MeshCollider)wallGameObject1.GetComponent(typeof(MeshCollider)); | |
if (collider1 != null) | |
{ | |
UpdateWallCollider(portal1, collider1); | |
} | |
collider2 = (MeshCollider)wallGameObject2.GetComponent(typeof(MeshCollider)); | |
if (collider2 != null) | |
{ | |
UpdateWallCollider(portal2, collider2); | |
} | |
} | |
lastCollider1 = collider1; | |
lastCollider2 = collider2; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UdonSharp; | |
using UnityEngine; | |
using VRC.SDKBase; | |
using VRC.Udon; | |
public class Gun : UdonSharpBehaviour | |
{ | |
public GameObject portal; | |
public GameObject anotherPortal; | |
public Vector3 offset; | |
public string button; | |
public GameObject moon; | |
public GameObject moonSurface; | |
public AudioSource audioSource; | |
public AudioClip shootEnable; | |
public AudioClip shootDisable; | |
private bool pickup; | |
private float dropTime; | |
private const int targetLayer = 25; | |
private const int noTargetLayer = 0; | |
void Update() | |
{ | |
var localPlayer = Networking.LocalPlayer; | |
if (localPlayer != null) | |
{ | |
var now = Time.time; | |
if (pickup) | |
{ | |
dropTime = now; | |
} | |
if (now - dropTime > 5.0f) | |
{ | |
var head = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head); | |
transform.position = head.position + head.rotation * offset; | |
transform.rotation = head.rotation; | |
} | |
if (!localPlayer.IsUserInVR() && Input.GetButtonDown(button)) | |
{ | |
var head = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head); | |
var origin = head.position; | |
var direction = head.rotation * new Vector3(0.0f, 0.0f, 1.0f); | |
ShootAndSound(origin, direction); | |
} | |
} | |
} | |
public override void OnPickup() | |
{ | |
pickup = true; | |
} | |
public override void OnDrop() | |
{ | |
pickup = false; | |
} | |
private bool CheckGameObject(Vector3 origin, Vector3 normal, GameObject obj) | |
{ | |
RaycastHit hit; | |
var layerMask = 1 << targetLayer; | |
if (!Physics.Raycast(origin + normal * 0.01f, -normal, out hit, 0.02f, layerMask)) | |
{ | |
return false; | |
} | |
if (hit.transform.gameObject != obj) | |
{ | |
return false; | |
} | |
if (Vector3.Dot(hit.normal, normal) < Mathf.Cos(1.0f * Mathf.Deg2Rad)) | |
{ | |
return false; | |
} | |
if (Mathf.Abs(Vector3.Dot(hit.point - origin, normal)) > 0.01f) | |
{ | |
return false; | |
} | |
return true; | |
} | |
private float Bisect(Vector3 origin, Vector3 normal, GameObject obj, Vector3 v, float range) | |
{ | |
var min = 0.0f; | |
var max = range; | |
while (max - min > 0.01) | |
{ | |
var mid = (min + max) * 0.5f; | |
if (CheckGameObject(origin + v * mid, normal, obj)) | |
{ | |
min = mid; | |
} | |
else | |
{ | |
max = mid; | |
} | |
} | |
return min; | |
} | |
private bool Shoot(Vector3 origin, Vector3 direction) | |
{ | |
RaycastHit hit; | |
var layerMask = (1 << targetLayer) | (1 << noTargetLayer); | |
if (!Physics.Raycast(origin, direction, out hit, Mathf.Infinity, layerMask)) | |
{ | |
return false; | |
} | |
if (hit.transform.gameObject == moon) | |
{ | |
var portalUdon = (UdonBehaviour)portal.GetComponent(typeof(UdonBehaviour)); | |
portalUdon.SetProgramVariable("wallGameObject", moonSurface); | |
portalUdon.SetProgramVariable("relativePosition", new Vector3()); | |
portalUdon.SetProgramVariable("relativeRotation", Quaternion.identity); | |
return true; | |
} | |
else if (hit.transform.gameObject.layer == targetLayer) | |
{ | |
var q = Quaternion.FromToRotation(new Vector3(0.0f, 1.0f, 0.0f), hit.normal); | |
var v1 = q * new Vector3(1.0f, 0.0f, 0.0f); | |
var v2 = q * new Vector3(0.0f, 0.0f, 1.0f); | |
var minMargin = 1.1f; | |
var p = hit.point; | |
for (int i = 0; i < 180; i += 45) | |
{ | |
var angle = (float)i * Mathf.Deg2Rad; | |
var sin = Mathf.Sin(angle); | |
var cos = Mathf.Cos(angle); | |
var v = v1 * cos + v2 * sin; | |
var margin1 = Bisect(p, hit.normal, hit.transform.gameObject, v, minMargin * 2.0f); | |
var margin2 = Bisect(p, hit.normal, hit.transform.gameObject, -v, minMargin * 2.0f); | |
float d = 0.0f; | |
if (margin1 + margin2 < 2.0f * minMargin) | |
{ | |
return false; | |
} | |
if (margin1 < minMargin) | |
{ | |
d = margin1 - minMargin; | |
} | |
else if (margin2 < minMargin) | |
{ | |
d = minMargin - margin2; | |
} | |
p += v * d; | |
} | |
for (int i = 0; i < 180; i += 10) | |
{ | |
var angle = (float)i * Mathf.Deg2Rad; | |
var sin = Mathf.Sin(angle); | |
var cos = Mathf.Cos(angle); | |
var v = v1 * cos + v2 * sin; | |
if (!CheckGameObject(p + v, hit.normal, hit.transform.gameObject)) | |
{ | |
return false; | |
} | |
} | |
var anotherUdon = (UdonBehaviour)anotherPortal.GetComponent(typeof(UdonBehaviour)); | |
var anotherWall = (GameObject)anotherUdon.GetProgramVariable("wallGameObject"); | |
if (anotherWall == hit.transform.gameObject) | |
{ | |
if (Vector3.Distance(anotherPortal.transform.position, p) < 2.2f) | |
{ | |
return false; | |
} | |
} | |
var invRot = Quaternion.Inverse(hit.transform.rotation); | |
var relativePosition = invRot * (p - hit.transform.position); | |
var relativeRotation = invRot * q; | |
var portalUdon = (UdonBehaviour)portal.GetComponent(typeof(UdonBehaviour)); | |
portalUdon.SetProgramVariable("wallGameObject", hit.transform.gameObject); | |
portalUdon.SetProgramVariable("relativePosition", relativePosition); | |
portalUdon.SetProgramVariable("relativeRotation", relativeRotation); | |
return true; | |
} | |
return false; | |
} | |
private bool ShootAndSound(Vector3 origin, Vector3 direction) | |
{ | |
if (Shoot(origin, direction)) | |
{ | |
audioSource.PlayOneShot(shootEnable); | |
return true; | |
} | |
else | |
{ | |
audioSource.PlayOneShot(shootDisable); | |
return false; | |
} | |
} | |
public override void OnPickupUseDown() | |
{ | |
var direction = transform.rotation * new Vector3(0.0f, 1.0f, 0.0f); | |
var origin = transform.position + direction * 0.1f; | |
ShootAndSound(origin, direction); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UdonSharp; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using VRC.SDKBase; | |
using VRC.Udon; | |
public class Portal : UdonSharpBehaviour | |
{ | |
public GameObject wallGameObject; | |
public GameObject visual; | |
public Vector3 relativePosition; | |
public Quaternion relativeRotation; | |
void Start() | |
{ | |
} | |
void Update() | |
{ | |
if (wallGameObject != null) | |
{ | |
transform.position = wallGameObject.transform.position + wallGameObject.transform.rotation * relativePosition; | |
transform.rotation = wallGameObject.transform.rotation * relativeRotation; | |
visual.SetActive(true); | |
} | |
else | |
{ | |
visual.SetActive(false); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UdonSharp; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using VRC.SDKBase; | |
using VRC.Udon; | |
public class Tracker : UdonSharpBehaviour | |
{ | |
public Camera refCamera; | |
public Camera camera; | |
public GameObject portal1; | |
public GameObject portal2; | |
void Start() | |
{ | |
var localPlayer = Networking.LocalPlayer; | |
if (localPlayer != null) | |
{ | |
camera.enabled = true; | |
camera.nearClipPlane = refCamera.nearClipPlane; | |
camera.farClipPlane = refCamera.farClipPlane; | |
} | |
} | |
private bool IsActive(GameObject portal) | |
{ | |
var udon = (UdonBehaviour)portal.GetComponent(typeof(UdonBehaviour)); | |
var wall = (GameObject)udon.GetProgramVariable("wallGameObject"); | |
return wall != null; | |
} | |
private Quaternion CalculateRotation(Quaternion r1, Quaternion r2) | |
{ | |
var v1 = r1 * new Vector3(0.0f, -1.0f, 0.0f); | |
var v2 = r2 * new Vector3(0.0f, 1.0f, 0.0f); | |
Quaternion q = Quaternion.identity; | |
if (v1.y < -0.99) | |
{ | |
q = Quaternion.Euler(180.0f, 0.0f, 0.0f) * q; | |
} | |
else if (v1.y < 0.99) | |
{ | |
var rotary = Mathf.Atan2(v1.z, v1.x) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, rotary, 0.0f) * q; | |
var tilt = Mathf.Acos(v1.y) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, 0.0f, tilt) * q; | |
} | |
if (v2.y < -0.99) | |
{ | |
q = Quaternion.Euler(180.0f, 0.0f, 0.0f) * q; | |
} | |
else if (v2.y < 0.99) | |
{ | |
var tilt = Mathf.Acos(v2.y) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, 0.0f, -tilt) * q; | |
var rotary = Mathf.Atan2(v2.z, v2.x) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, -rotary, 0.0f) * q; | |
} | |
return q; | |
} | |
void LateUpdate() | |
{ | |
var localPlayer = Networking.LocalPlayer; | |
if (localPlayer != null) | |
{ | |
camera.enabled = IsActive(portal1) && IsActive(portal2); | |
var rot = CalculateRotation(portal1.transform.rotation, portal2.transform.rotation); | |
var head = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head); | |
var pos = portal2.transform.position + rot * (head.position - portal1.transform.position); | |
var invQ = Quaternion.Inverse(camera.transform.localRotation); | |
var q = rot * head.rotation * invQ; | |
var scale = 1.0f / (camera.transform.localScale.x * camera.transform.localScale.x); | |
transform.localScale = Vector3.one * scale; | |
transform.position = pos - q * camera.transform.localPosition * scale; | |
transform.rotation = q; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UdonSharp; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using VRC.SDKBase; | |
using VRC.Udon; | |
public class Warp : UdonSharpBehaviour | |
{ | |
public GameObject portal1; | |
public GameObject portal2; | |
private float lastWarpTime; | |
public AudioSource audioSource; | |
public AudioClip[] warpAudioClips; | |
public Text debug; | |
private bool IsActive(GameObject portal) | |
{ | |
var udon = (UdonBehaviour)portal.GetComponent(typeof(UdonBehaviour)); | |
var wall = (GameObject)udon.GetProgramVariable("wallGameObject"); | |
return wall != null; | |
} | |
private Quaternion CalculateRotation(Quaternion r1, Quaternion r2) | |
{ | |
var v1 = r1 * new Vector3(0.0f, -1.0f, 0.0f); | |
var v2 = r2 * new Vector3(0.0f, 1.0f, 0.0f); | |
Quaternion q = Quaternion.identity; | |
if (v1.y < -0.99) | |
{ | |
q = Quaternion.Euler(180.0f, 0.0f, 0.0f) * q; | |
} | |
else if (v1.y < 0.99) | |
{ | |
var rotary = Mathf.Atan2(v1.z, v1.x) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, rotary, 0.0f) * q; | |
var tilt = Mathf.Acos(v1.y) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, 0.0f, tilt) * q; | |
} | |
if (v2.y < -0.99) | |
{ | |
q = Quaternion.Euler(180.0f, 0.0f, 0.0f) * q; | |
} | |
else if (v2.y < 0.99) | |
{ | |
var tilt = Mathf.Acos(v2.y) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, 0.0f, -tilt) * q; | |
var rotary = Mathf.Atan2(v2.z, v2.x) * Mathf.Rad2Deg; | |
q = Quaternion.Euler(0.0f, -rotary, 0.0f) * q; | |
} | |
return q; | |
} | |
private bool Check(GameObject portalA, GameObject portalB) | |
{ | |
var now = Time.time; | |
if (now - lastWarpTime < 0.1) | |
{ | |
return false; | |
} | |
var localPlayer = Networking.LocalPlayer; | |
var p1 = localPlayer.GetPosition(); | |
var p2 = localPlayer.GetBonePosition(UnityEngine.HumanBodyBones.Head); | |
var p = (p1 + p2) * 0.5f; | |
var v = p - portalA.transform.position; | |
var n = portalA.transform.rotation * new Vector3(0.0f, 1.0f, 0.0f); | |
var dot = Vector3.Dot(v, n); | |
if (dot >= -0.01 || dot < -5.0f) | |
{ | |
return false; | |
} | |
var proj = v - n * dot; | |
if (proj.magnitude > 1.5f) | |
{ | |
return false; | |
} | |
var rot = CalculateRotation(portalA.transform.rotation, portalB.transform.rotation); | |
var pos = portalB.transform.position + rot * (p - portalA.transform.position) + (localPlayer.GetPosition() - p); | |
localPlayer.TeleportTo(pos, rot * localPlayer.GetRotation(), VRC_SceneDescriptor.SpawnOrientation.AlignPlayerWithSpawnPoint, false); | |
localPlayer.SetVelocity(rot * localPlayer.GetVelocity()); | |
if (warpAudioClips.Length != 0) | |
{ | |
audioSource.PlayOneShot(warpAudioClips[Random.Range(0, warpAudioClips.Length)]); | |
} | |
lastWarpTime = now; | |
return true; | |
} | |
void Update() | |
{ | |
if (IsActive(portal1) && IsActive(portal2)) | |
{ | |
if (!Check(portal1, portal2)) | |
{ | |
Check(portal2, portal1); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment