Hi I am currently learning from the book (Learning c# by developing games with unity 2021).
1.Right now in the game I have created a bullet object this object is supposed to be destroyed after being created.
2.But since I want to display it in the scene for a time I created a floating point to see how much time I can give. I applied these are parameters in the destroy utility function.
problem:-
1.Instead of destroying it after a certain time it deleted it entirely after it was created.
This is a problem the code I wrote to create the bullet is attached to my player.
2.It deletes the prefab in the starting of the game itself
Player action:-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerBehavoiur : MonoBehaviour
{
//this is a bullet made and used
public GameObject Bullet;
//the speed with the bullet
public float BulletSpeed = 100f;
//checks if our player is shooting
private bool _isShooting;
//stores the desired distance to ground
public float distanceToGround = 0.1f;
//creates a reference variable of type layermask
public LayerMask GroundLayer;
//gets the collider stored in a variable that will be used to access it
private CapsuleCollider _col;
void Update()
{
/*MoveForward(_hInput1);
RotateUpWards(_vInput1);
*/
_isJumping |= Input.GetKeyDown(KeyCode.Space);
PrintIfJumping(_isJumping);
//this sets it to a method that checks if the key in the
//arguments pressed down on
IsFalling |= Input.GetKeyDown(KeyCode.G);
//scans for mouse input and sets the isShooting field to that value
//if that value is true or when the mouse is clicked then run the shoot method
//this is through prefabs which are are used
_isShooting |= Input.GetMouseButtonDown(0);
}
void PrintIfJumping(bool _isJumping)
{
if (_isJumping == true)
{
Debug.Log("Time to take a leap of faith!");
}
else
{
Debug.Log("Im on the ground this sucks!");
}
}
void Start()
{
_rb = GetComponent<Rigidbody>();
_rb.useGravity = true;
//sets isJumping to keycode.space which checks wether the key space is pressed
//gets the collider component and stores inside a variable for later use
_col = GetComponent<CapsuleCollider>();
}
void SetVerticalDirection()
{
_vInput1 = Input.GetAxis("Vertical") * MoveSpeed;
}
void SetHorizontalDirection()
{
_hInput1 = Input.GetAxis("Horizontal") * RotateSpeed;
}
public float MoveSpeed = 10f;
public float RotateSpeed = 75f;
public int hp = 0;
/// <summary>
/// stores a rigidbody component for a gameobject
/// </summary>
private Rigidbody _rb;
public float JumpVelocity = 5f;
private bool _isJumping;
private bool IsFalling;
public float FallVelocity;
/// <summary>
/// Start is called before the first frame update
/// </summary>
private float _hInput1;
private float _vInput1;
/// <summary>
/// Update is called once per frame
/// </summary>
/*public void MoveForward(float _vInput)
{
_vInput = Input.GetAxis("Vertical") * MoveSpeed;
this.transform.Translate()
}
public void RotateUpWards(float _hInput)
{
_hInput = Input.GetAxis("Horizontal") * RotateSpeed;
this.transform.Translate(Vector3.forward * _hInput * Time.deltaTime);
}
*/
void FixedUpdate()
{
SetVerticalDirection();
SetHorizontalDirection();
//makes the object move by horizontal input in the up direction
Vector3 rotation = Vector3.up * _hInput1;
/*this is the rotation of the game object
* moving up and then going at a fixed frame rate
*/
Quaternion angleRotation = Quaternion.Euler(rotation * Time.fixedDeltaTime);
//this takes vertical input and addes the position and makes it move forward
//the vertical input is the vertical axis whihc moves at a defined rate tht we can define
_rb.MovePosition(this.transform.position +
this.transform.forward * _vInput1 * Time.fixedDeltaTime);
/*the move rotation moves using the rigibody rotation times the
* horizontal input times and moves up and rotates at the rotate speed rate
*/
_rb.MoveRotation(_rb.rotation * angleRotation);
//performs a jump if object is in collision with ground and isJumping
if(IsGrounded() && _isJumping)
{
/*while(JumpVelocity > 0)
{
--JumpVelocity;
}
*/
_rb.AddForce(Vector3.up * JumpVelocity, ForceMode.Impulse);
}
Fall(IsFalling);
Shoot(_isShooting, Bullet);
}
private bool IsGrounded() {
//this defines the bottom of the capsule or the end
Vector3 capsuleBottom = new Vector3(_col.bounds.center.x, _col.bounds.min.y, _col.bounds.center.z);
//this checks if a object is touching start or bottom of a capsule and the raduis is distance to ground
//this sets the ground layer to the phy-system
bool grounded = Physics.CheckCapsule(_col.bounds.center, capsuleBottom, distanceToGround, GroundLayer, QueryTriggerInteraction.Ignore);
return grounded;
}
public void Fall(bool grounded)
{
bool Gpressed = Input.GetKeyDown(KeyCode.G);
Debug.Log("G is pressed");
Debug.LogFormat("The down direction is {0}", Vector3.down);
if (Gpressed ==true & grounded == false)
{
_rb.AddForce(Vector3.down * FallVelocity, ForceMode.Impulse);
}
else
{
Debug.Log("No falling allowed!");
}
}
public void Shoot(bool _isShooting,GameObject Bullet)
{
if (_isShooting == true)
{
//this is the instance of the prefab bullet which is created using the unity editor
//builds
GameObject newBullet = Instantiate(Bullet, this.transform.position + new Vector3(1, 0, 0), this.transform.rotation);
//create a new bullet rigidbody which captures the component rb
Rigidbody BulletRB = newBullet.GetComponent<Rigidbody>();
//set the velocity (speed x direction) basically
//so we want our bullet to go forward x a certian speed so...
BulletRB.velocity = this.transform.forward * BulletSpeed;
}
_isShooting = false;
}
/*Horizontal: ad
* Vertical: ws */
}
Its pretty long I know just read the shoot function and the stuff in update on shooting
So the bullet behaviour is:-
public class BulletBehaviour : MonoBehaviour
{
float OnScreenDelay = 3f;
void Start()
{
Destroy(this.gameObject,OnScreenDelay);
}
// Update is called once per frame
void Update()
{
}
public void Scale(float x, float y, float z)
{
this.transform.localScale = new Vector3(x, y, z);
}
}
Related
I'm trying to make a 2D top-down shooter in Unity. I want it so when the you hold down the left mouse button the player fires a series of bullets until you run out of ammo. The player's movement speed is slowed while firing and the players movement speed should be added to the bullet's movement speed. For some reason the players movement speed is only applied to the bullets AFTER the first bullet is fired. The first bullet always seems to keep the slightly faster 'sprint' movement speed.
Weapon script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weapon : MonoBehaviour
{
private GameObject bulletPrefab;
private Transform firePoint;
private PlayerControls player;
public float fireForce = 10f;
private bool cooldown = false;
private int bullets;
public int bulletDamage;
public int maxAmmo;
public float fireRate = 0.5f;
public float reloadRate = 2.5f;
public bool noAmmo = false;
public float walkSpeed = 2f;
private float timeSinceLastShot = 0f;
void Update()
{
// increase time since last shot
timeSinceLastShot += Time.deltaTime;
// if left-click is held down
if (Input.GetMouseButton(0))
{
// if enough time has passed since last shot
if (timeSinceLastShot >= fireRate && noAmmo == false)
{
player.moveSpeed = walkSpeed;
bullets -= 1;
cooldown = true;
if (bullets <= 0)
{
noAmmo = true;
player.moveSpeed = player.baseSpeed;
}
// instantiate a bullet
GameObject bullet = Instantiate(bulletPrefab, firePoint.transform.position, Quaternion.identity);
bullet.GetComponent<Bullet>().bulletDamage = bulletDamage;
// add player movement speed to bullet's speed
bullet.GetComponent<Rigidbody2D>().velocity = player.GetComponent<Rigidbody2D>().velocity;
bullet.GetComponent<Rigidbody2D>().AddForce(transform.up * fireForce, ForceMode2D.Impulse);
// reset time since last shot
timeSinceLastShot = 0f;
}
}
// if left-click is not held down
else
{
cooldown = false;
// restore player movement speed
player.moveSpeed = player.baseSpeed;
}
}
public void FillMag()
{
bullets = maxAmmo;
noAmmo = false;
}
}
PlayerControls:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControls : MonoBehaviour
{
public float moveSpeed = 5f;
public float baseSpeed = 5f;
public int health;
public Weapon weapon;
private Rigidbody2D rb;
Vector2 mousePosition;
Vector2 moveDirection;
public float walkSpeed = 2f;
void Update()
{
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
moveDirection = new Vector2(moveX, moveY).normalized;
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
rb.velocity = new Vector2(moveDirection.x * moveSpeed, moveDirection.y * moveSpeed);
Vector2 aimDirection = mousePosition - rb.position;
float aimAngle = Mathf.Atan2(aimDirection.y, aimDirection.x) * Mathf.Rad2Deg - 90f;
rb.rotation = aimAngle;
}
}
The player is moving from left to right.
Player firing
According to Unity's lifecycle, inputs are only calculated just before the Update method is called, but physics are applied during the FixedUpdate method. Is this what is causing my problems? I've tried moving some calculations into FixedUpdate and LateUpdate but nothing seems to make any difference.
Any help is appreciated. I've been banging my head against this for a few days now. I'm an amature, so feel free to explain like I'm 5.
So there are 2 problems with your code:
if you are not holding down left mouse, but multiple click instead:
the else statement in the Update() will immediately set it player back to base speed, which is not really matter if you intent to holding your mouse.
There are 2 concurrent things happen
first, you set player moveSpeed in Weapon Update()
at the same time, you calculate player velocity in Player Update()
But it TAKES TIME for player to update velocity before you get it right to your weapon.
Therefore, I recommend you to use IEnumerator to delay the fire action.
public class Weapon : MonoBehaviour
{
void FixedUpdate()
{
// increase time since last shot
timeSinceLastShot += Time.deltaTime;
// if left-click is held down
if (Input.GetMouseButton(0))
{
// if enough time has passed since last shot
if (timeSinceLastShot >= fireRate && noAmmo == false)
{
//player.moveSpeed = walkSpeed;
StopAllCoroutines();
StartCoroutine(SetSpeed());
bullets -= 1;
cooldown = true;
if (bullets <= 0)
{
noAmmo = true;
player.moveSpeed = player.baseSpeed;
}
// instantiate a bullet
StartCoroutine(FireBulelt());
// reset time since last shot
timeSinceLastShot = 0f;
}
}
// if left-click is not held down
}
IEnumerator SetSpeed()
{
player.moveSpeed = walkSpeed;
yield return new WaitForSeconds(0.5f);
cooldown = false;
// restore player movement speed
player.moveSpeed = player.baseSpeed;
yield return null;
}
IEnumerator FireBulelt()
{
yield return new WaitForSeconds(0.05f);
GameObject bullet = Instantiate(bulletPrefab, player.transform.position, Quaternion.identity);
print(" player.GetComponent<Rigidbody2D>().velocit " + player.GetComponent<Rigidbody2D>().velocity);
// add player movement speed to bullet's speed
Rigidbody2D bulletRB = bullet.GetComponent<Rigidbody2D>();
print(" bulletRB.velocit " + bulletRB.velocity);
bulletRB.velocity = player.GetComponent<Rigidbody2D>().velocity;
print(" after bulletRB.velocit " + bulletRB.velocity);
bulletRB.AddForce(transform.up * fireForce, ForceMode2D.Impulse);
}
}
And you should add print() like I did to keep track of code behavior when you're debugging.
I have a player in unity with the movement controlled by a rigidbody. The movement on the Z axis is kept contstant by the game to keep the player moving forward. However, this means that the rigidbody keeps speeding up so its speed at the start of the game is much slower than the speed at the end of the game. Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
public class Controller : MonoBehaviour
{
[Tooltip("Rigidbody component attached to the player")]
public Rigidbody rb;
public float forwardMax;
public float slowBy;
private float movementX;
private float movementY;
private float gravity = -9.81f;
private bool isJumping = false;
private bool isSlowing = false;
private bool isSpeeding = false;
private float speedX = 100;
private float speedY = 150000;
private float speedZ = 60;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
// if(!controller.isGrounded)
// {
// Vector3 gravityVector = new Vector3(0.0f, gravity, 0.0f);
// rb.AddForce(gravityVector * Time.deltaTime);
// }
}
void OnCollisionEnter(Collision collision)
{
// SceneManager.LoadScene(1);
}
// Update is called once per frame
void OnMove(InputValue movementValue)
{
Vector2 movementVector = movementValue.Get<Vector2>();
movementX = movementVector.x;
movementY = movementVector.y;
}
void OnJump()
{
isJumping = true;
}
void CalculateMovement()
{
if(rb.velocity.z > 20)
{
rb.drag = 20;
}
else
{
rb.drag = 0;
}
Vector3 movement = new Vector3(movementX * speedX, 0.0f, speedZ);
if(isJumping)
{
movement.y += Mathf.Sqrt(speedY * -3.0f * gravity);
isJumping = false;
}
rb.AddForce(movement);
Debug.Log("Speed is " + rb.velocity.z);
}
void FixedUpdate()
{
CalculateMovement();
}
}
Is there a way to keep the forward velocity constant? The problem is worse when the player jumps.
First I tried clamping the forward (z-axis) vector but that had no effect. Then, I tried adding a backward vector onto the total when the forward velocity was above a certain number but this led to it speeding up and slowing down all the time. Then I tried the same thing with the drag on the rigidbody but that had the same effect.
You can use rigidbody.velocity and set it to constant value or whatever you want instead of adding force. By adding force, your character's speed increases.
Also you can use AddForce but you have to tune the force value dynamically according to the current velocity.
rigidbody velocity
How about directly setting the z value you want at the end of FixedUpdate() ?
......
void FixedUpdate()
{
CalculateMovementWithoutZMovement();
rb.velocity = new Vector3 (rb.velocity.x, rb.velocity.y, ConstantZValue);
}
Hi I am using a rigidbody component attached to my game Object and I don't want to disable gravity but the game object keeps on falling. Moreover the enemy capsule just falls below the ground in my game. Im a little new to unity. The game I am making is with the help of the (Learning c# by developing games unity 2021) this is the 6th version.
The script for the player behaviour is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerBehavoiur : MonoBehaviour
{
public float MoveSpeed = 10f;
public float RotateSpeed = 75f;
public int hp = 0;
/// <summary>
/// stores a rigidbody component for a gameobject
/// </summary>
private Rigidbody _rb;
// Start is called before the first frame update
void Start()
{
_rb = GetComponent<Rigidbody>();
_rb.useGravity = true;
}
private float _hInput1;
private float _vInput1;
// Update is called once per frame
void Update()
{
/*MoveForward(_hInput1);
RotateUpWards(_vInput1);
*/
}
/*public void MoveForward(float _vInput)
{
_vInput = Input.GetAxis("Vertical") * MoveSpeed;
this.transform.Translate()
}
public void RotateUpWards(float _hInput)
{
_hInput = Input.GetAxis("Horizontal") * RotateSpeed;
this.transform.Translate(Vector3.forward * _hInput * Time.deltaTime);
}
*/
void FixedUpdate()
{
SetVerticalDirection();
SetHorizontalDirection();
//makes the object move by horizontal input in the up direction
Vector3 rotation = Vector3.up * _hInput1;
/*this is the rotation of the game object
* moving up and then going at a fixed frame rate
*/
Quaternion angleRotation = Quaternion.Euler(rotation * Time.fixedDeltaTime);
//this takes vertical input and addes the position and makes it move forward
//the vertical input is the vertical axis whihc moves at a defined rate tht we can define
_rb.MovePosition(this.transform.position +
this.transform.forward * _vInput1 * Time.fixedDeltaTime);
/*the move rotation moves using the rigibody rotation times the
* horizontal input times and moves up and rotates at the rotate speed rate
*/
_rb.MoveRotation(_rb.rotation * angleRotation);
}
void SetVerticalDirection()
{
_vInput1 = Input.GetAxis("Vertical") * MoveSpeed;
}
void SetHorizontalDirection()
{
_hInput1 = Input.GetAxis("Horizontal") * RotateSpeed;
}
/*Horizontal: ad
* Vertical: ws
*/
}
In the Inspector, you can set gravity scale to 0. Or set the mass to 0. If none works, go to the Rigdid Body and use the Constraints and freeze the y position. this will stop it from falling
I am also currently studying this book. You should check the third box in the RigidBody Freeze Rotation.
I'm new to coding and I've been playing around with unity and I've encountered a problem.
My problem is, if I move the player and activate the function SkillAttack1, the animation will cancel out and won't complete. Right now, as you see in the code belowif I activate theSkillAttack1`, it works, but still it won't complete the animation. Also, if I'm pressing the "w" button, for example, for 15 seconds the player gets stuck and moves forward. The only way to play the full animation is not moving, but that's not right.
[Animator1][1]
[Animator2][2]
[Animator3][3]
[1]: https://i.stack.imgur.com/BeziY.png
[2]: https://i.stack.imgur.com/310vz.png
[3]: https://i.stack.imgur.com/tOVVu.png
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float velocity = 5;
public float turnSpeed = 10;
Vector2 input;
float angle;
Quaternion targetRotation;
public Transform cam;
public Animator anim;
public bool IsAttacking = false;
void Start()
{
anim = GetComponent<Animator>();
}
void Update()
{
if(Mathf.Abs(input.x) < 0.5 && Mathf.Abs(input.y) < 0.5) return;
CalculateDirection();
Rotate();
Move();
}
void FixedUpdate()
{
if(IsAttacking == false)
{
GetInput();
}
SkillAttack1();
SkillAttack2();
}
/// Input based on Horizontal(a,d) and Vertical (w,s) keys
void GetInput()
{
input.x = Input.GetAxis("Horizontal");
input.y = Input.GetAxis("Vertical");
anim.SetFloat("VelX", input.x);
anim.SetFloat("VelY", input.y);
}
/// Direction relative to the camera rotation
void CalculateDirection()
{
angle = Mathf.Atan2(input.x, input.y);
angle = Mathf.Rad2Deg * angle;
angle += cam.eulerAngles.y;
}
/// Rotate toward the calculated angle
void Rotate()
{
targetRotation = Quaternion.Euler(0, angle, 0);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed
* Time.deltaTime);
}
/// This player only move along its own forward axis
void Move()
{
transform.position += transform.forward * velocity * Time.deltaTime;
}
public void SkillAttack1(){
if(Input.GetKeyDown("1"))
{
IsAttacking = true;
StartCoroutine(OnSkillAttack1());
}
}
public void SkillAttack2()
{
if(Input.GetKeyDown("2"))
{
anim.SetTrigger("SkillAttack2");
}
}
public IEnumerator OnSkillAttack1()
{
anim.SetTrigger("SkillAttack1");
yield return null;
yield return new WaitForSeconds(15.0f);
IsAttacking = false;
}
}
Looks like your animation controller is getting overridden by your movement code, when your player sends some input to walk left or right, it sets the VelX and VelY variables on your animation controller. Without access to your controller I can't tell you exactly why it's interrupting the attack, but it's likely you have an interrupt set up that triggers from "any state" when one of those variables is above 0 and transitions into the "walk" animation your controller has.
You'll need to adjust your animation transitions to handle this potential case, or alternatively, prevent movement code triggering during an attack animation.
I'm trying to shot a bullet in player direction but the bullet is instatiated but dont leave the initial position, not sure why, heres the code:
using UnityEngine;
using System.Collections;
public class AtackPlayer : MonoBehaviour {
public string playerTag = "Player";
public AnimationClip startAtack;
public AnimationClip endAtack;
public float atackInterval = 2f;
public GameObject enemyBullet;
public float bulletSpeed = 20f;
private Animator _anim;
private Transform _transform;
// Use this for initialization
void Start () {
_anim = GetComponentInParent<Animator>();
_transform = GetComponent<Transform>();
}
private IEnumerator Atack(Vector2 playerPosition)
{
_anim.Play(startAtack.name);
yield return new WaitForSeconds(startAtack.length); // executa o clipe e ataca
GameObject thisBullet = Instantiate(enemyBullet, _transform.position, Quaternion.identity) as GameObject; //instancia o bullet prefab
thisBullet.transform.position = Vector2.Lerp(thisBullet.transform.position, playerPosition, bulletSpeed * Time.deltaTime);
_anim.Play(endAtack.name);
yield return new WaitForSeconds(endAtack.length); // executa o clipe de finalização do ataque
yield return new WaitForSeconds(atackInterval); // executa o clipe de finalização do ataque
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D player)
{
if (player.gameObject.tag == playerTag)
{
Vector2 playerPos = player.transform.position;
StartCoroutine(Atack(playerPos));
}
}
}
The bullet prefab have a rigidbody2d and a circle collider, also sprite renderer and a animator to handle its animation.
Any help?
thisBullet.transform.position = Vector2.Lerp(thisBullet.transform.position, playerPosition, bulletSpeed * Time.deltaTime);
t = bulletSpeed * Time.deltaTime
When t = 0 returns a. When t = 1 returns b. When t = 0.5 returns the point midway between a and b.
In your game probably t has a value very close to 0. It means your
bullet's position stays almost the same position. Also you need a
loop in Atack function to make bullet has the same position with
bullet.
while (thisBullet.transform.position != playerPosition)
{
thisBullet.transform.position = Vector2.Lerp(thisBullet.transform.position, playerPosition, bulletSpeed * Time.deltaTime);
yield return new WaitForSeconds(0.1f);
}
You can set while condition here however you want for your game. In this code it move to player's position every 0.1f.