Add a cooldown to a Shooting Script - c#

I Have this simple scrip fot the player to shoot a prefab when clicking the "Disparo" button, in this case the left click. Now its broken because you can spam the click and shoot every second. I dont Know how to add a cooldown to this to make that you only can shoot every certain time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class ProjectileShooter : MonoBehaviour
{
public AudioClip disparo;
GameObject prefab;
public float shootSpeed;
// Start is called before the first frame update
void Start()
{
prefab = Resources.Load("Projectile") as GameObject;
}
// Update is called once per frame
void Update()
{
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
GameObject Projectile = Instantiate(prefab) as GameObject;
Projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = Projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * shootSpeed;
Destroy(Projectile, 2.2f);
}
}
}

One way to achieve what you want is to set a boolean to check if the process is in cooldown.
private bool isInCooldown = false;
Then in your if statement you can invoke a new method, after completing your computations. As explained in Unity docs Invoke method:
Invokes the method methodName in time seconds.
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
if(!isInCooldown){
//Your code here
Invoke("ResetCooldown", 2f);
isInCooldown = true;
}
}
And the ResetCooldown method is simply:
private void ResetCooldown () {
isInCooldown = false;
}
Hope this helps.

The script below sets the cool time easily. You can set the cooldown time by changing shootcoolTime. and do not touch youCanShootNow. that variable only use to save time when you can shoot again;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class ProjectileShooter : MonoBehaviour
{
public AudioClip disparo;
GameObject prefab;
public float shootSpeed;
public float shootcoolTime;
float youCanShootNow;
// Start is called before the first frame update
void Start()
{
prefab = Resources.Load("Projectile") as GameObject;
youCanShootNow = 0;
}
public void Update()
{
if (youCanShootNow < Time.time)
{
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
GameObject Projectile = Instantiate(prefab) as GameObject;
Projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = Projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * shootSpeed;
Destroy(Projectile, 2.2f);
youCanShootNow = Time.time + coolTime;
}
}
}
}

Related

GameObject reflecting off another gameObject error

I am new at Unity/c# and I wanted to make a pong game. I made this by watching a tutorial on youtube. There is no "error" except the ball doesn't move after touching the player.
This is ball code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallCode : MonoBehaviour
{
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
Vector2 position = transform.position;
position.x = position.x - 5.8f * Time.deltaTime;
transform.position = position;
}
}
This is ball bounce code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallBounce : MonoBehaviour
{
private Rigidbody2D rb;
Vector3 lastVelocity;
// Start is called before the first frame update
void Awake()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
lastVelocity = rb.velocity;
}
private void OnCollisionEnter2D(Collision2D coll)
{
var speed = lastVelocity.magnitude;
var direction = Vector3.Reflect(lastVelocity.normalized, coll.contacts[0].normal);
}
}
And this is player code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float moveSpeed = 4.5f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float vertical = Input.GetAxis("Vertical");
Vector2 position = transform.position;
position.y = position.y + moveSpeed * vertical * Time.deltaTime;
transform.position = position;
}
}
When I play the game the ball will collide with player, but it won't ricochet.
Your OnCollisionEnter2D method is not doing anything except set local variables that are quickly discarded. You need to make speed and direction variables of the BallCode or BallBounce class, then set up the BallCode class to use those variables in Update() when determining the motions it makes.
You can try adding a 2D rigid body property to the sphere and removing gravity.
Add a C# script to control the movement of the ball and add a 2D collider to the ball.
//Initial velocity
public float speed = 100f;
void Start()
{
this.GetComponent<Rigidbody2D>().AddForce
(Vector2.right * speed);
}
Add a 2D collider:
Add a 2D physical material to the sphere, so that the ball can bounce.
Modify 2D Physical Material Properties.
Added to the sphere's material.
Add player (Square) and control player movement script.
void Update()
{
// The mouse moves with the player
float y = Camer.main.ScreenToWorldPoint
(Input.mousePosition).y
this.transform.position = new Vector3
(transform.position.x,y,0);
}
Add the wall around the screen and the script Wall to control the randomness of the vertical speed and the direction of the ball when the ball collides with the wall.
public class Wall : MonoBehaviour
{
//Initial velocity
public float speed = 100f;
// Triggered when the collision ends
private void OnCollisionExit(Collision2D collision)
{
int r = 1;
if(Random.Range(0, 2) != -1)
{
r *= -1;
}
//add a vertical force
collision.gameObject.GetComponent<Rigidbody2D>().
AddForce(Vector2.up.*speed*r);
}
}
achieve effect:

