Spawning objects from a hit impact

This recipe is a guest tutorial. Ryan Pelcz gave me his kind permission to adapt his solution to spawning objects as a result of impacts upon another object. Imagine a vending machine that spits out plastic balls full of sweets each time it is hit. This is the kind of scenario we're going to create. The goal is to introduce the concept of placeable actors, spawnable actors, actors taking damage, and applying impulses to rigid bodies.

How to do it...

The placeable actor :

We have to code a placeable actor because it will have functionality a regular StaticMesh placed in the scene wouldn't have, which is the ability to produce other objects. Placeable objects are added from the Actor Classes tab not the Content Browser.

  1. Close UDK and open ConTEXT and create a new file. Choose from the drop-down Highlighters list which says Text Files the item UnrealEd so that text we'll type is format friendly for UnrealScript.
  2. The code starts: class MyPowerCore extends Actor placeable;
  3. The placeable lets us select the asset we're making from the Actor Classes tab in the Content Browser and place it in the scene.
  4. Adding the following lines gives us the mesh that will be placed using this class:
    DefaultProperties 
    { 
    Begin Object class=StaticMeshComponent
      Name=PowerCoreMesh
    //The line below sets the actual asset used, and can be replaced to suit.
    StaticMesh = Staticmesh'Packt.Mesh.PowerCore'
    End Object
    Components.Add(PowerCoreMesh)
    }
  5. So we have an object defined as a mesh from our Packt package, and now we can configure it. Add these lines also within the DefaultProperties brackets {}:
    DrawScale=3 //may be adjusted to suit
    bCollideActors=true
    bBlockActors=true
  6. DrawScale lets us declare how big or small we want the placed mesh to be, relative to the asset's built-in size. The next two lines ensure our mesh has collision when something touches it. The asset has already had a collision model defined in the Static Mesh Editor.
  7. Save this code to C:UDK~DevelopmentSrcMyGameClassesMyPowerCore.UC.

    Tip

    The code above will work as it is, but it would give a warning about inefficient lighting following the game build. To avoid this, add below the first line's class declaration:

    var() const editconst DynamicLightEnvironmentComponent LightEnvironment;

    Then, at the start of the DefaultProperties section, create a new object:

       Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
       bEnabled=TRUE
       End Object
    LightEnvironment=MyLightEnvironment
    Components.Add(MyLightEnvironment)

    Then you can add the lines:

    LightEnvironment=MyLightEnvironment
    bAcceptsLights=True

    in the definition of the StaticMesh object you added already PowerCoreMesh.

  8. Start UDK to compile the script changes, and re-run UDK, assuming the script compiles without a mistake. Once UDK loads, open any scene and press Ctrl + Shift + F and switch to the Actor Classes tab. Our placeable actor will show up in the Uncategorized category of actors as MyPowerCore. Highlight this and in the scene, right-click and choose Add MyPowerCore Here. Be sure it works before continuing.

The spawnable actor

  1. Start a new class in ConTEXT to fulfill our Ball requirement:
    class MyBall extends KActorSpawnable;
    
    DefaultProperties
    {
    Begin Object Name=StaticMeshComponent0 //not Name = Static...
    StaticMesh=StaticMesh'Packt.Mesh.BouncyBall'	
    bNotifyRigidBodyCollision=true
    HiddenGame=false
    ScriptRigidBodyCollisionThreshold=0.001
    LightingChannels=(Dynamic=true)
    End Object
    Components.Add(StaticMeshComponent0)
    CollisionComponent=StaticMeshComponent0
    DrawScale=0.25
    bCollideActors=true
    bNoDelete=false
    bStatic=false
    }
  2. As before the DefaultProperties define the mesh this class will use, and then describes the visibility, collision and lighting for it.
  3. Save this code to C:UDK~DevelopmentSrcMyGameClassesMyBall.UC.
  4. Right now if our object was spawned it wouldn't do much, so let's add some motion for it. Type the following in the MyBall.UC code under the first line:
    simulated function PostBeginPlay()
    {
    local Vector SetDirection;
    SetDirection.x = 15*FRand()-15*FRand();
    SetDirection.y = 15*FRand()-15*FRand();
    SetDirection.z = 150;
    StaticMeshComponent.AddImpulse(SetDirection);
    Super.Postbeginplay();
    }
  5. Save again. Here we are declaring a vector (direction from a position in space) randomly within the area the Ball spawns in X and Y and an upwards movement which is set to 150. Gravity will take over, given the object is a KActor.

