Announcement

Collapse
No announcement yet.

Get Colliding Actors

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Get Colliding Actors

    Very quick question:

    I know how to use GetOverlappingActors(), but is there a way to get the objects the character is "touching" without necessarily overlapping?

    Thank you in advance

    #2
    I'm not sure I understand. An overlap is detected when two collision shapes are overlapping. What is a "touching" if not precisely that?

    -Camille

    Comment


      #3
      For example the object the Actor is standing on, objects that bounce off him or that the actor itself is bouncing off of. GetOverlappingActors() doesn't work for those.

      Comment


        #4
        Originally posted by HammelGammel View Post
        GetOverlappingActors() doesn't work for those.
        Actually, it could, if you query it during the very brief period the collision is happening in. There's no such thing as perfect collision, even with continuous collision detection, so most "bounces" are usually triggered by a hairline overlap. Theoretically, you could set up a tick at just the right time for this to happen.

        That's not practical though, so there are various mechanisms to detect collisions as is instead of overlaps. For collisions, i.e.: "bouncing off", there's a physics property you can set:

        Code:
        	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Collision, meta=(DisplayName="Simulation Generates Hit Events"))
        	uint32 bNotifyRigidBodyCollision:1;
        Set that to true, and then you can subscribe to the OnComponentHit delegate to get notified of collisions.

        The surface the actor is standing on is a special case. Character physics isn't handled through raw physics in order to better control the character movement and avoid having erratic movement when standing on uneven surfaces. CharacterMovementComponent handles most of that, and there's a property on there that stores information about the floor should you need it:

        Code:
        	/** Information about the floor the Character is standing on (updated only during walking movement). */
        	UPROPERTY(Category="Character Movement", VisibleInstanceOnly, BlueprintReadOnly)
        	FFindFloorResult CurrentFloor;

        Comment


          #5
          Thank you Camille, that's what I was searching for. However, I am having a little bit of troube getting it to work. When I searched for OnComponentHit, I found that the First Person Shooter C++ tutorial uses it and tried to use it the same way:

          The header of my projectile
          Code:
          	UFUNCTION()
          	void OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
          The constructor
          Code:
          	MeshComponent->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);
          Code:
          void AProjectile::OnHit(AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
          {
          	GEngine->AddOnScreenDebugMessage(-1, 5.0, FColor::Green, "OnHit() called");
          }
          Unfortunately OnHit() is only called very rarely and only on NPCs. What am I doing wrong?

          Comment


            #6
            Sounds like might be collision channel settings. The projectile could be hitting the capsule before hitting the mesh. Have a look at it using the collision analyzer (console command canalyzer), between that and tracetag you can easily get to the bottom of collision issues.

            Comment


              #7
              But shouldn't this function be fired whenever my projectile collides with anything, no matter what?

              I did a bit of testing. You are correct, the CapsuleComponent prevents the collision with the Mesh, which is the reason why the function isn't called every time. However, why does the function only fire on the Mesh of my Characters and not on other components/actors?

              Comment


                #8
                Originally posted by HammelGammel View Post
                But shouldn't this function be fired whenever my projectile collides with anything, no matter what?
                Ah, you're right. I had a bit of a brain fart there and was reading OnComponentHit as being registered on the character mesh, not the projectile mesh.

                Be careful about registering delegates in constructors. In certain initialization paths you might end up constructing an object that's still using the CDO's delegate. Be sure to surround any delegates with template object checks:

                Code:
                if( !HasAnyFlags( RF_ClassDefaultObject | RF_ArchetypeObject ) )
                {
                	MeshComponent->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);
                }
                I doubt this is the problem here though, even if it was the CDO OnHit being called, you'd still get the on screen message.

                Compare collision response channels of your characters vs the others, that might give you some insight. It could also be physics updates missing the collision between updates (unlikely), try setting bUseCCD to true. Can't really think of anything else without being able to see what's happening myself.

                Comment


                  #9
                  I set the collision-channels for all the components to BlockAll (CCD is enabled), and still, only the NPC-meshes seem to fire the function. But the collision is definitly happening with the other components, my projectile ricochets from every actor in the scene as it should, which means the collision-responses should be fine, doesn't it? There must be something wrong with the way I set up OnHit.

                  After another bit of testing:

                  So initially I thought the problem that the function was only triggered sometimes was caused by the fact, that the mesh of the character was blocked by the capsule, and only the parts that were outside the capsule could be hit. I'm not sure about this anymore though. I created two new object-channels: Projectile and Capsule. I set the npc-capsule's channel to capsule and my arrow's to projectile and made projectile ignore the capsule but not the actual mesh. Now the function doesn't fire at all anymore, which is weird considering hit.Component was the mesh (Projectile and mesh are still properly colliding though. This alone is weird. I'd have assumed, OnComponentHit would work for every collision that is happening. Kind of low-level returning it from the collision-detection itself) and not the capsule-component. Only when the capsule is set to block, in some specific places of the hit character the function is called (For example on the knee, that is just outside the capsule it always works).

                  I don't have any clue anymore, what could be the problem. I must be misunderstanding something entirely. This is just confusing xD
                  Last edited by Naram-boiii; 12-11-2014, 02:49 PM.

                  Comment


                    #10
                    From what I gathered by looking through actor.h, what I need is the ReceiveHit()-function.

                    Code:
                    void AProjectile::ReceiveHit(class UPrimitiveComponent* MyComp, AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit)
                    {
                    	GEngine->AddOnScreenDebugMessage(-1, 5.0, FColor::Green, "ReceiveHit() Called");
                    }
                    But for some reason this just doesn't work at all. Can somebody help me with this? I can't believe something that simple is giving me so much trouble :/

                    Comment


                      #11
                      ReceiveHit is a BlueprintImplementableEvent that so Actor blueprints can implement to get notified of blocking hits. Being a BlueprintImplementableEvent, it already has an autogenerated thunk and yours won't get called (I'm surprised this compiles at all). Look at AActor::DispatchBlockingHit and you'll see that OnComponentHit is being called at the same time the ReceiveHit event is being fired.

                      If you want to detect any component being hit (as opposed to just a particular one as is currently the case), then register for OnActorHit instead of MeshComponent->OnComponentHit.

                      Comment


                        #12
                        Ok. I think I found the problem. I forgot to check Generate Hit Events on my projectile... That's kind of emberrassing :U

                        One last question though: How do I register for OnActorHit? It doesn't seem to work the same way as OnComponentHit. I am not even sure how these two work. I assume I need knowledge in a certain aspect of C++. Can you point me to any material I can use to better understand how they work?

                        Comment


                          #13
                          Originally posted by HammelGammel View Post
                          One last question though: How do I register for OnActorHit? It doesn't seem to work the same way as OnComponentHit. I am not even sure how these two work. I assume I need knowledge in a certain aspect of C++. Can you point me to any material I can use to better understand how they work?
                          It's not really C++ specific, it's just an UE4 multicast delegate. C++ does not come with delegates out of the box, so UE4 rolled out their own system. Read up on delegates if you need to, the very short version is it is a mechanism that lets you pass around functions like objects so they can be called by something else without being aware of who will handle that function.

                          OnActorHit is a multicast delegate just like OnComponentHit, except it is on the actor instead of one of its primitive components. So in your projectile constructor:

                          Code:
                          if( !HasAnyFlags( RF_ClassDefaultObject | RF_ArchetypeObject ) )
                          {
                          	OnActorHit.AddDynamic(this, &AProjectile::OnHit);
                          }
                          And since the signature of the delegate (the function parameters) is different, you will have to update your OnHit function from:
                          Code:
                          DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams( FComponentHitSignature, class AActor*, OtherActor, class UPrimitiveComponent*, OtherComp, FVector, NormalImpulse, const FHitResult&, Hit );
                          
                          void AProjectile::OnHit( class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit );
                          To:
                          Code:
                          DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams( FActorHitSignature, AActor*, SelfActor, AActor*, OtherActor, FVector, NormalImpulse, const FHitResult&, Hit );
                          
                          void AProjectile::OnHit( AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit );

                          Comment

                          Working...
                          X