Unity: issue with joystick - c#

For the third day I'm suffering with the control for a mobile game. I want to implement control via the joystick.
I want such control in the game as in Color Road - https://vk.com/video174341022_456239047
And I did this here (via joystick) - https://vk.com/video174341022_456239048
The difference is that in the game Color Road hamburger can be kept in the center without any strain, it is very convenient from the edge of the screen to go to the center. In my control to keep in the center of the screen you need to make a lot of effort, because if you push the joystick slightly more to the left, the triangle flies to the edge of the screen, and if you do not let the joystick go to the left, it will move at the speed of the turtle.
My joystick code:
public class VirtualJoystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler {
private Image backgroundImage;
private Image joystickImage;
private Vector3 inputVector;
private void Start()
{
backgroundImage = GetComponent<Image>();
joystickImage = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnDrag(PointerEventData eventData)
{
Vector2 pos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(backgroundImage.rectTransform, eventData.position,
eventData.pressEventCamera, out pos))
{
pos.x = (pos.x / (backgroundImage.rectTransform.sizeDelta.x));
//pos.y = (pos.y / backgroundImage.rectTransform.sizeDelta.y);
inputVector = new Vector3(pos.x * 2f, 0, 0);
inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;
joystickImage.rectTransform.anchoredPosition = new Vector3(inputVector.x * (backgroundImage.rectTransform.sizeDelta.x / 2),
inputVector.z * inputVector.y);
}
}
public virtual void OnPointerDown(PointerEventData eventData)
{
OnDrag(eventData);
}
public virtual void OnPointerUp(PointerEventData eventData)
{
inputVector = Vector3.zero;
joystickImage.rectTransform.anchoredPosition = Vector3.zero;
}
public float Horizontal()
{
if (inputVector.x != 0)
{
return inputVector.x;
}
else
{
return Input.GetAxis("Horizontal");
}
}
}
Control triangle:
public class PlayerMover : MonoBehaviour {
public VirtualJoystick joystick;
private Vector3 MoveVector;
private Rigidbody2D rigidbody;
public float moveSpeed = 10;
void Start()
{
rigidbody = gameObject.GetComponent<Rigidbody2D>();
}
void Update()
{
MoveVector = PoolInput();
Move();
}
private void Move()
{
rigidbody.velocity = Vector2.zero;
rigidbody.velocity = ((MoveVector * moveSpeed));
}
private Vector3 PoolInput()
{
Vector3 dir = Vector3.zero;
dir.x = joystick.Horizontal();
dir.y = 0;
dir.z = 0;
if (dir.magnitude > 1)
dir.Normalize();
Debug.Log("Dir = " + dir);
return dir;
}
}
I can not find any info to fix this. Everywhere the same tutorials. Maybe it's something else you need to implement? Not through the joystick? What is the problem with such a wooden control for me?
P.S Sorry for my bad english

Related

How I can move player left or right with infinite runner game here. using character controller

public class PlayerMove : MonoBehaviour
{
public float speed;
private float yVelocity;
public CharacterController player;
public float jumpHeight =10.0f;
public float gravity = 1.0f;
//public float gravityScale = 1;
private void Start()
{
player = GetComponent<CharacterController>();
}
void Update()
{
Vector3 direction= new Vector3(0, 0, 1);
Vector3 velocity= direction * speed;
if (player.isGrounded == true)
{
if (Input.GetKeyDown(KeyCode.Space))
{
yVelocity = jumpHeight;
}
}
else
{
yVelocity -= gravity;
}
velocity.y = yVelocity;
player.Move(velocity * Time.deltaTime);
}
}
I tried Rigidbody & much more script but my player doesn't jump if my player jump then my doesn't move left or right sometimes my player stocked in ground.. tell me the right way of script where I can use
For the left/right movements you can try this simple code :
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
public float speed;
private float yVelocity;
public CharacterController player;
public float jumpForce = 10.0f;
public float moveForce = 5.0f;
public float gravity = 1.0f;
private void Start()
{
player = GetComponent<CharacterController>();
}
void Update()
{
Vector3 direction = new Vector3(0, 0, 1);
Vector3 velocity = direction * speed;
// Add left/right movement
if (Input.GetKey(KeyCode.LeftArrow))
{
velocity += Vector3.left * moveForce;
}
else if (Input.GetKey(KeyCode.RightArrow))
{
velocity += Vector3.right * moveForce;
}
if (player.isGrounded)
{
if (Input.GetKeyDown(KeyCode.Space))
{
yVelocity = jumpForce;
}
}
else
{
yVelocity -= gravity;
}
velocity.y = yVelocity;
player.Move(velocity * Time.deltaTime);
}
}
You can also look at this post Moving player in Subway Surf like game using left/right swipe

