Rotating avatar at certain x coordinate Unity - c#

I have a problem with turning my avatar at a certain position on the map. The character moves back and forth, but he doesn't want to rotate at coordinates i entered. What am i doing wrong?
this is my code:
sing System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AvatarPingPong : MonoBehaviour {
// Use this for initialization
public float speed;
public float startXCord, endXCord;
float endTrunx, startTurnx;
public GameObject obj;
Vector3 EndPoint, StartPoint;
void Start () {
EndPoint = transform.position;
endXCord = EndPoint.x;
endTrunx = EndPoint.x - 2f;
StartPoint = transform.position;
StartPoint.x = startXCord;
startTurnx = StartPoint.x + 2f;
}
// Update is called once per frame
void Update () {
transform.position = new Vector3(PingPong (Time.time * speed, startXCord, endXCord ), transform.position.y, transform.position.z);
if (transform.position.x == startTurnx ) {
Debug.Log("start Check");
obj.transform.Rotate(0f, 180f, 0f);
}
if (transform.position.x == endTrunx ) {
obj.transform.Rotate(0f, 180f, 0f);
Debug.Log("einde check");
}
}
//function to change the default starting value of (0, 0, 0) to any value
float PingPong(float t, float minLength, float maxLength) {
return Mathf.PingPong(t, maxLength-minLength) + minLength;
}
}

I believe the problem is that you're trying to flip your avatar once he reaches a particular x-coordinate, but he may never reach that EXACT coordinate. if (transform.position.x == startTurnx) will only return true if the two values are EXACTLY the same, and your avatar isn't actually moving smoothly across the screen. He's actually jumping minute amounts every frame, so he may never land on exactly that point.
Instead, my recommendation would be to compare his new position against his old position to see which direction he's traveling in and flip him when he changes direction. Some code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AvatarPingPong : MonoBehaviour {
// Use this for initialization
public float speed;
public float startXCord, endXCord;
float endTrunx, startTurnx;
public GameObject obj;
Vector3 EndPoint, StartPoint;
//I'm going to assume you start it moving left. You may have to change this
bool goingLeft = false;
void Start () {
EndPoint = transform.position;
endXCord = EndPoint.x;
endTrunx = EndPoint.x - 2f;
StartPoint = transform.position;
StartPoint.x = startXCord;
startTurnx = StartPoint.x + 2f;
}
// Update is called once per frame
void Update () {
float prevX = transform.position.x;
float newX = PingPong (Time.time * speed, startXCord, endXCord );
transform.position = new Vector3(newX, transform.position.y, transform.position.z);
if (newX > prevX) {
//avatar is moving to the right, check to see if that's the direction it was going last Update
if (goingLeft) {
Debug.Log("Flipping Right");
obj.transform.Rotate(0f, 180f, 0f);
goingLeft = false;
}
}else if (newX < prevX){
//avatar is moving to the left, check to see it that's the direction it was going last Update
if (!goingLeft) {
Debug.Log("Flipping Left");
obj.transform.Rotate(0f, 180f, 0f);
goingLeft = true;
}
}
}
//function to change the default starting value of (0, 0, 0) to any value
float PingPong(float t, float minLength, float maxLength) {
return Mathf.PingPong(t, maxLength-minLength) + minLength;
}
}

Related

unity c# issue unable to get perfect position of a enemy in unity c# script using transform.position

