I am making shooting in Unity, what I want is to make a little delay, for example: to be able to shoot in every 0.5 seconds. Check the script, I want my bullet prefab to appear (instantiate) after 0.5 sec delay.
private Rigidbody2D rb2d;
private float h = 0.0f;
public float Speed;
public Transform firePoint;
public GameObject bulletPrefab;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
h = Input.GetAxisRaw("Horizontal");
if (h != 0.0f)
{
rb2d.velocity = new Vector2(h * Speed, rb2d.velocity.y);
}
if (h == 0.0f)
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
}
void Shoot()
{
Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
}
This should take you in the right direction, of course, this is only one of the ways to do it.
You can change fireDelay to change the rate of fire.
private Rigidbody2D rb2d;
private float h = 0.0f;
public float Speed;
public Transform firePoint;
public GameObject bulletPrefab;
float fireElapsedTime = 0;
public float fireDelay = 0.2f;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
h = Input.GetAxisRaw("Horizontal");
if (h != 0.0f)
{
rb2d.velocity = new Vector2(h * Speed, rb2d.velocity.y);
}
if (h == 0.0f)
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
fireElapsedTime += Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Space) && fireElapsedTime >= fireDelay)
{
fireElapsedTime = 0;
Shoot();
}
}
void Shoot()
{
Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
}
Related
I am working on a 2d zombie killing game but there was an error rotating the gun in my code, when I rotate the gun it turns wrong. Can you help me?
Video:https://youtu.be/8kUgXkEZc2M
Here is the code:
[SerializeField] Transform _arm;
float _offset = -90;
Vector3 _startingSize;
Vector3 _armStartingSize;
public GameObject Bullet;
public float BulletSpeed;
public Transform ShootPoint;
#region Start
// Start is called before the first frame update
void Start()
{
_startingSize = transform.localScale;
_armStartingSize = _arm.localScale;
}
#endregion
// Update is called once per frame
void Update()
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 perendicular = _arm.position - mousePos;
Quaternion val = Quaternion.LookRotation(Vector3.forward, perendicular);
val *= Quaternion.Euler(0, 0, _offset);
_arm.rotation = val;
if(transform.position.x - mousePos.x < -0.1)
{
transform.localScale = _startingSize;
_arm.localScale = _armStartingSize;
}
else if(transform.position.x - mousePos.x > 0.1)
{
transform.localScale = new Vector3(-_startingSize.x, _startingSize.y, _startingSize.z);
_arm.localScale = new Vector3(-_armStartingSize.x, -_armStartingSize.y, _armStartingSize.z);
}
if (Input.GetMouseButtonDown(0))
{
shoot();
}
}
void shoot()
{
cineShake.Instance.ShakeCamera(5f, .1f);
GameObject BulletIns = Instantiate(Bullet, ShootPoint.position, ShootPoint.rotation);
BulletIns.GetComponent<Rigidbody2D>().AddForce(BulletIns.transform.right * BulletSpeed);
}
I'm making a 2D platformer with Unity. I used this tutorial to write this code but changed it a little bit. I want to support both keyboard and gamepad, so I use the new Input System. I've defined three variables called GroundedRememeber, JumpPressedRemember and JumpPressedRememberTime and basically they work like timers and check if the player leaves the ground and then the player can jump when he is near the ground without need to touch it and I want to use it instead of famous "groundCheck". But the problem is that these timers are not working and the player can jump forever even in the air when I press jump button rapidly. Also, as you can see, I added a LayerMask named "groundLayers" for the player to jump only on this type of objects but when I choose "Ground" in the "groundLayers" slot in the Inspector, the player can't jump anymore.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour, PlayerInputActions.IPlayerActions
{
private PlayerInputActions controls;
[SerializeField] LayerMask groundLayers;
private Rigidbody2D rb;
private Animator anim;
private bool facingRight = true;
private Vector2 moveInput;
[SerializeField] private float jumpForce;
float JumpPressedRemember = 0;
[SerializeField] float JumpPressedRememberTime = 0.2f;
float GroundedRemember = 0;
[SerializeField] float GroundedRememberTime = 0.25f;
[SerializeField] float HorizontalAcceleration = 1;
[SerializeField] [Range(0, 1)] float HorizontalDampingBasic = 0.5f;
[SerializeField] [Range(0, 1)] float HorizontalDampingWhenStopping = 0.5f;
[SerializeField] [Range(0, 1)] float HorizontalDampingWhenTurning = 0.5f;
[SerializeField] [Range(0, 1)] float JumpHeight = 0.5f;
private void Awake()
{
controls = new PlayerInputActions();
controls.Player.SetCallbacks(this);
}
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void PlayerInputActions.IPlayerActions.OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
void Jump() {
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Force);
GroundedRemember = 0;
JumpPressedRemember = 0;
}
bool TryJump() {
if (GroundedRemember > 0) {
Jump();
return true;
} else {
JumpPressedRemember = JumpPressedRememberTime;
return false;
}
}
void PlayerInputActions.IPlayerActions.OnJump(InputAction.CallbackContext context)
{
jumpForce = context.ReadValue<float>();
switch (context.phase) {
case InputActionPhase.Performed:
TryJump();
break;
}
}
void FixedUpdate()
{
if(facingRight == false && moveInput.x > 0){
Flip();
}else if (facingRight == true && moveInput.x < 0){
Flip();
}
}
void Flip(){
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
void OnEnable()
{
controls.Enable();
}
void OnDisable()
{
controls.Disable();
}
void Update()
{
Vector2 GroundedBoxCheckPosition = (Vector2)transform.position + new Vector2(0, -0.01f);
Vector2 GroundedBoxCheckScale = (Vector2)transform.localScale + new Vector2(-0.02f, 0);
bool Grounded = Physics2D.OverlapBox(GroundedBoxCheckPosition, transform.localScale, 0, groundLayers);
GroundedRemember -= Time.deltaTime;
if (Grounded)
{
GroundedRemember = GroundedRememberTime;
}
JumpPressedRemember -= Time.deltaTime;
if ((JumpPressedRemember > 0)) {
TryJump();
}
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
float HorizontalVelocity = rb.velocity.x;
HorizontalVelocity += moveInput.x;
if (Mathf.Abs(moveInput.x) < 0.01f)
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenStopping, Time.deltaTime * 10f);
else if (Mathf.Sign(moveInput.x) != Mathf.Sign(HorizontalVelocity))
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenTurning, Time.deltaTime * 10f);
else
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingBasic, Time.deltaTime * 10f);
rb.velocity = new Vector2(HorizontalVelocity, rb.velocity.y);
}
}
If you know how much the player jumps for, then try maybe adding a delay to the next jump
Maybe using the Invoke() function ur just using Coroutines if you know how to use them.
But i would still recommend using a Ground Check since it's practical and just easier and i don't see a reason why you wouldn't use it.
I'm trying to find a way to rotate the enemy towards the player. Currently it follows/stops and shoots the player. Have not figured out how to make it rotate. Please help if you can. I've tried couple of different things on here but they dont seem to work.
I've tried creating a Flip function with isFacingRight.
private bool facingRight;
public float speed;
public float stoppingDistance;
public float retreatDistance;
private Animator enemyAnimation;
private bool isDead;
private float direction;
public static bool enemyShoot = false;
private float timeBtwShots;
public float startTimeBtwShots;
public GameObject projectile;
private Transform player;
[SerializeField]
private Stat health;
private void Awake()
{
health.Initialize();
}
// Start is called before the first frame update
void Start()
{
//Player tag
player = GameObject.FindGameObjectWithTag("Player").transform;
enemyAnimation = GetComponent<Animator>();
isDead = false;
}
// Update is called once per frame
void Update()
{
if (Vector2.Distance(transform.position, player.position) > stoppingDistance)
{
transform.position = Vector2.MoveTowards(transform.position, player.position, speed * Time.deltaTime);
timeBtwShots = startTimeBtwShots;
if(player.position.x > transform.position.x && !facingRight) //if the target is to the right of enemy and the enemy is not facing right
Flip();
if(player.position.x < transform.position.x && facingRight)
Flip();
}
else if (Vector2.Distance(transform.position,player.position) <= stoppingDistance && Vector2.Distance(transform.position,player.position)>retreatDistance)
{
transform.position = this.transform.position;
}
else if (Vector2.Distance(transform.position, player.position) > retreatDistance)
{
transform.localScale = new Vector2(-1f, 1f);
transform.position = Vector2.MoveTowards(transform.position, player.position, -speed * Time.deltaTime);
timeBtwShots = 100;
enemyAnimation.SetTrigger("Attack");
}
if (enemyShoot == true)
{
//Stops animation Loop
enemyShoot = false;
enemyAnimation.SetTrigger("Shoot");
}
if (timeBtwShots <= 0)
{
Instantiate(projectile, transform.position, Quaternion.identity);
timeBtwShots = startTimeBtwShots;
}
else
{
timeBtwShots -= Time.deltaTime;
}
if (health.CurrentVal == 0)
{
timeBtwShots = 100;
FindObjectOfType<SoundsScript>().Play("SaibaDeath");
isDead = true;
enemyAnimation.SetBool("Dead", isDead);
Destroy(gameObject, 2f);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "ProjectileEnem")
{
health.CurrentVal -= 50;
enemyAnimation.SetTrigger("Hurt");
}
}
//Disables enemeies when off screen
private void OnBecameInvisible()
{
GetComponent <Enemy> ().enabled = false;
}
//Re enables enemies once they are visible
private void OnBecameVisible()
{
GetComponent<Enemy>().enabled = true;
}
void Flip(){
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
facingRight = !facingRight;
}
}
Try this:
spriteRenderer.flipX = transform.position.x < player.position.x;
SpriteRenderer contains the flipX and flipY property, you do not need to create your own Flip() function.
You need a reference to the SpriteRenderer on your GameObject.
The above code is assuming that your sprite faces left on default. If your sprite faces right normally, change the < to >.
I am just starting out with unity and am also making a game for a school project. My 2d game character can do the walk animation when I press the "a" and "d" keys and the sprite flips, but it stays in the same position. Below is my PlayerController script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float speed = 3f;
private Animator anim;
private SpriteRenderer sr;
// Start is called before the first frame update
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
Move();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
Vector3 temp = transform.position;
if (h > 0)
{
temp.x += speed * Time.deltaTime;
sr.flipX = true;
anim.SetBool("Walk", true);
}
else if (h < 0)
{
temp.x -= speed * Time.deltaTime;
sr.flipX = false;
anim.SetBool("Walk", true);
}
else if (h == 0)
{
anim.SetBool("Walk", false);
}
}
}
You're setting 'temp' to equal transform.position, but that doesn't mean that transform.position equals 'temp'. Here, the below script should give you what you want
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float speed = 3f;
private Animator anim;
private SpriteRenderer sr;
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
void Update()
{
Move();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector2.right * (h * speed * Time.deltaTime));
anim.SetBool("Walk", h != 0f);
if (anim.GetBool("Walk"))
Flip(h > 0f);
}
void Flip(bool facingRight)
{
sr.flipX = !facingRight;
}
}
I am working on a Character Controller Script and everything is working fine but the problem is that once my player starts to fall it is so sudden and jerks down. I would like the player to gradually fall down, this is my character controller script -
using UnityEngine;
using System.Collections;
public class CharacterController : MonoBehaviour {
public float inputDelay = 0.1f;
public float forwardVel = 12;
public float rotateCel = 12;
public float JumpHeight = 20;
public Vector3 Gravity = new Vector3 (0, -180, 0);
public bool CanPress;
private float jumpTime;
public float _initialJumpTime = 0.4f;
//[HideInInspector]
public bool isGrounded;
Quaternion targetRotation;
Rigidbody rBody;
Vector3 forwardInput, turnInput;
public bool HasJumped;
public Quaternion TargetRotation
{
get {return targetRotation;}
}
// Use this for initialization
void Start () {
Physics.gravity = Gravity;
targetRotation = transform.rotation;
if (GetComponent<Rigidbody> ())
rBody = GetComponent<Rigidbody> ();
else {
Debug.LogError("Character Needs Rigidbody");
}
// forwardInput = turnInput = 0;
forwardInput = turnInput = Vector3.zero;
}
// Update is called once per frame
void Update () {
GetInput ();
//Turn ();
if (CanPress == true) {
if (Input.GetKeyDown (KeyCode.Space)) {
HasJumped = true;
jumpTime = _initialJumpTime;
}
}
if (HasJumped == true) {
rBody.useGravity = false;
jumpTime -= 1 * Time.deltaTime;
if (jumpTime > 0) {
Jump();
}
else {
HasJumped = false;
rBody.useGravity = true;
}
}
}
void GetInput() {
//forwardInput = Input.GetAxis ("Vertical");
//turnInput = Input.GetAxis ("Horizontal");
forwardInput = new Vector3 (Input.GetAxis ("Horizontal") * rotateCel, 0, Input.GetAxis ("Vertical") * forwardVel);
forwardInput = transform.TransformDirection (forwardInput);
if (Input.GetKeyUp (KeyCode.Space)) {
//HasJumped = false;
}
}
void Jump() {
Vector3 up = transform.TransformDirection (Vector3.up);
GetComponent<Rigidbody> ().AddForce (up * 5, ForceMode.Impulse);
}
void FixedUpdate() {
Run ();
}
void Run() {
if (Mathf.Abs (10) > inputDelay) {
//Move
//rBody.velocity = transform.forward * forwardInput * forwardVel;
rBody.velocity = forwardInput;
} else {
//zero velocity
rBody.velocity = Vector3.zero;
}
}
void Turn() {
// targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
// transform.rotation = targetRotation;
}
void OnTriggerEnter(Collider col) {
isGrounded = true;
CanPress = true;
}
void OnTriggerExit(Collider col) {
isGrounded = false;
CanPress = false;
}
}
My character has a Rigidbody attactches which uses gravity and has X,Y,Z constraints for Rotation.
The player goes up smoothly and falls down smoothly but the transition between the two is very abrupt and sudden.
Thanks for the help. :)
Okay, so I took your code and had a play.
I think the issue was that in your Run() function, you were altering the velocity of the rigidbody which was affecting your jumping.
I've taken that stuff out and improved your script slightly and tested it. Attach this to a capsule with a rigidbody on it, with a floor underneath with a box collider on and hit space, and you should get a smooth jump.
Your new(ish) script:
using UnityEngine;
using System.Collections;
public class CharacterController : MonoBehaviour
{
public float inputDelay = 0.1f;
public float forwardVel = 12;
public float rotateCel = 12;
public float jumpHeight = 10;
private float jumpTime;
public float _initialJumpTime = 0.4f;
//[HideInInspector]
public bool isGrounded;
Quaternion targetRotation;
Rigidbody rBody;
Vector3 forwardInput, turnInput;
public bool canJump;
public Quaternion TargetRotation
{
get { return targetRotation; }
}
void Start()
{
targetRotation = transform.rotation;
if (GetComponent<Rigidbody>())
rBody = GetComponent<Rigidbody>();
else
{
Debug.LogError("Character Needs Rigidbody");
}
// forwardInput = turnInput = 0;
forwardInput = turnInput = Vector3.zero;
}
void Update()
{
GetInput();
//Turn ();
if (Input.GetKeyDown(KeyCode.Space) && canJump)
{
rBody.AddForce(Vector3.up * jumpHeight, ForceMode.Impulse);
}
}
void GetInput()
{
//forwardInput = Input.GetAxis ("Vertical");
//turnInput = Input.GetAxis ("Horizontal");
forwardInput = new Vector3(Input.GetAxis("Horizontal") * rotateCel, 0, Input.GetAxis("Vertical") * forwardVel);
forwardInput = transform.TransformDirection(forwardInput);
}
void FixedUpdate()
{
//Run();
}
void Run()
{
//HERE YOU SET THE RIGIDBODYS VELOCITY, WHICH IS CAUSING YOUR JUMP TO NOT WORK PROPERLY. DO NOT MODIFY THE VELOCITY
//OF A RIGIDBODY
if (Mathf.Abs(10) > inputDelay)
{
//Move
//rBody.velocity = transform.forward * forwardInput * forwardVel;
rBody.velocity = forwardInput;
}
else
{
//zero velocity
rBody.velocity = Vector3.zero;
}
}
void Turn()
{
// targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
// transform.rotation = targetRotation;
}
void OnCollisionEnter(Collision col)
{
isGrounded = true;
canJump = true;
}
void OnCollisionExit(Collision col)
{
isGrounded = false;
canJump = false;
}
}
Couple of points:
name your variables inThisKindOfFashion (jumpHeight, isOnGround, camelCaseExample), having variables beginning with a capital letter like Gravity and JumpHeight can get confusing.
as someone once answered on one of my questions, don't modify the velocity of a rigidbody unless you know what you are doing! Seems odd, but after following that advice I've never had a problem since!
In your script I have used OnCollision rather than OnTrigger. If you put a floor with a box collider underneath your capsule with a collider, rigidbody and this script on, your character will stop on the ground. If you use a trigger, he will fall through (at least in my experience!)
Happy coding! :-)
Edit
To respond to your comments:
"How do you suggest I move the player"
Movement can be done in a variety of different ways, but I usually use this one all the time unless I need to do something a bit differently:
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
transform.position += Vector3.left * speed * Time.deltaTime; //speed could be 5f, for example (f means float);
}
// then do the same for other directions, RightArrow -.right, UpArrow - .forward, DownArrow - .back
}
"How do I adjust how fast the player jumps"
You can alter the jumpHeight variable for a higher or smaller jump. If by faster you mean falls down faster, go to Edit>Project Settings>Physics> and change Y gravity to something smaller, such as -20.
Tutorials can be found here
They have a wide variety of tutorials, and even have ones that come with example projects so you can just put it together following the video.