Chapter 10. Odds and Ends

Random knick knacks

We're pretty much done with our lessons in UnrealScript. By now you should have enough confidence to start poking around in the scripts on your own to learn how things work. There are a few other random topics I wanted to discuss though, ones that didn't really fit with any of the other chapters.

In this chapter we will:

  • Discuss the use of Components in our Actor classes

  • Interact with code outside the UDK (Unreal Development Kit) with DLLBind

  • Discuss other resources for UnrealScript

So with that, let's take a look at Components!

Using Components

Components let us add objects to our Actors through its default properties. We can think of it like a weapon-upgrade system in a game: You can add a silencer, laser sight, a bigger clip to a weapon. With an Actor, we could add a static mesh, a directional light, or an ambient sound using Components. Let's take a look.

Creating Components

Time for action Adding a Component to an Actor

For these experiments, we'll go back to our AwesomeGame classes, specifically our AwesomeActor. We'll take a look at how to add and remove Components and how to manipulate them through our functions.

  1. We'll need a blank map for our experiments, so open AwesomeTestMap in the editor and delete all of the Kismet, AwesomeEnemySpawners, the look target, and the weapon spawner. All that should be left is the ground, the player start, and the lights.

  2. Save the map and close the editor.

  3. Open AwesomeActor.uc in ConTEXT.

  4. Components are found under Object in the class tree. The one we're most concerned with for this is ActorComponents, which is the one that will be used most when working with UnrealScript. We'll start by adding a SpriteComponent to a new class we'll create, AwesomeComponentActor. SpriteComponents are most commonly used to give the Actor a physical representation in the editor. First let's create a new file called AwesomeComponentActor.uc in Development/Src/AwesomeGame/Classes and write the following code in it:

    class AwesomeComponentActor extends Actor;
    defaultproperties
    {
    }
    
  5. Let's add a SpriteComponent to the default properties and also make this class placeable:

    class AwesomeComponentActor extends Actor
    placeable;
    defaultproperties
    {
    Begin Object Class=SpriteComponent Name=MySprite
    Sprite=Texture2D'EditorResources.S_Keypoint'
    End Object
    Components.Add(MySprite)
    }
    
  6. Anything can be used as the Name of the Component, just make sure the name is the same in the Components.Add() line.

  7. Compile the code and open up AwesomeTestMap in the editor.

  8. Select AwesomeComponentActor in the Actor tab of the content browser and place one in the map. We'll see the sprite on it:

    Time for action Adding a Component to an Actor
  9. Save and close the map. If you deleted the batch file to run the game or don't have one, then create a new file called Awesome Test Map.bat and write the following in it:

    C:UDKUDK-AwesomeGameBinariesWin32UDK.exe AwesomeTestMap?GoalScore=0?TimeLimit=0?Game=AwesomeGame.AwesomeGame -log
    
  10. Run the game and we'll also see the sprite in game.

  11. Good so far, but we usually don't see the sprites of Actor classes in game. If we take a look at SpriteComponent's parent class, PrimitiveComponent, then we can see a few properties we may find useful:

    var(Rendering) const bool HiddenGame;
    var(Rendering) const bool HiddenEditor;
    /** If this is True, this component won't be visible when the view actor is the component's owner, directly or indirectly. */
    var(Rendering) const bool bOwnerNoSee;
    /** If this is True, this component will only be visible when the view actor is the component's owner, directly or indirectly. */
    var(Rendering) const bool bOnlyOwnerSee;
    /** If true, bHidden on the Owner of this component will be ignored. */
    var(Rendering) const bool bIgnoreOwnerHidden;
    
  12. These options control when the Component is visible. For this Actor, we want it to be visible in the editor, but not in game, so let's add that to the Component's properties:

    defaultproperties
    {
    Begin Object Class=SpriteComponent Name=MySprite
    Sprite=Texture2D'EditorResources.S_Keypoint'
    HiddenGame=true
    End Object
    Components.Add(MySprite)
    }
    
  13. Now when we compile the code, we can see the Component in the editor, but not in game.

  14. Sprites are nice, but let's see if we can find something more useful. We'll add a SkeletalMeshComponent to our AwesomeComponentActor. Start by deleting SpriteComponent.

  15. Now let's add a SkeletalMeshComponent to the default properties:

    defaultproperties
    {
    Begin Object Class=SkeletalMeshComponent Name=AwesomeMesh
    SkeletalMesh=SkeletalMesh 'CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA'
    End Object
    Components.Add(AwesomeMesh)
    }
    
  16. Compile the code and open AwesomeTestMap in the editor. We can see the skeletal mesh, but it's all dark!

    Time for action Adding a Component to an Actor
  17. In order for our Component to be able to receive light, we also need to add a DynamicLightEnvironmentComponent. Any subclass of PrimitiveComponent can have a light environment assigned to its LightEnvironment variable, but they're mainly only used for StaticMeshComponents and SkeletalMeshComponents. Sprites and other components don't really need lighting calculations.

  18. Let's add a DynamicLightEnvironmentComponent to our AwesomeComponentActor:

    Begin Object Class=DynamicLightEnvironmentComponent Name=AwesomeLightEnvironment
    End Object
    Components.Add(AwesomeLightEnvironment)
    
  19. As we're not changing any of the variables in the light environment declaring one is as simple as those three lines. However, if for example, we didn't want our mesh to cast shadows, we could write it like this if we wanted:

    Begin Object Class=DynamicLightEnvironmentComponent Name=AwesomeLightEnvironment
    bCastShadows=false
    End Object
    Components.Add(AwesomeLightEnvironment)
    
  20. Now that we have the light environment, we can assign it in our SkeletalMeshComponent:

    Begin Object Class=SkeletalMeshComponent Name=AwesomeMesh
    SkeletalMesh=SkeletalMesh 'CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA'
    LightEnvironment=AwesomeLightEnvironment
    End Object
    Components.Add(AwesomeMesh)
    
  21. Our AwesomeComponentActor class should look like the following code snippet:

    class AwesomeComponentActor extends Actor
    placeable;
    defaultproperties
    {
    Begin Object Class=SpriteComponent Name=MySprite
    Sprite=Texture2D'EditorResources.S_Keypoint'
    HiddenGame=true
    End Object
    Components.Add(MySprite)
    Begin Object Class=DynamicLightEnvironmentComponent Name=AwesomeLightEnvironment
    End Object
    Components.Add(AwesomeLightEnvironment)
    Begin Object Class=SkeletalMeshComponent Name=AwesomeMesh
    SkeletalMesh=SkeletalMesh 'CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA'
    LightEnvironment=AwesomeLightEnvironment
    End Object
    Components.Add(AwesomeMesh)
    }
    
  22. Compile the code and open AwesomeTestMap in the editor. Now we can see him!

