I am currently working on a game prototype, this game would require to
spawn some GameObjects which I call "stars", all good with
instantiating, but when I try to delete them when there are to many
around it does not work, I am trying to put all instantiated
GameObjects in a list and then delete the last object from it when
the new one was instantiated. As you can see from the code, when 3
objects are spawned the script should delete one from the beginning
and spawn a new one in the same time.
Now, the problem is that I don't know what am I missing here, the code does not work and I don't know why. Please help me. Thank you!
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnStar : MonoBehaviour {
public float addedSpeed = -200f;
private GameObject spawned;
private float randomX;
public GameObject starToSpawn;
private List<GameObject> activeGO;
void Start ()
{
activeGO = new List<GameObject> ();
Invoke ("InstantiateStar", 2f);
}
// Update is called once per frame
void FixedUpdate ()
{
GetComponent<Rigidbody>().AddForce( new Vector3( 0f, addedSpeed, 0f));
}
void InstantiateStar ()
{
randomX = Random.Range (-3f, 3f);
GameObject GO;
GO = Instantiate (starToSpawn, new Vector3(randomX, 5f, 0f), transform.rotation) as GameObject;
activeGO.Add (GO);
if ( activeGO[0].transform.position.y < -2f)
{
DeleteActiveGO ();
}
}
void DeleteActiveGO ()
{
Destroy (activeGO [0]);
activeGO.RemoveAt (0);
}
}
I am back with an update. The problem was that I was trying to do 2 thing in one script...short story: To solve the problem I created an empty object in the scene, divided my script in 2 separated scripts, one that makes the spawned object move faster and one that is spawning the object, I put the script that moves the object on to the object that will be spawned and The other script on the empty GameObject that will spawn the "Stars" and it worked like a charm.
Thank you for all your answers!
here are the final scripts:
Spawning script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnStars : MonoBehaviour {
public GameObject[] starsToSpawn;
private List<GameObject> spawnedStars;
private float randomX;
void Start ()
{
spawnedStars = new List<GameObject> ();
InvokeRepeating ("SpawnStar", 0f, 3f);
}
void SpawnStar ()
{
randomX = Random.Range (-3, 3);
GameObject GO;
GO = Instantiate ( starsToSpawn[0], new Vector3 (randomX, 5f, 0f), transform.rotation);
spawnedStars.Add (GO);
if (spawnedStars.Count > 2 )
{
Destroy (spawnedStars [0]);
spawnedStars.RemoveAt (0);
}
}
}
Moving script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveStar : MonoBehaviour {
public float acceleration = -5f;
void FixedUpdate ()
{
GetComponent<Rigidbody>().AddForce( new Vector3( 0f, acceleration,0f));
}
}
Your code Invoke ("InstantiateStar", 2f); only call once.
You can change to InvokeRepeating("InstantiateStar",2f,2f );
The Code GetComponent<Rigidbody>().AddForce( new Vector3( 0f, addedSpeed, 0f)); seem like should attach to the Generate Gameobject.
Also note your delete condition.
good luck.
#Noobie: What you are trying to do is called Object Pooling. Your implementation is rather not correct.
It would be better for you to learn the same and implement.
Read more here: https://unity3d.com/learn/tutorials/topics/scripting/object-pooling
Related
So I'm writing a script for respawning objects for a 2d game on unity, however whenever i try to call the object that is to respawn, it says that the object is either a method or statement. I feel like I've made a mistake somewhere. Please help correct me where im wrong. This is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public GameObject spike;
public class Spikegenerator: MonoBehaviour
{
void Start()
{
for (int i = 0; i < 10; i++)
{
float spawnY = Random.Range
(Camera.main.ScreenToWorldPoint(new Vector2(0, 0)).y,
Camera.main.ScreenToWorldPoint(new Vector2(0, Screen.height)).y);
float spawnX = Random.Range
(Camera.main.ScreenToWorldPoint(new Vector2(0, 0)).x,
Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, 0)).x);
Vector2 spawnPosition = new Vector2(spawnX, spawnY);
Instantiate(spike, spawnPosition, Quaternion.identity);
// the gameobject is 'spike'
}
}
}'''
The spike variable u are providing doesn't exist yet in the code.
Make sure you add public GameObject spike
Inside your class and insert the prefab spike via the editor.
Make sure you added spike on the inspector of your GameObject.
As you can see in the screenshoot I can't see prefabs in the game tab but only in the editor. I have made a simple function for shooting(not finished yet), it works fine, it spawns the prefabs but i can't see them in the game tab, I have already tried changing the Sorting Layer, move the camera, change Z position but nothing appen.
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAttack : MonoBehaviour
{
[SerializeField]
float delayBetweenShots = 0.4f;
float timePassedSinceLast = 0f;
// Start is called before the first frame update
void Start()
{
timePassedSinceLast = delayBetweenShots;
}
// Update is called once per frame
void Update()
{
Aiming();
Shooting();
}
void Aiming()
{
var objectPos = Camera.main.WorldToScreenPoint(transform.position);
var dir = Input.mousePosition - objectPos;
transform.rotation = Quaternion.Euler(new Vector3(0,0,Mathf.Atan2(-dir.x, dir.y) * Mathf.Rad2Deg));
}
void Shooting()
{
if(Input.GetMouseButton(0) && timePassedSinceLast >= delayBetweenShots)
{
GameObject bullet = (GameObject)Instantiate(Resources.Load("bullet"), transform.position, transform.rotation);
timePassedSinceLast = 0f;
}
else
{
timePassedSinceLast += Time.deltaTime;
}
}
}
The prefabs get instantiated correctly. As others suggested as well, the best way to find "lost" objects in your game is to shoot some stuff, pause the game, go into scene view, turn on 3D mode and double click one of the prefabs in the hierarchy. The camera will take you straight to your object.
I'm new to Unity and to C#. I was trying to code a 2D platformer movement script, but for some reasons the code I'm creating doesn't work.
The script is referred to a circle. I've added "Rigidbody2D" and "Circle Collider 2D".
I've tried to use this script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
public Rigidbody2D rb;
public void FixedUpdate()
{
if (Input.GetKey(KeyCode.RightArrow))
{
rb.AddForce(10, 0, 0);
}
}
}
The code should give an hit to the circle to make it move right, but Visual Studio says that "rb.AddForce" is an error. Can you help me, please?
Are you sure you have actually referenced the rigidbody? Did you drag the rigidbody in the editor? If you have not, you could also say the following (if the script is attached to object that holds the rigidbody you would like to move):
private Rigidbody2D rb;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
1)Make sure your Rigidbody component is NOT set to Kinematic.
2)Depending on the mass and linear drag of the rigidbody, you would need to change the force you apply to it accordingly. The code may be working but you would not see the body moving if you do not apply enough force.
3)Addforce() expects a Vector as an argument. This is your problem.
public float thrust; //set in editor, this is how strong you will be pushing the object
private Rigidbody2D rb;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
if (Input.GetKey(KeyCode.RightArrow))
{
rb.AddForce(transform.right * thrust); //this will move your RB to the right while you hold the right arrow
}
}
4) Set a linear drag of your rigidbody so that it can actually stop after applying the force to it. In order to make it work, set the mass and linear drag both to 1 for example and then just experiment with the thrust variable, it will eventually start moving. After that you can reduce/increase the linear drag and the thrust until you achieve the desired effect.
BONUS
If you wish to use a Vector3D the way you have tried in your code, you could do the following and it will work too:
private void FixedUpdate()
{
if (Input.GetKey(KeyCode.RightArrow))
{
rb.AddForce(new Vector3(10, 0, 0)); //this will move your RB to the right while you hold the right arrow
}
}
Because of Rigidbody2D implementation it takes Vector2 in constructor as an argument instead of simple Rigidbody which can take Vector3 and Vector2 as Vector3. Consider Vector3 v3 = new Vector2(10, 0); and
Vector2 v2 = new Vector3(10, 0, 0);
Try this
rb.AddForce(new Vector2(10, 0));
or
rb.AddForce(new Vector3(10, 0, 0));
You need to add ForceMode2D.Impulse for it to work:
using UnityEngine;
public class TestControl : MonoBehaviour
{
public Rigidbody2D rb2d;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.RightArrow))
{
rb2d.AddForce(new Vector2(5, 0 ), ForceMode2D.Impulse);
Debug.Log("RightArrow was Pressed");
}
}
}
You can find more info in here: https://www.studytonight.com/game-development-in-2D/right-way-to-move
In my FPS Game, I am trying to make my player throw a grenade. I know there are similar questions like this, but the posts are old and they the answers did not help me at all. When I tried to make my grenade throw using the AddForce() method, the grenade merely spawned right in front of the player, like the AddForce() method was never called. The same happened when I set its velocity to a value. It seems like the grenade won't move at all! I have made sure that:
The grenade is NOT Kinematic
It doesn't work with both gravity on and off
No Positions/Rotations are frozen
There is a rigid body attatched
There isn't a character controller attached to the grenade
The mass is only one
My code is below:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Script : MonoBehaviour {
[SerializeField] GameObject grenade;
public int throwForce = 30;
Vector3 spawnPosition;
// Use this for initialization
void Start () {
instantiateVariables ();
}
void instantiateVariables(){
}
void throwGrenade(){
print (spawnPosition);
GameObject tempGrenade = (GameObject) Instantiate (grenade, spawnPosition, transform.rotation);
Vector3 direction = new Vector3(transform.forward.x, transform.forward.y, transform.forward.z );
Rigidbody rb = grenade.GetComponent<Rigidbody> ();
if (rb != null){
rb.velocity = direction.normalized * 10f;
Destroy (tempGrenade, 10);
}
else {
Debug.LogError ("There is no rigid body on your cube!");
}
}
// Update is called once per frame
void Update () {
spawnPosition = transform.forward + transform.position;
print (spawnPosition);
if (Input.GetMouseButtonDown (1)) {
throwGrenade ();
}
}
}
Inspector:
Shouldn't you store the tempGrenade's rigidBody Component in rb instead of grenade's rigidBody? I would recommend using tempGrenade's rigidBody and then modifying rb.velocity.
Like:
rb = tempGrenade.GetComponent<Rigidbody> ();
EDIT: Corrected the line of code by removing the velocity field
I'm having a bit of trouble getting the Vector3 wayPointPosition to my other script called Walking and changing it into the Transform target. My troubles lie in the fact that I'm trying to grab this dynamic variable from WayPointPositioner (it changes depending on what object is clicked in the stage and whether the player overlaps with this waypoint) and import and use it in another script.
Below is the code I'm using.
WayPointPositioner
using UnityEngine;
using System.Collections;
public class WayPointPositioner : MonoBehaviour {
public Vector3 wayPointPosition = Vector3.zero;
private bool checkPlayerWaypointCollision;
void Start()
{
}
void OnTriggerStay2D (Collider2D other)
{
// Check if collision is occuring with player character.
if (other.gameObject.name == "Player")
{
checkPlayerWaypointCollision = true;
}
else
{
checkPlayerWaypointCollision = false;
}
}
//Check if object is clicked
void OnMouseDown ()
{
// If its the player, then return a new position for the player to move to for walking
// Else debug that its not so
if (checkPlayerWaypointCollision == false)
{
Debug.Log ("Object not colliding and retrieving position");
Debug.Log (wayPointPosition);
Debug.Log (gameObject.name);
wayPointPosition = new Vector3 (transform.position.x, transform.position.y, 10);
wayPointPosition = Camera.main.ScreenToWorldPoint(wayPointPosition);
}
else
{
Debug.Log ("Object is colliding, no movement needed");
}
}
}
Walking
using UnityEngine;
using System.Collections;
public class Walking : MonoBehaviour {
public Transform target;
public WayPointPositioner wayPointPosition;
public bool walkingAnimation = false;
private Animator anim;
void Awake ()
{
anim = GetComponent<Animator> ();
wayPointPosition = GameObject.FindGameObjectWithTag ("Waypoint").GetComponent<WayPointPositioner> ();
}
void Start ()
{
}
void Update ()
{
Debug.Log ("This is in Walking, WPP =" + wayPointPosition);
}
}
As you can see I'm trying to import the wayPointPosition from the seperate class which is attached to the gameobjects called "Waypoint" (In my current layout those are empty objects with circle colliders to check if they have been clicked). However when I run this, I am not getting my Vector, but I'm getting the name of the last waypoint in the hierarchy (I have currently 6 waypoints which can be clicked) and not a Vector.
I hope someone is able to help me / point out my mistake. I'm still learning C# so I might've made a strange / odd assumption which isn't working.
Kind regards,
Veraduxxz.
It looks like invoking GameObject.FindGameObjectWithTag("Waypoint").GetComponent<WayPointPositioner>(); retrieves a component from the game object which matches the specified tag, as well as a type argument T which derives from MonoBehavior.
Calling this should actually give you an instance of your WayPointPositioner class, which you can then pass to whichever methods you want, and interact with its Vector3 however you would like.