using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour {
public int Player_Health = 100;
public GameObject Player;
public Rigidbody Bullet;
public Transform Guun;
public bool Player_Dead = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space))
{
Rigidbody rocketInstance;
rocketInstance = Instantiate(Bullet, Guun.position, Guun.rotation) as Rigidbody;
rocketInstance.AddForce(Guun.forward * 5000);
}
if(Player_Health == 0)
{
Player_Dead = true;
}
if(Player_Dead == true)
{
Destroy(Player);
}
}
private void OnCollisionEnter(Collision col)
{
if(col.gameObject.name == "Player")
{
Player_Health = Player_Health - 20;
Debug.Log(Player_Health);
}
}
}
1.So when i instantiate by pressing space it first instantiates 1 then 2 then 4 then 8 and so on - why doesnt it just instantiate 1 each press.
I am trying to make a gun here and obviously need it to only fire one bullet at a time because at the moment it fires multiple. As i have already explained first it fires one bullet then next time i fire it doubles it and so on.
1.So when i instantiate by pressing space it first instantiates 1 then 2 then 4 then 8 and so on - why doesnt it just instantiate 1 each
press.
If the behavior is that each prefab duplicates each time the key is pressed, it simply means that the script is also attached to the prefab or multiple GameObjects. I see similar problems each time.
Please remove the script from the prefabs if it is attached to any prefab. Remove it from every GameObject in the scene then attach it to one GameObject only.
Select the script, go to Assets --> Find References in Scene. It will show you every GameObject that has this script attached to it. Remove it from all of them except for one.
Related
I want to replace the broken table with a fixed table but when I press the button it places the table multiple times around the background. This is the script for the replacement.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ReplaceObjects : MonoBehaviour
{
public GameObject Broken_Table;
public GameObject Table;
private bool used = false;
void Start()
{
}
void Update()
{
if (Input.touchCount > 0)
{
GameObject broken_Table = Instantiate(Broken_Table) as GameObject;
GameObject table = Instantiate(Table) as GameObject;
Replace(broken_Table, table);
used = true;
}
}
void Replace(GameObject obj1, GameObject obj2)
{
Instantiate(obj2, obj1.transform.position, obj1.transform.rotation);
Destroy(obj1);
}
}
You are instantiating 3 objects for every frame you have input.
GameObject broken_Table = Instantiate(Broken_Table) as GameObject;
GameObject table = Instantiate(Table) as GameObject;
and
Instantiate(obj2, obj1.transform.position, obj1.transform.rotation);
All of the above statements clone objects into your scene. You're then destroying the broken_Table right after creating it, meaning you're creating 2 fixed tables for every frame your finger is held down.
To fix this, you can do both of the following things:
Only enact logic on the first frame your player "touches" the object, rather than every frame. The best way to do this is to utilize the GetTouch method and only act during TouchPhase.Began.
Do not instantiate more than 1 "fixed table" in this code.
Your code will be called every frame while your touchcount is superior than zero.
So as long as you hold your finger on the screen it will call the Replace() method.
You can add your "used" bool to the previous if to avoid that, like so:
void Update()
{
if (Input.touchCount > 0 && !used)
{
Replace(broken_Table, table);
used = true;
}
}
I am trying to practice creating a clone of Galaga following the same ruleset as the original. I am currently stuck trying to attempt a limit on the amount of cloned prefabs that can be in the scene at any one time, in the same way that Galaga's projectiles are limited to 2 on screen at any time. I want to make it so the player can shoot up to two projectiles, which destroy after 2 seconds or when they collide (this part is functioning), followed by not being able to shoot if two projectile clones are active and not yet destroyed in the hierarchy (Not working as I can instantiate projectiles over the limit of 2).
I have combed through Google for about 3 hours with no solutions that have worked for me, at least in the ways that I had attempted to implement them.
Thank y'all so much for the help!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerController : MonoBehaviour
{
public float moveSpeed = 1.0f;
public playerProjectile projectile;
public Transform launchOffset;
public int maxBullets = 0;
private GameObject cloneProjectile;
public Rigidbody2D player;
// Start is called before the first frame update
void Start()
{
player = this.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
MovePlayer();
PlayerShoot();
}
public void MovePlayer()
{
player.velocity = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")) * moveSpeed;
}
public void PlayerShoot()
{
if (Input.GetKeyDown(KeyCode.Z))
{
var cloneProjectile = Instantiate(projectile, launchOffset.position, launchOffset.rotation);
maxBullets++;
if (maxBullets >= 3)
{
Destroy(cloneProjectile, 0.1f);
maxBullets --;
return;
}
}
}
}
You could change the logic up a bit. An instance of the playerController class is active as long as the game is active, so it will know and retain the value of 'maxBullets' until you die or exit the program.
So instead, every time you click "z", the first thing you should do is run the check. If the current amount of live projectiles equals the maximum, have the logic 'return' and exit out of the method.
I have problem spawning enemies in unity 2d. Enemies clones themselves too quickly and it lags. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
public Transform[] spawnPoints;
public GameObject enemy;
public float spawnTime = 5f;
public float spawnDelay = 3f;
// Use this for initialization
void Start () {
InvokeRepeating ("addEnemy", spawnDelay, spawnTime);
}
void addEnemy() {
int spawnPointIndex = Random.Range(0, spawnPoints.Length);
Instantiate (enemy, spawnPoints[spawnPointIndex].position,
spawnPoints[spawnPointIndex].rotation);
}
}
Oh, I am currently making a 2D game where I have to spawn enemies and here is what code I used, edited for you of course:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
public GameObject enemyPrefab;
public float interval = 100;
private float counter = 0;
// Update is called once per frame
void FixedUpdate()
{
counter += 1;
if(counter >= interval){
counter = 0;
Instantiate(enemyPrefab, transform.position,transform.rotation);
}
}
}
Simply create a new game object, put this script it, add the enemy prefab in the Game Object variable and you are set. You can edit the interval between each enemy with the interval variable. Good luck with your project :)
I'm assuming they are spawning more than every 3 seconds? Do you have multiple 'EnemySpawner' scripts attached to objects in the scene?
edit sounds like you have an ‘EnemySpawner’ script in your prefab, remove it from prefab and put it on a separate GameObject in your scene.
You should not as in the accepted answer use FixedUpdate for this! It uses 100 fixed update steps .. but who wants to calculate how long this actually takes?
By default fixed update step is 0.02s so 100 means 2 real-time seconds - but what if you change the fixed update step for any reason?
I would rather do it using a simple timer in Update:
public class EnemySpawner : MonoBehaviour
{
public GameObject enemyPrefab;
// In seconds
[SerializeField]private float interval = 2f;
private float timer = 0f;
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if(timer >= interval){
timer = 0f;
Instantiate(enemyPrefab, transform.position,transform.rotation);
}
}
}
Actually what you had should also work! Depends of course also on the values you set via the Inspector.
BUT What I can see from the image you posted is: In enemy you referenced the object itself!
=> The next time there are 2 enemy instances including this spawner
=> The next time there are 4 enemy instances including this spawner
=> The next time there are 8 enemy instances ...
=> etc
Therefore they are called Enemy[Clone] then Enemy[Clone][Clone] then Enemy[Clone][Clone][Clone] etc so
Not sure if this was intended but I would rather put the spawner script on one single object in the scene and rather reference a prefab without an additional spawner script.
this should be a very simple answer. I'm following a Unity with C# tutorial for making a simple Space Invaders game, and at one point it is shown that when our enemyHolder object has no child objects left (when all enemies are destroyed) the attached text under the winText function should be displayed.
So we have
if (enemyHolder.childCount == 0)
{
winText.enabled = true;
}
When I run the code the text isn't displayed after the enemies are destroyed and no child object is left. It's like the code stops getting read at that point, although the character is still movable and you can generate new shots.
If I create two "Enemy" child objects and tell it to display the winText rather when the childCount reaches 1, it does work.
So why is it not working when the function calls for == 0?
EDIT: Complete class code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyController : MonoBehaviour
{
private Transform enemyHolder;
public float speed;
public GameObject shot;
public Text winText;
public float fireRate = 0.997f;
// Start is called before the first frame update
void Start()
{
winText.enabled = false;
InvokeRepeating("MoveEnemy", 0.1f, 0.3f);
enemyHolder = GetComponent<Transform>();
}
void MoveEnemy()
{
enemyHolder.position += Vector3.right * speed;
foreach (Transform enemy in enemyHolder)
{
if (enemy.position.x < -10.5 || enemy.position.x > 10.5)
{
speed = -speed;
enemyHolder.position += Vector3.down * 0.5f;
return;
}
if (enemy.position.y <= -4)
{
GameOver.isPlayerDead = true;
Time.timeScale = 0;
}
if (enemyHolder.childCount == 1)
{
CancelInvoke();
InvokeRepeating("MoveEnemy", 0.1f, 0.25f);
}
if (enemyHolder.childCount == 0)
{
winText.enabled = true;
}
}
}
}
Your code is inside the void MoveEnemy() function.
I'm assuming your script is attached to in-game enemies. Your code doesn't run because the MoveEnemy function no longer runs if there are no enemies.
So, you need to handle enemy movement and scene handling in different scripts.
The code that checks the enemy holder's number of children should be placed inside a void Update() function. This Update() function should be placed on an object that never gets deleted. Its advantage is that it runs every frame.
As a convention, devs generally use separate empty objects or even the camera to attach scripts which contain Update functions that handle the scene. Good luck!
Read more on Update
I'm trying to make a grenade throwing script but when i test it, it always spawn 2 grenade at the same time.
public class GrenadeThrow : MonoBehaviour {
public GameObject bulletprefab;
float speed =20f;
// Use this for initialization
void Start () { }
// Update is called once per frame
void Update () {
if (Input.GetButtonUp("Fire1"))
{
Camera cam = Camera.main;
GameObject Grenade = Instantiate(bulletprefab, cam.transform.position + cam.transform.forward, cam.transform.rotation);
Grenade.GetComponent<Rigidbody>().AddForce(cam.transform.forward * speed, ForceMode.Impulse);
}
}
}
First of all, Input.GetButtonDown is more appropriate for this than Input.GetButtonUp. You can try it and see if Input.GetButtonDown is still what you want.
when i test it, it always spawn 2 grenade at the same time
Assuming that this is the actual code you are using to spawn and throw Objects, then it should work fine.
There two likely problems:
1.The GrenadeThrow script is likely attached to the-same GameObject multiple times.
2.The problem is likely to be that you have your GrenadeThrow script attached to multiple GameObjects. It should only be attached to one GameObject.