Bullet not moving after implementing object pooling

I tried to implement object pooling for my asteroid mockup, but the bullet won’t move anymore, just stays at where it is activated.

Pooling script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class Preload : MonoBehaviour
{
    public static Preload SharedInstance;
    public List<GameObject> preloadobj;
    public GameObject objtoload;
    public int preloadamount;
    public float bspeed = 10f;

    public PBullet_Pis ppisbullet;

    private Rigidbody2D brb;

    private void Awake()
    {
        SharedInstance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        preloadobj = new List<GameObject>();
        GameObject tmp;
        for (int i = 0; i < preloadamount; i++)
        {
            tmp = Instantiate(objtoload);
            tmp.SetActive(false);
            preloadobj.Add(tmp);
        }
        brb = ppisbullet.GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()  
    {
       
    }

    public GameObject GetPreloadObject()
    {
        for (int i = 0; i < preloadamount; i++)
        {
            if (!preloadobj[i].activeInHierarchy)
            {
                return preloadobj[i];
            }
        }
        return null;
    }
    public void Shooting(Vector2 direc) //Me desperately trying to bring moving func from bullet script
    {
        brb.AddForce(direc * this.bspeed); //add a force to bullet
        //Destroy(this.gameObject , this.time); //destroy when time up
    }
}

Bullet Script:

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEditor.Tilemaps;
using UnityEngine;

public class PBullet_Pis : MonoBehaviour
{
    private Rigidbody2D rb; //bullet physics refer
    private Vector2 bulletdirec;

    public GameObject bspawn;

    public float bspeed = 10.0f; //bullet speed
    public float time = 10.0f; //time for bullet to despawn

    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        //get components
    }

    private void FixedUpdate()
    {
        if (gameObject.activeInHierarchy)
        {
            rb.velocity = this.transform.forward * bspeed;
         //   rb.AddForce(bspawnup.transform. * bspeed);
            if (time> 0)
            {
               time -= Time.deltaTime;
            }
            else
            {
                gameObject.SetActive(false);
                time = 10;
            }
        }
    }

    public void Shooting() //shooting function, direc variable is refered from player:this.bspawn.up
    {
        //rb.AddForce(direc * this.bspeed); //add a force to bullet
        //Destroy(this.gameObject , this.time); //destroy when time up
    }
}

