x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Office Holiday

Epic Games' offices will be on holiday from June 22nd to July 7th. During this period support will be limited. Our offices will reopen on Monday, July 8th. 

cannot call a function from another class! No errors UE4 just closes itself

Hey Guys, First of all, really sorry for my bad english :D I hope you can help me out. I am really new to c++ / UE an I am following a general c++ tutorial. My problem is applying the things to unreal engine. I am struggling at calling a basic function from another class.

So I opened the standard FirstPerson Project from ue and with the help of a tutorial i created a raycast line which returns the name of the hitted object. What I am trying to do now, is creating an Actor "EnemyActor" which has a private Variable 'int health' and a public function which is called 'void ApplyDamage()'.

Whenever I use the Raycast hotkey, the Character class should call the function AEnemyActor::ApplyDamage().

Here is my Code:

EnemyActor.cpp

 #include "MyRaycastProject.h"
 #include "EnemyActor.h"
 #include "Engine.h"
 
 
 // Sets default values
 AEnemyActor::AEnemyActor()
 {
      // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
     PrimaryActorTick.bCanEverTick = true;
     health = 100;
 
 }
 
 // Called when the game starts or when spawned
 void AEnemyActor::BeginPlay()
 {
     Super::BeginPlay();
     
 }
 
 // Called every frame
 void AEnemyActor::Tick( float DeltaTime )
 {
     Super::Tick( DeltaTime );
 
 }
 
 void AEnemyActor::ApplyDamage()
 {
     health -= 10;
     GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Applied Damage.. %d Health left"), health));
 }

From the MyRaycastProjectCharacter.cpp..

 void AMyRaycastProjectCharacter::PerformRaycast()
 {
 
     AEnemyActor EActorObject;
     AEnemyActor* EActor = &EActorObject;
 
     FHitResult* HitResult = new FHitResult;
     FVector StartTrace = FirstPersonCameraComponent->GetComponentLocation();
     FVector ForwardVector = FirstPersonCameraComponent->GetForwardVector();
     FVector EndTrace = ((ForwardVector * 5000.0f) + StartTrace);
     FCollisionQueryParams* TraceParams = new FCollisionQueryParams;
 
     if (GetWorld()->LineTraceSingleByChannel(*HitResult, StartTrace, EndTrace, ECC_Visibility, *TraceParams))
     {
         DrawDebugLine(GetWorld(), StartTrace, EndTrace, FColor(255, 0, 0), true);
         //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("You Hit: %s"), *HitResult->Actor->GetName()));
 
         
         if (!HitResult->GetActor()->IsValidLowLevel())
         {
             
             return;
         }
 
         //Assign the hit actor to EActor
         EActor= Cast<AEnemyActor>(HitResult->GetActor());
         
         
 
         EActor->ApplyDamage();
     }
 }

The Raycast thing is alright. But whenever I try to call the function ApplyDamage(), my UE just closes and restarts. I hope you guys can help me. I am facing this problem since 2-3 days. but there are no c++ tutorials for ue. All I can see is Blueprint ;(

Product Version: Not Selected
Tags:
more ▼

asked Apr 10 '16 at 08:24 PM in C++ Programming

avatar image

AnGaraa
10 4 6

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

8 answers: sort voted first

Hello AnGaraa,

You are not assigning the hit actor, I.E HitResault->GetActor()

This is my interaction method so far for my player. I put all the line tracing into a static function library to keep everything nice and neat and callable from anywhere.

 void AplayerCharacter::Interact( )
 {
     FHitResult hitResaults(ForceInit); //This hit resault structure our line trace will output too.
 
     if (!UStaticFunctionLibrary::playerLineTrace(this, hitResaults))
     {
             //Logging here
         return;
     }
 
     AActor * hitActor = hitResaults.GetActor();
 
     if (Cast<AItem>(hitActor))
     {
         AItem * tmpItem = Cast<AItem>(hitResaults.GetActor());
 
         tmpItem->Interact(this);
     }
 }

As you can see, I get the hit actor from the FHitResults structure: AActor * hitActor = hitResaults.GetActor();. In my static function I also check if the hit actor is valid:

 if (outResaults.GetActor()->IsValidLowLevel())
 {
         return true;
 } 

So when KingCole32 said that EActor is never assigned is because it is never initialized so you will get bugs and errors. May I suggest using the Visual Studio Debugging Tool to debug if you are fairly new to C++! Using the debugger will allow you to add break points, check values of variables and what not. Make sure you follow this Visual Studio Debugger Extension(works with UE4 and Visual Studio 2015). It will allow you to see the values of some data structures defined in Unreal Engine, such as FString.

Back on topic, All you have to do is assign the hit actor to EActor and you should be all good to go, so try this:

  void AMyRaycastProjectCharacter::PerformRaycast()
  {
      
      AEnemyActor EActor;
  
      FHitResult* HitResult = new FHitResult;
      FVector StartTrace = FirstPersonCameraComponent->GetComponentLocation();
      FVector ForwardVector = FirstPersonCameraComponent->GetForwardVector();
      FVector EndTrace = ((ForwardVector * 5000.0f) + StartTrace);
      FCollisionQueryParams* TraceParams = new FCollisionQueryParams;
  
      if (GetWorld()->LineTraceSingleByChannel(*HitResult, StartTrace, EndTrace, ECC_Visibility, *TraceParams))
      {
          DrawDebugLine(GetWorld(), StartTrace, EndTrace, FColor(255, 0, 0), true);
          GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("You Hit: %s"), *HitResult->Actor->GetName()));

         //Check if hit actor is valid
         if (!HitResaults->GetActor()->IsValidLowLevel())
         {
                 //Some logging here and what not
                 return;
         } 

         //Assign the hit actor to EActor
         EActor = HitResults->GetActor();

          EActor.ApplyDamage();
      }
  }


