Spawning Grenade causes ammo count to reset to default values

I am releasing the grenade and detaching the grenade using an anim notify event. I can’t figure out how to spawn the grenade again in my character’s hand. I am using anim notify events in order to release and spawn the grenade. I am using the control rotation in order to control the direction. I got the weapon to spawn and I was able to lose control of the first grenade but the ammo count gets reset to it’s default value once the new grenade spawns. The grenade is derived from a base class and when it spawns it resets the ammo count to default values. How can I allow those default values to be modified at runtime?

//Get weapon mesh is defined in the header file. It returns the weapon's mesh.
UFUNCTION()
class USkeletalMeshComponent* GetWeaponMesh() { return WeaponBaseMesh; }
void AGrenade::OnReleased(FVector ForwardVector)
{
CurrentMagazineAmmo--;
if (ACharacter* Player = Cast<ACharacter>(UGameplayStatics::GetPlayerCharacter(this, 0)))
{
Player->bIsThrowing = false;
ForwardVector *= 2500;
Player->CurrentWeapon->GetWeaponMesh()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
Player->CurrentWeapon->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
 Player->CurrentWeapon->GetWeaponMesh()->SetSimulatePhysics(true);
Player->CurrentWeapon->GetWeaponMesh()->SetPhysicsLinearVelocity(FVector::ZeroVector);
Player->CurrentWeapon->GetWeaponMesh()->AddImpulse(ForwardVector);
GetWorldTimerManager().SetTimer(ExplodeTimerHandle, this, &AGrenade::Explode, ExplodeTimer, false);
		}
}
void AGrenade::OnSpawned()
{
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
if (ACharacter* Player = Cast<ACharacter>(UGameplayStatics::GetPlayerCharacter(this, 0)))
{
  --CurrentMagazineAmmo;
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
if (ACharacter* Player = Cast<ACharacter>(UGameplayStatics::GetPlayerCharacter(this, 0)))
{
Player->bIsThrowing = false;
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
//This is where I am spawning the grenade that is resetting my ammo count. The grenade is a derived class of the base class which is the currentweapon base class. How can I fix this ammo count issue.
Player->CurrentWeapon = GetWorld()->SpawnActor<AGrenade>(Player->ThirdWeaponClass, SpawnParams); 
			Player->CurrentWeapon->AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));
			Player->CurrentWeapon->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
		}
		//Here is the idle animation that i am using to spawn the grenade if possible.
                 //How do I spawn the grenade using the idle animation?
		//Here I don't want to reattach the grenade because in most games you just spawn another grenade but for some reason when I spawn a new grenade in hand the character doesn't lose control of the first grenade thrown and is tied to the first grenade. How do I lose control of the first grenade thrown and gain control of the second. I know I don't have to add another grenade to the array I have set up because that would reset the ammo count due to the grenade being counted as a new weapon within the array. 
	}
	
}

Anim Notifies

I don’t fully understand the intention of how your classes are structure, but if I were to guess, it appears that CurrentMagazineAmmo is a variable in your grenade class which would mean a new copy is instantiated every time a grenade is spawned and would have that class’s starting value. If CurrentMagazineAmmo were a variable within your Player or PlayerController, this would not be the case and might be more what you are intending.

On the other issues, the situation may be similar. It would appear that your grenade class is causing the Player to spawn another grenade rather than the Player or PlayerController directly handling that function.

I may be confused and this is what you are doing, but the code shown suggests the Grenade class (which is temporal for only the lifetime of the grenade) is handling functionality and variables that would normally be handled by the Player, PlayerController or some other class that stays alive and can thus manage ammo usage.

Alternatively (and I can’t imagine why it would be structured this way), if it is your intention that the grenade class handle it’s own ammo count, it would require passing the current ammo count to the newly spawned grenade so it is maintained rather than lost when the original grenade explodes.

Sorry in advance if I’m misunderstanding what you are trying to do.

2 Likes

Here is my solution to the issue.

if (ACharacter* Player = Cast<ACharacter>(UGameplayStatics::GetPlayerCharacter(this, 0)))
{
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
switch (Player->CurrentWeapon->CurrentMagazineAmmo)
{
case 2:
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
//Spawning a new grenade in order to allow a quick throwing mechanic.
Player->CurrentWeapon = GetWorld()->SpawnActor<AGrenade>(Player->ThirdWeaponClass, SpawnParams);
//Casting to the weapon base class variable inside of the character. 
Player->CurrentWeapon->CurrentMagazineAmmo = 2;
Player->CurrentWeapon->AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));			Player->CurrentWeapon->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
case 1:
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
Player->CurrentWeapon = GetWorld()->SpawnActor<AGrenade>(Player->ThirdWeaponClass, SpawnParams);
//Regulating the ammo count of the weapon base class...
//This class variable was created in my character in order to allow for easy access to my base weapon class.
Player->CurrentWeapon->CurrentMagazineAmmo = 1;
Player->CurrentWeapon->AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));		Player->CurrentWeapon->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
case 0:
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
Player->CurrentWeapon->CurrentMagazineAmmo = 0;
Player->CurrentWeapon->GetWeaponMesh()->SetHiddenInGame(false);
break;
default:
break;
}
}

