so I'm using the following script which uses Google's GvrLaserPointerImpl (Google Daydream) to teleport around my scene:
public class PlayerTeleport : MonoBehaviour {
void Update() {
if (GvrController.AppButtonUp) {
GvrLaserPointerImpl laserPointerImpl = (GvrLaserPointerImpl)GvrPointerManager.Pointer;
if (laserPointerImpl.IsPointerIntersecting) {
transform.position = new Vector3(laserPointerImpl.PointerIntersection.x, transform.position.y, laserPointerImpl.PointerIntersection.z);
}
}
}
}
For my game, I need to know what the GvrLaserPointerImpl raycast is hitting. If you look at the GvrLaserPointerImpl script OnPointerEnter arguments you can see that there is a targetObject but it not being publicly exposed or handled in any way:
/// Implementation of GvrBasePointer for a laser pointer visual.
/// This script should be attached to the controller object.
/// The laser visual is important to help users locate their cursor
/// when its not directly in their field of view.
public class GvrLaserPointerImpl : GvrBasePointer {
/// Small offset to prevent z-fighting of the reticle (meters).
private const float Z_OFFSET_EPSILON = 0.1f;
/// Size of the reticle in meters as seen from 1 meter.
private const float RETICLE_SIZE = 0.01f;
public Camera MainCamera { private get; set; }
public Color LaserColor { private get; set; }
public LineRenderer LaserLineRenderer { get; set; }
public GameObject Reticle { get; set; }
public float MaxLaserDistance { private get; set; }
public float MaxReticleDistance { private get; set; }
// Properties exposed for testing purposes.
public Vector3 PointerIntersection { get; private set; }
public bool IsPointerIntersecting { get; private set; }
public Ray PointerIntersectionRay { get; private set; }
public override float MaxPointerDistance {
get {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
return MaxReticleDistance;
#else
return 0;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
}
public GvrLaserPointerImpl() {
MaxLaserDistance = 0.75f;
MaxReticleDistance = 2.5f;
}
#if !(UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR))
public override void OnStart() {
// Don't call base.Start() so that this pointer isn't activated when
// the editor doesn't have UNITY_HAS_GOOGLE_VR.
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public override void OnInputModuleEnabled() {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (LaserLineRenderer != null) {
LaserLineRenderer.enabled = true;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnInputModuleDisabled() {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (LaserLineRenderer != null) {
LaserLineRenderer.enabled = false;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerEnter(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
IsPointerIntersecting = true;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerHover(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(GameObject targetObject) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = Vector3.zero;
PointerIntersectionRay = new Ray();
IsPointerIntersecting = false;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerClickDown() {
// User has performed a click on the target. In a derived class, you could
// handle visual feedback such as laser or cursor color changes here.
}
public override void OnPointerClickUp() {
// User has released a click from the target. In a derived class, you could
// handle visual feedback such as laser or cursor color changes here.
}
public override void GetPointerRadius(out float enterRadius, out float exitRadius) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (Reticle != null) {
float reticleScale = Reticle.transform.localScale.x;
// Fixed size for enter radius to avoid flickering.
// This will cause some slight variability based on the distance of the object
// from the camera, and is optimized for the average case.
enterRadius = RETICLE_SIZE * 0.5f;
// Dynamic size for exit radius.
// Always correct because we know the intersection point of the object and can
// therefore use the correct radius based on the object's distance from the camera.
exitRadius = reticleScale;
} else {
enterRadius = 0.0f;
exitRadius = 0.0f;
}
#else
enterRadius = 0.0f;
exitRadius = 0.0f;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public void OnUpdate() {
// Set the reticle's position and scale
if (Reticle != null) {
if (IsPointerIntersecting) {
Vector3 difference = PointerIntersection - PointerIntersectionRay.origin;
Vector3 clampedDifference = Vector3.ClampMagnitude(difference, MaxReticleDistance);
Vector3 clampedPosition = PointerIntersectionRay.origin + clampedDifference;
Reticle.transform.position = clampedPosition;
} else {
Reticle.transform.localPosition = new Vector3(0, 0, MaxReticleDistance);
}
float reticleDistanceFromCamera =
(Reticle.transform.position - MainCamera.transform.position).magnitude;
float scale = RETICLE_SIZE * reticleDistanceFromCamera;
Reticle.transform.localScale = new Vector3(scale, scale, scale);
}
if (LaserLineRenderer == null) {
Debug.LogWarning("Line renderer is null, returning");
return;
}
// Set the line renderer positions.
Vector3 lineEndPoint;
if (IsPointerIntersecting) {
Vector3 laserDiff = PointerIntersection - base.PointerTransform.position;
float intersectionDistance = laserDiff.magnitude;
Vector3 direction = laserDiff.normalized;
float laserDistance = intersectionDistance > MaxLaserDistance ? MaxLaserDistance : intersectionDistance;
lineEndPoint = base.PointerTransform.position + (direction * laserDistance);
} else {
lineEndPoint = base.PointerTransform.position + (base.PointerTransform.forward * MaxLaserDistance);
}
LaserLineRenderer.SetPositions(new Vector3[] {base.PointerTransform.position, lineEndPoint});
// Adjust transparency
float alpha = GvrControllerVisual.AlphaValue;
LaserLineRenderer.SetColors(Color.Lerp(Color.clear, LaserColor, alpha), Color.clear);
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
I want to extend the GvrLaserPointerImpl class and override the OnPointerEnter method to publicly expose the targetObject so I can do a check in my PlayerTeleport script to do a check to see if the raycast is hitting a targetObject with a tag. I'm not sure what to put in the overrided OnPointerEnter method to access to targetObject class though. GvrLaserPointerImpl inherits from the abstract GvrBasePointer class so there is nothing in the abstract class which tells me how I could do this.
Any help would be appreciated!
The typical design pattern when using Unity's Event System for interaction would be to place a script on the target object that implements an IEventSystemHandler. Example:
public class ClickResponder : MonoBehaviour, IPointerClickHandler {
public void OnPointerClick(PointerEventData eventData) {
Debug.Log("Clicked!");
}
}
If that doesn't work for your use case, you may also be able to access the object currently being pointed at via this API: https://docs.unity3d.com/ScriptReference/EventSystems.EventSystem-currentSelectedGameObject.html
If neither of those approaches work for your needs, you can expose the target Object in GvrLaserPointerImpl like this:
public GameObject TargetObject { get; private set; }
public override void OnPointerEnter(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
TargetObject = targetObject;
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
IsPointerIntersecting = true;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(GameObject targetObject) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
TargetObject = null;
PointerIntersection = Vector3.zero;
PointerIntersectionRay = new Ray();
IsPointerIntersecting = false;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
I hope that helps!
Related
I have been making a game on Unity following the tutorial by Sykoo, this one.
And I have a problem with the crafting system, when I want the items to be destroyed when the craft is made, but I dont know how to do it. Can someone help me please?
here is the craft item script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CraftableItem : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public GameObject thisItem;
public int requiredItems;
public GameObject[] item;
private bool hovered;
private GameObject player;
private GameObject itemManager;
public void Start()
{
player = GameObject.FindWithTag("Player");
itemManager = GameObject.FindWithTag("ItemManager");
}
public void Update()
{
if (hovered == true)
{
if(Input.GetMouseButtonDown(0))
{
CheckForRequiredItems();
}
}
}
public void CheckForRequiredItems()
{
int itemsInManager = itemManager.transform.childCount;
if (itemsInManager > 0)
{
int itemsFound = 0;
for(int i = 0; i < itemsInManager; i++)
{
for (int z = 0; z < requiredItems; z++)
{
if (itemManager.transform.GetChild(i).GetComponent<Item>().type == item[z].GetComponent<Item>().type)
{
itemsFound++;
break;
}
}
}
if (itemsFound >= requiredItems)
{
GameObject spawndedItem = Instantiate(thisItem, /* pos,*/player.transform.position, Quaternion.identity);
}
}
}
public void OnPointerEnter(PointerEventData eventData)
{
hovered = true;
}
public void OnPointerExit(PointerEventData eventData)
{
hovered = false;
}
}
the inventory script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
//Instructions *correct
public GameObject inventory;
public GameObject slotHolder;
public GameObject itemManager;
private bool inventoryEnabled;
private int slots;
private Transform[] slot;
private GameObject itemPickedUp;
private bool itemAdded;
private GameObject player;
//Start *correct
public void Start()
{
// slots being detected
inventoryEnabled = true;
slots = slotHolder.transform.childCount;
slot = new Transform[slots];
DetectInventorySlots();
}
// Inventory GUI
public void Update()
{
if (Input.GetKeyDown(KeyCode.I))
{
inventoryEnabled = !inventoryEnabled;
}
if(inventoryEnabled)
{
inventory.GetComponent<Canvas>().enabled = true;
Time.timeScale = 0;
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
else
{
inventory.GetComponent<Canvas>().enabled = false;
Time.timeScale = 1;
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
}
// Inventory Pick *correct
public void OnTriggerStay(Collider other)
{
if (other.tag == "Item")
{
itemPickedUp = other.gameObject;
AddItem(itemPickedUp);
}
}
public void OnTriggerExit(Collider other)
{
if (other.tag == "Item")
{
itemAdded = false;
}
}
// Add Item *correct
public void AddItem(GameObject item)
{
for (int i = 0; i < slots; i++)
{
if (slot[i].GetComponent<Slot>().empty && itemAdded == false)
{
slot[i].GetComponent<Slot>().item = itemPickedUp;
slot[i].GetComponent<Slot>().itemIcon = itemPickedUp.GetComponent<Item>().icon;
//attachs the item to the hand *correct
item.transform.parent = itemManager.transform;
item.transform.position = itemManager.transform.position;
//equipar arma
item.transform.localPosition = item.GetComponent<Item>().position;
item.transform.localEulerAngles = item.GetComponent<Item>().rotation;
item.transform.localScale = item.GetComponent<Item>().scale;
Destroy(item.GetComponent<Rigidbody>());
itemAdded = true;
item.SetActive(false);
}
}
}
// Detect slots *correct
public void DetectInventorySlots()
{
for (int i = 0; i < slots; i++)
{
slot[i] = slotHolder.transform.GetChild(i);
}
inventory.GetComponent<Canvas>().enabled = true;
inventoryEnabled = false;
}
}
and the slot script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems; // Required when using Event data.
using UnityEngine.UI;
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
//instructions *correct
private bool hovered;
public bool empty;
public Image image;
public GameObject item;
public Texture itemIcon;
private GameObject player;
//Update *correct
void Start()
{
player = GameObject.FindWithTag("Player");
hovered = false;
image.enabled = false;
}
void Update()
{
if (item)
{
empty = false;
itemIcon = item.GetComponent<Item>().icon;
this.GetComponent<RawImage>().texture = itemIcon;
} else {
empty = true;
this.GetComponent<RawImage>().texture = null;
}
}
//Pointer *correct
public void OnPointerEnter(PointerEventData eventData)
{
hovered = true;
}
public void OnPointerExit(PointerEventData eventData)
{
hovered = false;
}
public void OnPointerClick(PointerEventData eventData)
{
if(item)
{
Item thisItem = item.GetComponent<Item>();
//water
if(thisItem.type == "Water")
{
player.GetComponent<Player>().Drink(thisItem.decreaseRate);
Destroy(item);
}
//food
if (thisItem.type == "Food")
{
player.GetComponent<Player>().Eat(thisItem.decreaseRate);
Destroy(item);
}
//weapon
if(thisItem.type == "Weapon" && player.GetComponent<Player>().weaponEquipped == false)
{
thisItem.equipped = true;
item.SetActive(true);
imageEnabled();
}
if (thisItem.type == "Weapon" && player.GetComponent<Player>().weaponEquipped == true)
{
thisItem.equipped = false;
item.SetActive(false);
image.enabled = false;
player.GetComponent<Player>().weaponEquipped = false;
}
}
}
public void imageEnabled()
{
image.enabled = !image.enabled;
}
public class StackItem
{
public Item item = new Item();
public int amount = 1;
}
}
but i think you will only need the craft system script. Hope someone can help me.
Seems like your craft is completed on this instruction:
if (itemsFound >= requiredItems)
{
GameObject spawndedItem = Instantiate(thisItem, /* pos,*/player.transform.position, Quaternion.identity);
}
Next to GameObject spawndedItem... string you can specify your element deletion code, as an example:
if (itemsFound >= requiredItems)
{
GameObject spawndedItem = Instantiate(thisItem, /* pos,*/player.transform.position, Quaternion.identity);
Destroy(GameObject.Find("ObjectThatYouWantToDestroyName"));
}
I am using a free joystick pack off the unity asset store that I am modifying. I am using touch fields along with the joys sticks to control the player movement and looking. Everything works just fine in unity itself, however when i build it out to my android phone, the very first time i interact with the joysticks they move around and reposition just fine as i drag around. After this first interaction with them however they no longer reposition as I drag and I am stumped.
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class FixedTouchField : MonoBehaviour, IPointerDownHandler, IPointerUpHandler,
IDragHandler
{
[HideInInspector]
public Vector2 TouchDist;
[HideInInspector]
public Vector2 PointerOld;
[HideInInspector]
protected int PointerId;
[HideInInspector]
public bool Pressed;
public FixedJoystick joystick;
public Image joystickHandle;
private float timeTakenDuringLerp = 1.0f;
private float timeStartedLerping;
void Update()
{
if (Pressed)
{
float timeSinceStarted = Time.time - timeStartedLerping;
float percentageComplete = timeSinceStarted / timeTakenDuringLerp;
joystick.GetComponent<Image>().color = Color.Lerp(new Color(1,1,1,0), Color.white, percentageComplete);
joystickHandle.color = Color.Lerp(new Color(1, 1, 1, 0), Color.white, percentageComplete);
if (PointerId >= 0 && PointerId < Input.touches.Length)
{
TouchDist = Input.touches[PointerId].position - PointerOld;
PointerOld = Input.touches[PointerId].position;
}
else
{
TouchDist = new Vector2(Input.mousePosition.x, Input.mousePosition.y) - PointerOld;
PointerOld = Input.mousePosition;
}
}
else
{
float timeSinceStarted = Time.time - timeStartedLerping;
float percentageComplete = timeSinceStarted / timeTakenDuringLerp;
joystick.GetComponent<Image>().color = Color.Lerp(Color.white, new Color(1, 1, 1, 0), percentageComplete);
joystickHandle.color = Color.Lerp(Color.white, new Color(1, 1, 1, 0), percentageComplete);
TouchDist = new Vector2();
}
}
public void OnPointerDown(PointerEventData eventData)
{
Pressed = true;
PointerId = eventData.pointerId;
PointerOld = eventData.position;
timeStartedLerping = Time.time;
joystick.RepostionJoystick(eventData);
}
public void OnPointerUp(PointerEventData eventData)
{
Pressed = false;
joystick.input = Vector2.zero;
joystick.handle.anchoredPosition = Vector2.zero;
}
public void OnDrag(PointerEventData eventData)
{
joystick.RepostionJoystick(eventData);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
public float Horizontal { get { return (snapX) ? SnapFloat(input.x, AxisOptions.Horizontal) : input.x; } }
public float Vertical { get { return (snapY) ? SnapFloat(input.y, AxisOptions.Vertical) : input.y; } }
public Vector2 Direction { get { return new Vector2(Horizontal, Vertical); } }
public float HandleRange
{
get { return handleRange; }
set { handleRange = Mathf.Abs(value); }
}
public float DeadZone
{
get { return deadZone; }
set { deadZone = Mathf.Abs(value); }
}
public AxisOptions AxisOptions { get { return AxisOptions; } set { axisOptions = value; } }
public bool SnapX { get { return snapX; } set { snapX = value; } }
public bool SnapY { get { return snapY; } set { snapY = value; } }
[SerializeField] private float handleRange = 1;
[SerializeField] private float deadZone = 0;
[SerializeField] private AxisOptions axisOptions = AxisOptions.Both;
[SerializeField] private bool snapX = false;
[SerializeField] private bool snapY = false;
[SerializeField] protected RectTransform background = null;
[SerializeField] public RectTransform handle = null;
private RectTransform baseRect = null;
private Canvas canvas;
private Camera cam;
public Vector2 input = Vector2.zero;
protected virtual void Start()
{
HandleRange = handleRange;
DeadZone = deadZone;
baseRect = GetComponent<RectTransform>();
canvas = GetComponentInParent<Canvas>();
if (canvas == null)
Debug.LogError("The Joystick is not placed inside a canvas");
Vector2 center = new Vector2(0.5f, 0.5f);
background.pivot = center;
handle.anchorMin = center;
handle.anchorMax = center;
handle.pivot = center;
handle.anchoredPosition = Vector2.zero;
}
public virtual void OnPointerDown(PointerEventData eventData)
{
// OnDrag(eventData);
}
public void OnDrag(PointerEventData eventData)
{
}
public void RepostionJoystick(PointerEventData eventData)
{
cam = null;
if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
cam = canvas.worldCamera;
Vector2 position = RectTransformUtility.WorldToScreenPoint(cam, background.position);
Vector2 radius = background.sizeDelta / 2;
input = (eventData.position - position) / (radius * canvas.scaleFactor);
FormatInput();
HandleInput(input.magnitude, input.normalized, radius, cam);
handle.anchoredPosition = input * radius * handleRange;
}
protected virtual void HandleInput(float magnitude, Vector2 normalised, Vector2 radius, Camera cam)
{
if (magnitude > deadZone)
{
if (magnitude > 1)
input = normalised;
}
else
input = Vector2.zero;
}
private void FormatInput()
{
if (axisOptions == AxisOptions.Horizontal)
input = new Vector2(input.x, 0f);
else if (axisOptions == AxisOptions.Vertical)
input = new Vector2(0f, input.y);
}
private float SnapFloat(float value, AxisOptions snapAxis)
{
if (value == 0)
return value;
if (axisOptions == AxisOptions.Both)
{
float angle = Vector2.Angle(input, Vector2.up);
if (snapAxis == AxisOptions.Horizontal)
{
if (angle < 22.5f || angle > 157.5f)
return 0;
else
return (value > 0) ? 1 : -1;
}
else if (snapAxis == AxisOptions.Vertical)
{
if (angle > 67.5f && angle < 112.5f)
return 0;
else
return (value > 0) ? 1 : -1;
}
return value;
}
else
{
if (value > 0)
return 1;
if (value < 0)
return -1;
}
return 0;
}
public virtual void OnPointerUp(PointerEventData eventData)
{
//input = Vector2.zero;
//handle.anchoredPosition = Vector2.zero;
}
protected Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
{
Vector2 localPoint = Vector2.zero;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, screenPosition, cam, out localPoint))
{
Vector2 pivotOffset = baseRect.pivot * baseRect.sizeDelta;
return localPoint - (background.anchorMax * baseRect.sizeDelta) + pivotOffset;
}
return Vector2.zero;
}
}
public enum AxisOptions { Both, Horizontal, Vertical }
these are the scripts interacting with each other to reposition the joysticks
Here is the original joystick without the modifications for the touchfield
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
public float Horizontal { get { return (snapX) ? SnapFloat(input.x, AxisOptions.Horizontal) : input.x; } }
public float Vertical { get { return (snapY) ? SnapFloat(input.y, AxisOptions.Vertical) : input.y; } }
public Vector2 Direction { get { return new Vector2(Horizontal, Vertical); } }
public float HandleRange
{
get { return handleRange; }
set { handleRange = Mathf.Abs(value); }
}
public float DeadZone
{
get { return deadZone; }
set { deadZone = Mathf.Abs(value); }
}
public AxisOptions AxisOptions { get { return AxisOptions; } set { axisOptions = value; } }
public bool SnapX { get { return snapX; } set { snapX = value; } }
public bool SnapY { get { return snapY; } set { snapY = value; } }
[SerializeField] private float handleRange = 1;
[SerializeField] private float deadZone = 0;
[SerializeField] private AxisOptions axisOptions = AxisOptions.Both;
[SerializeField] private bool snapX = false;
[SerializeField] private bool snapY = false;
[SerializeField] protected RectTransform background = null;
[SerializeField] private RectTransform handle = null;
private RectTransform baseRect = null;
private Canvas canvas;
private Camera cam;
private Vector2 input = Vector2.zero;
protected virtual void Start()
{
HandleRange = handleRange;
DeadZone = deadZone;
baseRect = GetComponent<RectTransform>();
canvas = GetComponentInParent<Canvas>();
if (canvas == null)
Debug.LogError("The Joystick is not placed inside a canvas");
Vector2 center = new Vector2(0.5f, 0.5f);
background.pivot = center;
handle.anchorMin = center;
handle.anchorMax = center;
handle.pivot = center;
handle.anchoredPosition = Vector2.zero;
}
public virtual void OnPointerDown(PointerEventData eventData)
{
OnDrag(eventData);
}
public void OnDrag(PointerEventData eventData)
{
cam = null;
if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
cam = canvas.worldCamera;
Vector2 position = RectTransformUtility.WorldToScreenPoint(cam, background.position);
Vector2 radius = background.sizeDelta / 2;
input = (eventData.position - position) / (radius * canvas.scaleFactor);
FormatInput();
HandleInput(input.magnitude, input.normalized, radius, cam);
handle.anchoredPosition = input * radius * handleRange;
}
protected virtual void HandleInput(float magnitude, Vector2 normalised, Vector2 radius, Camera cam)
{
if (magnitude > deadZone)
{
if (magnitude > 1)
input = normalised;
}
else
input = Vector2.zero;
}
private void FormatInput()
{
if (axisOptions == AxisOptions.Horizontal)
input = new Vector2(input.x, 0f);
else if (axisOptions == AxisOptions.Vertical)
input = new Vector2(0f, input.y);
}
private float SnapFloat(float value, AxisOptions snapAxis)
{
if (value == 0)
return value;
if (axisOptions == AxisOptions.Both)
{
float angle = Vector2.Angle(input, Vector2.up);
if (snapAxis == AxisOptions.Horizontal)
{
if (angle < 22.5f || angle > 157.5f)
return 0;
else
return (value > 0) ? 1 : -1;
}
else if (snapAxis == AxisOptions.Vertical)
{
if (angle > 67.5f && angle < 112.5f)
return 0;
else
return (value > 0) ? 1 : -1;
}
return value;
}
else
{
if (value > 0)
return 1;
if (value < 0)
return -1;
}
return 0;
}
public virtual void OnPointerUp(PointerEventData eventData)
{
input = Vector2.zero;
handle.anchoredPosition = Vector2.zero;
}
protected Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
{
Vector2 localPoint = Vector2.zero;
if
(RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, screenPosition, cam, out localPoint))
{
Vector2 pivotOffset = baseRect.pivot * baseRect.sizeDelta;
return localPoint - (background.anchorMax *
baseRect.sizeDelta) + pivotOffset;
}
return Vector2.zero;
}
}
public enum AxisOptions { Both, Horizontal, Vertical }
I gutted all the above from the project and added https://assetstore.unity.com/packages/tools/input-management/ultimate-touchpad-108921 to the project without altering anything. It is doing the exact same thing.
I have one problem, I am not running the "OnTriggerEnter2D" method on the prefab.
I took the object, threw a script on it, added the right components and made it prefab.
I have a hero when he attacks a collider appears which is a trigger.
If this collider is a player's sword then the enemy receives damage.
A regular object (not a prefab) gets damaged, but if I do this object a prefab and drag it onto the stage then the "OnTriggerEnter2D" method does not work.
Here's the enemy script. I also poured my project on the Github, for a better understanding. I will be very grateful for the help, because I could not understand the reason. My project -
https://github.com/OleksandrKupchuk/SimpleGame
//Enemy Archer
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyArcher : EnemyBase
{
[SerializeField] GameObject arrowPrefab;
[SerializeField] Transform startPositionArrow;
public override void Start()
{
base.Start();
ChangeStateEnemy(new IdleState());
}
public new void Update()
{
//ChangeState(currentState);
StateEnemy();
}
private void StateEnemy()
{
currentState.Execute();
}
public override void Attack()
{
timeAttack += Time.deltaTime;
enemyAnimator.SetFloat("animatorEnemyRun", 0);
if (timeAttack >= delayAttack)
{
CanAttack = true;
timeAttack = 0;
}
if (CanAttack)
{
enemyAnimator.SetTrigger("animatorEnemyAttack");
CanAttack = false;
}
}
public void FireArrow()
{
if (facingRight)
{
enemyAnimator.SetTrigger("animatorEnemyAttack");
GameObject arrow = Instantiate(arrowPrefab, startPositionArrow.position, Quaternion.identity);
arrow.GetComponent<EnemyArrowMove>().ArrowInitialization(Vector2.right);
}
else
{
GameObject arrow = Instantiate(arrowPrefab, startPositionArrow.position, Quaternion.Euler(new Vector3(0f, 180f, 0f)));
arrow.GetComponent<EnemyArrowMove>().ArrowInitialization(Vector2.left);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("PlayerSword"))
{
Debug.Log("Take");
TakeDamage();
EnemyTarget = collision.gameObject;
}
}
}
//////
//Enemy Base
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(BoxCollider2D))]
[RequireComponent(typeof(CircleCollider2D))]
public class EnemyBase : CharacterBase
{
public IStateEnemy currentState;
protected float timeAttack;
[SerializeField] protected float delayAttack;
public bool CanAttack { get; set; }
protected float dirPlayer;
public GameObject EnemyTarget { get; set; }
[SerializeField] protected float enemyRangeAttack;
[SerializeField] int experienceForTheEnemy;
public bool EnemyRangeAttack
{
get
{
if (EnemyTarget != null)
{
if (Vector2.Distance(EnemyTarget.transform.position, transform.position) <= enemyRangeAttack)
{
return true;
}
}
return false;
}
}
public bool EnemyOutsideEdge
{
get
{
if(transform.position.x >= rightEdge.position.x || transform.position.x <= leftEdge.position.x)
{
return true;
}
return false;
}
}
//edges for enemy
[SerializeField] protected Transform leftEdge;
[SerializeField] protected Transform rightEdge;
public bool EnemyDie
{
get
{
if(health <= 0)
{
return true;
}
return false;
}
}
[SerializeField] EdgeCollider2D enemySword;
[SerializeField] private Rigidbody2D enemyRigidbody;
public Rigidbody2D EnemyRigidbody { get => enemyRigidbody; set => enemyRigidbody = value; }
public Animator enemyAnimator;
[SerializeField] int takeDamage;
public bool EnemyAttack { get; set; }
public bool EnemyHit { get; set; }
protected float directionEnemy;
public override void Start()
{
base.Start();
enemyAnimator = GetComponent<Animator>();
}
public void Update()
{
}
public void TakeDamage()
{
if (!EnemyDie)
{
enemyAnimator.SetTrigger("animatorEnemyHit");
health -= takeDamage;
if (health <= 0)
{
enemyAnimator.SetTrigger("animatorEnemyDie");
Destroy(gameObject, 1.5f);
Player.PlayerInstance.AddIndicatorForPlayer(experienceForTheEnemy);
}
}
}
public void EnemySwordEnabled()
{
enemySword.enabled = true;
}
public void EnemySwordDisabled()
{
enemySword.enabled = false;
}
public void Flip()
{
//Debug.Log("Flip");
facingRight = !facingRight;
transform.localScale = new Vector2(transform.localScale.x * -1, transform.localScale.y);
//transform.Rotate(0f, 180f, 0f);
}
public void Walk()
{
if (!EnemyAttack && !EnemyDie && !EnemyHit)
{
if ((ChangeSide().x > 0 && transform.position.x < rightEdge.position.x) || (ChangeSide().x < 0 && transform.position.x > leftEdge.position.x))
{
enemyAnimator.SetFloat("animatorEnemyRun", 1);
transform.Translate(ChangeSide() * speed * Time.deltaTime);
}
}
}
public Vector2 ChangeSide()
{
if (facingRight)
{
return Vector2.right;
}
return Vector2.left;
}
public void ChangeDirection()
{
if (transform.position.x >= rightEdge.position.x || transform.position.x <= leftEdge.position.x)
{
Flip();
}
}
public void EnemyLookTarget()
{
if (!EnemyDie && EnemyTarget != null)
{
directionEnemy = EnemyTarget.transform.position.x - transform.position.x;
if (directionEnemy < 0 && facingRight || directionEnemy > 0 && !facingRight)
{
Flip();
}
}
}
public virtual void Attack()
{
timeAttack += Time.deltaTime;
//enemyAnimator.SetFloat("animatorEnemyRun", 0);
if (timeAttack >= delayAttack)
{
CanAttack = true;
timeAttack = 0;
}
if (CanAttack)
{
enemyAnimator.SetTrigger("animatorEnemyAttack");
CanAttack = false;
}
}
public void ChangeStateEnemy(IStateEnemy newState)
{
currentState = newState;
currentState.Enter(this);
}
}
I am getting #endregoin diretive expected in this class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MobileInput : MonoBehaviour {
private const float DEADZONE = 100.0f;
public static MobileInput Instance { set; get; }
private bool tap, swipeLeft, swipeLeft, swipeRight, swipeUp, swipeUp, swipeDown;
private Vector2 swipeDelta, startTouch;
public bool Tap { get { return tap; } }
public Vector2 SwipeDelta { get { return swipeDelta; } }
public Vector2 SwipeLeft { get { return swipeLeft; } }
public Vector2 SwipeRight { get { return swipeRight; } }
public Vector2 SwipeUp { get { return swipeUp; } }
public Vector2 SwipeDown { get { return swipeDown; } }
private void Awake()
{
Instance = this;
}
private void Update()
{
//reseting all the bool
tap = swipeLeft = swipeRight = swipeDown = swipeUp = false;
//lets check input
#region Standalone Inputs
if (Input.GetMouseButtonDown(0))
{
tap = true;
startTouch = Input.mousePosition;
}
else if (Input.GetMouseBottonUp(0))
{
startTouch = swipeDelta = Vector2.zero;
}
#region Mobile Inputs
if (Input.touches.Length != 0)
{
if (Input.touches[0].phase == TouchPhase.Began)
{
tap = true;
startTouch = Input.mousePosition;
}
else if (Input.touches[0].phase == TouchPhase.Ended || Input.touches[0].phase == TouchPhase.Canceled)
{
startTouch = swipeDelta = Vector2.zero;
}
}
#endregion
//Calculate
swipeDelta = Vector2.zero;
if (startTouch != Vector2.zero)
{
//let's check
if (Input.touches.Length != 0)
{
swipeDelta = Input.touches[0].position - startTouch;
}
//lets check standalone
else if (Input.GetMouseButton(0))
{
swipeDelta = (Vector2)Input.mousePosition - startTouch;
}
}
//Check dead zone
if (swipeDelta.magnitude > DEADZONE)
{
// this is a confirmed swip
float x = swipeDelta.x;
float y = swipeDelta.y;
if (Mathf.Abs(x) > Mathf.Abs(y))
{
//left
if (x < 0)
swipeLeft = true;
else
swipeRight = true;
}
else
{
//up or down
if (y < 0)
swipeDown = true;
else
swipeUp = true;
}
startTouch = swipeDelta = Vector2.zero;
}
}
}
Your #region Standalone Inputs is missing an #endregion further down in your code.
In my 2D Unity project my player does not always jump while pressing the "jump" button. He does no jump the second i land on the ground but after a second of "being grounded" he can jump again. What can this problem be?
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class player : MonoBehaviour {
private static player instance;
public static player Instance
{
get
{
if (instance == null)
{
instance = GameObject.FindObjectOfType<player>();
}
return instance;
}
}
private Animator myAnimator;
[SerializeField]
public static float movementSpeed;
private bool facingRight = true;
[SerializeField]
private Transform[] groundPoints;
[SerializeField]
private float groundRadius;
[SerializeField]
private LayerMask whatIsGround;
[SerializeField]
private bool airControl;
[SerializeField]
private float jumpForce;
public bool canMove;
public AudioClip jump001;
public AudioClip jump002;
private float direction;
private bool move;
private float btnHorizontal;
public Rigidbody2D MyRigidbody { get; set; }
public bool Attack { get; set; }
public bool Jump { get; set; }
public bool OnGround { get; set; }
// Use this for initialization
void Start() {
facingRight = true;
MyRigidbody = GetComponent<Rigidbody2D>();
myAnimator = GetComponent<Animator>();
}
void Update()
{
HandleInput();
}
// Update is called once per frame
void FixedUpdate()
{
OnGround = IsGrounded();
float horizontal = Input.GetAxis("Horizontal");
if (move)
{
this.btnHorizontal = Mathf.Lerp(btnHorizontal, direction, Time.deltaTime * 5);
HandleMovement(btnHorizontal);
Flip(direction);
}
else
{
HandleMovement(horizontal);
Flip(horizontal);
}
if (!canMove)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, GetComponent<Rigidbody2D>().velocity.y);
myAnimator.SetFloat("speed", 0);
return;
}
HandleLayers();
}
private void HandleMovement(float horizontal)
{
if (MyRigidbody.velocity.y < 0)
{
myAnimator.SetBool("land", true);
}
if (!Attack && (OnGround || airControl))
{
MyRigidbody.velocity = new Vector2(horizontal * movementSpeed, MyRigidbody.velocity.y);
}
if (Jump && MyRigidbody.velocity.y == 0)
{
SoundManager.instance.RandomizeSfx(jump001, jump002);
MyRigidbody.AddForce(new Vector2(0, jumpForce));
}
myAnimator.SetFloat("speed", Mathf.Abs(horizontal));
}
private void HandleInput()
{
if (canMove)
{
//Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.W) ||
if (Input.GetButtonDown("Jump"))
{
myAnimator.SetTrigger("jump");
}
if (Input.GetKeyDown(KeyCode.Z) || Input.GetButton("Fight") && OnGround && !Jump)
{
myAnimator.SetTrigger("attack");
}
}
}
private void Flip(float horizontal)
{
if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight && canMove)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
private bool IsGrounded()
{
{
}
if (MyRigidbody.velocity.y <= 0)
{
foreach (Transform point in groundPoints)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, whatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
return true;
}
}
}
}
return false;
}
private void HandleLayers()
{
if (!OnGround)
{
myAnimator.SetLayerWeight(1, 1);
}
else
{
myAnimator.SetLayerWeight(1, 0);
}
}
//TouchKnappar
public void BtnJump()
{
if (canMove)
{
myAnimator.SetTrigger("jump");
Jump = true;
}
}
public void BtnAttack()
{
myAnimator.SetTrigger("attack");
Attack = true;
}
public void BtnMove(float direction)
{
this.direction = direction;
this.move = true;
}
public void BtnStopMove()
{
this.direction = 0;
this.btnHorizontal = 0;
this.move = false;
}
public void BtnStopJump()
{
Jump = false;
}
}
I had the same problem and this fixed it for me.
This code identifies if the character is grounded in FixedUpdate()
Collider2D groundCol = Physics2D.OverlapBox(groundCheck.position, groundBoxRadius, 0f, whatIsGround);
this.grounded = (groundCol != null && !groundCol.isTrigger && this.rigbody2d.velocity.y > -0.01f && this.rigbody2d.velocity.y < 0.01f);
Some explanation:
groundCheck is an empty object at the feet of the character
In the condition I'm checking if the Overlay box collided with something a and if that something is not a trigger
Lastly the velocity speed can sometimes be not exactly a 0 so +-0.01f worked for me