Enemy attack that works like vacuum suction

I’m in a bit of a bind here with trying to look up ideas to have the player get pulled toward an enemy like they’re being sucked into a vacuum (e.g. Dust Man from Megaman 4) but practically everything I’ve Googled so far is for creating a vacuum weapon (e.g. the Poltergust from Luigi’s Mansion). Any ideas? (Note that this is one of three possible attacks by the enemy in question, so it will be selected at random using a behavior tree. Also, it’s for a 2D side scroller.)

Hi, can you elaborate a little bit more?

  • Attacker-> Target → MoveTowards(Attacker) (EX: Player->GroundSlam->TargetMovesCloser)
    • Move Direction Target —> Attacker
  • Attacker->PulledTowards(Target) (EX: Player->GrappleHook->MoveTarget->Punch)
    • Move Direction Attacker—> Target

so these things about who owns the attack and movement. I feel you are asking something like a grapple hook? how to implement or do one ? or other ideas?

Edit:
You can launch player from AI like this

It would be more accurate than using force additionally you can do on tick movement like a magnet.

If you are using GAS there is quite nice root motions already integrated.

I should note that I’m referring to the enemy character (specifically a boss) activating a function in its attack barrel which instead of firing a projectile creates a vacuum that pulls the player toward itself, which the player then has to counteract (typically by facing the other way and moving like normal so that they’re against the wind (or so to speak) and their constant attempts to move in the opposite direction of where the vacuum suction is coming from counters the enemy’s attempts to… well, suck ‘em up).

Great understood.

In ability system there is a apply root motion with constant force is exactly what your are looking for.

If you are not using gas for the boss prototype, you can apply launch with some intervals however I feel Add movement input would be a better feeling like player is still in control.

AddMovementInput(Direction, VacuumStrength)

So when you barrel hits ground, get all pawns in radius (collision)

Direction = Normalize (SelfLocation-TargetLocation)

OnTick (OrTimer)-> ForEach (Pawn in Pawns) AddMovementInput(Direction, VacuumStrength)

Okay, it’s in the blueprints but I’m still having trouble. Specifically, I have it set to be based on the player alone since it’s a boss, but the suction is not doing its thing. What should I have it act on and how?

A simple approach would be something like this.

An actor with a sphere collision with radius, checks every 0.1 seconds of player class and promotes array to a variable.
If ActorsArray has something foreach apply world offset direction towards actor center. Additionally the more you get close the power of movement increases.

Result :

Basically OnEnemyAttack->SpawnActorFromClass(YourSuctionBlueprint)
Then you can add your damage logic etc if any or other gameplay aspects.

As example a simple damage logic

Let us know, happy developing.

So kind of like a whirlpool, wind tunnel or black hole as well based on the images. I’ll put these in when I get back to my desk.

And thanks again.

EDIT: For the sake of record, I ended up going with the added movement approach from the second of the three suggestions; however, I believe that they are all valid examples (with the exception of the “launch character” approach, which I would only recommend for grapple attacks from my experiences with this). Consequently, what I would therefore suggest for the second example is that it’s the one which is best suited to my use case in a 2D platformer, while the black hole option is more adaptable to a 3D game. And for anyone who finds this, I hope that helps in deciding between these three methods.

1 Like

One last thing I need to know. The boss in question is done with a paper 2D asset, and when the player collides with the boss they both go jank and end up moving around all over the place. Consequently, I need an idea or two on how to keep the boss weighted in place so that this doesn’t happen.

Simply you need neglect affecting boss (AI) class. Not sure what you base classes are but here is some common techniques that you can use.

  • GetAllActorsOfAClass (ClassName) . If you have different classes for AI and Player (is recommended)
  • You can assign actor tags to Player and AI, such as EnemyCharacter PlayerCharacter ThenYouCan either use GetAllActorsWithTag or GetAllActorsOfAClass and then you can use existing library function ActorHasTag()
  • You can query Actor->GetComponentByClass() and ask a specific class that can distinguish player and enemy. Can be implementsInterface() too.
  • You can get controller → IsValid and check that controller is a player controller.

