Announcement

Collapse
No announcement yet.

[Video] How to Make Destructible Apex Kactors, shoot Kactors into physics pieces!

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [Video] How to Make Destructible Apex Kactors, shoot Kactors into physics pieces!

    Dear Community,

    I've finally done it!

    I've created a hybrid object that is both a Kactor and an Apex Destructible Mesh!

    So now you can push around a kactor in all ways a normal kactor behaves, and then shoot it to destroy it in tiny pieces!

    Launch a kactor high into the air! Watch it spin! Then make it explode in mid air!

    I made a video of me doing this using my game engine!

    This video footage is entirely one continous shot and un-edited, all the saving/loading and changing of maps is done real-time in my game engine.

    I spent many months to create this in-game 3D editor with saving/loading features, and this is only one small part of my game engine

    Enjoy watching exploding Apex Destructible Kactors!

    Below the video is all the core code you need to be able to implement Destructible Kactors



    ~~~

    All the Core Code You Need To Do This

    With the code below I am providing you with several options, all from a static mesh actor placeholder that you put in the level where you want to spawn a kactor, or an apex that does not move.

    So there's two major cases

    1. static mesh actor becomes apex directly

    2. static mesh actor becomes kactor, which then blows up as an apex

    see spawnApex()

    and becomeKActor()

    for respective cases, in the static mesh actor place holder class.

    Why have a place holder static mesh actor?

    Well both the kactor and the apex get destroyed, because they take up more system resources than a simple static mesh.

    So to restart the simulation, you can just keep reactivating the static mesh place holder wherever you position it in your level.

    Static mesh actor is never destroyed, just made invisible and no collision

    ~~~

    The Base Custom Apex Destructible Class
    With Set Inner and Outer Materials


    Code:
    class JoyfulDestruction extends ApexDestructibleActorSpawnable
    placeable;
    
    function joyfulSetMaterial(Material outside, Material inside) {
    	if (outside == None || inside == None) {
    		`log("joyfulSetMaterial: sent invalid materials");
    		return;
    	}
    	
    	 //note the index of 1 for the inner material
    	//that is visible when apex is destroyed
    	StaticDestructibleComponent.SetMaterial(0, outside);
    	StaticDestructibleComponent.SetMaterial(1, inside);
    }
    
    defaultproperties
    {
        Begin Object name=DestructibleComponent0
    		
    		bAllowAmbientOcclusion=false
            
    		//change to your asset, look up entire path of your APEX by going into UDK
            //right click on your APEX and get the full name, copy into your code
            Asset = ApexDestructibleAsset'JoyfulPackage.Destruction.CubeCutOut256'
    		
            //sets collison/colliding on fracture pieces of Apex mesh
            //I looked this up in Engine/ActorFactoryApexDestructible.uc 
           //and added "RB" to front of "CollideWithChannels"
    	RBChannel=RBCC_EffectPhysics
    	RBCollideWithChannels={(
               Default=TRUE,
               BlockingVolume=TRUE,
               GameplayPhysics=TRUE,
               EffectPhysics=TRUE
            )}
        End Object
    }
    A specific instance of base Apex Class
    That utilizes a specific Apex Asset You Make


    Code:
    class VictoryDestructionCube extends JoyfulDestruction
    placeable;
    
    defaultproperties
    {
        Begin Object class=DynamicLightEnvironmentComponent Name=joyLightEnv
    		bEnabled = true
    		bCastShadows = true //false
    	End Object
    	
        Components.Add(joyLightEnv)
    	
    	Begin Object name=DestructibleComponent0
    		
    		LightEnvironment=joyLightEnv
    		
    		//replace this with the package name of your own
    		//destructible asset
    		//to make destructible assets go to nvidia website
    		//and download apex labs
    		//http://supportcenteronline.com/ics/support/default.asp?deptID=1949
            Asset = ApexDestructibleAsset'VictoryPackage3.apex.cube256TotalDestroy';
    		
        End Object
    
    
    }
    ~~~

    The Static Mesh Actor Place Holder

    This is the placeholder static mesh actor

    It is made invisible at game/simulation start if you are using the Kactor option, otherwise it stays visible as a static solid mesh until a projectile collides with it, at which point it turns into apex and gets destroyed/

    See the GameMode() section.

    That is the code you can translate to your project as “start simulation” or “restart simulation”

    so you can blow up the apex multiple times without leaving your game completely.

    Code:
    class VictoryDWall extends StaticMeshActor placeable; 
    
    //custom player controller class
    var CustomController custController;
    
    //this is a simplified version
    //of my save/load struct
    //You can use basicsaveobject
    //to save states of each of your objs
    //to computer hard disk
    //only using structs
    
    //dynamic objects cannot be saved
    //by basicsave object
    
    
    //so all pertinent data must be stored
    //as a struct
    
    //for this tutorial though
    //this is irrelevant
    //but that's why this info is in a struct
    struct DWallstruct
    {
    	
    	var string meshType;
    	var string materialType;
    	var string interiorMaterialType;
    
            var vector startlocation;
            var rotator startrotation;
    
    	//KActor
    	var bool isKactor;
    	var bool kActorStartsAwake;
    	
    	var bool destroyed;
    
    	structdefaultproperties
    	{
    		isKactor = true
    		//default inner material for apex
                    interiorMaterialType = 
                        "JoyfulPackage.DestructionMaterials.Blackrock02_destructionmat"
    		kActorStartsAwake = true
    	}
    };
    
    var DWallstruct info;
    
    
    //not-saved Kactor child link
    var JoyKactor childJoyKactor;
    
    
    function SetDisabled(bool b) {
    
    	//disabled
    	info.disabled = b;
    	
    	//KACTOR
    	if(info.isKactor) {
    	
    		//check has child kactor
    		if (childJoyKactor == none) return;
    		
    		//hidden
    		childJoyKactor.setHidden(b);
    		
    		//collision
    		if(b)
    			childJoyKactor.SetCollisionType(COLLIDE_BlockAll);
    		else childJoyKactor.SetCollisionType(COLLIDE_NoCollision);
    	}
    	
    	//NON KACTOR
    	else {
    		setHidden(b);
    		if(b)
    			SetCollisionType(COLLIDE_BlockAll);
    		else SetCollisionType(COLLIDE_NoCollision);
    	}
    	
    }	
    
    function setStart() {
    	info.startlocation = Location;
    	info.startRotation = Rotation;
    }
    
    function spawnApex() {
    	local JoyfulDestruction d;
    	
    	//hide parent
    	info.destroyed = true;
    	SetHidden(true);
    	SetCollisionType(COLLIDE_NoCollision);
    	
    	if(info.meshtype == "JoyfulPackage.Meshes.basicCube256"){
    		
    	   d = Spawn(class'VictoryDestructionCube',,, Location,Rotation);
    	
    	   //set to material of this instance
    	   d.joyfulSetMaterial(Material(
                   DynamicLoadObject(PathName(StaticMeshComponent.GetMaterial(0)), class'Material')), 
    	       Material(DynamicLoadObject(info.interiorMaterialType, class'Material'))
    	   );
    	}
    	
            //store dynamic generated object in dynamic array
    	//custController.levelDestruction.addItem(d);
    }
    
    function becomeKActor() {
    	if (!info.isKactor) return;
    	
    	//hide parent
    	SetHidden(true);
    	SetCollisionType(COLLIDE_NoCollision);
    	
    	//create kactor
    	//set child
    	childJoyKactor = Spawn(class'JoyKactor',,, Location, Rotation);
    	
    	//set parent
    	childJoyKactor.parentDwall = Self;
    	
    	//** * * *** set to dwallkactor *** * * **
    	childJoyKactor.isDwallKactor = true;
    	
    	//init including MASS
    	childJoyKactor.joyInit(custController, info.meshType, info.materialtype, 100);
    	
    	
    	//WHETHER TO WAKE AT GAME START OR NOT
    	if (info.kActorStartsAwake)
    		childJoyKactor.wake();
    	
    }
    
    //hit by projectile
    function DwallHit(vector hitNormal) {
    	spawnApex();
    }
    
    
    //GAME MODE
    //you can use the core of this code
    //to see how to activate/initiate
    //your usage of this class.
    
    //For my game I toggle game mode
    //each time player loads/reloads map
    //while in the game editor
    function toggleGameMode(bool b) {
    
    	//GAME MODE
    	if (b) {
    		
    		//KACTOR
    		if (info.isKactor) {
    			becomeKActor();
    		}
    		
    		//Non-KACTOR
    		else {
    			
    			//if it was hidden
    			if(bhidden){
    				SetHidden(false);
    				SetCollisionType(COLLIDE_BlockAll);
    			}
    			info.destroyed = false;
    		}
    		
    		
    		
    		//TEST CODE ONLY
    		//disable above code
    		//that turns it into Kactor
    		//to just make an apex first
    		//spawnApex();
    	}
    	//EDITOR MODE
    	else {
    		
    		//show disabled walls again
    		if(bhidden){
    			self.SetHidden(false);
    			self.SetCollisionType(COLLIDE_BlockAll);
    		}
    		
    	}
    	
    }
    
    //JoyInit
    //takes in strings that are the path
    //for the regular static mesh to use
    //and the material to use.
    //use PathName() to get the string for your
    //mesh and material assets
    
    //for example
    //PathName(StaticMeshActor(a).StaticMeshComponent.GetMaterial(0));
    function joyInit(CustomControllerer custControllerin, string curMeshType, 
                          string curMaterialType
    ) {
    	
    	custController = custControllerin;
    	
    	//collision
    	self.SetCollision(true,true);
    	self.SetCollisionType(COLLIDE_BlockAll);
    	self.CollisionComponent.SetRBCollidesWithChannel(RBCC_Default,true);
    	
    	//scale
    	//cant scale apex so use normal scaling
    	self.StaticMeshComponent.SetScale3D(vect(1,1,1));
    	
    	//Set Mesh From String
    	StaticMeshComponent.SetStaticMesh(
                 StaticMesh(DynamicLoadObject(curMeshType, class'StaticMesh')));
    
    	//Set Material from String
    	StaticMeshComponent.SetMaterial(0, Material(
                 DynamicLoadObject(curMaterialType, class'Material')));
    	
    	//info
    	info.meshtype = curMeshType;
    	info.materialType = curMaterialType;
    	
    	//Distance Culling
    	staticmeshcomponent.SetCullDistance(40000);
    	
    }
    
    
    DefaultProperties
    {
    	//if having performance issues try removing this
    	Begin Object class=DynamicLightEnvironmentComponent Name=joyLightEnv
    		bEnabled = true
    		bCastShadows = false 					//false
    	End Object
    	
        Components.Add(joyLightEnv)
    	
    	Begin Object Name=StaticMeshComponent0
    		LightEnvironment=joyLightEnv
    		CastShadow = false						//false
    		bUsePrecomputedShadows=false
    		
    		BlockRigidBody=true
    		BlockZeroExtent=true
    		
    		//RB Collision
    		bNotifyRigidBodyCollision = true
    		ScriptRigidBodyCollisionThreshold = 1
    
    		
    		//a default starting mesh
    		StaticMesh=StaticMesh'JoyfulPackage.Meshes.basicCube256'
    		RBCollideWithChannels=(Default=true)
    		
    		bAllowAmbientOcclusion=false
    	End Object
    	
    	
    	//important settings to enable mesh
    	//to be spawned using spawn(class'VictoryDwall')
    	bStatic=false
    	bMovable=true
    	CollisionComponent=StaticMeshComponent0
    	bCollideActors = true
    		
    }
    ~~~

    The Kactor Class Spawned by Static Mesh Class

    This is the in-game Kactor that moves around in all Kactor-y ways until player shoots it with custom projectile.

    Code:
    Class JoyKactor Extends KActorSpawnable
          Placeable;
    
    var bool isDwallKactor;
    var customController custController;
    var VictoryDWall parentDwall;
    
    
    //makes it so kactor will fall
    //if it is positioned to start in the air
    //at start of simulation/gametime
    function wake() {
    	StaticMeshComponent.WakeRigidBody();
    }
    
    //very useful to fine tune
    //interaction of kactor with apex
    //destructible chunks
    function setMass(float newMass) {
    	
    	local RB_BodySetup rbs;
    	
    	//invalid values
    	if (newMass <= 0) return;
    	
    	rbs = new Class'RB_BodySetup';
    	
    	rbs.MassScale = newMass;
    	
    	( Self.StaticMeshComponent.GetRootBodyInstance() ).UpdateMassProperties(rbs);
    		
    }
    function spawnApex() {
    	local JoyfulDestruction d;
    	
    	if (parentDwall == none){ 
    		`log(Self.name@"spawned kactor lost its parent");
    		return;
    	}
    	
    	
    	//destroy kactor
    	destroy();
    	
    	//set parent destroyed value
    	parentDwall.info.destroyed = true;
    	
    	//can add other shapes using similar code
    	//this is the mesh the previous class was using
    	//as its default
    	if(parentDwall.info.meshtype == "JoyfulPackage.Meshes.basicCube256"){
    		
    		//the specific destruction class explained earlier
    		//in this tutorial
    		d = Spawn(class'VictoryDestructionCube',,, Location,Rotation);
    	
    		//set inner and outer materials, see JoyfulDestruction
    		//base class
            d.joyfulSetMaterial(
              Material(DynamicLoadObject(parentDwall.info.materialtype, class'Material')), 
    	  Material(DynamicLoadObject(parentDwall.info.interiorMaterialType, class'Material'))
    	);
         }
    	
    }
    
    //hit by projectile
    function DwallKactorHit() {
    	spawnApex();
    }
    
    //see the note in the StaticMeshActor class
    //about how the init parameters work
    
    //addition is ability to set initial mass
    //very useful
    function joyInit(customController custControllerin, string meshType, string materialType, 
                            float mass) {
    	
    	custController = custControllerin;
    	
    	//add to array
    	//custController.levelJoyKactors.additem(Self);
    	
    	//mass
    	setMass(mass);
    	
    	//Set Mesh From String
    	StaticMeshComponent.SetStaticMesh(StaticMesh(
                   DynamicLoadObject(meshType, class'StaticMesh')));
    
    	//Set Material from String
    	StaticMeshComponent.SetMaterial(0, 
                  Material(DynamicLoadObject(materialType, class'Material')));
    }
    
    defaultproperties
    {
    	bCollideActors = true
    	//bWakeOnLevelStart = true
    }
    ~~~

    Custom Projectile to Blow Up the Kactor

    You must modify your custom projectile class so that it

    1. calls the kactor function to blow up the kactor

    2. has an affect on Apex Destructibles

    ~~~

    Essential Projectile Class Code

    Code:
    //this projectile class extended
    //UTGame/UTProjectile.uc
    
    //essential functions
    
    //in case you want your projectiles to bounce
    function bounce(vector HitNormal) {
    	
    	Velocity = MirrorVectorByNormal (Velocity, HitNormal);
    	Acceleration = AccelRate * Normal(Velocity);
    	SetRotation(Rotator(Velocity));
    	
    }
    
    //hitwall for kactors, dynamicStaticMesh Actors
    //NOT for apex
    
    //for apex projectile interaction see last section
    
    //you don't need to call super
    //I copied all essential code
    simulated event HitWall(vector HitNormal, Actor Wall, PrimitiveComponent WallComp)
    {
    	//projectile code
    	local KActorFromStatic NewKActor;
    	local StaticMeshComponent HitStaticMesh;
    	
    	
    	//pseudo code for case of projectile
    	//hitting your pawn
    	/*
    	if (Wall == playerpawn) {
    		//do nothing but bounce off
    	}
    	*/
    	
    	
    	//DWall
    	if (Wall.isa('VictoryDwall')){
    		
    		//case 1: static mesh placeholder to
    		//apex directly
    		VictoryDwall(Wall).DwallHit(HitNormal);
    		Destroy();
    		return;
    	}
    	//JoyKactor
    	else if (Wall.isa('joyKactor')){
    		
    		//case 2: kactor to apex
    		//Dwall Kactor ?
    		if (joyKactor(Wall).isDwallKactor) {
    			
    		//dwallKactor
    			joyKactor(Wall).DwallKactorHit();
    			
    		//make projectile stay so it hits the apex
    		//no bouncing no other code
    		//so projectle pushes against kactor
    		//and kactor turns into apex
    		//and projectle explodes on apex
    			
    		//see last section of tutorial for
    		//how to make apex asset react
    		//to projectile
    		
    			return;
    			
    		}
    		
    		//apply impulse if kactor not set to become apex
    		else {
    			joyKactor(Wall).StaticMeshComponent.AddImpulse(
    			HitNormal * 10000, Location);
    			Destroy();
    		}
    	}
    	
    	//all other walls
    	else {
    	
    	//Victory Code
    	MomentumTransfer = 1.0;
    	
    	
    	//actor code
    	TriggerEventClass(class'SeqEvent_HitWall', Wall);
    	
    	if ( Wall.bWorldGeometry )
    	{
    		HitStaticMesh = StaticMeshComponent(WallComp);
    	if ( (HitStaticMesh != None) && HitStaticMesh.CanBecomeDynamic() )
    	{
    	        NewKActor = class'KActorFromStatic'.Static.MakeDynamic(HitStaticMesh);
    	        if ( NewKActor != None )
    			{
    				Wall = NewKActor;
    			}
    	}
    	}
    	ImpactedActor = Wall;
    	if ( !Wall.bStatic && (DamageRadius == 0) )
    	{
    		Wall.TakeDamage( Damage, InstigatorController, 
                        Location, MomentumTransfer * Normal(Velocity), 
                        MyDamageType,, self
                    );
    	}
    
    	
    	//Explode(Location, HitNormal);
    	ImpactedActor = None;
    	
    	
    	
    	//Victory Bounce code
    	bounce(HitNormal);
    	
    	
    	} //END of all other walls case
    }

    ~~~

    Setting Custom Projectile to affect Apex Meshes

    Review my tutorial for some basic apex destructible info

    Here's the essential info from this tutorial:
    http://forums.epicgames.com/threads/...g-UnrealScript

    Using Custom Projectiles to Shoot Apex Mesh


    You have to tell the Apex engine to recognize your custom class projectiles as able to do damage and impart momentum to ALL apex destructibles, this is not specific to any 1 apex destructible


    1. Go into UDK
    2. click All Assets
    3. do a filter for apex
    4. Find the Apex Destructible Damage Parameters
    5. Double click on it and add a new element (green + sign)
    6. set the Name to be the name of your class, just the name itself
    7. set the values, make sure the momentum is something like 2000 or so
    8. Set base damage to something like 100 and radius to something like 50
    9. SAVE THE APEX PACKAGE by right clicking on the thing you just edited and click save

    ~~~

    Destructible Apex Kactors!

    This is all the core code you need to do what I did in the video!

    All the saving/loading and loading of different maps pertains more to my level editor and I stripped all that code so you can see the essential basics of the classes.

    Have fun implementing this fun Kactor-Apex techology!



    Rama

    #2
    bumping, fun video for you all, and complete code to add this hybrid physics technology to your own game



    Rama

    Comment


      #3
      Thanks rama, looks great, when i get round round it i might give it a try with some explosive boxes in my ghostship game after i manage to get my save system running

      Comment


        #4
        Good luck with you ghostship game!

        What sort of save system are you using?

        Rama

        Comment


          #5
          Hey by any chance could you tell me how did you learn to use Unreal Script was it via a book or just tutorials...

          Comment


            #6
            I learned Unrealscript pretty easily because I already knew c++, so transitioning to unrealscript was pretty easy.

            Hardest part for me was understanding all the built up infrastructure of unreal that is particular to the unreal engine, and how various classes interact, and these awesome forums and awesome people like Spoof and Angel_Mapper and TheAgent helped me figure out these things.

            The very hardest thing for me was figuring out how to connect my various classes once they were instanced into the game, my HUD and my playercontroller for example

            I describe how this works in my 3rd person camera and mouse tutorial
            http://forums.epicgames.com/threads/...7#post31030597



            Rama

            Comment


              #7
              I was thinking of starting with the one on udk gems, seen it a while back when i was thinking through the save system and came across that one. My save system is quite simple really and just involves saving the map name, player inventory (ammo, weapons, item pickups) and player kills. It will save at start of level in play, In ghostship each deck is a seperate map, so they need to be able to start the save game from the deck they was upto with all the player stuff. I need to be able to call the load in my scaleform front end (that part is easy enough) the save would be automatic.

              I was Looking at jodo-sun`s kismet varient which will probably be more ideally suited, but not sure how much he is charging for that, Im on a zero budget still.

              Have you any advice with save systems that could be helpfull Rama? any advice and help is very much appreciated as i am not a coder lol

              Comment


                #8
                So if I understand correctly, it is a kactor at first, then upon taking damage it is swapped with an apex actor and 'sploded? Looks great

                Comment


                  #9
                  Originally posted by madaboutagmes View Post
                  Have you any advice with save systems that could be helpfull Rama? any advice and help is very much appreciated as i am not a coder lol
                  My next tutorial is going to be about my save system

                  Rama

                  ~~~

                  Here's that new tutorial!




                  Simple Easy Powerful Fast Save/Load Engine
                  Save/Load during gameplay, Save Dynamically Generated Levels to Disk

                  Rama

                  Comment


                    #10
                    Originally posted by skwisdemon666 View Post
                    So if I understand correctly, it is a kactor at first, then upon taking damage it is swapped with an apex actor and 'sploded? Looks great
                    Yup, well actually it starts as a static mesh in the editor mode, gets swapped out with kactor at game start, and then swapped out with apex when hit by custom projectile.

                    Glad you like!



                    Rama

                    Comment


                      #11
                      bumping as Community resource



                      Rama

                      Comment


                        #12
                        Bumping for Community



                        Rama

                        Comment


                          #13
                          Bump for Community, enjoy the video

                          Rama

                          Comment


                            #14
                            It's really unnecessary to repeatedly bump all your own threads. The forum has a search feature, backed up by google and user signatures. People can find what they need if they need it.

                            Comment


                              #15
                              I dunno Spoof, I never get more than 3-4 pages back into the forum, so I want to make sure people see things that are new and different that they would not know to search for

                              Is there a place to post "innovative discoveries" as opposed to questions ?

                              that way people can find things they would not know to even ask for / search for

                              Rama

                              Comment

                              Working...
                              X