using Fragilem17.MirrorsAndPortals; using System.Collections; using System.Collections.Generic; using UnityEngine; #if ENABLE_LEGACY_INPUT_MANAGER using UnityEngine.XR; #endif #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER using UnityEngine.InputSystem; #endif namespace Fragilem17.MirrorsAndPortals { public class PortalGunExample : MonoBehaviour { public LayerMask layerMask; public Portal portal1; public Portal portal2; private Dictionary _portalSizes; private Portal _targetPortal; public new Light light; private bool _shooting = false; public bool alignWithViewDirectionOnHorizontalSurfaces = false; #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER public InputAction ShootAction1; public InputAction ShootAction2; private void OnEnable() { ShootAction1.Enable(); ShootAction2.Enable(); } private void OnDisable() { ShootAction1.Disable(); ShootAction2.Disable(); } #endif #if ENABLE_LEGACY_INPUT_MANAGER private UnityEngine.XR.InputDevice _rightHandDevice; void OnEnable() { List allDevices = new List(); InputDevices.GetDevices(allDevices); foreach (InputDevice device in allDevices) InputDevices_deviceConnected(device); InputDevices.deviceConnected += InputDevices_deviceConnected; } private void OnDisable() { InputDevices.deviceConnected -= InputDevices_deviceConnected; } private void InputDevices_deviceConnected(InputDevice device) { bool discardedValue; if (device.TryGetFeatureValue(CommonUsages.primaryButton, out discardedValue)) { if ((device.characteristics & InputDeviceCharacteristics.Right) == InputDeviceCharacteristics.Right) { _rightHandDevice = device; } } } #endif private void Start() { _portalSizes = new Dictionary(); if (portal1 && portal2) { _portalSizes[portal1] = portal1.transform.localScale; _portalSizes[portal2] = portal2.transform.localScale; } } // Update is called once per frame void Update() { _targetPortal = portal1; bool shouldShoot = false; #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER if (!_shooting && ShootAction1.ReadValue() > 0) { shouldShoot = true; _shooting = true; } if (!_shooting && ShootAction2.ReadValue() > 0) { shouldShoot = true; _shooting = true; _targetPortal = portal2; } if (_shooting && ShootAction1.ReadValue() == 0 && ShootAction2.ReadValue() == 0) { _shooting = false; } #endif #if ENABLE_LEGACY_INPUT_MANAGER bool buttonValue; _rightHandDevice.TryGetFeatureValue(UnityEngine.XR.CommonUsages.primaryButton, out buttonValue); //Debug.Log("buttonValue: " + buttonValue); if (!_shooting && (Input.GetMouseButton(0) || (_rightHandDevice.TryGetFeatureValue(UnityEngine.XR.CommonUsages.primaryButton, out buttonValue) && buttonValue))) { shouldShoot = true; _shooting = true; } if (!_shooting && (Input.GetMouseButton(1) || (_rightHandDevice.TryGetFeatureValue(UnityEngine.XR.CommonUsages.secondaryButton, out buttonValue) && buttonValue))) { shouldShoot = true; _shooting = true; _targetPortal = portal2; } if (_shooting && !(Input.GetMouseButton(0) || Input.GetMouseButton(1) || (_rightHandDevice.TryGetFeatureValue(UnityEngine.XR.CommonUsages.primaryButton, out buttonValue) && buttonValue) || (_rightHandDevice.TryGetFeatureValue(UnityEngine.XR.CommonUsages.secondaryButton, out buttonValue) && buttonValue))) { _shooting = false; } #endif if (shouldShoot) { //Debug.DrawRay(transform.position, transform.forward); RaycastHit hit; Ray ray = new Ray(transform.position, transform.forward); if (Physics.Raycast(ray, out hit, 40, layerMask)) { if (hit.collider) { StopAllCoroutines(); StartCoroutine(FadeInOut()); _targetPortal.transform.position = hit.point; _targetPortal.transform.rotation = Quaternion.FromToRotation(Vector3.back, hit.normal); _targetPortal.transform.localScale = Vector3.zero; _targetPortal.wallCollider = hit.collider.gameObject.GetComponentInChildren(); Vector3 euler = _targetPortal.transform.rotation.eulerAngles; _targetPortal.transform.rotation = Quaternion.Euler(euler.x, euler.y, 0); // is it a vertical wall? float vertical = Mathf.Abs(Vector3.Dot(_targetPortal.transform.up, Vector3.up)); //Debug.Log("verical: " + vertical); if (alignWithViewDirectionOnHorizontalSurfaces && vertical < 0.5f) { // Calculate the direction from the hit point to the player's position Vector3 playerDirection = transform.position - hit.point; // Calculate a new forward direction for the portal that is opposite to the direction towards the player Vector3 portalForward = -playerDirection.normalized; // Create a new rotation that aligns the portal's up direction with the direction towards the player, and its forward direction with the wall's normal Quaternion finalRotation = Quaternion.LookRotation(hit.normal, portalForward); // Set the rotation of the portal object _targetPortal.transform.rotation = finalRotation; _targetPortal.transform.Rotate(_targetPortal.transform.InverseTransformDirection(_targetPortal.transform.up), 180); } _targetPortal.transform.localScale = Vector3.zero; StartCoroutine(Scale(_targetPortal, 1)); } } } } IEnumerator FadeInOut() { if (light != null) { light.enabled = true; yield return StartCoroutine(Fade(5f)); yield return StartCoroutine(Fade(0)); light.enabled = false; } } IEnumerator Fade(float to) { float diff = (to - light.intensity); while (Mathf.Abs(diff) > 0.01f) { //Debug.Log("diff " + diff); light.intensity += diff * 0.5f; diff = (to - light.intensity); yield return null; } } IEnumerator Scale(Portal portal, float to) { float diff = ((to * _portalSizes[portal].x) - portal.transform.localScale.x); while (Mathf.Abs(diff) > 0.01f) { //Debug.Log("diff " + diff); portal.transform.localScale += _portalSizes[portal] * diff * 0.1f; diff = ((to * _portalSizes[portal].x) - portal.transform.localScale.x); yield return null; } } } }