when I command or set an enemy to go left and then at reaching a particular state or position i say my enemy to go right but it is not going right and not reaching to perfect position here is the code I think there is no issue in the code but it is not working properly so here are some images of the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enem : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position = transform.position + new Vector3(-3f, 0f, 0f)* 1 * Time.deltaTime;
if (transform.position.x > -29)
{
transform.position = transform.position + new Vector3(3f, 0f, 0f) * 1 * Time.deltaTime;
}
}
}
Before adding any bool logic, try first simply moving your element:
using UnityEngine;
public class SimeMoveMove : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
transform.position += new Vector3(3f, 0f, 0f);
}
}
}
I smiled a little the moment I understood what you were trying to do.
I wrote the code imagining the result you were trying to make!
Create a cube, attach this code as component, and run the game.
// Gift for you friend
public class MoveTest : MonoBehaviour
{
private int _direction = 1;
void Start()
{
transform.position = Vector3.zero;
}
void Update()
{
Vector3 position = transform.position;
int direction = ShouldWeSwitchDirection(position.x, 0f);
if (direction != 0)
{
_direction = direction;
}
transform.position += _direction * new Vector3(3f, 0f, 0f) * 3f * Time.deltaTime;
}
private int ShouldWeSwitchDirection(float value, float center = 0f)
{
float direction = Mathf.Sign(value - center);
float distance = Mathf.Abs(value - center);
// If X Position is larger than 29
if (Mathf.Abs(distance) > 29)
{
// If X is on right side
if (direction >= 0)
{
return -1;
}
// If X is on left side.
else
{
return 1;
}
}
else
{
return 0;
}
}
}

Rotate 2D Sprite with Virtual Joystick

