Download

Grabbing a simple bool variable from another actor

Hi,

Just wondering what a good way of getting this would be. Basically, I have an Actor class called Wall that reports back true when it has been hit, and saves it to a bool variable called PositiveHit. What I want to do is take that varibale and use it in an if statement in my main character file. I did some research and found a way to access the actor in another file, using an ActorIterator, however for some reason it only ever reports back one of my walls, rather than all of them. I also imagine I’ll need to use casting for this, but I’m not entirely sure of what syntax I would need for it. Any help would be appreciated. Here is the relevant code:

FirstPersonCharacter.cpp




bool AFirstPersonCharacter::GetHitBool() {
        for (TActorIterator<AWall> ActorIt(GetWorld()); ActorIt; ++ActorIt) {
                Wall = *ActorIt;
                AActor * WallHit = Wall;
                GLog->Log(*WallHit->GetName()); //weird scenario - literally only mywall3 is being detected in the world at all times.
                break;
        }
        PositiveHit = Wall->PositiveHit; 
        if (PositiveHit == true) {
                return true;
        }
        else (PositiveHit == false); {
                return false;
        };

}


bool HitBool = AFirstPersonCharacter::GetHitBool();
if (HitBool == true) {
         VelocityMultiplier = BaseMomentum;
}
else (HitBool == false); {
         VelocityMultiplier = VelocityMultiplier * 1.0f;
}
if (HitBool == true) {
         HitBool = false;
}



Wall.cpp



void AWall::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
        GLog->Log(*OtherActor->GetName());
        PositiveHit = true;
}

void AWall::Tick(float DeltaTime)
{
       Super::Tick(DeltaTime);
       frames = frames + 1.0f; //this is setup to make sure the velocitymultiplier starts increasing again afterwards, as there was a bug where it would stay at base forever.
       if (fmod(frames, 30.f) == 0) {
               PositiveHit = false;
       }
}


This code works perfectly for the one wall, but all the others just don’t change the velocity after being hit.

Please excuse me if I’ve posted wrongly, this is my first time on the forum haha

Thanks in advance!



bool AFirstPersonCharacter::GetHitBool() {
for (TActorIterator<AWall> ActorIt(GetWorld()); ActorIt; ++ActorIt) {
Wall = *ActorIt;
AActor* WallHit = Wall;
GLog->Log(*WallHit->GetName()); //weird scenario - literally only mywall3 is being detected in the world at all times.
break; // YOU BREAK THE LOOP IN THE FIRST ACTOR FOUND.
}
PositiveHit = Wall->PositiveHit;
if (PositiveHit == true) {
return true;
}
else (PositiveHit == false); { // WRONG ';' HERE.
return false;
}; // USELESS ';' HERE.

}


bool HitBool = AFirstPersonCharacter::GetHitBool();
if (HitBool == true) {
VelocityMultiplier = BaseMomentum;
}
else (HitBool == false); { // WRONG ';' HERE.
VelocityMultiplier = VelocityMultiplier * 1.0f;
}
if (HitBool == true) {
HitBool = false;
}

thank you, I’ll give it a go later. - appreciate it!

The first thing that is realy bad about this, is that you iterate all walls.
A better way of doing this is passing the attacker with the attack. The default projectile class has the “instigator” attribute for that. So the wall, when hit, can cast the “instigator” to the player and call a function on him.

That does fix the issue of not going through every actor, however now the issue is that the boolean value cannot be read from Wall. I’m assuming it just isn’t actually returning the actor from the loop now that I removed break;, but I can’t think of a way to get them both to work fine

I don’t doubt that my code is inefficient, but it would probably mean rewriting most of my logic if that was the case. I’m also not entirely certain what you mean by that, I’m quite a begininner relatively speaking.

You need to re-think your entire logic. Just removing the break will not fix the issue for you as the code after the for loop will run only for the last actor of the loop - and removing the break it was running only for the first as pointed out. If you put the code inside the loop it will not fix either as it will return right after checking the very first actor.

Gotcha, guess I’ll get started then hahaha

Just in case anyone is wondering, I managed to get it sorted. So just incase anyone wants to follow my probably incredibly inefficient solution here is the code!



bool AFirstPersonCharacter::GetHitBool() {
         TArray<AWall*> Walls;
         for (TActorIterator<AWall> ActorIt(GetWorld()); ActorIt; ++ActorIt) {
                 Wall = *ActorIt; //adds the actor for the wall in this iteration to Wall
                 Walls.Add(Wall); //adds the wall to the Walls array
                 int WallsSize = Walls.Num();
                 if (WallsSize == WallCount) { //compares the amount of walls added to total walls in scene , 6 atm, defined in the editor
                         break; //goes into while loop
                 } 
          } //array of all wall actors in scene should be built now
          int index = 0;
          result = false; //resets result to false
          while (index<WallCount) { //while there are still walls left to check
                    PositiveHit = Walls[index]->PositiveHit; //grabs the bool for that wall
                    if (PositiveHit == true) {
                            result = true;
                            break; //returns result, and empties the array again ready for the next loop
                    }
                    index = index + 1; //gets ready for the next wall
           }
           Walls.Empty();
           return result;

}



If you plan to do a project that is more then a week, seriously take a break and do some coding practice.
E.,g. https://www.codewars.com/ They give you a task and you have to write a function for it. You can look at the code of others to see how they solved the exact same problem.

As far as I can tell you want to do something if ANY wall was hit:



bool AFirstPersonCharacter::WasWallHit()
{
   bool Result = false;
   for (TActorIterator<AWall> ActorIt(GetWorld()); ActorIt; ++ActorIt)
   {
      Result |= (*ActorIt)->PositiveHit; // Result will always be true if it was true once
      (*ActorIt)->PositiveHit = false; // Need to reset the hit
   }
   return Result;
}


P.S. can Unreal please finally stop fu**** up the forum?

thanks a bunch for the recommendation, I’ll be sure to follow up on it! This project is what I’m working on for my coursework in my computer science class, hence why I’m just wanting to get it done rather than perfect it at this stage. (Not long left before it needs submitting) I had never delved into unreal before starting it, so I’ve been learning along the way.

Hey, I’ll get a higher grade for improving the code after doing those challenges you suggested! But yeah, I’m definitely gonna have to do some intense practice before I head off to university this autumn Haha.