I want to implement drag and drop on contents of scroll view.
The problem is when you try drag items in scroll view you can't scroll the view.
First, I've tried to implement drag and drop by IDragHandler, IBeginDragHandler, IEndDragHandle and IDropHandler interfaces. In a first sight, It worked pretty good but the problem was you can't scroll the ScrollRect.
I think the problem is because of overriding, When I use event triggers that the same as scroll rect like drag, the parent one don't work properly.
So after that, I've thought by myself and implement it by IPointerDown, IPointerUp interfaces and specific time for holding drag-gable UI in ScrollRect and if you don't hold it in specific time the scrolling work well.
But the problem is by enabling DragHandler script that I wrote before the OnDrag, OnBeginDrag and OnEndDrag functions doesn't work when time of holding ended.
First I want to know there is any way to call these functions ?
Second is there any way to implement drag and drop UI without using drag interfaces ?
DragHandler :
using System;
using UnityEngine;
using UnityEngine.EventSystems;
public class DragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
public static GameObject itemBeingDragged;
private Vector3 startPos;
private Transform startParent;
DragHandler dragHandler;
public void Awake()
{
dragHandler = GetComponent<DragHandler>();
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("Begin");
itemBeingDragged = gameObject;
startPos = transform.position;
startParent = transform.parent;
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log("Drag");
transform.position = Input.mousePosition;
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("End");
itemBeingDragged = null;
if (transform.parent == startParent)
{
dragHandler.enabled = false;
transform.SetParent(startParent);
transform.position = startPos;
}
}
}
ScrollRectController:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ScrollRectController : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public float holdTime;
public float maxVelocity;
private Transform scrollRectParent;
private DragHandler dragHandler;
private ScrollRect scrollRect;
private float timer;
private bool isHolding;
void Awake()
{
scrollRectParent = GameObject.FindGameObjectWithTag("rec_dlg").transform;
dragHandler = GetComponent<DragHandler>();
dragHandler.enabled = false;
}
// Use this for initialization
void Start()
{
timer = holdTime;
}
// Update is called once per frame
void Update()
{
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("Down");
scrollRect = scrollRectParent.GetComponent<ScrollRect>();
isHolding = true;
StartCoroutine(Holding());
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("Up");
isHolding = false;
}
IEnumerator Holding()
{
while (timer > 0)
{
//if (scrollRect.velocity.x >= maxVelocity)
//{
// isHolding = false;
//}
if (!isHolding)
{
timer = holdTime;
yield break;
}
timer -= Time.deltaTime;
Debug.Log(timer);
yield return null;
}
dragHandler.enabled = true;
//dragHandler.OnBeginDrag();
}
}
Slot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
DragHandler.itemBeingDragged.transform.SetParent(transform);
}
}
Answer:
I wrote some codes that handle drag and drop in scrollRect(scrollView) without using DragHandler interfaces.
DragHandler:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragHandler : MonoBehaviour, IPointerExitHandler
{
public static GameObject itemBeingDragged;
public static bool isCustomerDragged;
public Transform customerScrollRect;
public Transform dragParent;
public float holdTime;
public float maxScrollVelocityInDrag;
private Transform startParent;
private ScrollRect scrollRect;
private float timer;
private bool isHolding;
private bool canDrag;
private bool isPointerOverGameObject;
private CanvasGroup canvasGroup;
private Vector3 startPos;
public Transform StartParent
{
get { return startParent; }
}
public Vector3 StartPos
{
get { return startPos; }
}
void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
}
// Use this for initialization
void Start()
{
timer = holdTime;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
//Debug.Log("Mouse Button Down");
scrollRect = customerScrollRect.GetComponent<ScrollRect>();
isPointerOverGameObject = true;
isHolding = true;
StartCoroutine(Holding());
}
}
if (Input.GetMouseButtonUp(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
//Debug.Log("Mouse Button Up");
isHolding = false;
if (canDrag)
{
itemBeingDragged = null;
isCustomerDragged = false;
if (transform.parent == dragParent)
{
canvasGroup.blocksRaycasts = true;
transform.SetParent(startParent);
transform.localPosition = startPos;
}
canDrag = false;
timer = holdTime;
}
}
}
if (Input.GetMouseButton(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
if (canDrag)
{
//Debug.Log("Mouse Button");
transform.position = Input.mousePosition;
}
else
{
if (!isPointerOverGameObject)
{
isHolding = false;
}
}
}
}
}
public void OnPointerExit(PointerEventData eventData)
{
isPointerOverGameObject = false;
}
IEnumerator Holding()
{
while (timer > 0)
{
if (scrollRect.velocity.x >= maxScrollVelocityInDrag)
{
isHolding = false;
}
if (!isHolding)
{
timer = holdTime;
yield break;
}
timer -= Time.deltaTime;
//Debug.Log("Time : " + timer);
yield return null;
}
isCustomerDragged = true;
itemBeingDragged = gameObject;
startPos = transform.localPosition;
startParent = transform.parent;
canDrag = true;
canvasGroup.blocksRaycasts = false;
transform.SetParent(dragParent);
}
public void Reset()
{
isHolding = false;
canDrag = false;
isPointerOverGameObject = false;
}
}
Some explanation for this piece of code :
Your draggable UI element need intractable option, for me, I used button.
You need to attach this script to your draggable item.
Also you need add Canvas Group component.
customerScrollRect is a ScrollRect parent of your items.
dragParent can be a empty GameObject which is used because of mask of view port.
Slot:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
bool isEntered;
public void OnPointerEnter(PointerEventData eventData)
{
isEntered = true;
}
public void OnPointerExit(PointerEventData eventData)
{
isEntered = false;
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
if (isEntered)
{
if (DragHandler.itemBeingDragged)
{
GameObject draggedItem = DragHandler.itemBeingDragged;
DragHandler dragHandler = draggedItem.GetComponent<DragHandler>();
Vector3 childPos = draggedItem.transform.position;
//Debug.Log("On Pointer Enter");
draggedItem.transform.SetParent(dragHandler.StartParent);
draggedItem.transform.localPosition = dragHandler.StartPos;
draggedItem.transform.parent.SetParent(transform);
draggedItem.transform.parent.position = childPos;
isEntered = false;
}
}
}
}
}
Some explanation for this script:
1.Attach the script to the dropped item.
The easiest solution for this problem is actually to manually call the ScrollRect's events IF the user hasn't pressed long enough using ExecuteEvents.Execute. This solution has the least amount of additional code.
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragAndDropHandler : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IDragHandler, IBeginDragHandler, IEndDragHandler
{
// Don't forget to set this to TRUE or expose it to the Inspector else it will always be false and the script will not work
public bool Draggable { get; set; }
private bool draggingSlot;
[SerializeField] private ScrollRect scrollRect;
public void OnPointerDown(PointerEventData eventData)
{
if (!Draggable)
{
return;
}
StartCoroutine(StartTimer());
}
public void OnPointerExit(PointerEventData eventData)
{
StopAllCoroutines();
}
public void OnPointerUp(PointerEventData eventData)
{
StopAllCoroutines();
}
private IEnumerator StartTimer()
{
yield return new WaitForSeconds(0.5f);
draggingSlot = true;
}
public void OnBeginDrag(PointerEventData eventData)
{
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.beginDragHandler);
}
public void OnDrag(PointerEventData eventData)
{
if (draggingSlot)
{
//DO YOUR DRAGGING HERE
} else
{
//OR DO THE SCROLLRECT'S
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.dragHandler);
}
}
public void OnEndDrag(PointerEventData eventData)
{
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.endDragHandler);
if (draggingSlot)
{
//END YOUR DRAGGING HERE
draggingSlot = false;
}
}
}
I've managed to find an easier solution.
Maybe it must be customized by special needs, but if you put this script on your items and make the setup, it should work.
It's not easy from a prefab, but I let a controller make this.
I find all UIElementDragger inside a specified GameObject and add the needed GO instances programmatically.
But can use this code out of the box if you don't use prefabs.
using UnityEngine;
using UnityEngine.EventSystems;
public class UIElementDragger : MonoBehaviour, IPointerUpHandler, IPointerDownHandler
{
/// <summary>
/// Offset in pixels horizontally (positive to right, negative to left)
/// </summary>
[Range(40, 100)]
public float offsetX = 40;
/// <summary>
/// Offset in pixels vertically (positive to right, negative to left)
/// </summary>
[Range(40, 100)]
public float offsetY = 40;
/// <summary>
/// The Panel where the item will set as Child to during drag
/// </summary>
public Transform parentRect;
/// <summary>
/// The GameObject where the item is at start
/// </summary>
public Transform homeWrapper;
/// <summary>
/// The Object where the mouse must be when pointer is up, to put it in this panel
/// </summary>
public Transform targetRect;
/// <summary>
/// The GameObject where the item should live after dropping
/// </summary>
public Transform targetWrapper;
private int siblingIndex;
private bool dragging;
private void Start()
{
siblingIndex = transform.GetSiblingIndex();
}
private void Update()
{
if (dragging)
{
transform.position = new Vector2(Input.mousePosition.x + offsetX, Input.mousePosition.y + offsetY);
}
}
public void OnPointerDown(PointerEventData eventData)
{
transform.parent = parentRect;
dragging = true;
}
public void OnPointerUp(PointerEventData eventData)
{
if (eventData.pointerCurrentRaycast.gameObject.transform.IsChildOf(targetRect))
{
transform.parent = targetWrapper;
}
else
{
transform.parent = homeWrapper;
transform.SetSiblingIndex(siblingIndex);
}
dragging = false;
}
}
Here my solution, thank all.
I have to use a fake instance to keep the object over even if you move it down the list. I post a vertical and a horizontal solution. I hope it help
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragController : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
private RectTransform currentTransform;
private GameObject instancePrefab;
private GameObject mainContent;
private Vector3 initialePosition;
private int totalChild;
void Awake()
{
currentTransform = this.GetComponent<RectTransform>();
mainContent = currentTransform.parent.gameObject;
}
public void OnPointerDown(PointerEventData eventData)
{
initialePosition = currentTransform.position;
totalChild = mainContent.transform.childCount;
if (instancePrefab == null)
{
instancePrefab = Instantiate(this.gameObject, mainContent.transform.parent.transform);
instancePrefab.GetComponent<Image>().enabled = false;
}
}
public void OnDrag(PointerEventData eventData)
{
currentTransform.position = new Vector3(eventData.position.x, currentTransform.position.y, currentTransform.position.z);
if (instancePrefab != null)
{
instancePrefab.GetComponent<Image>().enabled = true;
currentTransform.GetComponent<Image>().enabled = false;
instancePrefab.transform.position = currentTransform.position;
}
for (int i = 0; i < totalChild; i++)
{
if (i != currentTransform.GetSiblingIndex())
{
Transform otherTransform = mainContent.transform.GetChild(i);
int distance = (int)Vector3.Distance(currentTransform.position, otherTransform.position);
if (distance <= 20)
{
Vector3 otherTransformOldPosition = otherTransform.position;
// Vertical
/*otherTransform.position = new Vector3(otherTransform.position.x, initialePosition.y,
otherTransform.position.z);
currentTransform.position = new Vector3(currentTransform.position.x, otherTransformOldPosition.y,
currentTransform.position.z);*/
// Horizontal
otherTransform.position = new Vector3(initialePosition.x, otherTransform.position.y,
otherTransform.position.z);
currentTransform.position = new Vector3(otherTransformOldPosition.x, currentTransform.position.y,
currentTransform.position.z);
currentTransform.SetSiblingIndex(otherTransform.GetSiblingIndex());
initialePosition = currentTransform.position;
}
}
}
}
public void OnPointerUp(PointerEventData eventData)
{
currentTransform.position = initialePosition;
instancePrefab.GetComponent<Image>().enabled = false;
currentTransform.GetComponent<Image>().enabled = true;
Destroy(instancePrefab);
instancePrefab = null;
}
}
You can just manually call ScrollRect events, because they are public. Smthing like this:
public void OnDrag(PointerEventData eventData)
{
_scrollRect.OnDrag(eventData);
}
Related
Here's my code for player movement. I have set up walking around and I am now Trying to change the sprite animation when walking in different directions. Everything was working fine but when I tried to change the sprite for walking up the sprite gets stuck in a loop and doesn't idle.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public Animator Animator;
[SerializeField] private float speed = 1f;
private Rigidbody2D body;
private Vector2 axisMovement;
// Start is called before the first frame update
void Start()
{
body = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
axisMovement.x = Input.GetAxisRaw("Horizontal");
axisMovement.y = Input.GetAxisRaw("Vertical");
Animator.SetFloat("Speed", Mathf.Abs(axisMovement.x));
if (Input.GetKey(KeyCode.W))
{
Animator.SetBool("isforward", true);
}
if (Input.GetKey(KeyCode.A))
{
Animator.SetBool("isforward", false);
}
if (Input.GetKey(KeyCode.S))
{
Animator.SetBool("isforward", false);
}
if (Input.GetKey(KeyCode.D))
{
Animator.SetBool("isforward", false);
}
}
private void FixedUpdate()
{
Move();
}
private void Move()
{
body.velocity = axisMovement.normalized * speed;
CheckForFlipping();
}
private void CheckForFlipping()
{
bool movingLeft = axisMovement.x < 0;
bool movingRight = axisMovement.x > 0;
if (movingLeft)
{
transform.localScale = new Vector3(-1f, transform.localScale.y);
}
if (movingRight)
{
transform.localScale = new Vector3(1f, transform.localScale.y);
}
}
}
I also tried doing Animator.SetFloat("Speed", Mathf.Abs(axisMovement.x)); but switch it with axisMovement.y but that stops all the animations moving left and right stop working. 😢
I've figured it out. here's the updated code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public Animator Animator;
[SerializeField] private float speed = 1f;
private Rigidbody2D body;
private Vector2 axisMovement;
// Start is called before the first frame update
void Start()
{
body = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
axisMovement.x = Input.GetAxisRaw("Horizontal");
axisMovement.y = Input.GetAxisRaw("Vertical");
Animator.SetFloat("Speed", Mathf.Abs(axisMovement.x + axisMovement.y));
if (Input.GetKey(KeyCode.W))
{
Animator.SetBool("isforward", true);
} else {
Animator.SetBool("isforward", false);
}
// if (Input.GetKey(KeyCode.A))
// {
// Animator.SetBool("isforward", false);
// }
// if (Input.GetKey(KeyCode.S))
// {
// Animator.SetBool("isforward", false);
// }
// if (Input.GetKey(KeyCode.D))
// {
// Animator.SetBool("isforward", false);
// }
}
private void FixedUpdate()
{
Move();
}
private void Move()
{
body.velocity = axisMovement.normalized * speed;
CheckForFlipping();
}
private void CheckForFlipping()
{
bool movingLeft = axisMovement.x < 0;
bool movingRight = axisMovement.x > 0;
if (movingLeft)
{
transform.localScale = new Vector3(-1f, transform.localScale.y);
}
if (movingRight)
{
transform.localScale = new Vector3(1f, transform.localScale.y);
}
}
}
In Unity i am using IBeginDragHandler, IDragHandler, IEndDragHandler to drag and drop object. it's working fine. My need is to reset the position of the draggable object to the starting position if it doesn't touch another object that contains IDropHandler. below is my code
Drag script:-
using UnityEngine.EventSystems;
public class Compiler_Drag : MonoBehaviour, IPointerDownHandler, IBeginDragHandler, IEndDragHandler, IDragHandler
{
[SerializeField] private Canvas canvas;
private RectTransform rectTransform;
private CanvasGroup canvasGroup;
Vector3 myPosition;
// Start is called before the first frame update
void Start()
{
myPosition = this.gameObject.transform.position;
}
private void Awake()
{
rectTransform =GetComponent<RectTransform>();
canvasGroup = GetComponent<CanvasGroup>();
}
// Update is called once per frame
void Update()
{
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("OnBeginDrag");
canvasGroup.alpha = .6f;
canvasGroup.blocksRaycasts = false;
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log("OnDrag");
rectTransform.anchoredPosition +=eventData.delta/ canvas.scaleFactor;
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("OnEndDrag");
canvasGroup.alpha = 1f;
canvasGroup.blocksRaycasts = true;
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("OnPointerDown");
}
}
> Drop object script:-
using UnityEngine.EventSystems;
public class Compiler_Drop_Handler : MonoBehaviour, IDropHandler
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void OnDrop(PointerEventData eventData)
{
Debug.Log("OnDrop");
if(eventData.pointerDrag !=null)
{
eventData.pointerDrag.GetComponent<RectTransform>().anchoredPosition = GetComponent<RectTransform>().anchoredPosition;
}
}
}
what I need is that I should be only able to drop the dragging object, to the object that contains/is attached to the second script.
I use a long press button, which works very well, on MouseDown and if I don't move the mouse, at the end of my delay, I have my action.
If I move the mouse (still pressing down and still on the button) it resets my button's delay, and I don't understand why.
if anyone has an idea, it would help me a lot.
Thx
Here's my code :
private bool _PointerDown;
public float DelaiReponse;
private float _PointerDownTimer;
private bool _IsValidate = false;
private float _Delai;
public void OnPointerDown(PointerEventData eventData)
{
_PointerDown = true;
}
public void OnPointerUp(PointerEventData eventData)
{
_PointerDown = false;
_PointerDownTimer = 0;
}
void Start()
{
_Delai = DelaiReponse;
}
private void Update()
{
if (_PointerDown) // Timer Button Validation Hold
{
_PointerDownTimer += Time.deltaTime;
if (_PointerDownTimer >= _Delai)
{
_IsValidate = true;
}
}
}enter code here
Using Input.GetMouseDown(0) and Input.GetMouseButtonUp(0) could fix the problem:
private void Update()
{
if (Input.GetMouseDown(0))
{
_PointerDown = true;
}
if (Input.GetMouseUp(0))
{
_PointerDown = false;
_PointerDownTimer = 0;
}
if (_PointerDown) // Timer Button Validation Hold
{
:
:
}
:
:
}
I finally found
OnMouseDown even worked outside my button, and I preferred the OnPointerDown method.
I added IDragHandler to my class, and create a bool _PointerDrag
private bool _PointerDown;
private bool _PointerDrag;
public float DelaiReponse;
private float _PointerDownTimer;
private bool _IsValidate = false;
private float _Delai;
public class LongClickButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
public void OnPointerDown(PointerEventData eventData)
{
_PointerDown = true;
}
public void OnPointerUp(PointerEventData eventData)
{
_PointerDown = false;
_PointerDownTimer = 0;
}
public void OnDrag(PointerEventData eventData)
{
_PointerDrag = true;
}
void Start()
{
_Delai = DelaiReponse;
}
private void Update()
{
if (_PointerDown || _PointerDrag) // Timer Button Validation Hold
{
_PointerDownTimer += Time.deltaTime;
if (_PointerDownTimer >= _Delai)
{
_IsValidate = true;
}
}
}
}
and it works.
Thanks for your time, Frenchy
Hello i am making a 2d game and I have a player that needs to collide with 2 objects. First object gives him more health and has the tag " power up " and works but the second that has the tag " Hurt" it's not working . What I should change in the script ? Here it's the script for " PowerUp" and here it's the script of the player.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
public class PowerUpDetector : MonoBehaviourPun
{
// reference this via the Inspector
[SerializeField] private Character healthbar;
[SerializeField] private Character health;
private void Awake()
{
if (!healthbar) healthbar = GetComponent<Character>();
}
private void OnTriggerEnter2D(Collider2D other)
{
// or whatever tag your powerups have
if (!other.CompareTag("PowerUp"))
{
Debug.LogWarning($"Registered a collision but with wrong tag: {other.tag}", this);
return;
}
var powerup = other.GetComponent<PowerUp>();
if (!powerup)
{
Debug.LogError($"Object {other.name} is tagged PowerUp but has no PowerUp component attached", this);
return;
}
Debug.Log("Found powerup, pick it up!", this);
powerup.Pickup(healthbar);
if (!other.CompareTag("Hurt"))
{
if (photonView.IsMine)
{
photonView.RPC("Damage", RpcTarget.All);
}
}
}
[PunRPC]
void Damage()
{
health -= 20;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using Photon.Pun;
using Photon.Realtime;
using Photon;
using UnityEngine.UI;
public class Character : MonoBehaviourPun,IPunObservable
{
Rigidbody2D rb;
float dirX;
[SerializeField]
float moveSpeed = 5f, jumpForce = 400f, bulletSpeed = 500f;
[SerializeField] private float health = 100;
[SerializeField] private Slider slider;
[SerializeField] private Gradient gradient;
[SerializeField] private Image fill;
Vector3 localScale;
public Transform barrel;
public Rigidbody2D bullet;
// Use this for initialization
void Start()
{
localScale = transform.localScale;
rb = GetComponent<Rigidbody2D>();
if (photonView.IsMine)
{
}
else
{
}
}
public float Health
{
get { return health; }
set
{
health = value;
slider.value = health;
fill.color = gradient.Evaluate(slider.normalizedValue);
}
}
private void OnCollisionEntered2D(Collision2D col)
{
if( col.gameObject.CompareTag ("Hurt"))
{
if (photonView.IsMine)
{
photonView.RPC("Damage", RpcTarget.All);
}
}
}
[PunRPC]
void Damage()
{
health -= 20;
}
// Update is called once per frame
void Update()
{
if (photonView.IsMine)
{
dirX = CrossPlatformInputManager.GetAxis("Horizontal");
if (dirX != 0)
{
barrel.up = Vector3.right * Mathf.Sign(dirX);
}
if (CrossPlatformInputManager.GetButtonDown("Jump"))
Jump();
if (CrossPlatformInputManager.GetButtonDown("Fire1"))
Fire();
}
else
{
}
}
void FixedUpdate()
{
if (photonView.IsMine)
{
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
}
}
void Jump()
{
if (photonView.IsMine)
{
if (rb.velocity.y == 0)
rb.AddForce(Vector2.up * jumpForce);
}
}
void Fire()
{
if (photonView.IsMine)
{
var firedBullet = Instantiate(bullet, barrel.position, barrel.rotation);
firedBullet.AddForce(barrel.up * bulletSpeed);
}
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
stream.SendNext(health);
}else if (stream.IsReading)
{
health = (float)stream.ReceiveNext();
}
}
public void SetMaxHealth(int value)
{
if (photonView.IsMine)
{
slider.maxValue = value;
// The property handles the rest anyway
Health = value;
}
}
}
I have an error in the "Power Up Detector" at health -= 20 (operator -= can't be applied ) to operands type "Character" and " int" .
I think you will have to use health.Health. Your variable health refers to the Character class. As you want to change the health, you would have to use the property of that class instead. So try:
health.Health -= 20;
I would recommend to rename the health variable to something else related to the Character class though.
I am doing a 2d game and my player collides with 2 different objects. One it's for gaining health and the other one it's for damage it. So I have two tags : PowerUp( and this one works) and Hurt( I get in the console a message like this and I don't understand why : Registered a collision but with wrong tag: Hurt ) This is the script that I used, what I should change at it for this action of DAMAGE to take place ( and I tried on collision entered too)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
public class PowerUpDetector : MonoBehaviourPun
{
// reference this via the Inspector
[SerializeField] private Character healthbar;
[SerializeField] private Character health;
private void Awake()
{
if (!healthbar) healthbar = GetComponent<Character>();
}
private void OnTriggerEnter2D(Collider2D other)
{
// or whatever tag your powerups have
if (!other.CompareTag("PowerUp"))
{
Debug.LogWarning($"Registered a collision but with wrong tag: {other.tag}", this);
return;
}
var powerup = other.GetComponent<PowerUp>();
if (!powerup)
{
Debug.LogError($"Object {other.name} is tagged PowerUp but has no PowerUp component attached", this);
return;
}
Debug.Log("Found powerup, pick it up!", this);
powerup.Pickup(healthbar);
if (!other.CompareTag("Hurt"))
{
if (photonView.IsMine)
{
photonView.RPC("Damage", RpcTarget.All);
}
}
}
[PunRPC]
void Damage()
{
health.Health -= 20;
}
}
Option 2 same error enter image description here
private void OnCollisionEntered2D(Collision2D col)
{
if( col.gameObject.CompareTag ("Hurt"))
{
if (photonView.IsMine)
{
photonView.RPC("Damage", RpcTarget.All);
}
}
}
[PunRPC]
void Damage()
{
health -= 20;
}
My players script with the healthbar
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using Photon.Pun;
using Photon.Realtime;
using Photon;
using UnityEngine.UI;
public class Character : MonoBehaviourPun,IPunObservable
{
Rigidbody2D rb;
float dirX;
[SerializeField]
float moveSpeed = 5f, jumpForce = 400f, bulletSpeed = 500f;
[SerializeField] private float health = 100;
[SerializeField] private Slider slider;
[SerializeField] private Gradient gradient;
[SerializeField] private Image fill;
Vector3 localScale;
public Transform barrel;
public Rigidbody2D bullet;
// Use this for initialization
void Start()
{
localScale = transform.localScale;
rb = GetComponent<Rigidbody2D>();
if (photonView.IsMine)
{
}
else
{
}
}
public float Health
{
get { return health; }
set
{
health = value;
slider.value = health;
fill.color = gradient.Evaluate(slider.normalizedValue);
}
}
/* private void OnCollisionEntered2D(Collision2D col)
{
if( col.gameObject.CompareTag ("Hurt"))
{
if (photonView.IsMine)
{
photonView.RPC("Damage", RpcTarget.All);
}
}
}
[PunRPC]
void Damage()
{
health -= 20;
}*/
// Update is called once per frame
void Update()
{
if (photonView.IsMine)
{
dirX = CrossPlatformInputManager.GetAxis("Horizontal");
if (dirX != 0)
{
barrel.up = Vector3.right * Mathf.Sign(dirX);
}
if (CrossPlatformInputManager.GetButtonDown("Jump"))
Jump();
if (CrossPlatformInputManager.GetButtonDown("Fire1"))
Fire();
}
else
{
}
}
void FixedUpdate()
{
if (photonView.IsMine)
{
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
}
}
void Jump()
{
if (photonView.IsMine)
{
if (rb.velocity.y == 0)
rb.AddForce(Vector2.up * jumpForce);
}
}
void Fire()
{
if (photonView.IsMine)
{
var firedBullet = Instantiate(bullet, barrel.position, barrel.rotation);
firedBullet.AddForce(barrel.up * bulletSpeed);
}
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
stream.SendNext(health);
}else if (stream.IsReading)
{
health = (float)stream.ReceiveNext();
}
}
public void SetMaxHealth(int value)
{
if (photonView.IsMine)
{
slider.maxValue = value;
// The property handles the rest anyway
Health = value;
}
}
}
// or whatever tag your powerups have
if (!other.CompareTag("PowerUp")) {
Debug.LogWarning($"Registered a collision but with wrong tag: {other.tag}", this);
return;
}
This statement will log an error whenever you collide with something that is not tagged "PowerUp" (I.E. if it's tagged "Hurt").
The return statement then boots you out of the function and that means it does not get to the part where it deals damage.
You may want to change this to include && !other.CompareTag("Hurt") to the if statement. A better approach may be to remove this if statement entirely. You should be checking tags like this :
if(has this tag) {
Do this
}
if(has that tag) {
Do that
}
Instead of seeing if it doesn't have the tag and returning.
Something like this, see below. But please read the comment related to the "Hurt" tag. Wrote it in this text editor, but I think syntax is correct.
private void OnTriggerEnter2D(Collider2D other)
{
switch (other.tag)
{
case "PowerUp":
var powerup = other.GetComponent<PowerUp>();
powerup.Pickup(healthbar);
break;
// You use '!other.CompareTag("Hurt")'. So you check if the tag is NOT hurt? Is that correct? I would assume you would check to see if it IS 'Hurt'?
case "Hurt":
if (photonView.IsMine)
{
photonView.RPC("Damage", RpcTarget.All);
}
break;
default:
Debug.Log("did not recognize this tag:" + other.tag);
break;
}
}