-4

Im new to programming in c++ and trying to get a some boids all move to center, I have two methods updateboid and cohesion. In cohesion Im trying to return a normalized vector into updateBoid, and when I do the boids just all move sideways and not towards center. Im doing something silly here, some help will be greatly appreciated.

void Scene::updateBoid()
{
    for(size_t i=0; i<m_collection.size(); ++i)
    {
        for(auto &m :m_collection[i])
        {
            m->acc = cohesion();

            m->pos += m->acc * 0.05f ;
        }
    }
}


Vec3 Scene::cohesion()
{
    const float pi = 3.14f;

    Vec3 center;
    Vec3 test;

    for(size_t i=0; i<m_collection.size(); ++i)
    {
        for(auto _m :m_collection[i]) // all of the boids
        {
            center += _m->pos;
        }

        center /= m_collection[i].size(); // doing this gives the center

        /// Boids move to the center of their average positions
        for(auto &m :m_collection[i])
        {
            m->dir =center - m->pos; //vector between the two objects

            m->dir.normalize();

            return m->dir;
        }
    }

}

Previous Code in cohesion()

        m->dir =center - m->pos;        //length between the two objects
        m->dir.normalize();
        m->pos+=m->dir * 0.25f; //speed

This worked, but want another approach by using another method to update.

  • you should add more code cause right now I have no clue what the supposedly working normalize() does nor what m is – aldr Dec 17 '18 at 17:48

2 Answers2

0

You are always returning (basically) the same direction in each cohesion call, so you set all m->acc to the same value. That's because your return in cohesion exits for the first boid already.

The problem is that you haven't made up your mind what cohesion is supposed to do. If it is supposed to return the target direction of one boid, then you must tell it which boid to consider. You could also update m->acc directly in cohesion and just leave updateBoid to modify m->pos (and only reading m->acc - that's probably the better solution.

In code:


Option 1: Do not return anything. Only modify each boid. Do not call cohesion inside updateBoid, just once.

void Scene::updateBoid()
{
    for(size_t i=0; i<m_collection.size(); ++i)
    {
        for(auto &m :m_collection[i])
        {
            float acc = m->dir;
            m->pos += acc * 0.05f;
        }
    }
}


void Scene::updateCohesion()
{
    for(size_t i=0; i<m_collection.size(); ++i)
    {
        // This must be in here, otherwise it will be slightly wrong later.
        Vec3 center;

        for(auto _m :m_collection[i]) // all of the boids
        {
            center += _m->pos;
        }

        center /= m_collection[i].size(); // doing this gives the center

        /// Boids move to the center of their average positions
        for(auto &m :m_collection[i])
        {
            m->dir =center - m->pos; //vector between the two objects

            m->dir.normalize();
        }
    }
}

Option 2: Return the direction for each boid. This is inefficient because you calculate the center again every time.

void Scene::updateBoid()
{
    for(size_t i=0; i<m_collection.size(); ++i)
    {
        for(auto &m :m_collection[i])
        {
            float acc = cohesionForBoid(m_collection[i], m);
            m->pos += acc * 0.05f;
        }
    }
}

// What are these types? We don't know, that is missing from the question.
Vec3 Scene::cohesionForBoid(??? collection, ??? m)
{
    Vec3 center;

    for(auto _m : collection) // all of the boids
    {
        center += _m->pos;
    }

    center /= collection.size(); // doing this gives the center

    Vec3 dir = center - m->pos; //vector between the two objects
    dir.normalize();
    return dir;
}
Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • sorry Im new to c++, I still dont get it. Im trying to do for the whole collection and not just one boid – Clarence Rajaratnam Dec 17 '18 at 17:04
  • Which boid should cohesion return? – stark Dec 17 '18 at 17:17
  • Im trying to return a normalized vector so it could increment with position in the update() function – Clarence Rajaratnam Dec 17 '18 at 17:19
  • @ClarenceRajaratnam When a function returns, it ends. If you _always_ return `m->dir` for the first `m` in `m_collection[i]`, you will _never_ get to the second `m`, because the function is already done. If you have three boids and always return the direction of the first (that's what you currently do), then you will never get the correct direction for the other two in `updateBoid`. – Max Langhof Dec 17 '18 at 17:20
  • It is pretty clear what you want to do, but (with respect) it's also pretty clear that you don't really understand how functions work in C++. I recommend stepping through your code with a debugger to see what the computer actually does. – Max Langhof Dec 17 '18 at 17:23
  • so is there a way for the cohesion() to constantly release the m->dir and to be used in the update()? – Clarence Rajaratnam Dec 17 '18 at 17:24
  • There are several ways to do what you want, but you should first understand why what you are doing right now does not work: Functions don't "constantly release" as you want them to. Every time they are called, the code in them runs, until a `return` happens. – Max Langhof Dec 17 '18 at 17:26
  • So I updated the post, previously I had code just working properly inside cohesion() but I just want to break it apart and use through another method. – Clarence Rajaratnam Dec 17 '18 at 17:26
  • @ClarenceRajaratnam I added two code samples that hopefully help you understand. But this is very basic C++ that is better learned from a [book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) than question-by-question on stackoverflow (because it does not really help others). – Max Langhof Dec 17 '18 at 17:36
  • Greatly Appreciated @ Max Langhof . I'm really sorry, for asking this basic question, I was stuck in a tutorial purgatory for c++ and couldnt seem to go ahead with anything, until I started this project. I just want to keep going through this project and see it completed. Thank you again. – Clarence Rajaratnam Dec 17 '18 at 20:03
  • @Max Langhof, Thanks for your examples, Please can I get some information on your 1st example, I dont get how both void functions recognise the same m->dir being used to update the position? – Clarence Rajaratnam Dec 17 '18 at 21:24
  • Sorry, that is way beyond what can be explained here. Those are the absolute basics of **objects**, please consider some educational material. – Max Langhof Dec 18 '18 at 08:42
0
for(auto &m :m_collection[i])
{
    m->dir =center - m->pos; //vector between the two objects
    m->dir.normalize();
    return m->dir; // <- Always return on the first iteration
}

The for-loop will only be executed once as Max Langhof already pointed out. I'd call that a bug. Begin with amending your code.