Try asking correct classes, if classes (base) is same , try using tags.

Example

as said if you choose correct classes and you have different boss and player class (recommended) there wouldn’t be problems.

If you have further questions, feel free to ask or put script screenshots for debug.

1 Like

I’m probably not going to test it immediately while I’m dealing with shoulder pain, but here’s my updated logic with the tag detection added in. I’ll follow up after I’m in a more comfortable position for testing things out, should I need a bit more than this.

EDIT: No go. For some reason the enemy robot is still being knocked around on collisions. Unless there’s something I’m missing, it’s likely to take a look at the enemy’s own physics to get things done from here.

That script is fine, simply checks

IsAlive (bool)
IsPlayer (tag)

and applies MovementInput, should be correctly selecting your player pawn only if tag is applied only to player.

If you have problems you can simply

  • Be sure that only player has that tag. You can print out actor names if you like on tick.
  • Check spawned object (sucktion bp) collisions are not blocking pawns but overlapping more likely.

Okay, thanks. One more thing I’d like to know: if that’s not enough for the case in question, would it make a difference if I weighted the robot down by some ridiculous amount (like over 9,000 for instance)?

It’s ok that what the forums/community are for, no worries on that.

So when we do MovementInput() SetActorLocation() or AddActorWorldOffset() as delta distance, its fundamentally a kinematic motion on the pawn meaning that its after the physics simulation on the tick and its not effected by physics.

So if your robot weights 9000 or more its not effected by this since calculation of movement is kinematic. Meaning
-It doesn’t calculate mass
-It doesn’t considers inertia
-It doesn’t considers weight

If you are simulating physics on your robot at that moment of gameplay or any other times, during this movement (sucktion) which can be preferred sometimes

  • If 2 forces rushing to each other, kinematic & simulation generally simulation physics win.
  • MovementInput() SetActorLocation() or AddActorWorldOffset() can be ignored or can stop working depending on the flags defined on simulation
  • Sometimes it can work but can have jitters or movement errors
  • And generally if you are making a physics simulation best way to achive sucktion with physics : AddImpulse() or AddForce()

In your case I don’t think you are using physics simulation on your robot since if it was the case, movement input would’t be working at all (most of the time). If you use simulation sometimes then on your scripts you can check IsSimulatingPhysics() and branch on what calculation to apply (Force or Location - In other words : Physics Siumulation or Kinematic Movement).

Also just as a side note, AddMovementInput() sometimes preferred by animblueprints and movement input can effect animations thus sometimes can break immersion but it should be ok with your 2D setup and if you encounter it you can just switch methods of application.

Ultimately what I settled on was a sort of control switch approach that determines as to whether or not the suction effect should be applied to the player, though since this still wasn’t enough to stop the behavior when toggled using the boss sprite (and in fact it didn’t solve the problem at all) the best I was finally able to do was to set an area of the boss room with a second blueprint that would serve as the suction effect zone with the boss spawning at a point adjacent to the side of it. So ultimately, once the boss fully… uh, sucks the player to its position, she is outside of the effect zone; at this point, the susceptibility switch is turned off and the boss collision processed separately; if she escapes this and makes her way back in the designated zone, the switch is turned back on and the effect resumes (though obviously assuming that the boss hasn’t switched to a different attack by then).

EDIT: It also seems as if a part of the problem is with the boss actor itself, as entering the area where the base capsule collision is located was still knocking it around (possibly from being set to overlap only pawns, though I’m not 100% sure). However, the suction effect itself is resolved so I’ll address the other part separately.

EDIT 2: I have since gone back through my blueprints and noticed that the base for the definition of boss characters has custom collision settings that I had moved away from during the troubleshooting process, so I switched the enemy in question back to those defaults and will test accordingly before making my next decision on dealing with this.

1 Like