I am sorry for the convoluted code it is something at this point that I can only read. I figured it out by casting to the current weapon or my base class weapon (I am not using my player character I am using a weapon class in order to store the ammo variables.) and changing the default values within the base weapon class inside of the grenade class. I have made a brute force solution I know it is not the most elegant looking but it works. I created a weapon base class variable inside of my character and am using that in order to grab variables from my weapon base class. I stored classes inside of my character that relate to my weapon classes.

I do that with my normal weapon classes (store the ammo count within), but for a grenade, I’m not sure I’d handle it that way. We don’t have grenades so I hadn’t given it much thought. But with a special category weapon like that, it seems that having a weapon class that stays alive and spawns off projectiles rather like a gun might be the ticket. That must be what your grenade class is doing. I assumed it was spawning a unique grenade class for every toss. If I were doing that, I’d probably use a spawn deferred and pass the ammo count on to the newly spawned grenade prior to finishing the spawn. Then the Ammo count would be correct rather than the default.

2 Likes

The only issue is when I switch back to the grenade the default ammo count is reset.

You are spawning the new CurrentWeapon and then setting the parameter. Given possible timing issues, I would as mentioned before:

SpawnDeferred (regular spawn with the setting: SpawnInfo.bDeferConstruction = true;)
Set the ammo count in the spawned Grenade
FinishSpawning to allow the spawned grenade to take off and BeginPlay

This would cause the spawned grenade to have the correct count as it initializes.

2 Likes

When you say “regular spawn” what do you mean?

Just a spawn as you are doing (a SpawnActor(…), but by setting that flag, the spawn doesn’t complete yet and waits for you to do a pointer->FinishSpawning(…). In between the spawn statement and the FinishSpawning statement, you can force any values you want to set into the spawned object that alter the defaults. So for example, after executing the spawn, you can use that pointer to set variables in the spawned object that would have defaulted to something else.

The only thing to remember is that you need to provide the spawn transform on the FinishSpawning statement.

The only reason I mentioned this is then you would be certain that the ammo count would start out at the altered quantity instead of a default quantity.

I’m still wondering if this solves your problem or if there isn’t actually some other things going on that I’m not aware of.

1 Like

I spawn the actor then I set the default values to new values it’s just when I switch back to the grenade the default values are reset. The default values are being modified every time I spawn the grenade. It is just that when I switch to a new weapon then switch back to the grenade the grenade’s default values reset. Those values I am modifying are not inside the constructor of the grenade class they are inside the weapon base class.

I presume that switching back doesn’t mean respawning the grenade? If you are respawning it then I’m mistaken about the architecture/design.

If not, I would put displays in to log the value of the variable and see when it resets.

1 Like

Well I suppose it respawns due to the fact that when the grenade gets switched back to the default value is reset to 2 and the grenade spawns in hand even after I had just modified the values all the way down to zero I might add. This is probably due to the anim notify.

That is indeed a different situation than I was thinking. My design has two weapons that are spawned when the player selects which weapons he is using and they remain alive. I will be adding grenades at some point and it will just be another (third) weapon class like the guns. The actual grenade will be a projectile. With that sort of design, the weapon class will hold the ammo count, but it sounds like your grenade is an actor being used as what I would consider a projectile class and can be spawned by something other than the weapon class “firing” its projectile. The firing in your case is from triggering an anim notify. Very different in concept.

If a key is pressed to throw the grenade, I might want to manage the ammo count based on that rather than an animation and keep the ammo count in the player (though I’d do this in the weapon class the way I’m doing things). It’s a difference in the way we look at design and neither is wrong. I guess the way you are doing it, I’d just heavily log each spawn and ensure they match how you expect them to be working.

I also still might recommend the deferred spawn because I don’t trust trying to set values after the spawn is complete due to timing in the same frame. Then you are sure that the spawned actor is at the right place to accept the value, but doing it after the spawn, you don’t really know the point it’s reached in his startup.

Sorry I’m not being more help, but your approach is different than I’ve pondered.

1 Like

What would I use as a an FTransform Variable if I use deferred spawned?

I am also spawning the grenade using an anim notify event it is just every time it spawns the ammo count resets.

You can create the transform from your location and rotation you use in the SpawnActor. I don’t know why both the SpawnActor and FinishSpawning require the placement.

Yes, I realize you are using the anim notify event. But my concern is that the setting you are doing to poke the new ammo amount into the spawned grenade, may not be set at the correct time. It is in the same frame that you are spawning the grenade and pushing the count into it. I am more comfortable inserting such values prior to the spawn completing, then the spawned actor has the values during it’s initialization. Further, I’d poke the value into the variable that serves as the default ammo count (you are probably doing that, but I mention it just for completeness).

1 Like

When I try to set the values prior to the spawn the values don’t change.

I could try using booleans to check for each grenade thrown as well that might do something.

You wouldn’t be able to set them prior to the SpawnActor or the pointer would be (I’m guessing) pointing to the previous grenade which wouldn’t affect the new one. It looked like you were setting it after the SpawnActor. This is where I was suggesting to set the deferred flag, then set the default ammo count to whatever it should be, then do the FinishSpawning to complete the spawn for the grenade.