I am trying to rotate a GameObject along z-axis using Joystick, but its rotating y-axis. I might missed some math calculation. Any Help??
Reference Image
void FixedUpdate()
{
// get input from joystick
// get input from joystick
rightJoystickInput = rightJoystick.GetInputDirection();
float xMovementRightJoystick = rightJoystickInput.x; // The horizontal movement from joystick 02
float zMovementRightJoystick = rightJoystickInput.y; // The vertical movement from joystick 02
// if there is only input from the right joystick
if (rightJoystickInput != Vector3.zero)
{
// calculate the player's direction based on angle
float tempAngle = Mathf.Atan2(zMovementRightJoystick, xMovementRightJoystick);
xMovementRightJoystick *= Mathf.Abs(Mathf.Cos(tempAngle));
zMovementRightJoystick *= Mathf.Abs(Mathf.Sin(tempAngle));
// rotate the player to face the direction of input
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
if (lookDirection != Vector3.zero)
{
rotationTarget.localRotation = Quaternion.Slerp(rotationTarget.localRotation, Quaternion.LookRotation(lookDirection) * Quaternion.Euler(0, 45f, 0), rotationSpeed * Time.deltaTime);
}
}
}
You don't need most of the code in your question and this is really simple.
1.Find the angle with Mathf.Atan2 then multiple it with Mathf.Rad2Deg.
2.Use Quaternion.Euler(new Vector3(0, 0, angle)) to get the rotation then apply it to the Object.
This should be one in the Update function not FixedUpdate because FixedUpdate is used to move Rigidbody Objects.
public Transform rotationTarget;
public bool flipRot = true;
void Update()
{
rightJoystickInput = rightJoystick.GetInputDirection();
float horizontal = rightJoystickInput.x;
float vertical = rightJoystickInput.y;
float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rotationTarget.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
If using Rigidbody2D then use Rigidbody2D.MoveRotation in the FixedUpdate function. The rest of the code stays the-same.
public Rigidbody2D rg2d;
public bool flipRot = true;
void FixedUpdate()
{
rightJoystickInput = rightJoystick.GetInputDirection();
float horizontal = rightJoystickInput.x;
float vertical = rightJoystickInput.y;
float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rg2d.MoveRotation(angle);
}
EDIT:
But only the problem is when i leave joystick its rotation is setting
to 0 instantly which looks too odd. How can i fix it?
You have to detect when you release the joystick in OnPointerUp then slowly lerp the joystick thump back to the Zero position. You also have to lerp the current target object angle to zero or to its default value and this should be done in a coroutine function. When OnPointerDown is called, stop the current coroutine function. Prevent the code in FixedUpdate from running when finger is released so that it won't interfere with the coroutine function.
For the sake of completeness, below is the combination of a Joystick code and the Rigidbody answer above:
public class VirtualJoystickController : MonoBehaviour,
IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image bgImg;
private Image joystickImg;
public float mas_distance = 7f;
void Start()
{
bgImg = GameObject.Find("JoystickBGImage").GetComponent<Image>(); // the joysticks background
joystickImg = GameObject.Find("Joystickthumb").GetComponent<Image>(); // the joystick object to use
}
private Vector3 _inputDirection = Vector3.zero;
//the movementDirection
public Vector3 joystickInputDirection
{
set
{
//Change only if value is different from old one
if (_inputDirection != value)
{
_inputDirection = value;
Debug.Log("Dir: " + _inputDirection);
}
}
get
{
return _inputDirection;
}
}
public void OnDrag(PointerEventData eventData)
{
dragJoyStick(eventData);
}
void dragJoyStick(PointerEventData eventData)
{
Vector3 tempDir = Vector3.zero;
Vector2 pos = Vector2.zero;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle
(bgImg.rectTransform,
eventData.position,
eventData.pressEventCamera,
out pos))
{
pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
pos.y = (pos.y / bgImg.rectTransform.sizeDelta.y);
float x = (bgImg.rectTransform.pivot.x == 1) ? pos.x * 2 + 1 : pos.x * 2 - 1;
float y = (bgImg.rectTransform.pivot.y == 1) ? pos.y * 2 + 1 : pos.y * 2 - 1;
tempDir = new Vector3(x, y, 0);
if (tempDir.magnitude > 1)
{
tempDir = tempDir.normalized;
}
joystickImg.rectTransform.anchoredPosition = new Vector3(
tempDir.x * (bgImg.rectTransform.sizeDelta.x / mas_distance),
tempDir.y * (bgImg.rectTransform.sizeDelta.y / mas_distance));
joystickInputDirection = tempDir;
}
}
public void OnPointerDown(PointerEventData eventData)
{
released = false;
//Stop current coroutine
if (retCoroutine != null)
StopCoroutine(retCoroutine);
if (eventData.pointerCurrentRaycast.gameObject == bgImg.gameObject ||
eventData.pointerCurrentRaycast.gameObject == joystickImg.gameObject)
{
OnDrag(eventData);
}
}
public void OnPointerUp(PointerEventData eventData)
{
released = true;
//Stop current coroutine then start a new one
if (retCoroutine != null)
StopCoroutine(retCoroutine);
retCoroutine = StartCoroutine(SlowReturn(returnTime));
}
IEnumerator SlowReturn(float duration)
{
RectTransform thumbstickTransform = joystickImg.rectTransform;
Vector3 toPosition = Vector3.zero;
float counter = 0;
//Get the current position of the object to be moved
Vector2 currentThumb = thumbstickTransform.anchoredPosition;
while (counter < duration)
{
counter += Time.deltaTime;
//Slowly returns thumbstick
Vector2 tempThumbStickVal = Vector2.Lerp(currentThumb, toPosition, counter / duration);
joystickInputDirection = tempThumbStickVal;
thumbstickTransform.anchoredPosition = tempThumbStickVal;
//Slowly returns the target Object to original pos
float tempTargetObjAngle = Mathf.Lerp(angle, originalAngle, counter / duration);
rg2d.MoveRotation(tempTargetObjAngle);
yield return null;
}
}
public float returnTime = 1.0f;
public Rigidbody2D rg2d;
public bool flipRot = true;
const float originalAngle = 0;
bool released = true;
float angle;
Coroutine retCoroutine;
void FixedUpdate()
{
if (released)
return;
float horizontal = joystickInputDirection.x;
float vertical = joystickInputDirection.y;
angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rg2d.MoveRotation(angle);
}
}
your function calculates a point where you want to look at:
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
this point is on the XZ plane, that is why the car rotates on Y axis
if you want to rotate on Z axis, calculate a point on XY plane like this:
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.y += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
PS: i don't know why you multiply with Quaternion.Euler(0, 45f, 0) - that is a constant angle on Y axis, it just means that each lookDirection will be rotated for 45 degrees - i would have to see your scene to know why you need this...