Time for action Adding a Component to an Actor

What just happened?

As we can see, Components are primarily used to give our Actors a physical representation. It could just be a sprite whose only use is to let us know where our Actor is in the editor so we can select it, or it could be a character or vehicle mesh that's used in game.

Components are inherited from parent classes just as variables and functions are. But what if we don't want a Component from our parent class? With a function we could just override it in the subclass and empty it out, but with Components there is a function that we can use in the default properties to do this. Taking our example SpriteComponent:

defaultproperties
{
Begin Object Class=SpriteComponent Name=MySprite
Sprite=Texture2D'EditorResources.S_Keypoint'
HiddenGame=true
End Object
Components.Add(MySprite)
}

Removing it in a subclass would only require one line in the subclass' default properties:

Components.Remove(MySprite)

This way we have complete control over our Actor's appearance.

Components being inherited can also create a problem that we need to avoid when working with them. In the previous chapter, we discussed compiler errors, and Components have one specifically for them. Let's take a look.

Time for action Component compiler error

The problem happens when we declare a Component that has already been created in our parent class. To see it we'll create a new class with a Component:

  1. Create a new file in Development/Src/AwesomeGame/Classes called AwesomeInfo.uc.

  2. Open AwesomeInfo.uc in ConTEXT and write the following code in it:

    class AwesomeInfo extends Info
    placeable;
    defaultproperties
    {
    Begin Object Class=SpriteComponent Name=Sprite
    Sprite=Texture2D'EditorResources.S_Keypoint'
    HiddenGame=true
    End Object
    Components.Add(Sprite)
    }
    
  3. Compile the code and we'll get the following error:

    [0004.20] Log: R:UDKUDK-AwesomeGameDevelopmentSrc AwesomeGameClassesAwesomeInfo.uc(6) : Error, BEGIN OBJECT: The component name Sprite is already used (if you want to override the component, don't specify a class): Begin Object Class=SpriteComponent Name=Sprite
    
  4. This error is telling us that the name Sprite is already being used by a Component, and if we take a look at AwesomeInfo's superclass,(Info), we can see it in the default properties there:

    Begin Object Class=SpriteComponent Name=Sprite
    Sprite=Texture2D'EditorResources.S_Actor'
    HiddenGame=TRUE
    AlwaysLoadOnClient=FALSE
    AlwaysLoadOnServer=FALSE
    End Object
    Components.Add(Sprite)
    
  5. If we didn't want to override this Component, then we would need to choose a different name for our own. However, if we did want to override this Component and change some variables, then we would just need to remove the Class= part of our Component:

    Begin Object Name=MySprite
    Sprite=Texture2D'EditorResources.S_Keypoint'
    HiddenGame=true
    End Object
    Components.Add(MySprite)
    
  6. Compiling that code works, and now we would be able to change the properties of that Component inherited from our parent class.

What just happened?

This is another case of a scary looking compiler error with a simple solution, it all depends on whether we wanted to override the Component or not. The only other compiler error dealing with Components has to do with putting variables in one that don't exist for that Component class, so when working with them, make sure the variables you're setting in the Component actually exist.

Interacting with Components

Being able to create Components is essential, but what if we need to change them during gameplay? To do this, we can create a variable out of the Component and use them in functions, or access their variables directly. Let's try that out now.

Time for action Components as variables

As our new AwesomeInfo class doesn't have any subclasses, we can mess around with it without worrying about breaking anything, so let's keep working there.

  1. First, we're going to put a StaticMeshComponent in the class, similar to what we did with our AwesomeEnemy class. Let's rewrite our AwesomeInfo class to look like the following code snippet:

    class AwesomeInfo extends Info
    placeable;
    defaultproperties
    {
    Begin Object Class=StaticMeshComponent Name=MyMesh
    StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_Dup'
    Materials(0)=Material'EditorMaterials.WidgetMaterial_Y'
    Scale3D=(X=0.25,Y=0.25,Z=0.25)
    End Object
    Components.Add(MyMesh)
    bHidden=false
    }
    
  2. As we're using an emissive material, we don't need to set a light environment for the StaticMeshComponent. The Info class has bHidden set to True, we need to change it so we can see the AwesomeInfo in game.

  3. Compile the code, and open AwesomeTestMap in the editor.

  4. If the AwesomeActor is still there, delete it.

  5. Select AwesomeInfo in the Actor tab of the Content Browser (under Actor | Info) and place one in the map near the player start. In its properties, make sure Display | Hidden is unchecked.

  6. Save the map and close the editor.

  7. Run the game, and we'll see the AwesomeInfo Actor in the game. Exit the game.

  8. Now that the AwesomeInfo Actor is there, we need a way to interact with it. We can do this by declaring a variable of the Component's class. Add this line to the top of AwesomeInfo under the class declaration:

    var StaticMeshComponent MyMeshComponent;
    
  9. Next, we'll add a line at the end of our Component declaration in the default properties:

    defaultproperties
    {
    Begin Object Class=StaticMeshComponent Name=MyMesh
    StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_Dup'
    Materials(0)=Material'EditorMaterials.WidgetMaterial_Y'
    Scale3D=(X=0.25,Y=0.25,Z=0.25)
    End Object
    Components.Add(MyMesh)
    MyMeshComponent=MyMesh
    bHidden=false
    }
    
  10. Setting the variable such that it lets us interact with the component through script. If we wanted to make the StaticMeshComponent changeable in the editor, then we could add the parentheses to the variable declaration like the following code:

    var() StaticMeshComponent MyMeshComponent;
    

This would be useful in, for example, a decorative class that had some UnrealScript functionality behind it, like to for example, if you wanted to have it explode when shot. You'd want the level designer to be able to set the static mesh that it used along with other properties, so you would make the class user editable.

  1. Now that we have the variable, let's see if we can use it. We'll use some Kismet to toggle the material that's on it. First, let's declare two variables in our class for the materials. Add the following line to the top, under the class declaration line:

    var Material GreenMat, RedMat;
    
  2. Now let's define their default properties:

    GreenMat=Material'EditorMaterials.WidgetMaterial_Y'
    RedMat=Material'EditorMaterials.WidgetMaterial_X'
    
  3. Now for the function that will interact with the Component. We'll use the OnToggle function so we can use the Toggle Kismet action on our AwesomeInfo Actor:

    simulated function OnToggle(SeqAct_Toggle Action)
    {
    if(Action.InputLinks[2].bHasImpulse)
    {
    if(MyMeshComponent.GetMaterial(0) == GreenMat)
    MyMeshComponent.SetMaterial(0, RedMat);
    else
    MyMeshComponent.SetMaterial(0, GreenMat);
    }
    }
    

    In this function, we check if the material on the Component is GreenMat, if it is set it to RedMat. If it's not, then we know it's RedMat, so set it to GreenMat.

  4. Compile the code.

  5. Open AwesomeTestMap in the editor.

  6. Click on the AwesomeInfo Actor to select it, and then open the Kismet editor.

  7. Right-click and select New Object Var Using AwesomeInfo_0.

  8. Right-click above the object variable and select New Action | Toggle | Toggle.

  9. Connect the Target variable link to the AwesomeInfo_0 object variable.

  10. Close the Kismet editor and select Trigger in the Actor tab of the Content Browser.

  11. Add a Trigger near the AwesomeInfo Actor.

  12. Double-click to open the Trigger's properties, and uncheck Display | Hidden.

  13. With the Trigger still selected, open the Kismet editor.

  14. Right-click to the left of the other two parts of the sequence and hit New Event Using Trigger_0 | Touch.

  15. With the Trigger event selected, set its Sequence Event | Max Trigger Count to 0.

  16. Connect the Touched output of the Trigger event to the Toggle input of the Toggle action. The Kismet sequence should look like the following screenshot:

    Time for action Components as variables
  17. Save the map and close the editor.

  18. Run the game, and every time you run over the trigger the AwesomeInfo Actor will toggle its material.

What just happened?

This was a simple example of interacting with Components, but with a little experimentation this could be used for a lot of different purposes. For example, if we had a vehicle that could be modified with different parts, then we could use the SetStaticMesh or SetSkeletalMesh functions to change the component appearance.

Have a go hero Using SetStaticMesh

Using all the knowledge you've gained from the previous chapters, see if you can create an array of static meshes (choose any you can find in the Content Browser, right-click and select Copy Full Name to Clipboard to get them for your default properties) and toggle through them when the player runs over a Trigger. Remember that the static mesh component's scale is currently set to 0.25, so you may want to change that as well!

Note

Hint Creating an array of static meshes in the default properties will make this task easier.

A practical example

We had the hypothetical example of using Components to customize a vehicle, but let's see if we can come up with something more practical for our AwesomeGame. Sprites and meshes aren't the only thing we can use as Components, we can also use lights. Let's see if we can create a toggleable flashlight for our player.

Time for action Creating a toggleable flashlight

We'll be working in our AwesomePawn class for this, but first, let's set the mood.

  1. Open AwesomeTestMap in the editor.

  2. Select all of the lights, and in their properties set Light | Light Component | Brightness to 0.3.

  3. Rebuild the map by clicking on the Build All button in the top toolbar.

  4. Save the map and close the editor.

  5. Open AwesomePawn.uc in ConTEXT.

  6. We'll need a variable to store our light component, so let's add it:

    var SpotLightComponent Flashlight;
    
  7. Now let's add the Component to the default properties:

    Begin Object Class=SpotLightComponent Name=MyFlashlight
    bEnabled=true
    Radius=1024.000000
    Brightness=1.90000
    End Object
    Components.Add(MyFlashlight)
    Flashlight=MyFlashlight
    
  8. Compile the code and run the game. We have a flashlight!

    Time for action Creating a toggleable flashlight
  9. Now to toggle it. We can use an already existing function for this, Use(). It's in PlayerController, so we'll have to override it in our AwesomePlayerController class. If it's already there, then change it to the following code snippet. If not, then write the following code in AwesomePlayerController:

    exec function Use()
    {
    if(AwesomePawn(Pawn) != none)
    AwesomePawn(Pawn).Flashlight.SetEnabled (!AwesomePawn(Pawn).Flashlight.bEnabled);
    }
    
  10. Compile the code and run the game. Now when you click on Use (default key is E), the flashlight will toggle!

What just happened?

Now we can see some of the more practical uses of interacting with Components in our classes. Components help keep things organized by avoiding creating unnecessary classes and code. In our flashlight example, the light could be created as a separate Actor that's attached to our Pawn, but keeping it as a Component keeps things simple.

DLLBind

DLLBind gives us a way to interact with code outside of the UDK. It is not a replacement for UnrealScript, but lets us extend the functionality if we find we need to. As an example, as UnrealScript's only interaction with files is through the ini's by way of config variables, creating a save game system might be complicated or easily hacked. By using DLLBind, we can send calls to an external file to take care of that. Let's take a look at a simple DLL interaction.

Time for action Using DLLBind

One thing to note is that currently, DLLBind only works with the 32-bit code. If your ConTEXT or batch files are set up to run the Win64 folder's UDK.exe, then you need to change it to run from Win32 for DLLBind to work. You will get a compiler warning about it if you try to compile with the Win64 UDK.exe.

First up, we need to create the DLL. I've provided one in the files included with the book, but for reference sake, here is the code inside it:

#include "stdafx.h"
#include <stdio.h>
extern "C"
{
__declspec(dllexport) void DLLFunction(wchar_t* s)
{
MessageBox(0, s, L"DLL has been called!", MB_OK);
}
}

Basically, we're creating a function called DLLFunction that takes a wchar_t (equivalent of a string) and pops up an OK box with the string as a message.

  1. Grab AwesomeDLL.dll from the files included with the book and place the .dll in the UDK-AwesomeGameBinariesWin32UserCode folder.

  2. Now for the UnrealScript side of things. We're going to use our AwesomeInfo.uc Actor for this, so let's write it as follows:

    class AwesomeInfo extends Info
    placeable
    DLLBind(AwesomeDLL);
    dllimport final function DLLFunction(string s);
    simulated function PostBeginPlay()
    {
    local string s;
    s = "Hi DLL!";
    DLLFunction(s);
    }
    defaultproperties
    {
    }
    

    We use DLLBind as a class keyword with the name of the DLL in parentheses. The DLL function must be declared as dllimport final, and we're passing it a string called s (the name of the variable is arbitrary).

    In PostBeginPlay, we create a local string, assign it a value, and then call our DLLFunction with it.

  3. Compile the code. If the compiler gives you any warnings about the DLL, make sure it is in the right location and the name is the same as in UnrealScript. Furthermore, make sure you're compiling with the Win32 version of UDK.exe.

  4. We still have the AwesomeInfo Actor placed in AwesomeTestMap, but open the editor to make sure it's there. You may get a warning about a missing component (we've removed them from the default properties), if so just click on OK and save and close the editor.

  5. Run the game. We should see a message box pop up as the game starts!

