First of all thank you for your time. I'm quite new in this so I'm struggling a bit. I'm trying to make a drag and release shooter which doesn't really depend on colliders or raycasts but solely depends on mouse delta and camera position. The way I'm trying to have it done is I'm mapping mouse position (x,y) to velocity direction such as new Vector3(mouseX, 0f, mouseY) then rotating it about Y axis to match the visual drag on the screen.
void OnMouseUp()
{
releasePos = Input.mousePosition;
Vector2 m_direction = releasePos - initialPos;
Vector3 direction = new Vector3(m_direction.x, 0, m_direction.y);
float userDrag = Mathf.Clamp(direction.magnitude, 0f, maxVelocity);
direction = Translation(direction);
direction = Vector3.Normalize(direction);
rigidbody.velocity = (direction * userDrag) * force;
}
private Vector3 Translation(Vector3 direction)
{
Vector3 camPos = Camera.main.transform.position;
camPos.y = 0;
float angle = Vector3.Angle(new Vector3(0f, 0f, 1f), camPos);
Quaternion translatedAngle = Quaternion.AngleAxis(angle, Vector3.up);
direction = translatedAngle * direction;
But as the angle changes it kinda fails to deliver what I'm asking for. Is there a way I can avoid bunch of if, else statements for the angle value or a shorter way of doing this?
Example
OnMouseUp is fundamentally a collider method.
Meaning, the mouse MUST be over the GameObject's collider for the GameObject this code is attached to. If you want to move away from using colliders, then you need to move away from this method.
The generic works-anywhere way of saying "is the mouse button up or down?" is the static methods available in the Input class:
Input.GetMouseButtonDown() True on the single frame after the mouse button is depressed
Input.GetMouseButtonUp() True on the single frame after the mouse button is released
Input.GetMouseButton() True any frame the mouse button is depressed (otherwise false)
So I think I have a solution finally and I thought I'd share it for people who might be interested.
The challenge was to rotate mouse delta's direction according to camera position so it gives a natural vibe to the player when dragging and releasing the ball for putting. I did some tests to see where my code had problems rotating delta direction properly(so it matches the screen) and realized when I'm "looking from" (0,0,1) for comparison while the camera's x position is positive it works fine. But when x is negative it doesn't because Vector3.Angle doesn't return a negative value as far as I'm concerned so I just multiplied the result with minus. Seems to work.
Here is the final code:
private void Start()
{
rigidbody = GetComponent<Rigidbody>();
}
void OnMouseDown()
{
ballPos = Input.mousePosition;
}
void OnMouseUp()
{
Vector2 m_direction = Input.mousePosition - ballPos;
Vector3 direction = new Vector3(m_direction.x, 0, m_direction.y);
float userDrag = Mathf.Clamp(direction.magnitude, 0f, maxVelocity);
direction = Translation(direction);
direction = Vector3.Normalize(direction);
rigidbody.velocity = (direction * userDrag) * force;
}
private Vector3 Translation(Vector3 direction)
{
float angle = GetAngle();
Quaternion translatedAngle = Quaternion.AngleAxis(angle, Vector3.up);
direction = translatedAngle * direction;
return direction;
}
private float GetAngle()
{
Vector3 camPos = Camera.main.transform.position;
camPos.y = 0;
if (camPos.x > 0)
{
angle = Vector3.Angle(Vector3.forward, camPos);
}
else if (camPos.x <0)
{ angle = -Vector3.Angle(Vector3.forward, camPos); }
return angle;
}
please do share if you have suggestions regarding the code.
Related
Currently, my gun is able to instantiate new bullets that work fine (they have velocity and shoot towards the mouse's position). However, if the mouse is close to the player, I noticed the velocity is drastically lessened because it is targeting the mouse's position instead of the general direction.
Is there a way to get the angle from the player to the mouse, as well as apply velocity to the bullet, without it going exactly to the mouse's position?
public GameObject bullet;
public GameObject player;
// All the following is within an update function
//Gets the mouse position, and assigns direction from gun to mouse
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = mousePosition - transform.position;
float angle = Vector2.SignedAngle(Vector2.right, direction);
Vector2 PlayerDimensions = player.transform.lossyScale;
Vector2 PlayerLocation = player.transform.position;
//If the Gun weapon type is selected
if (weaponType == 2)
{
// Is used to flip the player sprite based on if the gun is facing left or right
if (PlayerLocation.x > mousePosition.x)
{
PlayerDimensions.x = -1;
player.transform.localScale = new Vector2(PlayerDimensions.x, PlayerDimensions.y);
}
else if (PlayerLocation.x < mousePosition.x)
{
PlayerDimensions.x = 1;
player.transform.localScale = new Vector2(PlayerDimensions.x, PlayerDimensions.y);
}
// Aims the gun based on if player is facing left or right
if (player.transform.lossyScale.x > 0)
{
transform.eulerAngles = new Vector3(0, 0, angle);
}
else if (player.transform.lossyScale.x < 0)
{
transform.eulerAngles = new Vector3(0, 0, 180 + angle);
}
}
if (Input.GetMouseButtonDown(0) && weaponType == 2)
{
Debug.Log("Shoot");
Vector3 myPos = new Vector3(transform.position.x, transform.position.y);
GameObject Bullet = Instantiate(bullet, myPos, Quaternion.identity);
Physics2D.IgnoreCollision(Bullet.GetComponent<BoxCollider2D>(), player.GetComponent<BoxCollider2D>(), GameObject.Find("blue_bullet_medium(Clone)"));
Bullet.GetComponent<Rigidbody2D>().velocity = new Vector2(direction.x, direction.y);
}
You can use normalized vector and speed instead of just direction to get constant bullet speed. In code it will be like this:
Vector2 direction = mousePosition - transform.position;
direction.Normalize();
Vector2 bulletVelocity = direction * _speed; // assume _speed can be tuned
The normalized vector will always have length 1, so the speed will not depend on the distance from the player to the cursor position
I have two GameObjects with a box collider. One is the player, moved with a fixed velocity towards the other. The collision stops the player (the Poo character ;D)
But they overlap, you can see it here:
I don't know why this is happening. Colliding with the top or bottom works just fine...The same effect happens from the left side. The green block has just a collider, no RigidBody.
Gif:
Another Gif, with MovePosition() ... Colliding fromt the top works, but "reentering" stops the character. Why?!:
GIF, moving up and down is okay, left and right at the top of the blocks slows him down. Weird...
Movement Script:
public class PlayerController : MonoBehaviour
{
public float Speed = 10f;
private Rigidbody2D rb2D;
private Vector2 DirectionLeft;
private Vector2 DirectionRight;
private Vector2 DirectionUp;
private Vector2 DirectionDown;
private Vector2 CurrentDirection;
// Use this for initialization
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
DirectionLeft = new Vector2(Speed*-1, 0);
DirectionRight = new Vector2(Speed, 0);
DirectionUp = new Vector2(0, Speed * -1);
DirectionDown = new Vector2(0, Speed);
CurrentDirection = DirectionLeft;
}
void SetAnimationDirection()
{
Vector3 scale = transform.localScale;
if (CurrentDirection == DirectionLeft)
scale.x = 1;
else
scale.x = -1;
transform.localScale = scale;
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
if (moveHorizontal > 0)
CurrentDirection = DirectionRight;
if (moveHorizontal < 0)
CurrentDirection = DirectionLeft;
if (moveVertical < 0)
CurrentDirection = DirectionUp;
if (moveVertical > 0)
CurrentDirection = DirectionDown;
Debug.Log(CurrentDirection);
SetAnimationDirection();
rb2D.velocity = CurrentDirection;
}
The solution to the first problem (overlapping):
I used transform.localScale = scale to change the direction of the sprite on every FixedUpdate() and also forgot to update the factor of the scale, since I added a new extension, which resized my object by 1 more Unity unit.
The other problem (getting stuck at the edge) is solved adding setting the Edge Radius of the Collider 2D to something below 1.0f (e.g 0.09f) and also resize the bounding box. This will prevent the object from getting stuck at the edges, because the bounding box edges are now rounded.
My goal is to make this line rotate around the face while pointing to my cursor each frame.
What ive gotten until now is this:
void Update () {
float AngleOfMouse = GetAngle (MiddleOfTheFace.position);
transform.RotateAround (MiddleOfTheFace.position, Vector3.back, AngleOfMouse);
}
void GetAngle(){
Vector2 MousePosition = Input.mousePosition;
Vector3 ScreenPoint = Camera.main.WorldToScreenPoint(point);
Vector2 BulletOffset = new Vector2(MousePosition.x - ScreenPoint.x, MousePosition.y - ScreenPoint.y);
float Angle = Mathf.Atan2(BulletOffset.y, BulletOffset.x) * Mathf.Rad2Deg;
return Angle;
}
But it just rotates weirdly super fast and doesn't stop when its pointing at my cursor. Am I not approaching this right? Thanks in advance!
I'm making a 2D platformer game where the player has an arm that points towards the mouse cursor. This mechanism is used to aim the player's weapon. However, I am experiencing some glitches when rotating the arm.
I know the reason why I am getting these errors: The arm (in the hierarchy) is a child of the player, and what I'm doing to the player is flipping (inverting) its transform.localScale.x value whenever it moves in a specified direction, so that the player sprite looks in the given direction. Since the arm is a child of the player, its own transform is flipped as well, making it look in the same direction as the player, which is what I want. However, this causes some errors with the arm rotation. Since the arm's transform.localScale.x value is flipped, the rotation is all messed up, and I can't figure out how to solve it.
Here are some example scripts for moving the player and arm. They are simplified so that you can read it better.
// Update is called once per frame
void Update () {
var input = Input.GetAxis("Horizontal");
if(input > 0) {
if(!facingRight) {
ChangeOrientation(gameObject, new Vector3(-1,1,1));
facingRight = !facingRight;
}
}
if(input < 0) {
if(facingRight) {
ChangeOrientation(gameObject, new Vector3(-1,1,1));
facingRight = !facingRight;
}
}
rbody.velocity = new Vector2(speed * input, rbody.velocity.y);
}
public static void ChangeOrientation (GameObject g, Vector3 changeBy) {
var newTransform = g.transform.localScale;
newTransform.x *= changeBy.x;
newTransform.y *= changeBy.y;
newTransform.z *= changeBy.x;
g.transform.localScale = newTransform;
}
And my arm rotation script:
void Update () {
//rotation
Vector3 mousePos = Input.mousePosition;
mousePos.z = 0;
Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0,
(PlayerRunMovementController.facingRight ? angle : angle )));
}
Thanks for any help you can offer.
Okay, So I have come this far:
public class CameraScript : MonoBehaviour {
public void RotateCamera()
{
float x = 5 * Input.GetAxis("Mouse X");
float y = 5 * -Input.GetAxis("Mouse Y");
Camera.mainCamera.transform.parent.transform.Rotate (y,x,0);
}
}
My camera has a parent which I rotate based on my mouse position. The only problem is that I can only swipe with the mouse to rotate the object. How can I rotate the object which is my camera is attached to based on my mouse position if I just click next to the object. Thanks in advance!
The value will be in the range -1...1 for keyboard and joystick input.
If the axis is setup to be delta mouse movement, the mouse delta is
multiplied by the axis sensitivity and the range is not -1...1. Unity Document
Note: This link is usefull please check it.
So you need to change your code like this.
public void RotateCamera()
{
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); // Gets mouse position to Unity World coordinate system
Camera.mainCamera.transform.parent.transform.Rotate (mousePosition);
}
if there are problem you can do like this
public void RotateCamera()
{
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y,0);
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(position); // Gets mouse position to Unity World coordinate system
Camera.mainCamera.transform.parent.transform.Rotate (mousePosition);
}
one more option is rotateTowards.
public float speed=10; //any value > 0
public void RotateCamera()
{
Vector3 targetDir = Camera.main.ScreenToWorldPoint(Input.mousePosition) - Camera.mainCamera.transform.parent.transform.position;
float step = speed * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0F);
Camera.mainCamera.transform.parent.transform.rotation = Quaternion.LookRotation(newDir);
}
Maybe some syntax errors, i don't check them.