Is that a good usecase of delegates and events in Unity?

I just started learning Unity and wanna try to use events/delegates in FlappyBird game.
Flappy bird screenshot
As on this pic, I need to replace text with current score + 1, when the bird triggers collider between pipes.
public class BirdController : MonoBehaviour
{
private SpriteRenderer sr;
private Rigidbody2D rigidBody;
private Animator anim;
[SerializeField]
private float movementXForce, movementYForce, rotationSpeedUp,
rotationSpeedDown;
private float lastPosY;
float rotation;
private string FLY_ANIMATION = "fly";
private void Awake() {
sr = GetComponent<SpriteRenderer>();
rigidBody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
lastPosY = transform.position.y;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
fly();
moveRight();
animFly();
}
void fly()
{
if (Input.GetButtonDown("Jump")) {
rigidBody.AddForce(new Vector2(0f, movementYForce),
ForceMode2D.Impulse);
lastPosY = transform.position.y;
}
if (rigidBody.velocity.y < 0 && rigidBody.rotation > -30) {
rotation = -1f * rotationSpeedDown;
transform.Rotate(Vector3.forward * rotation);
} else if (rigidBody.velocity.y >= 0 && rigidBody.rotation < 30) {
rotation = 1f * rotationSpeedUp;
transform.Rotate(Vector3.forward * rotation);
}
}
void moveRight()
{
transform.position += new Vector3(1f, 0f, 0f) * Time.deltaTime *
movementXForce;
}
void animFly()
{
if (lastPosY < transform.position.y) {
anim.SetBool(FLY_ANIMATION, true);
} else {
anim.SetBool(FLY_ANIMATION, false);
}
}
private void OnTriggerEnter2D(Collider2D other) {
if (other.CompareTag("Ground") || other.CompareTag("Trap")) {
Destroy(gameObject);
}
}
private void OnTriggerExit2D(Collider2D other) {
if (other.CompareTag("Score")) {
}
}
}
I am about to add extra field in BirdController, something like
public delegate void OnTriggerScoreLine();
public static event OnTriggerScoreLine onTriggerScoreLine;
Then in OnTriggerExit2D I will
if (onTriggerScoreLine != null) {
OnTriggerScoreLine();
}
After that I will create new script ScoreController and there I will subscribe onTriggerScoreLine on method that will change the score text on score + 1 and also static scoreValue variable
And I just wanted to ask if I correctly understood delegates and events. Is it a good example of its using? Thanks:)

Unity how to "power bounce" one object from another relative to it's angle?