Unassigned variable in Unity

I've just started learning Unity 2D with the "How to make a 2D game" course from Brackeys on YouTube about 3 hrs ago. I'm using Unity 2018.4.1f1 on Ubuntu 18.04, and because JS is not supported in my version so I have to use C# instead. But I've encountered this error on the third video: The variable mainCam of GameSetup has not been assigned. This is my code in C#:
GameSetup.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameSetup : MonoBehaviour
{
public Camera mainCam;
public BoxCollider2D topWall, bottomWall, leftWall, rightWall;
public Transform Player1, Player2;
// Start is called before the first frame update
void Start()
{
// topWall = GetComponent<BoxCollider2D>();
// mainCam = GetComponent<Camera>();
// If I uncomment this, there would be a new error: There is no 'Camera' attached to '_GM' game object, but a script is trying to access it.
}
// Update is called once per frame
void Update()
{
// Move each wall to its edge location
topWall.size = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(Screen.width * 2.0f, 0f)).x, 1.0f);
topWall.offset = new Vector2(0f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.width, 0f)).y + 0.5f);
}
}
With the help of Google, I've add rb2d.GetComponent<Rigibody2D>() in Start() from the script of the second video under and prevent the error (there are no Start() in the video)
PlayerControls.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControls : MonoBehaviour
{
public KeyCode moveUp, moveDown;
public float speed = 10;
private Rigidbody2D rb2d = new Rigidbody2D();
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(moveUp))
{
Vector3 v = rb2d.velocity;
v.y = speed;
rb2d.velocity = v;
// rb2d.velocity.y = speed;
}
else if (Input.GetKey(moveDown))
{
Vector3 v = rb2d.velocity;
v.y = speed * (-1);
rb2d.velocity = v;
}
else
{
Vector3 v = rb2d.velocity;
v.y = 0;
rb2d.velocity = v;
}
}
}
How can I fix the bug in GameSetup.cs ? I've done exactly what said in the video, but only changed the language from JS to C#
Either assign it null:
public Camera mainCam = null;
But you are most likely missing to attach a camera object to it in the Unity3D editor. Check your inspector and make sure that whatever object that is using this script(GameSetup.cs) has a camera object assigned to its public variable.
Should look something like this. You have to drag and drop a camera object to the Gameobject.

How to add force to an object after a collision in unity2d, to simulate hitting a baseball with a bat

