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.
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.
class MyPowerCore extends Actor placeable;
placeable
lets us select the asset we're making from the Actor Classes tab in the Content Browser and place it in the scene. 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)
}
DefaultProperties
brackets {}:DrawScale=3 //may be adjusted to suit bCollideActors=true bBlockActors=true
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.C:UDK~DevelopmentSrcMyGameClassesMyPowerCore.UC
.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.
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 }
DefaultProperties
define the mesh this class will use, and then describes the visibility, collision and lighting for it.C:UDK~DevelopmentSrcMyGameClassesMyBall.UC
.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(); }
Spawning upon Take Damage
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)
{ spawnNewBall(); }
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); }
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.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.
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 [ ], 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!
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!
3.145.12.242