I'm working on a simple 3D game where some balls (fixed Z position) fall along a path (using gravity and physics material) to a small flat platform and "power bounce" off this platform. The player can rotate this platform so I want to recreate a realistic bounce direction according to the platform's angle.
I'm new to coding but so far I've figured the relationship between the vector of the ball as it comes into collision with the platform and the platform's normal, which should be a perpendicular line from the surface and that can be used to reflect the ball's vector to the other direction.
I already used OnCollisionEnter and if statement to detect whether it's the platform you are colliding with, but I don't understand where to indicate the normal of the surface and how to access it. Should it be as a public class in the other object or can it be detected from the ball game object?
I tried some examples from this and other websites and got this far:
public class OnCollision : MonoBehaviour
{
public float speed = 25f;
public Rigidbody rb;
private Rigidbody rigid;
private void Start()
{
rigid = transform.GetComponent<Rigidbody>();
}
private void OnCollisionEnter(Collision collision)
{
if (collision.transform.tag == "BouncePad") {
rb.velocity = transform.up * speed;
}
}
}
Now it bounces off vertically, so I'm guessing I should change the code where the transform.up * speed part is.
Could anyone guide me, please?
Much appreciated.
If you are already using Physics material, look into the Bounciness property. A value of 0 means no bounce, a value of 1 will lead to no loss of energy. The angle of the bounce will be calculated for you. Make sure you drag the physics material onto each object-- both the ball and the wall's material will have an effect.
Finally somebody gave me a hand and came to this solution:
public class Bounce : MonoBehaviour
{
public Rigidbody rb;
public float str = 0.21f;
public float str2 = 0.15f;
// Start is called before the first frame update
private void Start()
{
rb = GetComponent<Rigidbody>();
}
private void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "BouncePad")
{
rb.AddForce(rb.velocity * str, ForceMode.Impulse);
}
if (col.gameObject.tag == "BouncePad2")
{
rb.AddForce(rb.velocity * str2, ForceMode.Impulse);
}
}
// Update is called once per frame
void Update()
{
}
}
public class BouncTest : MonoBehaviour
{
[SerializeField] private float hight = 3;
[SerializeField] private int times = 5;
[SerializeField] private float speed = 8;
private Vector3 _startPos;
private bool _checkUP;
private int _countTimes;
private float _hightbuf;
[HideInInspector]
public bool _bounceEnd;
private void Awake()
{
_startPos = transform.position;
}
public void TurnOnBounceEffect()
{
_bounceEnd = true;
_checkUP = false;
_hightbuf = hight;
_countTimes = 0;
}
private void FixedUpdate()
{
BounceEffect();
}
private void BounceEffect()
{
if (_bounceEnd)
{
if (!_checkUP)
{
if (transform.position.y <= (_startPos.y + _hightbuf))
transform.position = Vector2.MoveTowards(transform.position, new Vector2(_startPos.x, transform.position.y) + (Vector2.up * _hightbuf), speed * Time.fixedDeltaTime);
else
{
_checkUP = true;
}
}
else if (times != _countTimes)
{
if (transform.position.y > _startPos.y)
transform.position = Vector2.MoveTowards(transform.position, _startPos, speed * Time.fixedDeltaTime);
else
{
_countTimes++;
_checkUP = false;
_hightbuf /= 2;
}
}
else
{
transform.position = Vector2.MoveTowards(transform.position, _startPos, speed * Time.fixedDeltaTime);
if (transform.position.y <= _startPos.y)
{
_bounceEnd = false;
}
}
}
}
}

Unity Why wont my FPS pause menu stop the camera rotation?

