Some questions about ECollisionChannels and detection

Hi, how are you guys doing?
I’m a begginer to UE4 and I would like to make some questions, if you don’t mind. :slight_smile:

1:
I’m making an Arkanoid game and I decided to make my own CollisionChannels to better understand my code. I went to Project Settings → Engine → Collision and created some under Object Channels. On my ball, trought the aid of the function SweepResult.GetComponent()->GetCollisionObjectType(), inside of the OnComponentBeginOverlap() delegate function, I’ve got the integer return value as ball hitted the wall, the screen border, the blocks and itself.

int test = SweepResult.GetComponent()->GetCollisionObjectType();
UE_LOG(LogTemp, Warning, TEXT("CollisionChannel Type: %d."), test);

With that, I’ve noted that:
Paddle is 14.
Ball is 15.
Block_SM is 16.
ScreenBorder is 17.

Note the integer values above is what I’ve got trought the pointview of the ball, as the ball hitted those objects. With the information of hovering my mouse on the ECC_GameTraceChannels in the EngineTypes.h, I’ve made this defines on the top of the .cpp of the files that I deal with collision:

#define ECC_Paddle               ECC_GameTraceChannel1
#define ECC_Ball                    ECC_GameTraceChannel2
#define ECC_BlockSM            ECC_GameTraceChannel3
#define ECC_ScreenBorder    ECC_GameTraceChannel4

Now in the OnComponentBeginOverlap() of the Block, I’ve made this:

int test = SweepResult.GetComponent()->GetCollisionObjectType();
	if(test == 15)
		UE_LOG(LogTemp, Warning, TEXT("Block: I was hitted by the ball."));

This if statement doesn’t trigger when the block is hitted by the ball. With some effort, I have made two blocks collide and value returned by

int test = SweepResult.GetComponent()->GetCollisionObjectType();
UE_LOG(LogTemp, Warning, TEXT("Block: %d."), test);

was 16 when the block was hitted by another block. When the block was hitted by the ball I’ve got the same value: 16. I would like to know some fix or workaround for this. :smiley:

2:
Sometimes the ball collides with two things in the same frame. I’ve detected this using the GFrameNumber global variable and other boolean to know this. It worked and its quite normal. So, some problems are happening because too many collision are happening in quick sucession or together. I would like to know if I can only process the ScreenBorder collision and ignore the others.

3:
As my game is "2D’, I’m trying to make my collision 2D as well for performace. I’m giving the Paddle and the Block UBoxComponent made for collision with the Y value at 0.0f in the Box Extent FVector. With my ScreenBorder, it’s two UBoxComponent with 0.0f scale applied to X and Y rooted to a empty USceneComponent. As I hit play, I get this from the log. I tried to disable everything related to physics.

LogPhysics: Warning: Scale for /Engine/Transient.World_10:PersistentLevel.ScreenBorderCollision_BP_C_0.Left Side has a component set to zero, which will result in a bad body instance. Scale:X=0.000 Y=0.000 Z=200.000

I get one for the Right Side too. Is this aproach going to a problem? If so, what do you guys sugest?

-----

Whow, I think I’m done. Sorry for this.
Thanks so much for reading trough this.
Stay safe. :slight_smile:

I will work myself from what I can understand.

The physics warning is normal because the collision is still 3D all you have done is scaled things to zero.
Instead, change these scales back to a non-zero value.

Are you using TileMaps/Sprites?
If you are, there might be an option for using 2D collision, although from my knowledge this has been experimental for a while and using 3D physics and collision are the default settings (suggesting that you should use them over the 2D collision).

As for the collisions not working, the issue might be the zero scaling. Nevertheless, I recommend you to change the way you are checking collisions. (test == 15) is not clear and it will be very hard to understand later on. You can try and do (collisionType == ECC_Ball), which will be much more clear, but still a bit hard to maintain when you have lots of Components under the same Ball Actor.

I do not know what you are trying to achieve but I recommend Casting on the Actor you are hitting rather than checking if one of the (possibly many) components that the Actor has is of collision type ECC_Ball. This would look something like

if(ABall* ball = Cast<ABall>(SweepResult.GetActor())
{
  //do stuff here when ball actor is swept
} else
{
  //do stuff here when the swept actor is NOT a ball.
}

This is just an example. If you have many actors that inherit or are of class ABall, then this is the way to go (so you don’t have to check for each component having ECC_Ball collision). For the component to work you would have to make sure that all the Components in the hierarchy that you want to process are of type ECC_Ball. Whereas the above example will guarantee that if the if-statement succeeds the Actor class inherits from or is an ABall class.

Thanks for answering. :slight_smile:
I’ve changed all my scale values back to non-zero, nothing changed.
And your suggestion is what actually I’m using:

if (SweepResult.GetComponent()->GetCollisionObjectType() == ECC_ScreenBorder)

I just showed the int cast to show what number I’ve got from the ENUMs.
Sorry, I could not make you Casting on the Actor aproach works. I have tried using my Ball class name, AArkanoidBall or ArkanoidBall, without sucess. I even tried to forward declare class AArkanoidBall; on my .h file, but it gave me errors…

This image is what my Block collision used to look like before I’ve changed the Y back to non-zero. I do not use sprites.

Okay, so my guess is that your Ball class is a Blueprint class. There is two ways you can do this in a fairly straightforward way without using all those messy asset paths to find a blueprint class.

  1. Create a parent class for Ball in C++, put all base functionality there and override this class in Blueprint. That way you have access to it in C++, and you can do casting like in the original answer.

  2. Create a UClass* variable. define the UPROPERTY specifiers so that it can be edited in the Editor to the class of the Ball. And then do a check whether the UClass specified is the same as the class of the actor hit.

If you still want to continue with your other approach, I might suggest printing the component hit, the actor hit and the collision type all at the same time so that you can see what is being hit.

My Blueprint classes are derived from my C++, so I guess the 1) is already done?.
About the step 2), I’ll have to do some research in how to do that.

Thanks!

Hmm, if I make the block movable and the block hits another objects, the function give me correct ENUM numbers, but if the block is set to Static, it won’t. Maybe SweepResult only works on movable object?

Edit1:
Can I use the function GetCollisionObjectType() from the AActor*? I’m thinking to use with “OtherActor” variable.

Edit2:
The following code worked. I guess if safe it will only work with the ball?

if (OtherActor->GetComponentsCollisionResponseToChannel(ECC_Ball) == ECR_Overlap)
	UE_LOG(LogTemp, Warning, TEXT("It worked!"));

Here’s a video: Unreal Engine 4 Collision Drama - YouTube