Time for action Using DLLBind

What just happened?

DLLBind is useful when you need some functionality that the UDK doesn't provide on its own, but as I said before it is not a replacement for UnrealScript. If you come into it thinking that any core functionality of your game is going to be through DLLBind, then you need to rethink your approach.

Final Thoughts

No amount of reading books and tutorial is going to explain everything about UnrealScript to you. The lessons you've learned in this book are enough to get you started, but the best way to learn more is by experimenting with the code on your own. I really can't stress enough the importance of reading through the source code. Object, Actor, Controller, and Pawn are the four most important classes to read through. Reading through these classes, taking a look at the functions and variables they have that you can use, and seeing how they do things will help you understand how everything fits together in the UDK world.

Take your time, and be patient. Unless you're coming into UnrealScript with years of experience in another programming language, don't expect to create an entire game in a few weeks or even months. Personally, it took me a few years to get to the point where I felt comfortable programming an entire game using UnrealScript. Start small, creating variations on the weapons that come with the UDK, or altering the rules of the GameInfo a bit. Don't set your initial goals so high that they'll be unattainable, you'll only become frustrated.

And finally, have fun! You are making video games after all.

Other Resources

There are resources available on the internet to help you along. Here are the ones that I use:

  • http://udn.epicgames.com/Three/WebHome.html

    The Unreal Developer Network is Epic Games' official site for everything related to developing games with the Unreal Engine and the UDK in particular. There are resources here for everything from UnrealScript to level design to the material editor.

  • http://forums.epicgames.com/

    The official Epic forums are a great place to get answers to your UDK questions and show off your work. I post there pretty often, so if your question is answered by Angel Mapper you know you've come to the right place!

  • http://wiki.beyondunreal.com/

    Another great resource for UnrealScripters. The information here spans all versions of the Unreal Engine going back more than 10 years, so make sure the information you're reading applies to Unreal Engine 3!

  • http://forums.beyondunreal.com/

    The Beyond Unreal forums are another great place to post questions and show off your work.

  • http://www.unrealplayground.com/forums/

    My personal favorite hangout. It's not as active as it used to be, but I'm loyal. UP'ers unite!

I hope you've enjoyed reading this book, and I hope the lessons you've learned here will help you make some awesome UDK games. I always love to hear from fans, so if you'd like you can send me an email at . I can't wait to see what you create!

Pop quiz Components and DLLBind

  1. How are components created?

    a. As a variable declaration

    b. As a function declaration

    c. In the default properties

  2. How are components interacted with through script?

  3. What two function modifiers need to be declared in a DLL binding function?

  4. How awesome are you now?

Summary

We learned a lot in this chapter about components and DLLBind.

Specifically, we covered:

  • How Components are created and how to interact with them through script

  • How to use DLLBind to extend the functionality of the UDK

  • Other resources you can use in your quest to learn UnrealScript

Now that we've learned about UnrealScript, you're ready to start making games. Have fun!

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

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