When player shoot, the bullet fly to the center of the screen. But if player stay too close to some object, then bullet hits it not in the center, because it flies from the gun on the right side of the screen. How can I fix this?
public Rigidbody projectile;
public int speed = 50;
public Transform startBulletPosition;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Rigidbody clone;
clone = Instantiate(projectile, startBulletPosition.position, transform.rotation) as Rigidbody;
var centre = new Vector3(0.5f, 0.5f, 0f);
var ray = Camera.main.ViewportPointToRay(centre);
clone.velocity = ray.direction * speed;
}
}
public Rigidbody projectile;
public Transform startBulletPosition;
public float speed;
public float rotationSpeed;
public Camera camera;
Vector3 startingDirection;
void Start() {
startingDirection = startBulletPosition.transform.forward;
}
void Update() {
if (Input.GetButtonDown("Fire1")) {
RaycastHit hit;
Vector3 targetDirection;
if (Physics.Raycast(Camera.main.transform.position, camera.transform.forward, out hit)){
targetDirection = hit.transform.position - startBulletPosition.position;
} else {
targetDirection = startingDirection;
}
Vector3 newDirection = Vector3.RotateTowards( startBulletPosition.transform.forward, targetDirection, rotationSpeed * Time.deltaTime, 0.0f);
startBulletPosition.transform.forward = newDirection;
Rigidbody clone;
clone = Instantiate(projectile, startBulletPosition.position, startBulletPosition.rotation) as Rigidbody;
clone.velocity = targetDirection * speed;
}
}
I would do a Raycast from the Camera Position to see what you can hit and then rotate the weapon to that direction. As in my Example Code. The weapon will point to exactly Center View on what your camera Raycast hits.
Also you can control the max turnspeed by that public float. This will make for a nice weapon movement and not just instantaneous jumps.
Here are the docu links of what I used in this snippet:
https://docs.unity3d.com/ScriptReference/RaycastHit.html
https://docs.unity3d.com/ScriptReference/Vector3.RotateTowards.html
If the raycast misses, the stored original direction of the weapon will be used. (Assuming startBulletPosition is the transform of the weapon...)
If you want, you can add the maxDistance Parameter to the Physics.Raycast call to limit the distance on which this behaviour is active.
Related
I'm trying to make a basic FPS game in Unity and I'm having an issue where the projectiles I shoot won't instantiate in the right place. From what I can tell, the projectile instantiates in roughly the same position relative to the player regardless of where I look (that position being a little to the left of the starting angle of the player).
Here's a 20 second video demonstration of what I'm talking about.
https://youtu.be/WLVuqUtMqd0
Even when I'm facing the exact opposite direction of where the projectile usually instantiates it still spawns in the same place, which means the projectile ends up spawning behind the player and hitting the player.
I tried using Debug.DrawRay() to see if maybe the firepoint itself is wrong (which would be shown by the ray starting somewhere other than the gun barrel). However it seems like the starting point of the ray is correct every time.
I'm not sure if this is related to the issue above, but I have noticed that the ray direction is wrong if I'm looking a little below the horizon. It seems like the projectile's direction is correct regardless though.
Ray directions when looking slightly above the horizon vs. lower
Here's my code for intantiating/shooting the projectile. I think the most relevant parts are probably shootProjectile() and instantiateProjectile(). This script is attached to the player character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting : MonoBehaviour
{
public Camera cam;
public GameObject projectile;
public Transform firePoint;//firePoint is set to the end of the barrel.
public float projectileSpeed = 40;
//private var ray;
private Vector3 destination;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//var ray = cam.ViewportPointToRay(new Vector3(0.5f,0.5f,0));
//Debug.DrawRay(ray.origin, ray.direction);
if(Input.GetButtonDown("Fire1")) {
//player is shooting
ShootProjectile();
}
}
void ShootProjectile() {
Ray ray1 = cam.ScreenPointToRay(Input.mousePosition);
//Debug.Log(ray.direction);
RaycastHit hit;
if(Physics.Raycast(ray1, out hit))//checking whether the player is going to hit something
{
destination = hit.point;
}
else {
destination = ray1.GetPoint(1000);
}
Debug.DrawRay(firePoint.position, destination, Color.white, 10f);
InstantiateProjectile(firePoint);
}
void InstantiateProjectile(Transform firePoint) {
var projectileObj = Instantiate (projectile, firePoint.position, Quaternion.identity) as GameObject;//projectile is instantiated
projectileObj.GetComponent<Rigidbody>().velocity = (destination - firePoint.position).normalized * projectileSpeed;//projectile is set in motion
}
}
Here's the location of firePoint.
firePoint (i.e. where the projectile should instantiate)
I would appreciate any help on this, as I've been trying to fix it (on and off) for several days, and really have no idea what the problem is.
Edit: Here's my player movement script(s) as well. The first one is PlayerController.cs, and it converts the player's inputs into the appropriate movement vectors and camera rotation. It then calls methods from PlayerMotor.cs, which actually performs the movements.
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
[SerializeField]
public float speed = 10f;
[SerializeField]
private float lookSens = 3f;
private PlayerMotor motor;
void Start() {
motor = GetComponent<PlayerMotor>();
//Debug.Log("PlayerControllerStart");
Cursor.lockState = CursorLockMode.Locked;
}
void Update() {
//Debug.Log("PlayerControllerUpdate");
//calculate movement velocity as 3D vector.
float xMov = Input.GetAxisRaw("Horizontal");
float zMov = Input.GetAxisRaw("Vertical");
Vector3 movHorizontal = transform.right * xMov;
Vector3 movVertical = transform.forward * zMov;
Vector3 velocity = (movHorizontal + movVertical).normalized * speed;
motor.move(velocity);
//speed*=(float)1.15;
//rotation
float yRot = Input.GetAxisRaw("Mouse X");
Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSens;
motor.rotate(rotation);
float xRot = Input.GetAxisRaw("Mouse Y");
Vector3 cameraRotation = new Vector3 (xRot, 0f, 0f) * lookSens;
motor.rotateCamera(cameraRotation);
if (Input.GetKeyDown(KeyCode.Space) == true && motor.isGrounded()) {
motor.canJump=true;
}
if (Input.GetKey(KeyCode.W) == true) {
motor.accel=true;
}
else{
motor.accel=false;
}
}
}
PlayerMotor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{
[SerializeField]
private Camera cam;
private Vector3 velocity = Vector3.zero;
private Vector3 rotation = Vector3.zero;
private Vector3 cameraRotation = Vector3.zero;
private Vector3 jumpVector = new Vector3 (0f, 5f, 0f);
private PlayerController pc;
private Rigidbody rb;
public bool canJump;
public bool accel;
public float acceleration;
int jumpCount;
void Start() {
rb = GetComponent<Rigidbody>();
pc = GetComponent<PlayerController>();
canJump=false;
jumpCount=0;
accel=false;
//acceleration = 1.0;
//distToGround = collider.bounds.extents.y;
//Debug.Log("PlayerMotorStart");
}
//sets velocity to a given movement vector.
public void move(Vector3 _velocity) {
velocity = _velocity;
}
public void rotate(Vector3 _rotation) {
rotation = _rotation;
}
public void rotateCamera(Vector3 _cameraRotation) {
cameraRotation = _cameraRotation;
}
public bool isGrounded() {
return Physics.Raycast(transform.position, -Vector3.up, (float)2.5);
}
public void jump() {
rb.AddForce(transform.up * 250f);
//Debug.Log("Jump"+jumpCount);
jumpCount++;
canJump=false;
}
void FixedUpdate() {
performMovement();
performRotation();
if (canJump) {
jump();
}
//Debug.Log("PlayerMotorUpdate");
if(accel&&pc.speed<20f&&isGrounded())
{
//Debug.Log("W Pressed");
pc.speed*=(float)1.005;
}
else if(!accel) {
pc.speed=7f;
}
}
void performMovement() {
if(velocity != Vector3.zero) {
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
//Debug.Log("Movement");
}
}
void performRotation() {
rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
if(cam != null) {
cam.transform.Rotate(-cameraRotation);
}
}
}
Here are some pictures of my projectile prefab as well.
To solve one first confusion: The method Debug.DrawRay takes as paramters
a start position
a ray direction(!)
You are passing in another position which is not what you want.
This might only work "accidentally" as long as you stand on 0,0,0 so maybe it wasn't that notable but the debt ray definitely points into a wrong direction.
Rather do e.g.
Debug.DrawRay(firePoint.position, destination - firePoint.position, Color.white, 10f);
Or instead rather use Debug.DrawLine which rather actually takes
start position
end position
Then you don't need to calculate the direction first
Debug.DrawLine(firePoint.position, destination, Color.white, 10f);
Then I suspect the following is happening: The spawned projectileObj actually is placed correctly but it is the visuals inside that projectile prefab that have a local offset against the parent prefab root.
Since you always spawn the projectile in world rotation Quaternion.identity that offset stays the same no matter where you look.
I guess a simple fix would already be to also apply the same rotation like
var projectileObj = Instantiate (projectile, firePoint.position, firePoint.rotation);
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 trying to make my Player Teleport to my mouse position but whenever I right click it seems to teleport far away from my camera and generally where my mouse pointer was.
I am not getting any error messages nor am I getting warnings.
for example, if I click in the middle of the screen with my mouse it will teleport to the center of the text Canvas.
I couldn't seem to find any solutions to my issue on the unity forums.
maybe someone here could help me
my code:
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour
{
public float moveSpeed;
public float jumpHeight;
public GameObject bullet;
public float speed = 5.0f;
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool grounded;
public Transform player; //Variable for Teleport funktion
void Awake()
{
player = GameObject.FindGameObjectWithTag("Player").transform; //Finding the player (Teleport)
}
void fixedUpdate()
{
grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
}
void Update()
{
if (Input.GetKeyDown("space"))
{
GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jumpHeight);
}
if (Input.GetKey(KeyCode.D))
{
GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed, GetComponent<Rigidbody2D>().velocity.y);
}
if (Input.GetKey(KeyCode.A))
{
GetComponent<Rigidbody2D>().velocity = new Vector2(-moveSpeed, GetComponent<Rigidbody2D>().velocity.y);
}
if (Input.GetMouseButtonDown(1))
{
player.position = (Input.mousePosition); // teleporting
}
if (Input.GetMouseButtonDown(0))
{
Vector2 target = Camera.main.ScreenToWorldPoint(new Vector2(Input.mousePosition.x, Input.mousePosition.y));
Vector2 myPos = new Vector2(transform.position.x, transform.position.y);
Vector2 direction = target - myPos;
direction.Normalize();
Quaternion rotation = Quaternion.Euler(0, 0, Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg);
GameObject projectile = (GameObject)Instantiate(bullet, myPos, rotation);
projectile.GetComponent<Rigidbody2D>().velocity = direction * speed;
}
}
}
You just need to transform the input position from screen to world, like you did in your shooting code:
if (Input.GetMouseButtonDown(1))
{
Vector3 target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
player.position = target; // teleporting
}
I'm trying to understand the code of the PlayerController made by Unity(Survival Shooter Tutorial).I understand everything, except the reason, why they wrote the difference between FLOOR-POINT(where the mouse is directed) and the player (transform position).I tried to write only the floor point without the player position and its worked.Why they wrote that? Maybe someone passed this tutorial and can help me with that?
Unity tutorial : https://unity3d.com/learn/tutorials/projects/survival-shooter/player-character?playlist=17144
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float speed= 6f;
Vector3 movement;
Animator anim;
Rigidbody playerRigidbody;
int floorMask;
float camRayLength=100f;
void Awake()
{
floorMask = LayerMask.GetMask("Floor");
anim = GetComponent<Animator> ();
playerRigidbody = GetComponent<Rigidbody> ();
}
void FixedUpdate()
{
float v = Input.GetAxisRaw ("Vertical");
float h = Input.GetAxisRaw ("Horizontal");
Move (h, v);
Turning ();
Animating(h,v);
}
void Move(float h,float v)
{
movement.Set (h,0f,v);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition (transform.position+movement);
}
void Turning()
{
Ray camRay = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit floorHit;
if(Physics.Raycast(camRay,out floorHit,camRayLength,floorMask))
{
Vector3 playerToMouse = floorHit.point-transform.position ;********
playerToMouse.y = 0f;
Quaternion newRotation = Quaternion.LookRotation (playerToMouse);
playerRigidbody.MoveRotation (newRotation);
}
}
void Animating(float h,float v)
{
bool wakling = h != 0f || v != 0f;
anim.SetBool("IsWalking",wakling);
}
}
Raycasts need a direction, which is usually given as (someVector - someOtherVector). The result from this subtraction is a new vector that takes someVector as the origin point. In your case, the relative vector from the mouse to the player probably never changes, so the subtraction seems not needed. However, it is good practice to use the subtraction of two vectors as direction.
I have been writing a script for enemy movement in my game, but when the target(Player) jumps, the enemy begins to gradually float up to the same y position the target was in. I would like it if the enemy stayed at the same position as the ground, but I have not found out how I would be able to do that. I am new to Unity, so the only thing I could think of was adding a rigidbody to the enemy but that did not seem to work. Would anyone have any Idea on how to do this? Here is my script:
public class EnemyMovement : MonoBehaviour {
//target
public Transform Player;
//the distace the enemy will begin walking towards the player
public float walkingDistance = 10.0f;
//the speed it will take the enemy to move
public float speed = 10.0f;
private Vector3 Velocity = Vector3.zero;
void Start(){
}
void Update(){
transform.LookAt (Player);
//finding the distance between the enemy and the player
float distance = Vector3.Distance(transform.position, Player.position);
if(distance < walkingDistance){
//moving the enemy towards the player
transform.position = Vector3.SmoothDamp(transform.position,
Player.position, ref Velocity, speed);
}
}
Just set the y value before doing the movement
public class EnemyMovement : MonoBehaviour {
//target
public Transform Player;
//the distace the enemy will begin walking towards the player
public float walkingDistance = 10.0f;
//the speed it will take the enemy to move
public float speed = 10.0f;
private Vector3 Velocity = Vector3.zero;
void Start(){
}
void Update(){
transform.LookAt (Player);
Vector3 target = Player.position;
target.y = transform.position.y;
//finding the distance between the enemy and the player
float distance = Vector3.Distance(transform.position, target);
if(distance < walkingDistance){
//moving the enemy towards the player
transform.position = Vector3.SmoothDamp(transform.position,
target, ref Velocity, speed);
}
}