Unity android 2d movement issue - c#

I want to create a game in which I can move box left and right to avoid falling boxes and it works, but the problem is when I hold my finger in one place, the player box then is shaking left and right. You can see this at this gif http://gfycat.com/FragrantBrokenEyas. And here's the code of C# script
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour {
private Camera m_cam;
private float m_offsetRight = 1.0F;
private float m_offsetLeft = 0.0F;
void Awake() {
m_cam = Camera.main;
}
void Update () {
rigidbody2D.velocity = new Vector2(0 * 10, 0);
Move ();
}
void Move () {
if (Application.platform == RuntimePlatform.Android) {
Vector3 player_pos = m_cam.WorldToViewportPoint(rigidbody2D.position);
Vector3 touch_pos = new Vector3(Input.GetTouch(0).position.x, 0, 0);
touch_pos = Camera.main.ScreenToViewportPoint(touch_pos);
if(touch_pos.x > player_pos.x)
rigidbody2D.velocity = new Vector2(1 * 10, 0);
else if (touch_pos.x < player_pos.x)
rigidbody2D.velocity = new Vector2(-1 * 10, 0);
}
else{
Vector3 player_pos = m_cam.WorldToViewportPoint(rigidbody2D.position);
float h = Input.GetAxis ("Horizontal");
if (h > 0 && player_pos.x < m_offsetRight)
rigidbody2D.velocity = new Vector2(h * 10, 0);
else if (h < 0 && player_pos.x > m_offsetLeft)
rigidbody2D.velocity = new Vector2(h * 10, 0);
else
rigidbody2D.velocity = new Vector2(0, rigidbody2D.velocity.y);
}
}
void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.name == "Enemy(Clone)") {
Destroy(other.gameObject);
GameSetUp.score -= 2;
} else if (other.gameObject.name == "Coin(Clone)") {
GameSetUp.score += 2;
Destroy(other.gameObject);
}
}
}
I think that the problem is somewhere over here:
touch_pos = Camera.main.ScreenToViewportPoint(touch_pos);
if(touch_pos.x > player_pos.x)
rigidbody2D.velocity = new Vector2(1 * 10, 0);
else if (touch_pos.x < player_pos.x)
rigidbody2D.velocity = new Vector2(-1 * 10, 0);

This "one place" is probably the place where the x coordinate of the touch is about the same than the x coordinate of the player box.
While your finger is pressing that area, on the first frame touch_pos.x > player_pos.x is true and the velocity is set to positive. On the next frame player has moved to positive direction and this time touch_pos.x < player_pos.x is true and speed is set to negative. This leads to the shaking effect.
To avoid it, you can for example increase and decrease the velocity slowly, rather than changing it completely to opposite in one frame. You can do this by changing your code to this:
touch_pos = Camera.main.ScreenToViewportPoint(touch_pos);
const float acceleration = 60.0f;
const float maxSpeed = 10.0f;
if(touch_pos.x > player_pos.x)
if(rigidbody2D.velocity.x < maxSpeed)
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x + acceleration * Time.deltaTime, 0);
else
rigidbody2D.velocity = new Vector2(maxSpeed, 0);
else if (touch_pos.x < player_pos.x)
if(rigidbody2D.velocity.x > -maxSpeed)
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x - acceleration * Time.deltaTime , 0);
else
rigidbody2D.velocity = new Vector2(-maxSpeed, 0);
Just adjust the acceleration to the value that seems right.

Related

Rotate Object Smoothly

i am trying to rotate object to 90 degrees smoothly on swipe here in my code its rotate instantly, how do i rotate object smoothly at given speed.
void Update()
{
if (fingerDown == false && Input.GetMouseButtonDown(0))
{
startPos = Input.mousePosition;
fingerDown = true;
}
if (fingerDown)
{
if (Input.mousePosition.x >= startPos.x + pixelDistToMove)
{
startPos = Input.mousePosition;
Vector3 rotationToAdd = new Vector3(0, 0, 90);
transform.Rotate(rotationToAdd);
fingerDown = false;
}
if (Input.mousePosition.x <= startPos.x - pixelDistToMove)
{
startPos = Input.mousePosition;
Vector3 rotationToAdd = new Vector3(0, 0, -90);
transform.Rotate(rotationToAdd);
fingerDown = false;
}
}
if (fingerDown && Input.GetMouseButtonUp(0))
{
fingerDown = false;
}
}
Thank you
transform.Rotate() rotates the object without animating it's rotation.
If you want it to rotate smoothly, you have to implement either an animation, or a turning state, or an IEnumerator.
My C# is a bit rusty, but I cooked this up:
public Vector3 desired_angle = Vector3.zero; // Turn the Gameobject to this angle
public float turn_time = 1f; // How long should turning take
public float rate = 60;
private void Update ()
{
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(TurnTo());
}
}
IEnumerator TurnTo ()
{
Vector3 original_angle = transform.rotation.eulerAngles;
for (float i = 0f; i < 1f + turn_time / rate; i += turn_time / rate)
{
transform.rotation = Quaternion.Euler(Vector3.Lerp(original_angle, desired_angle, i));
yield return new WaitForSeconds(turn_time/rate);
}
}

