I found this script: https://unity3d.college/2018/01/30/unity3d-ugui-hold-click-buttons/
I am using Vuforia btw.
I was wondering how to link it to my movement script.
using UnityEngine;
public class MyDragBehaviour : MonoBehaviour
{
void Update()
{
if (Input.touchCount == 1 && Input.GetTouch(0).phase ==
TouchPhase.Moved)
{
// create ray from the camera and passing through the touch
position:
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
// create a logical plane at this object's position
// and perpendicular to world Y:
Plane plane = new Plane(Vector3.up, transform.position);
float distance = 0; // this will return the distance from the camera
if (plane.Raycast(ray, out distance))
{ // if plane hit...
Vector3 pos = ray.GetPoint(distance); // get the point
transform.position = pos;
// pos has the position in the plane you've touched
}
}
}
}
The current movement script will move my object instantly to where the tap happened on screen. I would like to have it so that you have to long press the object before moving it to avoid having the object jump around on screen.
EDIT
using UnityEngine;
using UnityEngine.EventSystems;
public class MyDragBehaviour : MonoBehaviour
{
float pointerDownTimer = 0;
const float requiredHoldTime = 0.5f; //has to hold for 0.5 seconds
void Update()
{
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
pointerDownTimer += Time.deltaTime;
if (pointerDownTimer >= requiredHoldTime)
{
pointerDownTimer = 0;
if (!EventSystem.current.IsPointerOverGameObject())
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// create ray from the camera and passing through the touch position:
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
// create a logical plane at this object's position
// and perpendicular to world Y:
Plane plane = new Plane(Vector3.up, transform.position);
float distance = 0; // this will return the distance from the camera
if (plane.Raycast(ray, out distance))
{ // if plane hit...
Vector3 pos = ray.GetPoint(distance); // get the point
transform.position = pos; // pos has the position in the plane you've touched
} //whatever happens when you click
}
}
else
{
pointerDownTimer = 0;
}
}
}
}
You just need to implement a simple timer, that increases when you press and resets when you release:
float pointerDownTimer = 0;
const float requiredHoldTime = 0.5f //has to hold for 0.5 seconds
void Update(){
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
pointerDownTimer += Time.deltaTime;
if (pointerDownTimer >= requiredHoldTime){
...... //whatever happens when you click
}
} else{
pointerDownTimer = 0;
}
}
Related
I am trying to make Line Renderer's first point move along with Camera. When I do it with a Camera that is still, it works fine. But when camera changes position and in that position if I try to create new Line with Line Renderer it goes weird. I tried updating the position of first point by multiplying camera.tranform.position with dragBeginPos but it doesn't seem to help as it makes it even bad.
public class DragController : MonoBehaviour
{
[SerializeField] private float maxDrag = 3f; // Maximum drag distance
[SerializeField] private LineRenderer lr;
private Vector3 dragBeganPos; // Position of the mouse or touch when the drag began
private Vector3 dragEndPosPublic;
private Touch touch;
private PlayerBallMovement playerBallMovement;
[HideInInspector] public Vector3 dragDirection; // Pure drag direction without max drag distance
[HideInInspector] public Vector3 dragDirectionClamped; // Clamped drag direction with max drag distance
private enum ControlsType
{
Touch,
Mouse
}
private enum DirectionType
{
Normal,
Clamped
}
[SerializeField] private ControlsType controlsType = ControlsType.Mouse; // Default controls type are mouse
[SerializeField] private DirectionType directionType = DirectionType.Clamped; // Default direction type is clamped
void Update()
{
if (controlsType == ControlsType.Mouse)
{
DragWithMouse();
}
else if (controlsType == ControlsType.Touch)
{
DragWithTouch();
}
//UpdateLineRendererPointsPositions();
}
void DragWithMouse()
{
// Mouse button inputs
if (Input.GetMouseButtonDown(0)) DragBegan();
if (Input.GetMouseButton(0)) DragMoved();
if (Input.GetMouseButtonUp(0)) DragEnded();
}
void DragWithTouch()
{
// Touch inputs
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began) DragBegan();
if (touch.phase == TouchPhase.Moved) DragMoved();
if (touch.phase == TouchPhase.Ended) DragEnded();
}
}
// Drag begins defining start position of Line Rederer
void DragBegan()
{
dragBeganPos = Camera.main.ScreenToWorldPoint(
controlsType == ControlsType.Mouse ? Input.mousePosition : (Vector3)touch.position
);
dragBeganPos.z = 0f;
lr.positionCount = 1;
lr.SetPosition(0, dragBeganPos);
}
// Drag moved calculates the end point of the Line Rederer until mouse or touch is released
void DragMoved()
{
Vector3 dragMovedPos = Camera.main.ScreenToWorldPoint(
controlsType == ControlsType.Mouse ? Input.mousePosition : (Vector3)touch.position
);
dragMovedPos.z = 0f;
lr.positionCount = 2;
lr.SetPosition(1, dragMovedPos);
}
// Drag ended defines the end point of the Line Rederer and calculates the drag direction and clamped drag direction
void DragEnded()
{
lr.positionCount = 0;
Vector3 dragEndedPos = Camera.main.ScreenToWorldPoint(
controlsType == ControlsType.Mouse ? Input.mousePosition : (Vector3)touch.position
);
dragEndedPos.z = 0f;
dragEndPosPublic = dragEndedPos;
dragDirection = dragEndedPos - dragBeganPos; // It will apply force without any max speed defined (no clamp)
dragDirectionClamped = Vector3.ClampMagnitude(dragDirection, maxDrag); // It will apply force with max speed defined
Vector3 finalDirection = directionType == DirectionType.Clamped ? dragDirectionClamped : dragDirection;
// Here you can use dragDirection or dragDirectionClamped however you want
playerBallMovement = FindObjectOfType<PlayerBallMovement>();
playerBallMovement.ApplyVelocityInDirection(finalDirection);
}
}```
I'm using Unity to move my player sprite in a 2D platformer where it'll go right if right key is pressed & left if left key is pressed.
The right movement is working fine, but whenever the player moves left, I'm changing the Y rotation to 180 and the player is supposed to show left animation only but it keeps rotating back and forth when going left.
See the video sample.
This is my code:
private Rigidbody2D rb;
private void FixedUpdate() {
InputManager();
}
private void InputManager()
{
float hDir = Input.GetAxis("Horizontal");
if (state != State.hurt) {
if(!anm.GetCurrentAnimatorStateInfo(0).IsTag("attack"))
{
if (hDir < 0) // Go left
{
rb.velocity = new Vector2(-speedX, rb.velocity.y);
transform.Rotate(0f, 180f, 0f);
}
else if (hDir > 0) // Go right
{
rb.velocity = new Vector2(speedX, rb.velocity.y);
transform.Rotate(0f, 0f, 0f);
}
}
}
}
How can I make my player stick to left animation when going on left? Please do not suggest changing localScale as I know it works but for shooting purpose it's best that my player rotates.
Here is a thing transform.Rotate(0,180,0); is used to rotate 180 degree in y axis each time when this line of code execute that's why you player does not stop rotating
Here is the code you can use it will stop you player rotate according to the directions
private void InputManager()
{
float hDir = Input.GetAxis("Horizontal");
if (state != State.hurt)
{
if (!anm.GetCurrentAnimatorStateInfo(0).IsTag("attack"))
{
if (hDir < 0) // Go left
{
rb.velocity = new Vector2(-speedX, rb.velocity.y);
this.transform.rotation = Quaternion.AngleAxis(180, Vector3.up);
}
else if (hDir > 0) // Go right
{
rb.velocity = new Vector2(speedX, rb.velocity.y);
this.transform.rotation = Quaternion.AngleAxis(0, Vector3.up);
}
}
}
}
You need to add a bool Variable that is checking if the player is facing right, as well as a Flip Function that flips him:
bool bFacingRight = true;
private Rigidbody2D rb;
int _switch;
private void FixedUpdate() {
InputManager();
}
private void InputManager()
{
if (state == State.hurt || anm.GetCurrentAnimatorStateInfo(0).IsTag("attack"))
return;
float hDir = Input.GetAxis("Horizontal");
// Move the character by finding the target velocity
rb.velocity = new Vector2(hDir * 10f, rb.velocity.y);
if (hDir < 0 && bFacingRight) { // Flip Left
_switch = 0;
Flip(_switch);
}
else if (hDir > 0 && !bFacingRight) { // Flip Right
_switch= 1;
Flip(_switch);
}
}
private void Flip(int swth)
{
// Switch the way the player is labelled as facing.
bFacingRight = !bFacingRight;
// Multiply the player's x local scale by -1.
switch(swth)
{
case 0:
this.transform.rotation = Quaternion.AngleAxis(180, Vector3.up);
break;
case 1:
this.transform.rotation = Quaternion.AngleAxis(0, Vector3.up);
break;
}
}
I'm making a simple game in Unity in 2d. So I have the player and I have a grappler gun. And when I press the right mouse button and the mouse position is in the direction of any object it will grappler to this object. But my question is, I have a small circle (Grappling point) and it is very hard to put the mouse to the grappler point circle direction in the air. so can I add any offset f.e. when my mouse direction from the player is 2 units from the grappler point circle it will still grappler but automatically the grappler line will connect with the grappler point circle. Here is my grappler code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Grappler: MonoBehaviour
{
public LineRenderer Line;
DistanceJoint2D Joint;
Vector3 TargetPos;
RaycastHit2D Hit;
public float Distance = 10f;
public LayerMask Mask;
public float Step = 0f;
void Start()
{
Joint = GetComponent<DistanceJoint2D>();
Joint.enabled = false;
Line.enabled = false;
}
void Update()
{
if(Joint.distance > 1f)
{
Joint.distance -= Step;
}else
{
Line.enabled = false;
Joint.enabled = false;
}
if(Input.GetMouseButtonDown(1))
{
TargetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
TargetPos.z = 0;
Hit = Physics2D.Raycast(transform.position, TargetPos - transform.position, Distance, Mask);
if (Hit.collider != null && Hit.collider.gameObject.GetComponent<Rigidbody2D>() != null)
{
Joint.enabled = true;
Joint.connectedBody = Hit.collider.gameObject.GetComponent<Rigidbody2D>();
Joint.distance = Vector3.Distance(transform.position, Hit.point);
Line.enabled = true;
Line.SetPosition(0, transform.position);
Line.SetPosition(1, Hit.point);
}
}
if (Input.GetMouseButton(1))
{
Line.SetPosition(0, transform.position);
}
if (Input.GetMouseButtonUp(1))
{
Joint.enabled = false;
Line.enabled = false;
}
}
}
Any ideas?? Thanks
It sounds like you should simply make your collision bigger by 2 units (if that's the amount you want to cheat by). And then instead of using the ray trace hit location, use the location of the object you hit instead.
I am moving an object that consists of two cubes: left and right. These cubes are randomly generated on the y-axis upwards.
I am able to move them left and right with no problem, however, when I move one of the cubes left or right they all move.
How am I able to only move one of the cubes when touched only left or right rather than all of them? Here is my code below:
Generate cubes code:
public Transform block;
public Transform player;
private float objectSpawnedTo = 5.0f;
public static float distanceBetweenObjects = 5.0f;
private float nextCheck = 0.0f;
private ArrayList objects = new ArrayList();
void Start () {
maintenance(0.0f);
}
void Update () {
float playerX = player.position.y;
if(playerX > nextCheck)
{
maintenance(playerX);
}
}
private void maintenance(float playerX)
{
nextCheck = playerX + 30;
for (int i = objects.Count-1; i >= 0; i--)
{
Transform blck = (Transform)objects[i];
if(blck.position.y < (transform.position.y - 30))
{
Destroy(blck.gameObject);
objects.RemoveAt(i);
}
}
spawnObjects(5);
}
private void spawnObjects(int howMany)
{
float spawnX = objectSpawnedTo;
for(int i = 0; i<howMany; i++)
{
Vector3 pos = new Vector3(-3.5f,spawnX, 0);
//float firstRandom = Random.Range(-6.0f, 1.0f);
Transform blck = (Transform)Instantiate(block, pos, Quaternion.identity);
//blck.localScale+=new Vector3(firstRandom*2,0,0);
objects.Add(blck);
//pos = new Vector3(0,spawnX, 0);
//blck = (Transform)Instantiate(block, pos, Quaternion.identity);
//blck.localScale +=new Vector3((8.6f-firstRandom)*2,0,0);
//objects.Add(blck);
spawnX = spawnX + distanceBetweenObjects;
}
objectSpawnedTo = spawnX;
}
}
Cube-control code:
public float speed = 5;
// Use this for initialization
void Start () {
}
void Update() {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
// Get movement of the finger since last frame
Vector3 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across XY plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
Vector3 boundaryVector = transform.position;
boundaryVector.x = Mathf.Clamp (boundaryVector.x, -5.5f, -2.8f);
transform.position = boundaryVector;
}
}
}
The problem is your cube-control code has no condition in it about which cube is selected : you simply wait for Input.touchCount to be > 0 and then move the cube. So all the cube having this script will move.
I think what you need to do is a raycast to check which cube has been "touched" and then only move it if raycast is successful :
[SerializeField]
private float speed = 0.5f;
private int MAX_TOUCH_COUNT = 5;
private bool[] touched;
protected void Start()
{
touched = new bool[MAX_TOUCH_COUNT];
}
void Update()
{
if (Input.touchCount > 0)
{
for(int i = 0; i < (Input.touchCount <= MAX_TOUCH_COUNT ? Input.touchCount : MAX_TOUCH_COUNT); i++)
{
if(touched[i] && Input.GetTouch(i).phase == TouchPhase.Ended)
{
touched[i] = false;
}
else if (!touched[i] && Input.GetTouch(i).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
if (hitInfo.transform.GetComponentInChildren<*YOUR_CUBE_CONTROL_CLASS_NAME*>() == this)
{
touched[i] = true;
}
}
}
else if (touched[i] && Input.GetTouch(i).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector3 touchDeltaPosition = Input.GetTouch(i).deltaPosition;
// Move object across XY plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
Vector3 boundaryVector = transform.position;
boundaryVector.x = Mathf.Clamp (boundaryVector.x, -5.5f, -2.8f);
transform.position = boundaryVector;
}
}
else
{
touched = false;
}
}
}
Hope this help,
I am working on football penalty game i am using a image target for ground i have a plane put grass texture on it i have models for goal post etc for football i add a sphere and add a RigidBody to it then i add a script to it for swiping the ball the problem is that if the Grivity is checked i am unable to see my football on the ground and if gravity is unchecked i am able to see my football but without grivity when i kicked the ball i am unable to put the ball into the net ball move to sky etc.please help me to solve my problem thanks.
Here's my script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SwipeControl : MonoBehaviour
{
//variables for swipe input detection
private Vector3 fp; //First finger position
private Vector3 lp; //Last finger position
private float dragDistance; //Distance needed for a swipe to register
//variables for determining the shot power and position
public float power; //power at which the ball is shot
private Vector3 footballPos;
//initial football position for replacing the ball at the same posiiton
private float factor = 34f;
// keep this factor constant, also used to determine force of shot
public bool canShoot = true; //flag to check if shot can be taken
public int scorePlayer = 0; //score of player
public int scoreOpponent = 0; //score of oponent
public int turn = 0; //0 for striker, 1 for goalie
public bool isGameOver = false; //flag for game over detection
Vector3 oppKickDir; //direction at which the ball is kicked by opponent
public int shotsTaken = 0; //number of rounds of penalties taken
private bool returned = true; //flag to check if the ball is returned to its initial position
public bool isKickedPlayer = false; //flag to check if the player has kicked the ball
public bool isKickedOpponent = false; //flag to check if the opponent has kicked the ball
void Start()
{
Time.timeScale = 1; //set it to 1 on start so as to overcome the effects of restarting the game by script
dragDistance = Screen.height * 20 / 100; //20% of the screen should be swiped to shoot
Physics.gravity = new Vector3(0, -20, 0); //reset the gravity of the ball to 20
footballPos = transform.position; //store the initial position of the football
}
// Update is called once per frame
void Update()
{
if (returned)
{ //check if the football is in its initial position
if (turn == 0 && !isGameOver)
{ //if its users turn to shoot and if the game is not over
playerLogic(); //call the playerLogic fucntion
}
else if (turn == 1 && !isGameOver)
{ //if its opponent's turn to shoot
opponentLogic(); //call the respective function
}
}
}
void playerLogic()
{
//Examine the touch inputs
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fp = touch.position;
lp = touch.position;
}
if (touch.phase == TouchPhase.Ended)
{
lp = touch.position;
//First check if it's actually a drag
if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
{ //It's a drag
//x and y repesent force to be added in the x, y axes.
float x = (lp.x - fp.x) / Screen.height * factor;
float y = (lp.y - fp.y) / Screen.height * factor;
//Now check what direction the drag was
//First check which axis
if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y))
{ //If the horizontal movement is greater than the vertical movement...
if ((lp.x > fp.x) && canShoot) //If the movement was to the right)
{ //Right move
GetComponent<Rigidbody>().AddForce((new Vector3(x, 10, 15)) * power);
}
else
{ //Left move
GetComponent<Rigidbody>().AddForce((new Vector3(x, 10, 15)) * power);
}
}
else
{ //the vertical movement is greater than the horizontal movement
if (lp.y > fp.y) //If the movement was up
{ //Up move
GetComponent<Rigidbody>().AddForce((new Vector3(x, y, 15)) * power);
}
else
{ //Down move
}
}
}
canShoot = false;
returned = false;
isKickedPlayer = true;
StartCoroutine(ReturnBall());
}
else
{ //It's a tap
}
}
}
IEnumerator ReturnBall()
{
yield return new WaitForSeconds(5.0f); //set a delay of 5 seconds before the ball is returned
GetComponent<Rigidbody>().velocity = Vector3.zero; //set the velocity of the ball to zero
GetComponent<Rigidbody>().angularVelocity = Vector3.zero; //set its angular vel to zero
transform.position = footballPos; //re positon it to initial position
//take turns in shooting
if (turn == 1)
turn = 0;
else if (turn == 0)
turn = 1;
canShoot = true; //set the canshoot flag to true
returned = true; //set football returned flag to true as well
}
void opponentLogic()
{
//check for screen tap
int fingerCount = 0;
foreach (Touch touch in Input.touches)
{
if (touch.phase != TouchPhase.Ended && touch.phase != TouchPhase.Canceled)
fingerCount++;
}
//if tapped, the opponent will shoot the football after some time delay as mentioned below
if (fingerCount > 0)
{
StartCoroutine(DelayAdd()); //add delay before the ball is shot
isKickedOpponent = true; //set opponent kicked to true
shotsTaken++; //increase set of penalty taken
returned = false;
StartCoroutine(ReturnBall()); //return the ball back to its initial position
}
}
IEnumerator DelayAdd()
{
yield return new WaitForSeconds(0.2f); //I have added a delay of 0.2 seconds
oppKickDir = new Vector3(Random.Range(-4f, 4f), Random.Range(5f, 10f), Random.Range(6f, 12f)); //generate a random x and y value in the range mentioned
GetComponent<Rigidbody>().AddForce(oppKickDir, ForceMode.Impulse); //add the force
}
}