Also, may I suggest to not use a pointer for HitResult, it is simply not needed(check my example).

Cheers,

more ▼

answered Apr 11 '16 at 07:57 AM

avatar image

Aaron1178
19 1 4 10

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

There are actually a lot of tutorials for C++, though it is admittedly somewhat difficult to dig through all the blueprint results.

From a quick check, it looks like you never assign EActor. The engine just crashes with no error report or anything? Not the restart screen?

more ▼

answered Apr 11 '16 at 12:40 AM

avatar image

KingCole32
180 9 9 12

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Oh I see.. I totally forgot this part thank you.

I tried your Solution, but now its saying to me

 EActor  = HitResult->GetActor();


 no operator "=" matches these operands


I couldnt find a method to replace that "=".. How can I fix this now?

more ▼

answered Apr 11 '16 at 09:58 AM

avatar image

AnGaraa
10 4 6

avatar image Aaron1178 Apr 11 '16 at 10:02 AM

Sorry, I forgot to add the cast. So try this:

 EActor = Cast<AEnemyActor>(HitResults->GetActor());

So GetActor returns an AActor * and we have to cast it to an AEnemyActor, using the Cast method.

avatar image rYuxq Apr 11 '16 at 10:57 AM

First of all, please try to use comments instead of answers :D And the assigment does not work because of type incompatability. GetActor() returns a pointer to an actor, while your EActor is not a pointer but a regular object. Either use the assignment as is after dereferencing the pointer on the right side or change your EActor to type pointer of AEnemyActor. I recommend the latter.

avatar image AnGaraa Apr 11 '16 at 11:21 AM

wow, I tried different ways to fix it with pointers etc. before but I always got an error. And suddenly the error is gone and I can compile again. But my main problem (unreal engine 4 crash, when I press 'R' -> BindAction for Raycast) is still there :(

avatar image rYuxq Apr 11 '16 at 11:28 AM

Try commenting out the line with GEngine->... and see if the behaviour changes

avatar image AnGaraa Apr 11 '16 at 11:50 AM

still the same. Its crashing when I try to call 'ApllyDamage()'.

avatar image rYuxq Apr 11 '16 at 12:05 PM

Is your EActor a pointer now? If it is, you need to call EActor->AplyDamage() instead of EActor.ApplyDamage(), maybe you want to update your code in your question ;)

Edit: try removing your function call to ApplyDamage() at all and see if THAT is the problem. I can not see anything wrong with it. I think that something else might be amiss

avatar image AnGaraa Apr 11 '16 at 01:29 PM

I just updated my code in the question and yes it is a pointer. But what I found out now is that ApplyDamage() wasnt the reason for my Crash.

The reason are these two lines:

 AEnemyActor EActorObject;
     AEnemyActor *EActor = &EActorObject;

I commented them out and my code worked fine. Now I dont know, if I have to define EActorObject somewhere else?

avatar image rYuxq Apr 11 '16 at 02:13 PM

