Parallel execution of functions

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Parallel execution of functions

Post by thoma91 »

Hi!

How can I execute the same function twice at the same time?
My problem is, when more than one enemy should attack the player, only one does it.
And after the first enemy's enemyAttack function ends (dies,or something), the second enemy's function starts.
It's weird, and I want them to attack the player at the same time.

How can I achieve this?
(Maybe it's not an Irrlicht-specific question, but if you know the answer, share it with me/with the community, thx.)
cobra
Posts: 371
Joined: Fri Jan 23, 2009 2:56 am
Location: United States
Contact:

Re: Parallel execution of functions

Post by cobra »

This really isn't a good enough reason to implement multi-threading. You can do this by updating a list of the characters/enemies.

Just add three methods: startAttack() when the enemy notices the player (called once), makeDecisions() which will also call startAttack() or endAttack() when it needs to and it makes other decisions, and endAttack() which will end the attack on the player. I don't even see how you're logically putting all of the decision-making into one function that doesn't end until the enemy dies. It should produce really bad/choppy results in that case. However you're doing it is terribly wrong.

Post some code and we'll help you fix it.
Josiah Hartzell
Image
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Parallel execution of functions

Post by thoma91 »

Here's how the enemies work:
-I call an enemyAI function in the main loop for every enemy
-enemyAI function handles what to do:
+if the player's far away, the enemies are patrolling in the room
+if the player's closer, the enemies in that area starting to follow the player
+and when the player and the enemy are close enough, the attack starts
These are all separate functions, and working well, for example if 2 enemy needs to follow the player at the same time, it's ok.
But the attacking works like this, for example:
-there are 2 enemies in the room, they're far from the player
-i'm getting closer to the first,it starts to follow me
-it's near, it starts to attack, ok
-then i shoot the second one, to stop patrolling, and come to me, so it follows me
-when it gets near, and should start the attack, only ONE is attacking me, the one with the "less number" (enemynode[1],enemynode[2])
-if i shot enemynode[1] to death, the second one starts the attack

Here's the code for the enemyAttack, but I don't think that'll help, because the enemyFollowing code is more or less the same, only the "attack" and "follow" parts are different, but what works there, it isn't working here..
That's why I thought I should start enemyAttack functions parallel.
If you've got an idea, please help me.

Code: Select all

 
// gets an int to know, which enemy to deal with
void enemyAttack(int e)
{
scene::ICameraSceneNode* camera = smgr->getActiveCamera();
 
// which enemy's animations to handle
controller[e].setAnimatedMeshNode(EnemyNode[e]);
 
// setting up rotation, this is not important for now
// ...
 
 
    controller[e].playAnimationNow("attack");
    controller[e].playAnimation("walk");
    playerhealth -= 10;
    updateHealth();
    
    // value counts deltatime to separate attacks, it's not important here
    value=0;
 
}
 
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: Parallel execution of functions

Post by randomMesh »

Please show
- the function which calls the enemyAttack function.
- the playAnimationNow/playAnimation function of the controller class/struct/whatever. What is controller anyway?

Btw. C++ is an object oriented language. You should make the attack function a method of the Enemy or controller class.
"Whoops..."
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Parallel execution of functions

Post by thoma91 »

Controller is an animation controller, written by Sudi in one of my topics.
It handles which animation should played in certain cases.

CAnimationController.cpp

Code: Select all

 
/*
  Copyright (C) 2011 Daniel Sudmann
 
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.
 
  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:
 
  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
 
  Daniel Sudmann suddani@googlemail.com
*/
#include "CAnimationController.h"
 
CAnimationController::CAnimationController()
{
    animatedNnode = 0;
    animationRunning = false;
}
 
CAnimationController::~CAnimationController()
{
    if (animatedNnode)
    {
        animatedNnode->setAnimationEndCallback(0);
        animatedNnode->drop();
    }
    animatedNnode = 0;
}
 
void CAnimationController::OnAnimationEnd(irr::scene::IAnimatedMeshSceneNode *node)
{
    animationRunning = false;
    if ((nextAnimation.size() > 0 || currentAnimation.looping) && animatedNnode)
    {
        if (nextAnimation.size() > 0 )
        {
            setAnimation(nextAnimation[0]);
            nextAnimation.erase(0);
        }
        else
            setAnimation(currentAnimation);
    }
}
 
void CAnimationController::addAnimation(const irr::c8 *name, const irr::u32 &start, const irr::u32 &end, const bool& loop)
{
    animations[name] = Animation(name, start, end, loop);
}
 
void CAnimationController::setAnimatedMeshNode(irr::scene::IAnimatedMeshSceneNode *node)
{
    if (animatedNnode == node)
        return;
 
    nextAnimation.clear();
    animationRunning = false;
 
    if (animatedNnode)
    {
        animatedNnode->setAnimationEndCallback(0);
        animatedNnode->drop();
    }
 
    animatedNnode = node;
 
    if (animatedNnode)
    {
        animatedNnode->grab();
 
        currentAnimation.start = 0;
        currentAnimation.end = animatedNnode->getEndFrame(); //There is no way to get the actual frame count...
 
        animatedNnode->setAnimationEndCallback(this);
    }
}
 
void CAnimationController::playAnimation(const irr::c8 *name)
{
    if (animations.find(name) == 0)
        return;
 
    if (animationRunning)
    {
        nextAnimation.push_back(animations[name]);
    }
    else
        setAnimation(animations[name]);
}
 
void CAnimationController::playAnimationNext(const irr::c8* name)
{
    if (animations.find(name) == 0)
        return;
 
    nextAnimation.clear();
 
    if (animationRunning)
    {
        nextAnimation.push_back(animations[name]);
    }
    else
        setAnimation(animations[name]);
}
 
void CAnimationController::playAnimationNow(const irr::c8* name)
{
    if (animations.find(name) == 0)
        return;
 
    nextAnimation.clear();
 
    setAnimation(animations[name]);
}
 
 
void CAnimationController::setAnimation(const Animation& anim)
{
 
    printf("change Animation to %s\n", anim.name.c_str());
    currentAnimation = anim;
    animatedNnode->setFrameLoop(currentAnimation.start, currentAnimation.end);
    animatedNnode->setCurrentFrame(currentAnimation.start);
    animatedNnode->setLoopMode(false);
    animationRunning = true;
}
 
CAnimationController.h

Code: Select all

 
 
#ifndef CANIMATIONCONTROLLER_H
#define CANIMATIONCONTROLLER_H
 
#include <IAnimatedMeshSceneNode.h>
#include <irrMap.h>
 
class CAnimationController : public irr::scene::IAnimationEndCallBack
{
public:
    struct Animation
    {
        Animation()
        {
            name = "";
            start = 0;
            end = 1;
            looping = false;
        }
        Animation(const irr::c8* n, const irr::u32& s, const irr::u32& e, const bool& loop)
        {
            name = n;
            start = s;
            end = e;
            looping = loop;
        }
        Animation(const Animation& other)
        {
            name = other.name;
            start = other.start;
            end = other.end;
            looping = other.looping;
        }
 
        irr::core::stringc name;
        irr::u32 start;
        irr::u32 end;
        bool looping;
    };
 
    CAnimationController();
    virtual ~CAnimationController();
 
    //!Set the node that should be controlled
    void setAnimatedMeshNode(irr::scene::IAnimatedMeshSceneNode* node);
 
    //!Add an animation to the controller
    void addAnimation(const irr::c8* name, const irr::u32& start, const irr::u32& end, const bool& loop = false);
 
    //!Plays an animation when the previous ones finished. Animations chain up
    void playAnimation(const irr::c8* name);
    //!Plays this animation directly after the last one and clears the animation chain
    void playAnimationNext(const irr::c8* name);
    //!Plays this animation directly and clears the animation chain
    void playAnimationNow(const irr::c8* name);
 
    void OnAnimationEnd(irr::scene::IAnimatedMeshSceneNode* node);
protected:
    void setAnimation(const Animation& anim);
 
    irr::core::map<irr::core::stringc, Animation> animations;
    Animation currentAnimation;
    irr::core::array<Animation> nextAnimation;
    irr::scene::IAnimatedMeshSceneNode*animatedNnode;
    bool animationRunning;
};
 
#endif // CANIMATIONCONTROLLER_H
 
Here's the enemyAI function, this calls enemyAttack:
(it's only a series of if conditions, WHEN and WHAT to do)

Code: Select all

 
void enemyAI(int e)
{
 
scene::ICameraSceneNode* camera = smgr->getActiveCamera();
 
controller[e].setAnimatedMeshNode(EnemyNode[e]);
 
playerpos = camera->getPosition();
EnemyPosition[e] = EnemyNode[e]->getPosition();
 
if(EnemyHealth[e] > 0){
 
   if(playerpos.X-EnemyPosition[e].X >= 0 && playerpos.X-EnemyPosition[e].X >= 500 && playerpos.X-EnemyPosition[e].X < 2500){
      enemyPatrol(e);
      if(EnemyHealth[e] < 100){
      enemyFollow(e);}
      }
 
   else if(playerpos.X-EnemyPosition[e].X < 0 && playerpos.X-EnemyPosition[e].X <= -500 && playerpos.X-EnemyPosition[e].X > -2500){
      enemyPatrol(e);
      if(EnemyHealth[e] < 100){
      enemyFollow(e);}
      }
 
   else if(playerpos.Z-EnemyPosition[e].Z >= 0 && playerpos.Z-EnemyPosition[e].Z >= 500 && playerpos.Z-EnemyPosition[e].Z < 2500){
      enemyPatrol(e);
      if(EnemyHealth[e] < 100){
      enemyFollow(e);}
      }
 
   else if(playerpos.Z-EnemyPosition[e].Z < 0 && playerpos.Z-EnemyPosition[e].Z <= -500 && playerpos.Z-EnemyPosition[e].Z > -2500){
      enemyPatrol(e);
      if(EnemyHealth[e] < 100){
      enemyFollow(e);}
      }
 
 
if(playerpos.X-EnemyPosition[e].X < 0 && playerpos.Z-EnemyPosition[e].Z < 0 && EnemyHealth[e] > 0)
{
    if(playerpos.X-EnemyPosition[e].X > -120 && value > 500 && playerpos.Z-EnemyPosition[e].Z > -150){
 
    enemyAttack(e);
 
    }
    else if(playerpos.X-EnemyPosition[e].X <= -120 && playerpos.X-EnemyPosition[e].X > -500)
    {
    enemyFollow(e);
    
    }
    else if(playerpos.X-EnemyPosition[e].X > -120 && playerpos.Z-EnemyPosition[e].Z <= -150 && playerpos.Z-EnemyPosition[e].Z > -500){
 
    enemyFollow(e);
 
    }
 
}
 
else if(playerpos.X-EnemyPosition[e].X > 0 && playerpos.Z-EnemyPosition[e].Z >= 0 && EnemyHealth[e] > 0){
    if(playerpos.X-EnemyPosition[e].X < 120 && value > 500 && playerpos.Z-EnemyPosition[e].Z < 150){
 
    enemyAttack(e);
 
    }
    else if(playerpos.X-EnemyPosition[e].X > 0 && playerpos.X-EnemyPosition[e].X >= 120 && playerpos.X-EnemyPosition[e].X < 500){
 
    enemyFollow(e);
    
    }
    else if(playerpos.X-EnemyPosition[e].X < 120 && playerpos.Z-EnemyPosition[e].Z >= 150 && playerpos.Z-EnemyPosition[e].Z < 500){
 
    enemyFollow(e);
 
    }
 
}
 
else if(playerpos.X-EnemyPosition[e].X < 0 && playerpos.Z-EnemyPosition[e].Z >= 0 && EnemyHealth[e] > 0){
    if(playerpos.X-EnemyPosition[e].X > -120 && value > 500 && playerpos.Z-EnemyPosition[e].Z < 150){
 
    enemyAttack(e);
 
    }
    else if(playerpos.X-EnemyPosition[e].X <= -120 && playerpos.X-EnemyPosition[e].X > -500){
 
    enemyFollow(e);
    
    }
    else if(playerpos.X-EnemyPosition[e].X > -120 && playerpos.Z-EnemyPosition[e].Z >= 150 && playerpos.Z-EnemyPosition[e].Z < 500){
 
    enemyFollow(e);
 
    }
 
}
 
else if(playerpos.X-EnemyPosition[e].X > 0 && playerpos.Z-EnemyPosition[e].Z < 0 && EnemyHealth[e] > 0){
    if(playerpos.X-EnemyPosition[e].X < 120 && value > 500 && playerpos.Z-EnemyPosition[e].Z > -150){
 
    enemyAttack(e);
 
    }
    else if(playerpos.X-EnemyPosition[e].X > 0 && playerpos.X-EnemyPosition[e].X >= 120 && playerpos.X-EnemyPosition[e].X < 500){
 
    enemyFollow(e);
    
    }
    else if(playerpos.X-EnemyPosition[e].X < 120 && playerpos.Z-EnemyPosition[e].Z <= -150 && playerpos.Z-EnemyPosition[e].Z > -500){
 
    enemyFollow(e);
 
    }
 
}
 
 
} // if EnemyHealth
 
} // enemyAI
 
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Parallel execution of functions

Post by thoma91 »

No one knows how could I solve this problem?
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Parallel execution of functions

Post by mongoose7 »

I guess nobody has downloaded the code and tried to run it.

But maybe you can help yourself? I think all your functions take a parameter, e. As the first line of each function, use printf or cout to print the name of the function and the value of e. The condition that is troubling you is that one of the functions is not being called for one of the values of e, yes? By following the output you should see what functions are called with that value of e.

Either you are failing to call a function with the correct value, or you are calling it but it always does the same thing.
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Parallel execution of functions

Post by thoma91 »

I tried what you said of course, but I couldn't find the problem.

Here's how the program's running, an example with enemy no.1 and 2.

enemyAI(1) called
enemyAI(2) called
enemyAI(1) called
enemyAI(2) called
and so on

first I run to enemy no.2, and when the conditions are true, it begins to attack
enemyAttack(2) called
enemyAI(1) called
enemyAI(2) called
enemyAttack(2) called
enemyAI(1) called
enemyAI(2) called
enemyAttack(2) called

meanwhile enemy no.1 arrives, and starts to attack, but at the same time, enemy no.2 stops
but enemyAI(2) keeps running!!

enemyAI(1) called
enemyAttack(1) called
enemyAI(2) called
enemyAI(1) called
enemyAttack(1) called
enemyAI(2) called
enemyAI(1) called
enemyAttack(1) called
and so on

(Instead of:
enemyAI(1) called
enemyAttack(1) called
enemyAI(2) called
enemyAttack(2) called)

So that's what I do not understand, if enemyAI(2) runs, and the conditions should be true (I'm close to the enemy), why doesn't it attack me?
If I shot enemy no.1 to death, enemy no.2 starts to attack immediately.
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Parallel execution of functions

Post by thoma91 »

Hmm I think I caught the problem.. a variable's value is reset after an attack happens, but if enemy no.1 attacks, the enemy no.2's conditions will be never true because of this variable.
Thanks anyway :)
Post Reply