I am making a game where an object follows my finger. But I do not want the object to jump to my finger if I tap anywhere on the screen. I am using a raycast to do this. It works perfectly except if I move my finger too fast the object freezes.
My theory is that because of it being in Update() that once I move my finger off the object it detects that I can no longer drag it. I have no idea how to fix this.
public GameObject Bigball;
public GameObject Smallball;
// Update is called once per frame
private void Update ()
{
// lets ball follow finger
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(0).phase == TouchPhase.Stationary)
{
var touch = Input.GetTouch(0);
Vector3 fingerPos = touch.position;
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(fingerPos);
if (Physics.Raycast(ray, out hit) && (hit.collider.tag == "ball"))
{
Smallball.SetActive(false);
Bigball.SetActive(true);
Vector3 pos = new Vector3((Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position)).x,
(Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position)).y, 0);
Bigball.transform.position = pos;
}
}
else
{
Bigball.SetActive(false);
Smallball.SetActive(true);
Smallball.transform.position = new Vector3(Bigball.transform.position.x, Bigball.transform.position.y, 0);
}
}
It might make more sense to only Raycast once when the finger touches the screen. If that Raycast finds an object to drag, simply store that object and move it to follow the finger every Update(), as long as the finger continues to touch the screen.
Once the finger is released, just forget about the object until the next touch finds a new object to drag.
An alternative would be to use no Raycasts at all but build on IBeginDragHandler, IDragHandler and IEndDragHandler, as Bijan already mentioned.
Related
I have a problem in my mobile game , that I'm currently developing in Unity.
In my script I detect touches via a RaycastHit2D and then destroy the touched object (In my case a raindrop).
The only problem is that when I run the game and touch the raindrop, it doesn't always work.
It only works , when I slightly touch below it.
The Circle Collider 2D I'm using for my raindrop prefab is alright , so I don't think it causes the trouble.
My Script:
void Update()
{
GetInput();
}
private void GetInput()
{
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
Vector2 WorldPoint = Camera.main.ScreenToWorldPoint(touch.position);
RaycastHit2D hit = Physics2D.Raycast(WorldPoint, Vector2.zero);
GameObject collider = hit.collider.gameObject;
if (collider.tag == "Tropfen")
{
Destroy(collider);
}
}
}
}
It's like a mario game. The player is jumping around and has to collect some items.
The problem is that my ray isn't colliding with the item box colliders.
I need the ray to know, so i can destroy the right item that the player has collided.
void OnCollisionEnter2D(Collision2D colisor)
{
if((colisor.gameObject.name == "floor" || colisor.gameObject.name == "floor2" || colisor.gameObject.name == "floor3"))
{
anim.SetBool("jump", false);
anim.SetFloat("speed", 0);
}
if (colisor.gameObject.name == "space(Clone)")
{
RaycastHit hit;
Ray ray = new Ray(player.position, transform.right);
Debug.Log("hit1");
if (Physics.Raycast(ray, out hit))
{
BoxCollider bc2d = hit.collider as BoxCollider;
Debug.Log("hit2");
if (bc2d != null)
{
Destroy(bc2d.gameObject);
}
}
}
}
You're mixing 3d and 2d physics; Physics will only look for 3d objects, so you should be using Physics2D instead. This raycast may still fail if the cast starts inside the target, because the surface normals point in the wrong direction.
Also note that since you already have the Collision2D, you can just grab the otherCollider and shouldn't need to raycast in the first place.
Physics.Raycast isn't working with 2D objects. Instead you need to use Physics2D.Raycast or Graphic Raycaster.
Raycast2D - https://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html
Graphic Raycaster - https://docs.unity3d.com/eng/current/Manual/script-GraphicRaycaster.html
I'm making a mobile game based on android. When I was making a transfer code for my player object, I wrote code like this.
void Update() {
if(Input.touchcount == 1)
{
Touch touch = Input.GetTouch(0);
if(touch.phase == TouchPhase.Began)
{
//Move
}
else if(touch.phase == TouchPhase.Stationary)
{
//Move
}
}
}
It's moving at right direction and speed that I wanted. But when I touch quicker, these codes are don't working smoothly. I mean the player object is not moving smoothly.
Is there any solution for this problem?
P.S. I cant use AddForce in rigidbody
Goal: Detect when the cursor has entered a defined radius of the player.
Hello, I am in the process of trying to replicate the combat system from a game called CrossCode. The idea is that when the cursor is within a certain radius of the player, I will be able to switch to melee combat, and back to ranged once the cursor leaves this radius.
I have implemented one way I thought it could be done, however it feels slow or unreliable and I just wanted to know if there are any other methods I could possibly look into to achieve a smoother result.
Here is what I've done
attached to the player
void Update()
{
attackStyleSwitchRadius = colRef.radius;
playerCenter = colRef.transform.position;
if(Physics2D.OverlapCircle(playerCenter, attackStyleSwitchRadius, cursor))
{
meleeMode = true;
rangeMode = false;
}
else
{
meleeMode = false;
rangeMode = true;
}
}
And on a small 2D object I have this script so that it follows the cursor position.
void Update()
{
pos = Input.mousePosition;
gameObject.transform.position = Camera.main.ScreenToWorldPoint(pos);
}
when the small object enters the overlap circle it changes the bools around.
You can remove the collision detection overhead by doing something like this instead;
void Update ()
{
attackStyleSwitchRadius = colRef.radius;
playerCenter = colRef.transform.position;
var mouse = Input.mousePosition;
mouse.z = Vector3.Distance(Camera.main.transform.position, playerCenter);
var range = Vector2.Distance(Camera.main.ScreenToWorldPoint(mouse), playerCenter);
var inside = range < attackStyleSwitchRadius;
meleeMode = inside;
rangeMode = !inside;
}
Cursor
Make an object, name it cursor.
Add a small collider to the cursor object.
Add a script to the cursor object so its always at the mouses location.
Melee range zone
Add a GameObject as child of the player, name it MeleeRangeZone.
Add a collider to it, set it to be a Trigger. The size of this collider will be the players melee range,
Add a rigidbody to it so that collisions can be detected, but set the rigidbody to not rotate or change its position.
Add a script to the object and use the OnTriggerEnter and OnTriggerExit methods to detect whether or not the cursor has entered your melee zone.
You can now use the OnTriggerEnter and OnTriggerExit methods to switch between the players attack modes, meaning that when the cursor enters it changes to melee and when it exit it changes to ranged.
You can fire the ray to detect the location the cursor should have like this:
public LayerMask RaycastCollidableLayers;
public RaycastHit Hit;
public float CheckDistance = 200f;
public Transform Cursor;
void PerformRaycast(){
//Set up ray
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Fire ray
Physics.Raycast(ray, out Hit, CheckDistance + 0.1f, RaycastCollidableLayers);
if (Hit.collider == null)
{
//Debug.Log("Raycast hit nothing");
return;
}
else //Ray hit something
{
//Move cursor to Hit.point;
Cursor.position = Hit.point;
}
}
I am trying to get touch controls to work for iOS, the result i want is drag left to move left, drag right to move right and tap to jump. At the moment the functions do work but what happens is if i don't want to jump and just want to drag the character will jump first as soon as touch the screen. Is there a way i can get the result i want i have added my code below. I want the first touch to just register for the drag and when the player lifts and then taps or maybe double taps the character will jump. Thanks in advance.
//Mobile Touch Drag Controls
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across X plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
}
}
////Mobile Touch To Jump
{
if (Input.GetMouseButtonDown(0))
{
transform.Translate(Vector3.up * jumpForce * Time.deltaTime, Space.World);
}
When the button goes down, there is no way to know what the player wants to do. You should jump when the finger goes up instead.
An easy solution is to use a boolean to know if the player has moved before the finger was released. If yes, you don't want to jump
public class PlayerController // Or whatever name your class has
{
private bool _moved;
private void Update()
{
//Mobile Touch Drag Controls
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across X plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
_moved = true; // Remember that the player moved
}
////Mobile Touch To Jump
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
{
if(!_moved) // Only jump if we didnt move
{
transform.Translate(Vector3.up * jumpForce * Time.deltaTime, Space.World);
}
_moved = false;
}
}
}
I assume this code goes in your update function. This will work fine but here is a more elegant solution in case you want to try it:
Your class can implement IDragHandler and IEndDragHandler (among others, look for all possibilities that extend IEventSystemHandler)
When you implement these, you can override functions that get called when the user touches the screen, such as public void OnDrag(PointerEventData eventData)
With this you don't have to use the Update function anymore