Shooting function from player:

    void Shoot()
    {
        rigbod.velocity = new Vector2(rot.x , rot.y).normalized * thrust; //apply a new velocity with the negative direction and the thrust, find out the effects of normalized.
        GameObject bullet = Preload.SharedInstance.GetPreloadObject();
        if (bullet != null )
        {
            bullet.transform.position = bspawn.transform.position;
            bullet.transform.rotation = bspawn.transform.rotation;
            bullet.SetActive(true);
           // brb.AddForce(transform.forward * preload.Bspeed());
        }
       // PBullet_Pis bullet = Instantiate(this.bulletpf, this.bspawn.position, this.bspawn.rotation); //instance bullet

I tried calling transform from pooled object, doesn’t work. Tried calling rigidbody at pooling script from bullet and move the bullet there, doesn’t work. All other tutorial I found only let bullet travel in a fixed direction, instead on where the player is aiming…

Thanks in advance!!

Well there’s your problem! You have discovered some of the costs and issues associated with object pooling / pools:

https://discussions.unity.com/t/892797/10

https://discussions.unity.com/t/833104/2

Pooling is a disaster and will rarely benefit your project. I highly recommend RIPPING OUT all the pooling code.

If you really want to get it working then it is time for you to start debugging. Here’s how:

You must find a way to get the information you need in order to reason about what the problem is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://discussions.unity.com/t/700551 or this answer for Android: https://discussions.unity.com/t/699654

If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

When in doubt, print it out!™

Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.

In general, DO NOT OPTIMIZE “JUST BECAUSE…” If you don’t have a problem, DO NOT OPTIMIZE!

If you DO have a problem, there is only ONE way to find out. Always start by using the profiler:

Window → Analysis → Profiler

Failure to use the profiler first means you’re just guessing, making a mess of your code for no good reason.

Not only that but performance on platform A will likely be completely different than platform B. Test on the platform(s) that you care about, and test to the extent that it is worth your effort, and no more.

https://discussions.unity.com/t/841163/2

Remember that optimized code is ALWAYS harder to work with and more brittle, making subsequent feature development difficult or impossible, or incurring massive technical debt on future development.

Notes on optimizing UnityEngine.UI setups:

https://discussions.unity.com/t/846847/2

At a minimum you want to clearly understand what performance issues you are having:

  • running too slowly?
  • loading too slowly?
  • using too much runtime memory?
  • final bundle too large?
  • too much network traffic?
  • something else?

If you are unable to engage the profiler, then your next solution is gross guessing changes, such as “reimport all textures as 32x32 tiny textures” or “replace some complex 3D objects with cubes/capsules” to try and figure out what is bogging you down.

Each experiment you do may give you intel about what is causing the performance issue that you identified. More importantly let you eliminate candidates for optimization. For instance if you swap out your biggest textures with 32x32 stamps and you STILL have a problem, you may be able to eliminate textures as an issue and move onto something else.

This sort of speculative optimization assumes you’re properly using source control so it takes one click to revert to the way your project was before if there is no improvement, while carefully making notes about what you have tried and more importantly what results it has had.

1 Like

I will spare you a 100 line diatribe against pooling and say it should only require a bit of adjustment to get it to work. If there is a problem with pooling objects I’d like to see something official recommending that it not be done. Instead we have tutorials explaining how to do it.

That said I don’t think a List is a good collection to use (but it will work of course). I use a Queue. It doesn’t require but does support prefilling.

What you are experiencing I believe is something I spent a day on as well. It made no sense to me then and I still don’t understand what is going on behind the scenes BUT it is due to your setting the object inactive. Apparently (if the videos are to be believed) the use of an Array would not cause this behavior. So you can switch to an Array or see what happens if you do not inactivate the objects.

Again I’m queuing bullets in my Queue as they are fired so it only grows to the size needed in real-time use. If nobody fires a bullet the Queue remains empty. Firing 100’s of bullets doesn’t require 100 stored in the Queue, if a bullet is not available another is instantiated and the Queue grows to cover that case but typically some will have been returned before another one is needed.

Try it and let us know.

1 Like

I’ve kept my opinions to myself for months but do you honestly believe these types of answers result in the outcome you are hoping for? If you are unable to engage the profiler did he ask about the profiler?

1 Like

The outcome I’m hoping for is people start writing software in a constructive fashion without wasting time on silly things that do not help their project (object pooling) and generally wreck it (misdirected optimization in general).

By that measure, yes, I’ve already helped many people here avoid bad choices regarding the above two things, and I hope to help more people.

No but OP said, and I quote:

That either means:

  • “I wanna learn about object pooling!” in which case OP doesn’t need us because pooling is VERY well understood, even if it is in the general average case a useless gesture

  • or more likely OP “read on the internet that pooling makes games faster” (a total lie!!) and now they’ve wrecked their project by mis-implementing pooling.

If OP wants his game to be faster, at least START with the profiler.

I stand firmly by 100% of everything I posted above.

I agree that there is no point in object pooling. Unity has some tutorials that imply object pooling is useful for even small numbers of objects. This is…not really true.

Pooling might be useful if you’re running into serious garbage collection problems: lots of time being spent cleaning up and making room in memory for big piles of objects. It also might be useful if it’s very expensive to create and destroy the objects.

Neither of these are true for a few hundred bullets in a shmup.

(and if you really want to have tens of thousands of bullets flying all over the place…look into ECS)

1 Like

I want people to have fun making games: bullets and space ships and zombies and players and balls and monkeys and lasers and dynamite…

In my wildest dreams, people here should JUST GO CRAZY with game development!

Unity3D makes it possible for the average person to pick it up, learn a little bit at a time, and move towards something they can be proud of, something they can enjoy playing, something they can show their friends and parents (“Look what I made!” followed by “Whoa, you made a really fun game here!”) and something that they could perhaps even make money at someday.

That’s beautiful, truly a beautiful thing in this world.

In every way, speculative optimization and object pooling DESTROYS that. Speculative optimization and object pooling DESTROYS projects and makes me sad. And it’s just SO unnecessary, so much work and struggle and sadness created by these two simple things.

That’s why I try to guide people away from these poor choices.

1 Like

That’s why I use LINQ pretty frequently :smile:

var wokenUp = enemies.Where(x => (x.transform.position - player.transform.position).magnitude < 25)
.Where(x => x.name != "Sleepy Joe")
.Where(x => x.sleeping)
.Where(x => x.sleepiness < 1);

foreach (var enemy in wokenUp) {
  enemy.WakeUp();
}

Is it maximally efficient? Hell no. Is it fast enough for almost everything? Yep.

I only think about optimization when…

  • It’s a huge difference. Think about O(N) vs. O(2^N) vs O(N!)
  • The result is convenient for me. If I’m going to grab a reference to a component and never let go of it, I might as well just make a field for it.
  • It’s actually vital (and I have Profiler data to back me up). I wrote an AI system for an RTS game that does gradient descent to find the optimal location for buildings, units, etc. It got slow very quickly, so I learned how to rewrite the entire thing as a bursted parallel job – and hoo boy, it sure is fast now!

There isn’t some universally acceptable way to learn and if someone wants to implement object pooling it can be a good exercise. But that said the way to dissuade bad habits or to encourage good ones isn’t to post 100 line “hey look at all the paragraphs I can cut and paste”.

The generally accepted fact is that dialog works better than diatribe.

It is reasonable to believe that if object pooling had no value (or negative value as some would have us believe) then it wouldn’t have been implemented by Unity. It wouldn’t likely be the subject of numerous Unity-related videos, courses and such. Notable developers and instructors, Asbjørn Thirslund for instance, would have probably outlined the downsides rather than how to do accomplish it

Can it be misused? That goes without saying, but if the situation arises that will benefit from object pooling it is best to know how to do it correctly. That comes with practice. The same goes for generic lists, dictionaries and a host of other options available to us. If one has no understanding of how say pub/sub, works it seems to me if the perfect use case showed up, such a developer wouldn’t be able to leverage it.

Learn stuff when you don’t need it so you can use it confidently when you do.

I don’t really see issues in your code. The only thing I could imagine is that your player shoots more bullets than there are instances in the pool. But in this case your pool would just return null and no more bullets would be spawned.

The if (gameObject.activeInHierarchy) part seems unnecessary because FixedUpdate won’t be called on (components on) deactivated GameObjects.

Also your pool looks a bit stange to me. I would just create new projectiles if the pool is too small and let them all live in memory - or destroy them when they are returned to the pool.

Also you don’t have to set any velocity on your projectiles from your player or your pool, your projectile accelerates on it’s own.

My assumption is that your projectile-prefab has wrong settings. The bspeed variable is probably null, because otherwise it woule be moving. Or your Rigidbody is set to “isKinematic”. Or you don’t even have a prefab assigned but a scene object instead, which has bspeed set to 0.

TL;DR: Code seems fine to me, it’s probably a setting in the inspector of your Bullet-Script, Bullet-Rigidbody or Pool.

Also I would make the pool create itself on demand, so you don’t have to worry about having the singleton sit in your hierarchy.

And you should have a look at the pooling classes unity provides:
https://docs.unity3d.com/ScriptReference/Pool.ObjectPool_1.html

And to the whole conversation about speculative optimization:

Fixing Performance and rewriting code to be more performant isn’t really fun. It’s more fun to just keep a few patterns while writing the code so you don’t have to worry about it at all. At least in my experience.

And when you know that you will have thousands of bullets spawned and despawned within a few seconds, I see no reason to wait for the profiler to tell me that not using a pool was a bad decision.
Same with hundreds of raycasts per frame - there is a RaycastCommand suited for such cases.

I code everything with performance in mind, even when attending a game jam where I have to make a game in 2 or 3 days. It doesn’t slow me down at all. It won’t make my code any more complex because I have systems that handle such cases for me, it’s not like I re-invent pooling every time I need it, I just call ObjectPool.Get(prefab) and ObjectPool.Return(instance) instead of Instantiate(prefab) and Destroy(instance).

Worst case scenario in this regard is working on a game for one or two years, only to find out that the performance is really bad and you have to rewrite a lot of systems, which will introduce bugs into your game, this means you have to test and fix everything … and yea, this sounds really bad to me.
And when you see performance issues, when the game already stutters, it’s usually not just one new script that causes these problems, it usually means that all the performance problems have piled up and you have to fix everything to support this new level where 10 enemies are active at the same time.

In my second last game I wasted two entire months just fixing performance issues (and to find out that lightmapping does not work in big game worlds).

So unless you are working on a flappy bird clone or anything with very low complexity, I’d advice keeping performance in mind at all times, not just code, but also game-design, level-design and so on.

At the end of the day we are all working on realtime simulations that should run at consistent 30-60fps (or more). And “fixing it when needed” is not always the most efficient approach. Sometimes, sure, but not always.

Sorry for the wall of text. xD

As we reach the one-day mark on this post, why has OP not yet posted this:


"I put this line of code in PBullet_Pis.cs on line 27:

Debug.Log( "rb.velocity = " + rb.velocity);

And here is what printed out:"


Why don’t we have that post? Come on OP, you’re gonna have to debug this. Nobody here can.

EDIT: I guess OP hasn’t even come back yet… or maybe they came back and got scared by our raging conversation and ran away.

1 Like

I’m telling you it is due to him having set it inactive. I’m waiting for him to test the theory and to confirm that. Meanwhile I believe that he absolutely needs to reset force, position and rotation on spawned items. Both angular velocity and velocity should be set to zero when he is done with them or they are theoretically “still moving”.

To the original poster: I would tend to instantiate the List in Awake

But more importantly (I think) this isn’t a Singleton pattern if that is your intent.

 private void Awake()
    {
        SharedInstance = this;
    }
    // Start is called before the first frame update
    void Start()
    {
        preloadobj = new List<GameObject>();

Well, both the post commenters and my seniors are telling me to give up on it since I’m only making this as a side project and it didn’t even require enhancements in the first place… I wanted to put this in my portfolio but for now I might settle with spawn-despawn, tho I will try it out if I had the chance! Thanks for the info!

Sorry, I was busy on assignments (am a uni student) so I just came back now…

Thanks all of you for sharing your insights! I only got time now to fix it, but I am doing it now!

Both the rigidbody is dynamic and bspeed isn’t null:
8697339--1173819--upload_2023-1-1_22-1-2.png

rb.velocity = (0.00, 0.00)
This is the result.
I’m gonna try out using array instead of list. And should I make a new follow up post?