I am working on a 2D game project. I would like the user to be able to hit the ball when he presses on the "space" key. I assigned;
Circle collider 2D & Rigidbody 2D to the ball
Rigidbody 2D & Box Collider 2D to the hero
Edge Collider 2D to the baseball bat.
Here is my script which I have called "KickTheBall.cs":
using UnityEngine;
using System.Collections;
public class KickTheBall : MonoBehaviour {
public float bounceFactor = 0.9f; // Determines how the ball will be bouncing after landing. The value is [0..1]
public float forceFactor = 10f;
public float tMax = 5f; // Pressing time upper limit
private float kickStart; // Keeps time, when you press button
private float kickForce; // Keeps time interval between button press and release
private Vector2 prevVelocity; // Keeps rigidbody velocity, calculated in FixedUpdate()
[SerializeField]
private EdgeCollider2D BatCollider;
private Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate () {
if(kickForce != 0)
{
float angle = Random.Range(0,20) * Mathf.Deg2Rad;
rb.AddForce(new Vector2(0.0f,
forceFactor * Mathf.Clamp(kickForce, 0.0f, tMax) * Mathf.Sin(angle)),
ForceMode2D.Impulse);
kickForce = 0;
}
prevVelocity = rb.velocity;
}
void Update(){
if(Input.GetKeyDown (KeyCode.Space))
{
kickStart = Time.time;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if(hit.collider.name == "Ball") // Rename ball object to "Ball" in Inspector, or change name here
kickForce = Time.time - kickStart;
}
}
}
public void KickBall(){
BatCollider.enabled = true;
}
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Ground") // Do not forget assign tag to the field
{
rb.velocity = new Vector2(prevVelocity.x,
-prevVelocity.y * Mathf.Clamp01(bounceFactor));
}
}
}
However, I am unable to kick the ball when I press the space key. The ball is just bouncing because of colliders. What am I missing?
Check my result:
I would advocate something more like this to start with. This is the script you would add onto your baseball bat.
Part 1:
using UnityEngine;
using System.Collections;
public class KickTheBall : MonoBehaviour
{
public float forceFactor = 10f;
private float kickForce = 50f;
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Ball") // Do not forget assign tag to the field
{
rb = col.gameobject.GetComponent<Rigidbody>();
rb.AddForce(transform.right * kickForce);
}
}
}
I have simplified your AddForce function for demonstration purposes. Feel free to replace it with your more complex AddForce function if everything is working.
Part 2:
If you really want to include the part where holding the space button makes the hit stronger, then add this:
void Update()
{
if(Input.GetKey(KeyCode.Space))
{
kickForce += 0.5f;
}
}
and add at the end of the oncollisionenter
kickForce = 0;
What this will do is build up force while you hold the space button down. After a successful hit the force will reset to 0. So subsequent collisions will not result in a hit until the space button is held again.
Let me know if this did anything for you.
I solved the issue with the help of #TylerSigi. I updated my script file with these codes:
using UnityEngine;
using System.Collections;
public class KickTheBall : MonoBehaviour {
public float forceFactor = 10f;
private float kickForce = 0f;
private EdgeCollider2D BatCollider;
public GameObject Ball;
void Start () {
}
void Update()
{
if (Input.GetKey (KeyCode.Space)) {
kickForce = 1000;
} else {
kickForce = 0;
}
}
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Enemy") // Do not forget assign tag to the field
{
Ball.GetComponent<Rigidbody2D>().AddForce(transform.right * kickForce);
}
}
}

Unity How to limit Spawner?

I am working on a game like 2 cars. So there will be two lines and I have used two object spawner which is going to spawn two shapes, i,e Circle and Square. So when player collides with circle score should update. And when Square falls player is supposed to avoid it by going to another lane. But what is the problem is something both the spawner spawns square simultaneously or with small gap. So player is not able to escape. Any solution for this. Well I guess it does not help much but here is my script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiter : MonoBehaviour {
public GameObject[] gameobject;
public float SpawnDelay= 3f;
private GameObject objectkeeper;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
float Spawntime = SpawnDelay * Time.deltaTime; // 1 *1/60
if (Random.value < Spawntime) {
Spawn ();
}
}
void Spawn(){
int number = Random.Range (0, 2);// creating random number between 0 and 1
objectkeeper = Instantiate (gameobject [number], this.transform.position, Quaternion.identity) as GameObject;
objectkeeper.transform.parent = this.transform;
}
void OnDrawGizmos(){
Gizmos.DrawWireSphere (this.transform.position, 0.5f);
}
}
Thank you for your time and consideration
Try this,
It will only spawn one object at a time between the min-max period
It does not cleanup old objects
It allows for more than 2 prefabs
I tried keeping to your code format as much as possible
Disclaimer : I do not currently have a visual studio/mono develop open (in a boring meeting) so i have not tested this :]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiter : MonoBehaviour {
public GameObject[] prefabs;
// Adding a min-max allows full control of spawning behaviour without editing code again.
// for a fixed time use the same value
public float MinimumSpawnDelay = 3f;
public float MaximumSpawnDelay = 6f;
private GameObject spawnedObject;
// Made this static so it retains it's value across all instances of this script.
// If you want each Instantiter object to function on it's own, remove the static keyword
private static float nextSpawnTime;
// Use this for initialization
void Start () {
// Artificial delay so we do not spawn an object directly at startup
SetNextSpawnTime();
}
// Update is called once per frame
void Update () {
if (Time.time >= nextSpawnTime) {
Spawn ();
}
}
void Spawn(){
// allows you to add more objects to the prefabs array without changing code.
var prefabToSpawn = prefabs[Ranom.Range(0, prefabs.Length)];
spawnedObject = Instantiate (prefabToSpawn, transform.position, Quaternion.identity);
spawnedObject.transform.parent = transform;
SetNextSpawnTime();
}
void OnDrawGizmos() {
Gizmos.DrawWireSphere (transform.position, 0.5f);
}
void SetNextSpawnTime(){
// a simple variable to hold when we should spawn another object, efficient.
nextSpawnTime = Time.time + Random.Range(MinimumSpawnDelay, MaximumSpawnDelay);
}
}
Try using a static variable -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiter : MonoBehaviour {
public GameObject[] gameobject;
public float SpawnDelay= 3f;
private GameObject objectkeeper;
// Static variable shared across all instances of this script
public static float nextSpawn = 0f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// check if SpawnDelay duration has passed
if (Time.time >= nextSpawn) {
// Now spawn after ramdom time
float Spawntime = SpawnDelay * Time.deltaTime; // 1 *1/60
if (Random.value < Spawntime) {
Spawn ();
}
}
}
void Spawn(){
int number = Random.Range (0, 2);// creating random number between 0 and 1
objectkeeper = Instantiate (gameobject [number], this.transform.position, Quaternion.identity) as GameObject;
objectkeeper.transform.parent = this.transform;
// Set the nextSpawn time to after SpawnDelay Duration
nextSpawn = Time.time + SpawnDelay;
}
void OnDrawGizmos(){
Gizmos.DrawWireSphere (this.transform.position, 0.5f);
}
}