I am working on the pause menu for my FPS game and so far I am able to get the pause menu panel to show up and interact with it, but it does not stop the camera movement. Can someone tell me what I am doing wrong?
Here is the code:
public class PauseMenuu : MonoBehaviour
{
public static bool GameIsPaused = false;
public GameObject PauseMenu;
private void Start()
{
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (GameIsPaused)
{
Resume();
}
else
{
Pause();
}
}
}
void Resume()
{
PauseMenu.SetActive(false);
Time.timeScale = 1f;
GameIsPaused = false;
}
void Pause()
{
PauseMenu.SetActive(true);
Time.timeScale = 0f;
GameIsPaused = true;
}
}
here is my camera rotate code if this helps you figure out what is going on with the camera.
public class CameraRotate : MonoBehaviour
{
public float speed;
float time = 14.0f;
public GameObject HeadCamera;
public bool updateOn = true;
void Start()
{
StartCoroutine(updateOff());
}
void Update()
{
Rotation();
}
void Rotation()
{
RotateX += Input.GetAxis("Mouse X") * RotationSpeed;
RotateY += Input.GetAxis("Mouse Y") * RotationSpeed;
RotateY = Mathf.Clamp(RotateY, MinYAxis, MaxYAxis);
Camera.transform.localRotation = Quaternion.Euler(-RotateY, 0f, 0f);
transform.rotation = Quaternion.Euler(0f, RotateX, 0f);
}
}
It could solve it for you, try rotating the camera relative to its own position. So what you would do is add this to the top of your function call:
void Rotation()
{
if(Time.deltaTime == 0){
return;
}
...
Also note that you might need to change a couple of values to get the rotation amount like before.
Hope it helps!

Unity 2D, control a simple shot

I have to control a shot of a ball with touch. All works fine but I need to start my trajectory when I touch the screen, but the trajectory start only when the ball is touched. Is because the script is attached to the ball?
All touch input except touches on the ball is ignored.
Here is the C# script , can someone help me?
using UnityEngine;
using System.Collections;
using System;
namespace Shorka.BallTrajectory
{
public enum PullState
{
Idle,
UserPulling,
ObjFlying
}
public class PullCtrl : MonoBehaviour
{
#region fields
//[SerializeField] private Transform throwTarget;
[SerializeField] private ThrownObject throwObj;
[SerializeField] private Transform dotHelper;
[SerializeField] private Transform pullingStartPoint;
[Space(5)]
[Tooltip("this linerenderer will draw the projected trajectory of the thrown object")]
[SerializeField]
private LineRenderer trajectoryLineRen;
[SerializeField]
private TrailMaker trail;
[Space(5)]
[SerializeField]
private float throwSpeed = 10F;
[Tooltip("Max Distance between 'PullingStartPoint' and pulling touch point")]
[SerializeField]
private float maxDistance = 1.5F;
[SerializeField]
private float coofDotHelper = 1.5F;
[Tooltip("Related to length of trajectory line")]
[SerializeField]
private int qtyOfsegments = 13;
[Tooltip("Step of changing trajectory dots offset in runtime")]
[SerializeField]
private float stepMatOffset = 0.01F;
[Tooltip("Z position of trajectory dots")]
[SerializeField]
private float dotPosZ = 0F;
private PullState pullState;
private Camera camMain;
//private Collider2D collThrowTarget;
private Rigidbody2D rgThrowTarget;
private Vector3 posPullingStart;
private Vector3 initPos;
private TrajectoryCtrl trajCtrl;
#endregion
public Vector3 PosDotHelper { get { return dotHelper.position; } }
public Vector3 PosThrowTarget { get { return throwObj.transform.position; } }
public int QtyOfsegments { get { return qtyOfsegments; } }
public float DotPosZ { get { return dotPosZ; } }
public Vector3 PosPullingStart { get { return posPullingStart; } }
public float StepMatOffset { get { return stepMatOffset; } }
void Awake()
{
trail.emit = false;
trajCtrl = new TrajectoryCtrl(this, trajectoryLineRen);
}
void Start()
{
camMain = Camera.main;
pullState = PullState.Idle;
posPullingStart = pullingStartPoint.position;
initPos = PosThrowTarget;
}
void Update()
{
SwitchStates();
}
private void SwitchStates()
{
switch (pullState)
{
case PullState.Idle:
if (Input.touchCount> 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Debug.Log("Screen touched");
//get the point on screen user has tapped
Vector3 location = camMain.ScreenToWorldPoint(Input.GetTouch(0).position);
//if user has tapped onto the ball
if (throwObj.Collider == Physics2D.OverlapPoint(location))
pullState = PullState.UserPulling;
}
break;
case PullState.UserPulling:
dotHelper.gameObject.SetActive(true);
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
//get touch position
Vector3 touchPos = camMain.ScreenToWorldPoint(Input.GetTouch(0).position);
touchPos.z = 0;
//we will let the user pull the ball up to a maximum distance
if (Vector3.Distance(touchPos, posPullingStart) > maxDistance)
{
Vector3 maxPosition = (touchPos - posPullingStart).normalized * maxDistance + posPullingStart;
maxPosition.z = dotHelper.position.z;
dotHelper.position = maxPosition;
}
else
{
touchPos.z = dotHelper.position.z;
dotHelper.position = touchPos;
}
float distance = Vector3.Distance(posPullingStart, dotHelper.position);
trajCtrl.DisplayTrajectory(distance);
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Canceled || Input.GetTouch(0).phase == TouchPhase.Ended)
{
float distance = Vector3.Distance(posPullingStart, dotHelper.position);
trajectoryLineRen.enabled = false;
ThrowObj(distance);
}
break;
default:
break;
}
}
//private Vector2 velocityToRg = Vector2.zero;
private void ThrowObj(float distance)
{
Debug.Log("ThrowObj");
pullState = PullState.Idle;
Vector3 velocity = posPullingStart - dotHelper.position;
//velocityToRg = CalcVelocity(velocity, distance);
throwObj.ThrowObj(CalcVelocity(velocity, distance));
//rgThrowTarget.velocity = velocityToRg;
//rgThrowTarget.isKinematic = false;
trail.enabled = true;
trail.emit = true;
dotHelper.gameObject.SetActive(false);
}
public void Restart(Vector3 posThrownObj)
{
trail.emit = false;
trail.Clear();
StartCoroutine(ClearTrail());
trajectoryLineRen.enabled = false;
dotHelper.gameObject.SetActive(false);
pullState = PullState.Idle;
throwObj.Reset(posThrownObj);
}
private readonly WaitForSeconds wtTimeBeforeClear = new WaitForSeconds(0.3F);
IEnumerator ClearTrail()
{
yield return wtTimeBeforeClear;
trail.Clear();
trail.enabled = false;
}
Vector3 velocity = Vector3.zero;
public Vector3 CalcVelocity(Vector3 diff, float distance)
{
velocity.x = diff.x * throwSpeed * distance * coofDotHelper;
velocity.y = diff.y * throwSpeed * distance * coofDotHelper;
return velocity;
}
}
}
Its quite easy. you need to add these two scripts to the gameobject (not the ball but the one which is used to shoot the ball something like a gun)
TouchEventTrigger.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class TouchEventTrigger : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler {
public TouchEvent onClick;
public TouchEvent onDown;
public TouchEvent onUp;
public void OnPointerClick(PointerEventData e) {
onClick.Invoke(e);
}
public void OnPointerDown(PointerEventData e) {
onDown.Invoke(e);
}
public void OnPointerUp(PointerEventData e) {
onUp.Invoke(e);
}
}
[System.Serializable]
public class TouchEvent : UnityEvent<PointerEventData> {}
Shooter.cs
public void TryBeginAim(PointerEventData e) {
if(canShoot) {
initialTouchPos = e.position;
}
}
public void TryAim(PointerEventData e) {
if(canShoot) {
direction = initialTouchPos - e.position;
float mag = (initialTouchPos - e.position).magnitude;
float scale = Mathf.Clamp(mag/maxMagnitude, scaleThreshold, 1f);
angle = Mathf.Atan2(direction.y,direction.x) * Mathf.Rad2Deg + 90f;
aim.transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
aim.transform.localScale = Vector3.one * scale;
aim.SetActive(e.position.y < initialTouchPos.y);
}
}
public void TryShoot(PointerEventData e) {
if(canShoot && aim.activeInHierarchy) {
canShoot = false;
StartCoroutine(ShootRoutine(balls));
}
aim.SetActive(false);
}
private IEnumerator ShootRoutine(int b) {
// write code to start shooting balls.
}
Then connect the touch events with the methods like this:
1. OnPointerClick => TryBeginAim
2. OnPointerDown => TryAim
3. OnPointerUp => TryShoot
That's All !!
I hope this helps to solve this issue. Enjoy!

Categories