Spawning upon Take Damage

  1. Let's spawn the Ball up out of the top of the PowerCore when the PowerCore takes damage from being shot at by the player. Open up the MyPowerCore class and drop this rather long line in after the first line (it is an existing function in UnrealScript). All we need to know for now is that this will get called whenever the Powercore is shot:
    var actor NewBall; //tells the function what it will create
    
    simulated function TakeDamage(int DamageAmount, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitINfo HitInfo, optional Actor DamageCauser)
  2. Directly underneath, furnish the function with an instruction about what to do:
    {
    spawnNewBall();
    }
  3. This declaration of an actor variable to hold our soon to be spawned Ball now has a TakeDamage potential, but it doesn't have a spawn function yet. Enter the following code snippet next:
    function spawnNewBall()
    {
    local Vector myLoc;
    myLoc.x = Location.x;
    myLoc.y = Location.y;
    myLoc.z = Location.z+70;
    newBall = spawn(class'MyBall',,,myLoc, Rotation);
    'log("ShockRifle secondary fire (RMB) impacted on a PowerCore and spawned:" @ NewBall);
    }
  4. Once again we are declaring a local vector variable and we're calling this one myLoc. We then set the 'x' and 'y' coordinates of myLoc to the 'x' and 'y' coordinates of the placed MyPowerCore. The 'z' coordinate will be placed 70 units above the box so that it is not spawned inside of the mesh (that would be bad). We spawn the Ball class at the location of myLoc using the line newBall = spawn(class'Ball',,,myLoc, Rotation); and we're done.
  5. Having completed the two classes, all that needs to be done is load a level in UDK and press Ctrl + Shift + F, then look in the Uncategorized category of the Actor Classes tab, assuming you have the default Show Categories option ticked. Here you should see MyPowerCore. Highlight it, and in the scene, right-click and choose Add MyPowerCore Here. An example is provided in the map Packt_06_Spawnable_DEMO.UDK and you will notice a placed ShockRifle pickup. This is because the default LinkGun class doesn't include the ability to shoot up rigid bodies. You have to use the right-click fire method with the ShockRIfle.
  6. An example scene is provided: Packt_06_Spawnable_DEMO.UDK. The example map uses the classes PacktPowerCore and PacktBall which are otherwise the same as MyPowerCore and MyBall you've just created.

    Tip

    If you want to push the balls around using the character, open MyPawn.UC and add this line to the DefaultProperties section: bPushesRigidBodies=true.

How it works.

This was originally a tutorial by Ryan Pelcz (http://pelcz.squarespace.com). In essence all that's changed here are the actors used, and the formatting is arranged to match the book's recipe style. In short, this is what happens: The Powercore is declared as a placeable actor and that automatically means we'll find it in the Actor Classes tab, and then the Ball is declared as a spawnable and just needs something to spawn it. So we have a function which is a lot like the Take Damage event in Kismet but instead sits inside our Powercore class. Given there's some damage taken, it sets a location and impulse for a spawned Ball.

Note

Note, the DamageTaken depends on the secondary action of the ShockRifle in order to create a physics impulse on the placed Powercore. Other damage types won't work.

To have a bit of fun with this, and make the spawned balls bounce and float around, try changing gravity via Kismet using a SetGravity -100 command inside a Console Command action (New Action | Misc | Console Command) hooked up to a Level Loaded event. For this to work, you'll have to Play on PC [ How it works. ], so if you want to change it in config so that it works in PIE too, look to C:UDK~UDKGameConfigDefaultGameUDK.INI and scroll down to find the section [Engine.WorldInfo]. There you will see the next line is related to Gravity: DefaultGravityZ=-520.0. Changing that value will permanently affect gravity in game, so it would be best to comment out the line, then paste it in a copy of the line with the changed value. That way you won't have to remember the UDK's default value. You may also want to adjust RigidBody responsiveness by changing the next line: RBPhysicsGravityScaling=2.0 to 0.02, so there is a noticeable effect.

If you don't want the player to have control while they're off the ground, you can add: AirControl=+0.005 and DefaultAirControl=+0.0001 as an entry in your MyPawn.UC DefaultProperties section. Including the + here matters!

See also

The asset we're spawning in this recipe has a Physical Material Mask to set impact results. Hitting it in one spot may produce a different sound than in another spot.

See Chapter 9, The Devil is in the Details!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.12.242