Let object glide to mouse with constant speed Unity C#

I have a bullet object, that needs to glide to the mouse when the mouse is pressed (but should stop when it is released). I have tried multiple approaches, but every time the bullet accelerates, and makes circles around the mouse in a ellipse form (I also have gravity). How can I get it to just move towards the mouse at a constant speed?
This is my code:
using UnityEngine;
public class Bullet : MonoBehaviour {
public Rigidbody rigidbody;
void Start() {
rigidbody = GetComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.velocity = new Vector3(0, -0.3F, 0);
}
float getX(Vector3 transform_pos, Vector3 mouse_pos) {
float tx = transform_pos.x;
float mx = mouse_pos.x;
if (tx == mx) { return 0;
} else if (tx > mx) { return -1;
} else if (tx < mx ) { return 1;
}else { return 0; }
}
void Update() {
if (Input.GetMouseButton(0)) {
Vector3 mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.LookAt(mouse_pos);
float x = getX(transform.position, mouse_pos);
float y = transform.position.y > mouse_pos.y ? -0.03F : 0.03F;
rigidbody.AddForce(new Vector3(x, 0, transform.position.z), ForceMode.VelocityChange);
Debug.Log(x.ToString() + y.ToString());
}
if (transform.position.y < -5 | transform.position.y > 5) {
Destroy(transform.gameObject);
}
rigidbody.AddForce(Vector3.down, ForceMode.Force);
}
}
I tried a bit more, and found out, that using rigidbody.velocity() is better than rigidbody.AddForce(), so replace rigidbody.AddForce(new Vector3(x, 0, transform.position.z), ForceMode.VelocityChange); with rigidbody.velocity = new Vector3(x, y, transform.position.z); (replace x and y with the velocity and it should work. Note that this replaces the velocity, so all the movement will be stopped)

Moving the player on the y-axis