How to store mouse move position value in array?

Here I am trying to Store mouse position value in array so that my ball will move according to that array value.
Is there any better way to do this as I am stuck at the end of the project. Your help will be appreciated.
using UnityEngine;
using System.Collections;
[RequireComponent (typeof(Ball))]
public class BallDragLaunch : MonoBehaviour {
//MyScript
//public float powePerPixel;
public float maxPower;
public float sensitivity;
//private Vector3 touvhPos;
private bool isRolling;
private float rotation = 10f;
//
private Rigidbody rg;
private Vector3 dragStart, dragFlick, dragEnd;
private float startTime, endTime, flickTime;
private Ball ball;
public Rigidbody ballRigid;
public float [] mousePositionX, mousePositionY;
// Use this for initialization
void Start () {
ball = GetComponent<Ball> ();
//MyScript
isRolling = false;
//ballRigid = this.ball;
}
public void MoveStart (float speed) {
if (Input.GetAxis ("Mouse X") > 0) {
if (! ball.inPlay) {
dragStart = Input.mousePosition;
//transform.position = new Vector3(Mathf.Clamp(ball.transform.position.x + speed, ball.transform.position.x - speed, 0), -42.0f, 42.0f);
float xPos = Mathf.Clamp (ball.transform.position.x + speed, -42.0f, 42.0f);
float yPos = ball.transform.position.y;
float zPos = ball.transform.position.z;
ball.transform.position = new Vector3 (xPos, yPos, zPos);
Debug.LogError("Right");
}
}
if (Input.GetAxis ("Mouse X") < 0) {
if (! ball.inPlay) {
dragStart = Input.mousePosition;
//transform.position = new Vector3(Mathf.Clamp(ball.transform.position.x + speed, ball.transform.position.x - speed, 0), -42.0f, 42.0f);
float xPos = Mathf.Clamp (ball.transform.position.x - speed, -42.0f, 42.0f);
float yPos = ball.transform.position.y;
float zPos = ball.transform.position.z;
ball.transform.position = new Vector3 (xPos, yPos, zPos);
Debug.LogError("Left");
}
}
}
public void DragStart () {
if (! ball.inPlay) {
// Capture time & position of drag start
dragStart = Input.mousePosition;
startTime = Time.time;
Debug.LogError("Drag Start");
}
}
public void DragEnd () {
if (Input.GetAxis ("Mouse X") < 0.2f) {
if (! ball.inPlay) {
// Launch the ball
dragEnd = Input.mousePosition;
endTime = Time.time;
float dragDuration = endTime - startTime;
float launchSpeedX = (dragEnd.x - dragStart.x) / dragDuration;
float launchSpeedZ = (dragEnd.y - dragStart.y) / dragDuration;
transform.Rotate (0, rotation, 0);
Vector3 launchVelocity = new Vector3 (launchSpeedX * sensitivity, 0, launchSpeedZ);
ball.Launch (launchVelocity);
Debug.Log ("Drag End Ball Launch");
Debug.LogError("Left Ball Movemet ");
}
}
if (Input.GetAxis ("Mouse X") > 0.2f) {
if (! ball.inPlay) {
// Launch the ball
dragEnd = Input.mousePosition;
endTime = Time.time;
float dragDuration = endTime - startTime;
float launchSpeedX = (dragEnd.x - dragStart.x) / dragDuration;
float launchSpeedZ = (dragEnd.y - dragStart.y) / dragDuration;
transform.Rotate (0, rotation, 0);
Vector3 launchVelocity = new Vector3 (launchSpeedX * sensitivity, 0, launchSpeedZ);
ball.Launch (launchVelocity);
Debug.Log ("Drag End Ball Launch");
Debug.LogError("Right Ball Movemet ");
}
}
if (Input.GetAxis ("Mouse X") >= 0 ) {
if (! ball.inPlay) {
// Launch the ball
dragEnd = Input.mousePosition;
endTime = Time.time;
float dragDuration = endTime - startTime;
float launchSpeedX = (dragEnd.x - dragStart.x) / dragDuration;
float launchSpeedZ = (dragEnd.y - dragStart.y) / dragDuration;
transform.Rotate (0, rotation, 0);
Vector3 launchVelocity = new Vector3 (launchSpeedX * sensitivity, 0, launchSpeedZ);
ball.Launch (launchVelocity);
//Debug.Log ("Drag End Ball Launch");
Debug.LogError("Mid Ball Right Move");
}
}
}
}
in response to Lajos Arpad answer
I have to say use lists instead of arrays. They are so much better to work with, and you dont need to know how many variables will go into the list before hand.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent (typeof(Ball))]
public class BallDragLaunch : MonoBehaviour {
//MyScript
public List<Vector3> mousPositions;
in your code you can treat the list exactly the same way you would treat an array. To add mouse positions to the list simply write
mousePosition.Add(Input.mousePosition);
Your ball is moving in three dimensions and you use Vector3 for them. On the other hand, you have two arrays of float[] called mousePositionX and mousePositionY, respectively. You could use a Vector3[] for that purpose. This is how you declare it:
public Vector3[] mousePositions;
If you know its size, which, for instance is n, then this is how you initialize it:
mousePositions = new Vector3[n];
and if you want to set its i'th value, then this is how you can do it:
mousePositions[i] = ball.transform.position;
Problems you need to solve:
- you need to know the size of the array before you initialize it
- you need to keep track of the first index where you have not put a valid position yet
I believe you will not know the size of the array in advance and you also do not want to always keep track of indexes. So I would use a Queue if I were you. Don't worry, it is not difficult. Try to work with the array solution first to have some success and when you see it works, create a backup of your code and try experimenting with a Queue<Vector3>. Believe me, it is worth it.

Shooting to the center of the screen

This code is used to fire laser straight forward.
using UnityEngine;
using System.Collections;
public class LeftGun : MonoBehaviour {
public Rigidbody laser;
public AudioClip LaserShot;
float shotSpeed = 0.1f;
bool canShoot = true;
// Update is called once per frame
void Update () {
if(!Engine.escape)
{
shotSpeed -= Time.deltaTime;
if(shotSpeed <= 0f)
canShoot = true;
if(Input.GetButton("Fire1") && canShoot)
{
shotSpeed = 0.1f;
canShoot = false;
PlayerGUI.ammunition--;
audio.PlayOneShot(LaserShot);
Rigidbody clone = Instantiate(laser,transform.position, transform.rotation) as Rigidbody;
clone.velocity = transform.TransformDirection(-80, 0, 0);
Destroy(clone.gameObject, 3);
}
}
}
I would like to fire to the center of the screen (where crosshair is). How can I achive that?
Example image: http://i.imgur.com/EsVsQNd.png
You can use Camera.ScreenPointToRay. To get the ray from center of the main camera, use:
float x = Screen.width / 2f;
float y = Screen.height / 2f;
var ray = Camera.main.ScreenPointToRay(new Vector3(x, y, 0));
clone.velocity = ray.direction * laserSpeed;
laserSpeed is a public float which is the speed with which you want the laser to travel at. You can change it according to your needs (for the code you provided, laserSpeed would be 80).

How do I jump a fix distance in Unity 3d?

I have a Controller which moves my object diagonally. The left arrow should move the player forward and to the left 45 degrees, and the right arrow the same to the right. I would like to move the player relatively to its current position. Right now it moves relatively to the point(0,0,0).
My code:
public class JollyJumper : MonoBehaviour {
protected CharacterController control;
public float fTime = 1.5f; // Hop time
public float fRange = 5.0f; // Max dist from origin
public float fHopHeight = 2.0f; // Height of hop
private Vector3 v3Dest;
private Vector3 v3Last;
private float fTimer = 0.0f;
private bool moving = false;
private int number= 0;
private Vector2 direction;
public virtual void Start () {
control = GetComponent<CharacterController>();
if(!control){
Debug.LogError("No Character Controller");
enabled=false;
}
}
void Update () {
if (fTimer >= fTime&& moving) {
var playerObject = GameObject.Find("Player");
v3Last = playerObject.transform.position;
Debug.Log(v3Last);
v3Dest = direction *fRange;
//v3Dest = newVector* fRange + v3Last;
v3Dest.z = v3Dest.y;
v3Dest.y = 0.0f;
fTimer = 0.0f;
moving = false;
}
if(Input.GetKeyDown(KeyCode.LeftArrow)){
moving = true;
direction = new Vector2(1.0f, 1.0f);
number++;
}
if(Input.GetKeyDown(KeyCode.RightArrow)){
moving = true;
direction = new Vector2(-1.0f, 1.0f);
number++;
}
if(moving){
Vector3 v3T = Vector3.Lerp (v3Last, v3Dest, fTimer / fTime);
v3T.y = Mathf.Sin (fTimer/fTime * Mathf.PI) * fHopHeight;
control.transform.position = v3T;
fTimer += Time.deltaTime;
}
}
}
How can resolve this? Any ideas? Thanks a lot!
The short answer is: you hard-coded two locations you want to jump to: points (1, 1) and (-1, 1). You should create new Vector each time you start jumping. Replace each
direction = new Vector2(1.0f, 1.0f);
with this line:
v3Dest = transform.position + new Vector3(1.0f, 0, 1) * fRange;
and it should work.
While I'm on it, there are some other things I want to point:
There is a lot of floating point error after each jump. Notice that in your code v3T will never be equal to v3Dest (you never actually reach your destination), because you switch the moving flag earlier. You should explicitly set your position to v3Dest when the jump is over.
You are checking jump timers etc. every frame. A more elegent solution is to start a coroutine.
You use a sinusoid as your jump curve, which looks ok, but using a parabola would be conceptually more correct.
Right now it is possible to start next jump mid-air (I'm not sure whether it is intended or not)
Here is some code you may use that avoids those problems:
using System.Collections;
using UnityEngine;
public class Jumper : MonoBehaviour
{
#region Set in editor;
public float jumpDuration = 0.5f;
public float jumpDistance = 3;
#endregion Set in editor;
private bool jumping = false;
private float jumpStartVelocityY;
private void Start()
{
// For a given distance and jump duration
// there is only one possible movement curve.
// We are executing Y axis movement separately,
// so we need to know a starting velocity.
jumpStartVelocityY = -jumpDuration * Physics.gravity.y / 2;
}
private void Update()
{
if (jumping)
{
return;
}
else if (Input.GetKeyDown(KeyCode.LeftArrow))
{
// Warning: this will actually move jumpDistance forward
// and jumpDistance to the side.
// If you want to move jumpDistance diagonally, use:
// Vector3 forwardAndLeft = (transform.forward - transform.right).normalized * jumpDistance;
Vector3 forwardAndLeft = (transform.forward - transform.right) * jumpDistance;
StartCoroutine(Jump(forwardAndLeft));
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
Vector3 forwardAndRight = (transform.forward + transform.right) * jumpDistance;
StartCoroutine(Jump(forwardAndRight));
}
}
private IEnumerator Jump(Vector3 direction)
{
jumping = true;
Vector3 startPoint = transform.position;
Vector3 targetPoint = startPoint + direction;
float time = 0;
float jumpProgress = 0;
float velocityY = jumpStartVelocityY;
float height = startPoint.y;
while (jumping)
{
jumpProgress = time / jumpDuration;
if (jumpProgress > 1)
{
jumping = false;
jumpProgress = 1;
}
Vector3 currentPos = Vector3.Lerp(startPoint, targetPoint, jumpProgress);
currentPos.y = height;
transform.position = currentPos;
//Wait until next frame.
yield return null;
height += velocityY * Time.deltaTime;
velocityY += Time.deltaTime * Physics.gravity.y;
time += Time.deltaTime;
}
transform.position = targetPoint;
yield break;
}
}

Categories