Detect if enemy is facing Player

I am making a game in which if the distance is less than 2 and the enemy is facing the player, text comes up with a restart option. In the update there is an if and else statement which should detect if the enemy is behind or in front of the player. However, the in front option seems to be called once the distance is less than 2, regardless of if the player is facing the npc.
This script is attached to the Enemy:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class EnemyFollow : MonoBehaviour {
Transform player;
Transform enemy;
public GameObject EnemyCaughtCam;
public Text SheCaughtYou;
public GameObject Restart;
public float Speed = 3f;
public float rotS = 3f;
public float sT = 3f;
NavMeshAgent nav;
float timeTillOptionsMenu = 3.0f;
// Use this for initialization
void Awake() {
player = GameObject.FindGameObjectWithTag ("MainCamera").transform;
//enemy = GameObject.FindGameObjectWithTag ("Enemy").transform;
nav = GetComponent<NavMeshAgent> ();
EnemyCaughtCam.SetActive(false);
SheCaughtYou.text = "";
}
// Update is called once per frame
void Update () {
nav.SetDestination (player.position);
DistanceDeath();
if (npcIsFacingPlayer (player)&& !playerIsFacingNpc(player))
print ("Behind");
else if (npcIsFacingPlayer (player)&& playerIsFacingNpc(player))
print ("In Front");
DistanceDeath ();
}
public void DistanceDeath(){
float distance = Vector3.Distance(player.transform.position,
transform.position);
if (distance < 2 ){
EnemyCaughtCam.SetActive(true);
SheCaughtYou.text = "SHE CAUGHT YOU!";
timeTillOptionsMenu -= Time.deltaTime;
if(timeTillOptionsMenu < 0)
{
Restart.SetActive(true);
}
}
}
public bool npcIsFacingPlayer(Transform other)
{
Vector3 toOther =
other.position - transform.position;
return (Vector3.Dot(toOther, transform.forward) > 0);
}
public bool playerIsFacingNpc(Transform other)
{
Vector3 toOther =
transform.position - other.position;
return (Vector3.Dot(toOther, other.forward) > 0);
}
}
First, you are missing some brackets, second there is an stra DistanceDeathcall, here is how your function Update is read:
// Update is called once per frame
void Update () {
nav.SetDestination (player.position);
/** what does the call do here? */
DistanceDeath();
if (npcIsFacingPlayer (player)&& !playerIsFacingNpc(player))
print ("Behind");
else if (npcIsFacingPlayer (player)&& playerIsFacingNpc(player))
print ("In Front");
/** are you missing brackets here? Distance Death is always called */
DistanceDeath ();
}

Categories