I am working on a Pong-Clone for Android right now and have watched a tutorial about it. It works perfectly with the keyboard, but how do I get a similar control on the mobile phone. My current code looks like this:
private void Start()
{
ball = GameObject.FindGameObjectWithTag("Ball").GetComponent<Ball>();
col = GetComponent<BoxCollider2D>();
if (side == Side.Left)
forwardDirection = Vector2.right;
else if (side == Side.Right)
forwardDirection = Vector2.left;
}
private void Update()
{
if (!overridePosition)
MovePaddle();
}
private void MovePaddle()
{
float targetYPosition = GetNewYPosition();
ClampPosition(ref targetYPosition);
transform.position = new Vector3(transform.position.x, targetYPosition, transform.position.z);
}
private void ClampPosition(ref float yPosition)
{
float minY = Camera.main.ScreenToWorldPoint(new Vector3(0, 0)).y;
float maxY = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height)).y;
yPosition = Mathf.Clamp(yPosition, minY, maxY);
}
private float GetNewYPosition()
{
float result = transform.position.y;
if (isAI)
{
if (BallIncoming())
{
if (firstIncoming)
{
firstIncoming = false;
randomYOffset = GetRandomOffset();
}
result = Mathf.MoveTowards(transform.position.y, ball.transform.position.y + randomYOffset, moveSpeed * Time.deltaTime);
}
else
{
firstIncoming = true;
}
}
else
{
float movement = Input.GetAxisRaw("Vertical " + side.ToString()) * moveSpeed * Time.deltaTime;
result = transform.position.y + movement;
}
return result;
}
I want the player to move on the y Axis, but I have no idea how I can do it with touch controls (I am new to games). I would really appreciate any help, so I can continue programming :)
I'm going to assume what you want isove the padel by touch and drag up or down.
I would keep your code for debugging and add a switch to only use touch if touch is supported and your code otherwise.
// Adjust via the Inspector how much the user has to drag in order to move the padel
[SerializeField] private float touchDragSensitivity = 1;
private float lastTouchPosY;
// Make sure to store the camera
// Using Camera.main is quite expensive!
[SerializeField] private Camera _mainCamera;
private void Awake()
{
if(!_mainCamera) _mainCamera = GetComponent<Camera>();
...
}
private float GetNewPosition()
{
...
else
{
var movement = 0f;
if(!Input.touchSupported)
{
// For non-touch device keep your current code
movement = Input.GetAxisRaw("Vertical " + side.ToString()) * moveSpeed * Time.deltaTime;
}
else
{
if(Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
var touchPositionY = _mainCamera.ScreenToWorldPoint(touch.position).y;
if(touch.phase = TouchPhase.Moved)
{
var delta = touchPositionY - lastTouchPosY;
movement = delta * touchDragSensitivity;
}
lastTouchPosY = touchPositionY;
}
}
result = transform.position.y + movement;
}
}
Or alternatively if you rather wanted a similar experience as for the button input you could also only check whether the touch is on the bottom or top half of the screen and move the padel constantly like with your original code before:
private void Update()
{
...
else
{
var movement = 0f;
if(!Input.touchSupported)
{
// For non-touch device keep your current code
movement = Input.GetAxisRaw("Vertical " + side.ToString()) * moveSpeed * Time.deltaTime;
}
else
{
if(Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
var touchPositionY = touch.position.y;
movement = (touchPositionY >= Screen.height / 2f ? 1 : -1) * moveSpeed * Time.deltaTime;
}
}
result = transform.position.y + movement;
}
}
Update
As to your question
is there some way to split the screen so two players can play on the same screen
Yes: You can add a check on which side a touch is using touch.position.x >= screen.width / 2f => right side.
You could e.g. filter for valid touches like
if(Input.touchCount > 0)
{
if(side == Side.Right)
{
var validTouches = Input.touches.Where(t => t.position >= Screen.width / 2f).ToArray();
if(validTouches.Length > 0)
{
var touchPositionY = validTouches[0].position.y;
movement = (touchPositionY >= Screen.height / 2f ? 1 : -1) * moveSpeed * Time.deltaTime;
}
}
else
{
var validTouches = Input.touches.Where(t => t.position < Screen.width / 2f).ToArray();
if(validTouches.Length > 0)
{
var touchPositionY = validTouches[0].position.y;
movement = (touchPositionY >= Screen.height / 2f ? 1 : -1) * moveSpeed * Time.deltaTime;
}
}
}
If you want to press and hold make the object move you can make two buttons one for +y and the other for -y. then use Input.GetTouch to register the players input.

How can I stop my camera clipping through terrain?

