I have a ball that have a continuous bouncing, and I want to move it left and right in the x Axis with the mouse, so it follow the mouse's X movement.
I made the script bellow, but the ball didn't move with mouse!
Ball Script:
private Vector3 pos;
public Camera cam;
public Rigidbody Ball;
public float Speed;
public static float GlobalGravity = -9.8f;
public float GravityScale = 1.0f;
bool isforce = false;
private void Start(){
Ball = GetComponent<Rigidbody>();
Ball.useGravity = false;
}
private void FixedUpdate(){
Vector3 gravity = GlobalGravity * GravityScale * Vector3.up;
Ball.AddForce(gravity, ForceMode.Acceleration);
}
void force (){
isforce = false;
Ball.AddForce(Vector3.up * Speed, ForceMode.Impulse);
}
private void Update(){
if (isforce == true){
force();
}
if (Input.GetMouseButton(1)){
Vector3 mousePos = Input.mousePosition;
Vector3 wantedPos = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, transform.position.y, 10));
transform.position = wantedPos;
}
}
private void OnCollisionEnter(Collision collision){
isforce = true;
}
try this and let me know what happens. yours was set to right click, but i changed this one to left click, other than that i just sat the balls x to the raw x of the mouse input.
private void Update(){
if (isforce == true){
force();
}
if (Input.GetMouseButton(0)){
Vector3 mousePos = Input.mousePosition;
Vector3 wantedPos = transform.position;
wantedPos.x=Input.mousePosition.x;
transform.position = wantedPos;
}
}
When you use transform.position, the Unity Physics will no apply to the rigidBody. Find your mouse position relative to the ball and add Force in the X direction accordingly.
You have a couple of options depending on what it is you want.
Also as #Hamed answered, when using physics you don't want to update the transform directly but add force using the Rigidbody.
Force Constant relative to where the Mouse is
if (Input.GetMouseButton(0))
{
Vector2 force = Vector2.zero;
//Get the Balls current screenX position
float ballX = Camera.WorldToScreenPoint(Ball.transform.position).x;
//Check if Click was Left or Right of the Ball
if (ballX > Input.mousePosition.x)
{
//Click was Left of the Ball
force = new Vector2(-1f, 0f);
}
else if (ballX < Input.mousePosition.x)
{
//Click was Right of the Ball
force = new Vector2(1f, 0f);
}
//Adjust force amount to your suiting
Ball.Addforce(force * Time.deltaTime);
}
Force relative to the mouse movement
if (Input.GetMouseButton(0))
{
Vector2 force = Vector2.zero;
float mouseDelta = Input.GetAxis("Mouse X");
//Check if the Mouse is going Left or Right
if (mouseDelta < 0f)
{
//Click was Left of the Ball
force = new Vector2(-1f, 0f);
}
else if (mouseDelta > 0f)
{
//Click was Right of the Ball
force = new Vector2(1f, 0f);
}
// Update force relative to mouse movement
force = Mathf.Abs(mouseDelta) * force;
//Adjust force amount to your suiting
Ball.Addforce(force * Time.deltaTime)
}
Hastily written, look then write your own :)
Related
I have made a script for player movement in a 3D game in Unity.
I like how the movement works, but when I jump while moving, the player keeps moving in that direction at the same speed till it falls to the ground, which is the expected behavior for this script.
But I want to be able to move the player in the air slightly (not fully controllable.)
I'm imagining kinda like a minecraft like movement to be exact.
Any advice to improve this code would be greatly apprecciated.
This is my code.
using System.IO;
using UnityEngine;
public class VelocityMovement : MonoBehaviour
{
#region Variables
public float speed;
public float gravity;
public float maxVelocityChange;
public float jumpHeight;
public float raycastDistance;
public Rigidbody rb;
#endregion
private void Awake()
{
//gets rigidbody, freezes rotation of the rigidbody, disables unity's built in gravity system on rigidbody.
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
rb.useGravity = false;
}
private void Update()
{
//Jump system
if(Grounded())
{
if (Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = new Vector3(rb.velocity.x, CalculateJumpSpeed(), rb.velocity.z);
}
}
}
private void FixedUpdate()
{
//Moves the player when on the ground.
if (Grounded())
{
//Calculate how fast the player should be moving.
Vector3 targetVelocity = new Vector3(playerInputs.hAxis, 0, playerInputs.vAxis);
targetVelocity = transform.TransformDirection(targetVelocity);
targetVelocity *= speed ;
//Calculate what the velocity change should be
Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
//applies a force equal to the needed velocity change
rb.AddForce(velocityChange, ForceMode.VelocityChange);
}
//Adds gravity to the rigidbody
rb.AddForce(new Vector3(0, -gravity * rb.mass, 0));
}
//Checks if player is on the ground
private bool Grounded()
{
return Physics.Raycast(transform.position, Vector3.down, raycastDistance);
}
//calculates how high the player should be jumping
private float CalculateJumpSpeed()
{
return Mathf.Sqrt(2 * jumpHeight * gravity);
}
}
private void FixedUpdate()
{
//check how big the movement is. Swap SomeSmallValue with a float like 0.1f
float actualSpeed;
Vector3 velocity;
if(Grounded())
{
actualSpeed = speed;
//HERE IT IS NOT, THIS DOESN'T MATTER
velocity = rb.velocity
}
else{
actualSpeed = speed * SomeSmallValue;
//WITH THIS rb KEEPS THE SPEED IF ANY BUTTON IS PRESSED
velocity = 0;
}
//Moves the player ALWAYS.
//Calculate how fast the player should be moving.
Vector3 targetVelocity = new Vector3(playerInputs.hAxis, 0, playerInputs.vAxis);
targetVelocity = transform.TransformDirection(targetVelocity);
//if Grounded == true the movement is exactly the same than before, because actualSpeed = speed.
//If Grounded == false, the movement is so light
targetVelocity *= actualSpeed;
//Calculate what the velocity change should be
//I'VE PLACED THIS UP IN ORDER TO CALL Grounded() ONLY ONE TIME
//Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
//applies a force equal to the needed velocity change
rb.AddForce(velocityChange, ForceMode.VelocityChange);
//Adds gravity to the rigidbody
rb.AddForce(new Vector3(0, -gravity * rb.mass, 0));
}
If your code is working fine, try something like this. Just moved the grounded condition. Now the movement works also at air time. We check with that grounded bool how big the movement is.
If I understood you correctly you want to slow down what your movements do while mid air.
at least that is the case for left and right.
If I did undersand you correctly, you would make an else{} after the if(Grounded())
and go from there, may make some float variable that acts as a multiplier for you left/right control while mid air, aswell as another float variable for forward and backwards.
Inside that else you could just multiply you speed with the variables (depending on the axis) and you should get some form of slower movement there.
I hope that helped you out at least a bit.
I'm making a 2D game with two sides, left and right, so the player can only move to the left or right or jump. I made an AI as the enemy. The AI is working fine. He can go to the player to kill him.
The problem is the enemy can't rotate or face the player when he goes to kill him. I want the AI to look at the player. When the player is to the left of the enemy, the enemy should rotate to the left to look at the player. I searched many websites and I didn't get any correct solution. This is my enemy script:
public class enemy : MonoBehaviour
{
public float speed;
private Animator animvar;
private Transform target;
public GameObject effect;
public float distance;
private bool movingRight = true;
public Transform groundedDetection;
public float moveInput;
public bool facingRight = true;
void Start()
{
animvar = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
if (Vector3.Distance(target.position, transform.position) < 20)
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
else
{
transform.Translate(Vector2.right * speed * Time.deltaTime);
}
RaycastHit2D groundInfo = Physics2D.Raycast(groundedDetection.position, Vector2.down, distance);
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag.Equals("danger"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
if (col.gameObject.tag.Equals("Player"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
The game is 2D, left, right, with jump using Unity3D.
You need a function that would flip your sprite, you can do that by changing the scale of the transform, and keep a boolean to check where it's facing
bool facingRight;, so something like this
void Flip(){
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
facingRight = !facingRight;
}
and in your Update check if it needs to be flipped or not
if (Vector3.Distance(target.position,transform.position)<20)
{
transform.position=Vector2.MoveTowards(transform.position, target.position,speed*Time.deltaTime);
if(target.position.x > transform.position.x && !facingRight) //if the target is to the right of enemy and the enemy is not facing right
Flip();
if(target.position.x < transform.position.x && facingRight)
Flip();
}
Its simple enough, just get the Player x position and compare to Enemy's x position, then flip the enemy sprite accordingly
This is my Update() method in my Enemy script. This handles enemy movement and changing direction the sprite is facing:
if (moveRight )
{
transform.Translate(2 * Time.deltaTime * moveSpeed, 0, 0);
transform.localScale = new Vector2(6, 6); //6,6 is just a size that suits my sprite
}
else if (!moveRight)
{
transform.Translate(-2 * Time.deltaTime * moveSpeed, 0, 0);
transform.localScale = new Vector2(-6, 6);
}
This is my enemy Attack() method , I compare the Player X position to Enemy X position. If Player X is less( to the left of the Enemy), I flip the Enemy sprite to negative
if (transform.position.x > Player.position.x)
{
transform.localScale = new Vector2(-6, 6);
}
else if (transform.position.x < Player.position.x)
{
transform.localScale = new Vector2(6, 6);
}
I am trying to make a simple game where I am shooting a projectile when the user touches the screen, I first spawn 8 projectiles (sprites) and when the user touches the screen I would like the top projectile to fly in the touch direction. I was able to do this; However, every time I shoot, the projectile goes in the wrong direction, here is an image which will illustrate the issue.
Obviously the image is still here but the object will continue flying until it goes out of the screen and then gets destroyed.
Here is the code snippet that handles this
GameplayController.cs
if (Input.GetMouseButtonDown(0))
{
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
position = Camera.main.ScreenToWorldPoint(position);
GameObject target;
target = new GameObject();
target.transform.position = position;
Arrow comp = currentArrows[0].GetComponent<Arrow>();
comp.setTarget(target.transform);
comp.GetComponent<Arrow>().arrowSpeed = 12;
comp.GetComponent<Arrow>().shoot = true;
currentArrows.RemoveAt(0);
Destroy(target);
}
I know I am getting the mouse input here and not the phone touch and that's fine for me, later I will convert it to the touch input.
Arrow.cs
public bool shoot = false;
public float arrowSpeed = 0.0f;
public Vector3 myDir;
public float speed = 30.0f;
private Transform target;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(shoot)
{
transform.position += transform.right * arrowSpeed * Time.deltaTime;
}
}
public void setTarget(Transform targetTransform)
{
this.target = targetTransform;
Vector3 vectorToTarget = target.position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * speed);
}
private void OnBecameInvisible()
{
print("Disappeared");
Destroy(gameObject);
Gameplay.instance.isShooting = false;
}
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
I think that your problem is that you're getting the screen coordinates by click, not the world coordinates, which is actually two different things. In order to direct your projectile correctly you need to convert your screen coordinates to world like it's done here.
The next thing is how you move the projectile:
transform.position += transform.right * arrowSpeed * Time.deltaTime;
You're moving the projectile to the right and then rotating it somehow. Maybe you should try to move it with Vector3.Lerp, which will be easier and rotate it with Transform.LookAt.
When I use transform.Translate on my cube's x and z axis it moves according to pressing keys. But I want the cube to move back slowly to it's original position when user stops pressing keys and default axis are x=0 ,z=0.
public float move = 1f;
void Update ()
{
this.transform.Translate (Input.GetAxis ("Horizontal") / move, 0f, Input.GetAxis ("Vertical") / move);
}
So your best bet is to store the original position
private Vector3 _intialPosition;
private float _duration = 0.4f;
private float _startTime;
void Awake()
{
_initialPosition = transform.position;
}
void Start() {
_startTime = Time.time;
}
And then check if the key has been pressed, and if not, have it move back towards the initial position
void Update()
{
if(Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
//Logic here to move via arrows...
}
else
{
transform.position = Vector3.Lerp(transform.position, _initialPosition, (Time.time - _startTime ) / _duration);
}
}
Unity Documentation
Lerp
You could use Vector3.MoveTowards to slowly move your current transform to a target or original transform position.
private Transform original;
public float speed = 0.5f;
void Awake()
{
original = transform;
}
void Update() {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, original.position, step);
}
Unity3d documention - Vector3.MoveTowards
So here's the problem in video form
https://pbs.twimg.com/tweet_video/CPsvjgbWoAACKCp.mp4
When not moving the ship the shield moves around just fine, but when you start moving it can only drag behind you and move a little bit, which is just no good at all. I can't figure out what I've done wrong here!
public class ShieldMovement : MonoBehaviour {
public Transform target; //player shield is attaced to
public float circSpeed = 0.1f; // Speed Shield moves around ship
private Vector3 direction = Vector3.up;
private float distance = 0.8f; // distance from player so it doesn't clip
private float deadzone = 0.15f;
private float separation;
private bool canMove = true;
private Vector3 shipPos;
private Rigidbody2D tRB;
private Rigidbody2D rb;
// Use this for initialization
void Start ()
{
tRB = target.GetComponent<Rigidbody2D>();
rb = GetComponent<Rigidbody2D>();
}
void OnCollisionEnter2D (Collision2D other)
{
canMove = false;
}
void OnCollisionStay2d(Collision2D other)
{
canMove = false;
}
void OnCollisionExit2D (Collision2D other)
{
canMove = true;
}
// Update is called once per frame
void Update () {
float rh = Input.GetAxisRaw("rightH");
float rv = Input.GetAxisRaw("rightV");
shipPos = target.position;
separation = Mathf.Abs((transform.position - shipPos).magnitude);
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
Vector3 targetDir = new Vector3(rh, rv, 0.0f);
direction = Vector3.Slerp(transform.position-shipPos, targetDir, circSpeed);
}
Ray ray = new Ray(shipPos, direction); // cast ray in direction of point on circle shield is to go
if(canMove)
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
if(separation != distance) //If the shield get torn away from the ship
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
float angleY = transform.position.y - shipPos.y;
float angleX = -(transform.position.x - shipPos.x);
float angle = Mathf.Atan2 (angleY, angleX) * Mathf.Rad2Deg-90; //Get angle
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
transform.rotation = Quaternion.AngleAxis(angle,Vector3.forward*-1); // keep shield facing outwards in respect to player
}
}
void FixedUpdate ()
{
if(!canMove)
{
tRB.velocity = new Vector2(0.0f, 0.0f);
rb.velocity = new Vector2(0.0f, 0.0f);
}
}
Thanks a million for any help :)
You need to move the shield along with the ship. You can do this by adding the ship velocity to the shield.
Something like:
shipPos = target.position;
transform.position += shipVelocity;
separation = Mathf.Abs((transform.position - shipPos).magnitude);
Or make the shield a child object of the ship.
OK, so all I needed to do was to make the shield a child AND get rid of the conditional statement around the transform.rotation so it wouldn't inherit the parent rotation and ruin the shield. It's the little things!