You dont need it at all as far as I can see. You get the reference from GetActor() already. There is no need to declare another variable and reference it if you are never going to use it. Also, the reason for the crash is probably the fact that you must use CreateDefaultObject or such (https://docs.unrealengine.com/latest/INT/API/Runtime/CoreUObject/UObject/UClass/CreateDefaultObject/index.html) because UE does a lot of work behind the scenes.

avatar image AnGaraa Apr 12 '16 at 08:11 AM

but my problem is, I cant call ApplyDamage() whithout the declaration. I tried many things but its still crashing.

avatar image rYuxq Apr 12 '16 at 01:48 PM

You are supposed to remove the declaration for the EnemyObject only. Turn this:

AEnemyActor EActorObject; AEnemyActor* EActor = &EActorObject;

Into this:

AEnemyActor* EActor;

I dont see any reason why you would not be able to call the method this way.

avatar image rYuxq Apr 12 '16 at 05:51 PM

There might actually be another problem. Your GetActor() may not return a valid AEnemyActor object. You may hit something else. You should use the UE casting methods to cast the return value of GetActor() and check if EActor is NULL afterwards. If you do not, you may run into a null reference exception

avatar image AnGaraa Apr 12 '16 at 05:59 PM

I just tried to intilialize AEnemyActor in the header file and compiled it. Ue crashed and now every time I try to open the project its just crashes and gives me same error message xD I am at the end with my nerves. I dont know what can I do. :/

avatar image rYuxq Apr 12 '16 at 09:36 PM

Haha, dont worry. This should do the trick:

Go to your game project folder and open the Aeon.sln with visual studio. Undo the changes in your header file and rebuild the project. Starting your project should work fine afterwards.

Also remember: never put initializations into header files. You should not even think about using global variables (even if UE does)

avatar image ash9991win Apr 12 '16 at 09:45 PM

The reason it crashes is bcoz u are creating an actor on the stack and Unreal doesnt let you do that ( it garbage collects any actor created, meaning it tries to delete from the local stack, causing the crash ) To refer to an actor in the world, use an actorIterator or if you want to spawn an actor use SpawnActor

avatar image Aaron1178 Apr 12 '16 at 08:35 AM

Also, have you created the definition of the AEnemyActor::ApplyDamage() in your .cpp or .h file for AEnemyActor? E.G

 AEnemyActor::ApplyDamage()
 {
     //Call damage functions here
 }

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Thx for the fast rep but it seems it has nothing to do with, what you are setting EActor equal to.

'EActor' just dont want to accept the operand "="

I tried your new solution and its still the same error :/

more ▼

answered Apr 11 '16 at 10:38 AM

avatar image

AnGaraa
10 4 6

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Are you including the header that AEnemyActor is in?

Post your includes for this file please (#include blah at top of file)

more ▼

answered Apr 11 '16 at 10:52 AM

avatar image

Aaron1178
19 1 4 10

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

This is the whole Class. standard FirstPerson Script from unreal.

My custom function PerformRaycast is at the end.

 // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
 #include "MyRaycastProject.h"
 #include "MyRaycastProjectCharacter.h"
 #include "MyRaycastProjectProjectile.h"
 #include "Animation/AnimInstance.h"
 
 #include "GameFramework/InputSettings.h"
 #include "Engine.h"
 #include "EnemyActor.h"
 
 DEFINE_LOG_CATEGORY_STATIC(LogFPChar, Warning, All);
 
 //////////////////////////////////////////////////////////////////////////
 // AMyRaycastProjectCharacter
 
 AMyRaycastProjectCharacter::AMyRaycastProjectCharacter()
 {
     // Set size for collision capsule
     GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
 
     // set our turn rates for input
     BaseTurnRate = 45.f;
     BaseLookUpRate = 45.f;
 
     
 
     // Create a CameraComponent    
     FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
     FirstPersonCameraComponent->AttachParent = GetCapsuleComponent();
     FirstPersonCameraComponent->RelativeLocation = FVector(0, 0, 64.f); // Position the camera
     FirstPersonCameraComponent->bUsePawnControlRotation = true;
 
     // Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn)
     Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P"));
     Mesh1P->SetOnlyOwnerSee(true);
     Mesh1P->AttachParent = FirstPersonCameraComponent;
     Mesh1P->bCastDynamicShadow = false;
     Mesh1P->CastShadow = false;
 
     // Create a gun mesh component
     FP_Gun = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FP_Gun"));
     FP_Gun->SetOnlyOwnerSee(true);            // only the owning player will see this mesh
     FP_Gun->bCastDynamicShadow = false;
     FP_Gun->CastShadow = false;
     FP_Gun->AttachTo(Mesh1P, TEXT("GripPoint"), EAttachLocation::SnapToTargetIncludingScale, true);
 
 
     // Default offset from the character location for projectiles to spawn
     GunOffset = FVector(100.0f, 30.0f, 10.0f);
 
     // Note: The ProjectileClass and the skeletal mesh/anim blueprints for Mesh1P are set in the
     // derived blueprint asset named MyCharacter (to avoid direct content references in C++)
 }
 
 //////////////////////////////////////////////////////////////////////////
 // Input
 
 void AMyRaycastProjectCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
 {
     // set up gameplay key bindings
     check(InputComponent);
 
     InputComponent->BindAction("Raycast", IE_Pressed, this, &AMyRaycastProjectCharacter::PerformRaycast);
     InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
     InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
     
     //InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AMyRaycastProjectCharacter::TouchStarted);
     if( EnableTouchscreenMovement(InputComponent) == false )
     {
         InputComponent->BindAction("Fire", IE_Pressed, this, &AMyRaycastProjectCharacter::OnFire);
     }
     
     InputComponent->BindAxis("MoveForward", this, &AMyRaycastProjectCharacter::MoveForward);
     InputComponent->BindAxis("MoveRight", this, &AMyRaycastProjectCharacter::MoveRight);
     
     // We have 2 versions of the rotation bindings to handle different kinds of devices differently
     // "turn" handles devices that provide an absolute delta, such as a mouse.
     // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
     InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
     InputComponent->BindAxis("TurnRate", this, &AMyRaycastProjectCharacter::TurnAtRate);
     InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
     InputComponent->BindAxis("LookUpRate", this, &AMyRaycastProjectCharacter::LookUpAtRate);
 }
 
 void AMyRaycastProjectCharacter::OnFire()
 { 
     // try and fire a projectile
     if (ProjectileClass != NULL)
     {
         const FRotator SpawnRotation = GetControlRotation();
         // MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
         const FVector SpawnLocation = GetActorLocation() + SpawnRotation.RotateVector(GunOffset);
 
         UWorld* const World = GetWorld();
         if (World != NULL)
         {
             // spawn the projectile at the muzzle
             World->SpawnActor<AMyRaycastProjectProjectile>(ProjectileClass, SpawnLocation, SpawnRotation);
         }
     }
 
     // try and play the sound if specified
     if (FireSound != NULL)
     {
         UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation());
     }
 
     // try and play a firing animation if specified
     if(FireAnimation != NULL)
     {
         // Get the animation object for the arms mesh
         UAnimInstance* AnimInstance = Mesh1P->GetAnimInstance();
         if(AnimInstance != NULL)
         {
             AnimInstance->Montage_Play(FireAnimation, 1.f);
         }
     }
 
 }
 
 void AMyRaycastProjectCharacter::BeginTouch(const ETouchIndex::Type FingerIndex, const FVector Location)
 {
     if( TouchItem.bIsPressed == true )
     {
         return;
     }
     TouchItem.bIsPressed = true;
     TouchItem.FingerIndex = FingerIndex;
     TouchItem.Location = Location;
     TouchItem.bMoved = false;
 }
 
 void AMyRaycastProjectCharacter::EndTouch(const ETouchIndex::Type FingerIndex, const FVector Location)
 {
     if (TouchItem.bIsPressed == false)
     {
         return;
     }
     if( ( FingerIndex == TouchItem.FingerIndex ) && (TouchItem.bMoved == false) )
     {
         OnFire();
     }
     TouchItem.bIsPressed = false;
 }
 
 void AMyRaycastProjectCharacter::TouchUpdate(const ETouchIndex::Type FingerIndex, const FVector Location)
 {
     if ((TouchItem.bIsPressed == true) && ( TouchItem.FingerIndex==FingerIndex))
     {
         if (TouchItem.bIsPressed)
         {
             if (GetWorld() != nullptr)
             {
                 UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport();
                 if (ViewportClient != nullptr)
                 {
                     FVector MoveDelta = Location - TouchItem.Location;
                     FVector2D ScreenSize;
                     ViewportClient->GetViewportSize(ScreenSize);
                     FVector2D ScaledDelta = FVector2D( MoveDelta.X, MoveDelta.Y) / ScreenSize;                                    
                     if (ScaledDelta.X != 0.0f)
                     {
                         TouchItem.bMoved = true;
                         float Value = ScaledDelta.X * BaseTurnRate;
                         AddControllerYawInput(Value);
                     }
                     if (ScaledDelta.Y != 0.0f)
                     {
                         TouchItem.bMoved = true;
                         float Value = ScaledDelta.Y* BaseTurnRate;
                         AddControllerPitchInput(Value);
                     }
                     TouchItem.Location = Location;
                 }
                 TouchItem.Location = Location;
             }
         }
     }
 }
 
 void AMyRaycastProjectCharacter::MoveForward(float Value)
 {
     if (Value != 0.0f)
     {
         // add movement in that direction
         AddMovementInput(GetActorForwardVector(), Value);
     }
 }
 
 void AMyRaycastProjectCharacter::MoveRight(float Value)
 {
     if (Value != 0.0f)
     {
         // add movement in that direction
         AddMovementInput(GetActorRightVector(), Value);
     }
 }
 
 void AMyRaycastProjectCharacter::TurnAtRate(float Rate)
 {
     // calculate delta for this frame from the rate information
     AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
 }
 
 void AMyRaycastProjectCharacter::LookUpAtRate(float Rate)
 {
     // calculate delta for this frame from the rate information
     AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
 }
 
 bool AMyRaycastProjectCharacter::EnableTouchscreenMovement(class UInputComponent* InputComponent)
 {
     bool bResult = false;
     if(FPlatformMisc::GetUseVirtualJoysticks() || GetDefault<UInputSettings>()->bUseMouseForTouch )
     {
         bResult = true;
         InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AMyRaycastProjectCharacter::BeginTouch);
         InputComponent->BindTouch(EInputEvent::IE_Released, this, &AMyRaycastProjectCharacter::EndTouch);
         InputComponent->BindTouch(EInputEvent::IE_Repeat, this, &AMyRaycastProjectCharacter::TouchUpdate);
     }
     return bResult;
 }
 
 void AMyRaycastProjectCharacter::PerformRaycast()
 {
 
     AEnemyActor EActor;
 
     FHitResult* HitResult = new FHitResult;
     FVector StartTrace = FirstPersonCameraComponent->GetComponentLocation();
     FVector ForwardVector = FirstPersonCameraComponent->GetForwardVector();
     FVector EndTrace = ((ForwardVector * 5000.0f) + StartTrace);
     FCollisionQueryParams* TraceParams = new FCollisionQueryParams;
 
     if (GetWorld()->LineTraceSingleByChannel(*HitResult, StartTrace, EndTrace, ECC_Visibility, *TraceParams))
     {
         DrawDebugLine(GetWorld(), StartTrace, EndTrace, FColor(255, 0, 0), true);
         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("You Hit: %s"), *HitResult->Actor->GetName()));
 
         if (!HitResult->GetActor()->IsValidLowLevel())
         {
             
             return;
         }
 
         //Assign the hit actor to EActor
         EActor = Cast<AEnemyActor>(HitResult->GetActor());
         
         
 
         EActor.ApplyDamage();
     }
 }
more ▼

answered Apr 11 '16 at 11:00 AM

avatar image

AnGaraa
10 4 6

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Okay AnDarra, try this:

 AEnemyActor * EActor; //Create a variable, which is a pointer to a AEnemyActor class
 
 if(HitResults->GetActor() )
 {
     if( Cast<AEnemyActor>(HitResults->GetActor()) )
     {
         EActor = Cast<AEnemyActor>(HitResults->GetActor());
         EActor->ApplyDamage();
                  GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Applied damage to %s !"), *HitResults->GetActor()->GetName());
 
     }
     else
     {
          GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Could not cast actor %s to AEnemyActor !"), *HitResults->GetActor()->GetName());
     }
 }

You could get errors, I just typed it on my phone. Let me know how you go.

more ▼

answered Apr 12 '16 at 08:33 AM

avatar image

Aaron1178
19 1 4 10

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
  1. Dont create the actor from the stack, get the reference to it from the world using an actorIterator,

more ▼

answered Apr 12 '16 at 09:46 PM

avatar image

ash9991win
86 2 3 6

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question