Having a bit of a problem in Unity3D. I have a fly camera with both a box collider and rigidbody, and it still moves through my terrain, which has a terrain collider and a rigidbody. The thing is, it interacts with my capsules just fine, bounces them away and everything. Obvious this is the exact opposite of what I want ha ha...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FlyCamera : MonoBehaviour
{.
/*
Writen by Windexglow 11-13-10. Use it, edit it, steal it I don't care.
Converted to C# 27-02-13 - no credit wanted.
Simple flycam I made, since I couldn't find any others made public.
Made simple to use (drag and drop, done) for regular keyboard layout
wasd : basic movement
shift : Makes camera accelerate
space : Moves camera on X and Z axis only. So camera doesn't gain any height*/
float mainSpeed = 25.0f; //regular speed
float shiftAdd = 250.0f; //multiplied by how long shift is held. Basically running
float maxShift = 1000.0f; //Maximum speed when holdin gshift
float camSens = 0.25f; //How sensitive it with mouse
private Vector3 lastMouse = new Vector3(255, 255, 255); //kind of in the middle of the screen, rather than at the top (play)
private float totalRun = 1.0f;
void Update()
{
if (Input.GetKey(KeyCode.R))
{
transform.position = new Vector3(26f, 4f, 14f);
}
lastMouse = Input.mousePosition - lastMouse;
lastMouse = new Vector3(-lastMouse.y * camSens, lastMouse.x * camSens, 0);
lastMouse = new Vector3(transform.eulerAngles.x + lastMouse.x, transform.eulerAngles.y + lastMouse.y, 0);
transform.eulerAngles = lastMouse;
lastMouse = Input.mousePosition;
//Mouse camera angle done.
//Keyboard commands
float f = 0.0f;
Vector3 p = GetBaseInput();
if (Input.GetKey(KeyCode.LeftShift))
{
totalRun += Time.deltaTime;
p = p * totalRun * shiftAdd;
p.x = Mathf.Clamp(p.x, -maxShift, maxShift);
p.y = Mathf.Clamp(p.y, -maxShift, maxShift);
p.z = Mathf.Clamp(p.z, -maxShift, maxShift);
}
else
{
totalRun = Mathf.Clamp(totalRun * 0.5f, 1f, 1000f);
p = p * mainSpeed;
}
p = p * Time.deltaTime;
Vector3 newPosition = transform.position;
if (Input.GetKey(KeyCode.Space))
{ //If player wants to move on X and Z axis only
transform.Translate(p);
newPosition.x = transform.position.x;
newPosition.z = transform.position.z;
transform.position = newPosition;
}
else
{
transform.Translate(p);
}
}
private Vector3 GetBaseInput()
{ //returns the basic values, if it's 0 than it's not active.
Vector3 p_Velocity = new Vector3();
if (Input.GetKey(KeyCode.W))
{
if (transform.position.x > 2 && transform.position.x < 53)
{
if (transform.position.y > 0 && transform.position.y < 40)
{
if (transform.position.z > 5 && transform.position.z < 52)
{
p_Velocity += new Vector3(0, 0, 1);
}
}
}
}
if (Input.GetKey(KeyCode.S))
{
if (transform.position.x > 2 && transform.position.x < 53)
{
if (transform.position.y > 0 && transform.position.y < 40)
{
if (transform.position.z > 5 && transform.position.z < 52)
{
p_Velocity += new Vector3(0, 0, -1);
}
}
}
}
if (Input.GetKey(KeyCode.A))
{
if (transform.position.x > 2 && transform.position.x < 53)
{
if (transform.position.y > 0 && transform.position.y < 40)
{
if (transform.position.z > 5 && transform.position.z < 52)
{
p_Velocity += new Vector3(-1, 0, 0);
}
}
}
}
if (Input.GetKey(KeyCode.D))
{
if (transform.position.x > 2 && transform.position.x < 53)
{
if (transform.position.y > 0 && transform.position.y < 40)
{
if (transform.position.z > 5 && transform.position.z < 52)
{
p_Velocity += new Vector3(1, 0, 0);
}
}
}
}
return p_Velocity;
}
}
This flycam isn't mine so if it's not optimal for the use I'm looking for, please notify me about that too.
Basically you are. Transforming it not adding velocity thats why it is crossing the collider
You need to get reference of the rigidbody then add velocity to it
Then it won't cross the collider
You need to modify your code for that
Where you are transforming
Instead of transforming
You need to
Rigidbody.velocity= vector3(.....)
Never mind, I fixed the problem.
I ended up having Kinematic ticked on the box collider of the camera, so that must have messed it up.

How can I rotate an object to the same direction only if it's twice in a row?

The object is rotating to both directions randomly. Right or left.
The range is between 90 and 270.
But I want to add a rule that if the object rotated for example twice in a row on the left direction or the right direction the next random number should on the other side. So the object can rotate randomly only twice in a row in the same side.
If rotated twice on the same side range the next it must be rotating randomly on the other side.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateRandom : MonoBehaviour
{
bool noTarget = true;
Quaternion qTo;
Quaternion[] qTos;
float rotateSpeed = 3.0f;
float timer = 0.0f;
private void Start()
{
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
qTos = new Quaternion[100];
for(int i = 0; i < qTos.Length; i++)
{
qTos[i] = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
}
}
private void Update()
{
timer += Time.deltaTime;
if (noTarget == true)
{
if (timer > 2)
{ // timer resets at 2, allowing .5 s to do the rotating
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
timer = 0.0f;
}
transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * rotateSpeed);
}
}
}
I tried to add a qTos array and maybe to make that rule already in the Start or using this array to make the rule inside the Update.
Or maybe to make the rule directly already in the Euler line in the timer :
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
I tried this but it's not working like I wanted it keep just rotating randomly like before :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateRandom : MonoBehaviour
{
bool noTarget = true;
Quaternion qTo;
float speed = 1.25f;
float rotateSpeed = 3.0f;
float timer = 0.0f;
int counter = 0;
private void Start()
{
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
}
private void Update()
{
timer += Time.deltaTime;
if (noTarget == true)
{
if (timer > 2)
{
var rand = Random.Range(90.0f, 270.0f);
counter += 1;
if (rand >= 90 && rand <= 180)
{
if(counter == 2)
{
rand = Random.Range(180.0f, 270.0f);
counter = 0;
}
}
if (rand >= 270 && rand >= 180)
{
if (counter == 2)
{
rand = Random.Range(90.0f, 180.0f);
}
counter = 0;
}
qTo = Quaternion.Euler(new Vector3(0.0f, rand, 0.0f));
timer = 0.0f;
}
transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * rotateSpeed);
}
}
}

Categories