Kismet Mini-game

From RoboBlitz Editor Wiki

There have been some requests for a minigame map that makes extensive use of Kismet. I took this opportunity to delve into as many different parts of the map editor as I could, as well as give some general advice on gameplay design.

I kicked through a few ideas an settled on a map for RoboBlitz that plays like a Pinball machine. I want the only changes I make to be in the map editor, so this means no modifying Unrealscript. This also means I'd like my map to “just work” by dropping it into an unmodified RoboBlitz install and running RoboBlitz.exe RBArenaPinball. So I can't use any localization files or custom inis.

This page is a journal of my experience building RBArenaPinball. I've left out a lot of the redundant details, so give the final product a play through before you read might be a good idea. Feel free to follow me along the process in your own version, or just enjoy the finished map.

You'll find two versions of the map in the zip file. RBArenaPinball.rbd is the final version of the map after the artists helped me make it all pretty-like. RBArenaPinballDRAFT.rbd is the map I submitted to the artists. If you're interested in aesthetics, compare the differences and see what you can learn about making things look good in UE3. Also, this tutorial doesn't reflect the changes the artists made, so if you don't see something I mention here, look for it in the draft version.

Contents

Step Away From The Editor

I know you must be excited, but the first thing you need to do is close the editor. Yes, close it. I'm gonna start designing this map on paper, since it's a whole lot easier to prototype what I want with a pencil and some dead tree than with a map editor. (And this gives me a good excuse to take advantage of the comfy office couch.)

After sketching some preliminary plans for the layout of the the pinball field I felt like I was running low on ideas. There was still a big section of the map that was empty, so I decided to check out some pinball games for inspiration. It worked pretty well and my paper prototype filled up fairly quick (and my ideas stayed pretty original too).

One thing I tried to keep in mind were the models I had available to me. I'm not a 3D Modeler, so I'm just going to use props from RoboBlitz. That gave me a few ideas in itself (putting in the shredder from ammo for instance).

Get some source control

I lost a lot of work on several occasions because I didn't use Version Control as well as I should have. Check everything in and commit often. Even if your map isn't working at the moment, it's better to be able to revert to something broken than to lose several days work.

Throwing Together Some Geometry

At first I wanted to reserve the ability to adjust the angle of the level as a whole. Either in matinee (to simulate someone nudging a pinball machine) or just to tweak the angle of the level (in case I make it too steep or too shallow). Since I can't rotate BSP after I create it, it means everything in the level is going to need to be a static mesh.

Although after I gave it some thought, I realized it would be a lot simpler to just use a gravity volume to simulate the table's tilt. Even so, my decision to use static meshes instead of BSP stood.

I've also don't have a lot of time to dedicate to this map, so I plan to just chuck in some meshes as fast as I can and not worry about the fine details of the layout. The first thing I did was grab a few large flat meshes from PROP_Hub and MISC_PostDefaultLoad and changed up some of the Materials in the mesh's properties (Under Collision->CollisionComponent->Rendering->Materials, click the plus to add a new material override entry and put a reference to a material there.)

The Elevator

I wanted to have an elevator in my map, so I set it up in a matinee. One tricky bit was that since I'm going to have a huge gravity volume affecting the map, it's going to be hard to tell what angle I need to rotate the elevator to in order to keep the ball from rolling off. I winged it. I added some static meshes to the edge of the elevator to help the ball stop on the elevator.

Ultimately it was still too hard to hit the elevator; the balls kept rolling off over over. So I added an RTriggerVolume and attached the instigator to the elevator. In order for this to work I had to change the physics on the ball to PHYS_Interp since you can't attach a PHYS_RigidBody to an InterpActor.

I wanted to have the weapons compiler create more balls, so I was also concerned that a spare ball might fall into the elevator shaft while the elevator is busy raising another ball. To fix this I made the elevator go under the ground before it went up. This would force it underneath any balls that were waiting at the bottom.


Blocking Volumes

I want the elevator to raise the ball into a chute which launches the ball towards a fancake. If the ball goes through the fancake's fan, I want the player to earn lots of points, but I want it to bounce off the fancake's rim.

I did it like this.

Because of my placement of the fancake I had some issues with getting the fan to rotate correctly. You've probably already read about those on the elevator page though.

In hindsight, it would have been a lot easier to place the blocking volumes around the fan and then rotate them all together, rather than rotating the fan and then hassling with the brushes to get them lined up right.

I also could have used the brush surface or vertex editor to make one blocking volume which fit the fan more accurately.


The Flippers

I wasn't ready to explore how I would get input yet, so I decided to just put a button in the middle of my map and hook it up to the flippers to activate them. Later it would be easy to just replace the button used event with whatever I decided to use for input.

I could have made a hinge on the flippers and applied impulse to them to get them to flip, but this might have some unpredictable outcomes. They might not always fall back in place or they might hit the ball in strange ways. I decided to use a matinee instead.

Even though my flippers are RDestructibles I can use them in a matinee by setting their physics to PHYS_Interpolating. The Physics field is in the Movement section.

I think real pinball flippers snap up at about twice the speed that they fall back into place, so I setup a 1 second matinee and placed a keyframe at .33 seconds. My right flipper was rotated at -135 degrees when at rest and rotated -65 degrees when it's flipped. The left flipper is at the opposite angles, -45 at rest and -115 when flipping. I adjusted the matinee's playrate variable (it's visible in the kismet element's properties) to tune the flipper speed.

The Ball

There was only one choice for the ball's mesh. Of course it was going to be Blitz's ball. I scaled it up, but it felt pretty light weight, so it was time to play around with some physics I ended up going with PhysMat_StickyWheel. The StickyWheel has lots of friction which means it's not too heavy, but it resists movement, so when it was struck it wouldn't fly to far.

I increased the gravity on the table to about twice normal so the ball would bounce less.

Terrain

I added some terrain at the back of my table. Seems like most Pinball tables don't have a lot of curved surfaces for the ball to roll on. We'll see how people like it in my level.

Things were going well until I realized that RoboBlitz didn't ship with any terrain layers or terrain materials, so I'd have to make my own if I wanted my terrain to be textured. But that meant editing packages, which was something I was trying to avoid for this map. One of my goals was only using resources which shipped with RoboBlitz. Since I didn't think it was acceptable to have the gray and white default texture in my final map I came up with a hack. This isn't the right way to do things, but it's the only way I could fit terrain into my goals for the map.

I made the terrain significantly larger than I needed (I wanted 32x32 patches, but I used 64x64 instead) and then used the Visibility brush to hide the dark gray sections of the default texture, and any unused areas. I now had a great big white piece of terrain. I added some snow effects and some ice meshes, and bam, winter-wonderland. How's that for making do with what you have?

This probably has a negative impact on the performance of the game, but my level is small enough that I decided it was worth it.

The CollisionTesselationLevel greatly increases the file size. In order to keep the map a reasonable size and still have decent collision on the terrain I set it's value to 2. I suspect it made my terrain harder to work with, but I didn't want my map to be 15 megs, so I didn't have much of a choice.

Decals

I really love the Blitz emblem that's in the hub, so I decided to plop it down in the center of my mesh. Here's how to place one: Decals

The Control Room

Failed Ideas

Deciding how to control the flippers was probably the hardest part of the map. I could bind a key to a console event but that would mean editing .ini files, and that was another thing I was trying to avoid. I could pop up a text box at the beginning of the map with instructions, but there's unfortunately no 'bind' console command, so that wasn't a very practical option since players would just have to edit their own .ini files.

Control Room Version 1

I figured I had one flipper easy, since I could always just place a giant button in front of blitz and trigger the flipper on it's used event. That way the player can hit whatever their use button is to flip one flipper. For the other flipper I could put an RTriggerVolume above Blitz's head. Then whenever the player jumps the other flipper would flip. I didn't like the responsiveness on this, and didn't think it was the most robust solution. Alternatively I could put RTriggerVolumes on both sides of Blitz and have him move sideways into the volumes to activate the flipper. I could teleport him back to the center whenever he touched the volumes, but this still seemed like a lot of hassle for what should be a fairly simple event. I think too many things could go wrong with the trigger volume approach.

Control Room Version 2

Sticking with the giant button idea I ended up using a pneumatic tube mesh and pneumatic tube door mesh, since I could shrink them down, stick Blitz inside, and it wouldn't matter which direction Blitz looked, he would always be close enough to use them.

So far I haven't gotten any complaints about claustrophobia, but it's definitely a possibility.

For the other flipper I decided to use an RTriggerVolume just above Blitz's head. Since Blitz's movement was pretty well restricted by the control room meshes I figured this was safe enough. Unfortunately the response time on the right flipper is a little slower than I'd like. I might do some tuning of the meshes and RVolume later, but I figured it would take a keen eye to notice the difference.

Hi guys, I found so much useful things here. Thank you.

viagra | meridias capital | valium | ultram addiction stories ultram addiction

Control Room Breakage (Version 4)

I swear I had Control Room Version 3 working. I saw both flippers flipping at the same time. It happened! I swear! ... but then I broke it... apparently using an RMarker to teleport and then switching the camera sometimes breaks Blitz's ability to use things. The results are pretty random, and I've spent too many hours trying to track it down. I'm going to do what I can to make Control Room Version 2 work.

Let this also be a lesson to remember to use some type of Version Control when you're doing large projects. If I had checked my map into SVN when I started, and done nightly, or hourly checkins I could have rolled back to a working version of the control room and tracked down the differences in the map easily. I would have saved myself a few hours of work and an immense amount of frustration. I had it working! I swear! But now it's not!

I have appropriately named the section of kismet dealing with the control room “AAAAAAAAAAAAAH!!!!!”

I just don't have much to say lately. Eh. Not much on my mind lately.

mature ladies paddle | mature women naked | mature tits | mature mexican moms

Round Bumpers

The round bumpers were another sticking point. I knew I wanted to use the button meshes. They looked kinda like round pinball bumpers and they already had a light up animation. One problem was trying to get them to “bump”. The kismet Add Impulse action doesn't allow you to set the impulse vector dynamically, so I couldn't do that.

My bumpers need to be RDestructibles so I can get Collision events. The first thing I noticed is that the slanted gravity made them tumble off the table. I didn't want them moving at all, so I set their Physics (in the movement section) to PHYS_None. They'll stay put that way.

I found a neat actor called RBRadialForceActor. It applies forces from the center outward, kinda like a spherical ForceTube. This was exactly what I needed for the bumpers. Whenever the bumper gets a Collision event I toggle this actor on for a few seconds and BAM, the ball is flying. I couldn't get the RBRadialImpulseActor working, but the ForceActor worked fine, so I used that.

As my deadline was closing in I was down to one remaining bug. The RB_RadialForceActor didn't seem to be turning off. I was stumped. Luckily I'm a programmer with access to the engine code. Turns out the RB_RadialForceActors have a bug, they don't turn off. Luckily they do Toggle. I can imagine the toggles stepping on each other and perhaps turning the bumpers on when they shouldn't be, but it's better than not working at all. And a fix for the RB_RadialForceActors will be in the next patch. ;)

The Long Haul

I started to get discouraged once the lower half of the table was assembled. I set up the flippers and gravity to work, and placed most of the meshes for the map. It was hard to make progress at this point because most of what I was doing was fraught with problems and I had to stop working on one thing until something else was finished. Since everything was half-done, there weren't a lot of points of encouragement to keep me going. In the mist of this, I went through 3 control room versions and had to adjust quite a few of my designs.

I realized I needed to buckle down and push through this tough spot. I made completing the table layout a priority, since most of the issues were waiting on a general idea of the layout of the level. Even though I couldn't say exactly where something would end up, I started placing meshes and carving terrain until I had a pretty good idea of how each section would be laid out.

The Plunger

Every pinball table needs a plunger to launch the ball into play. The space cannon had the perfect mesh for this.

An Old Problem Returns

I wanted Blitz to pull back the plunger himself, so I had to teleport him in and out of the control room. I realized from my previous experience getting Blitz into the control room at the beginning of the level, that getting him in and out might cause problems. It did. I tracked the issue down to a very small section of kismet by bypassing kismet elements one at a time. After the plunger matinee finished I had a Set Camera Target and a Teleport set to receive impulse. This was the same setup I had at the beginning of the level; so I was pretty sure it was the same problem. I suspected that it was some kind of race condition, so I decided to add a delay. A delay of 1.0 seconds between the matinee and the Set Camera Target resolved my problem. I was able to narrow it down to between .35 and 5.0 seconds. I choose 5.0 seconds to be safe. There's a chance that this might still cause problems on a slower computer, but that will have to wait until testing. In any case, simply increasing the delay should fix the problem should it crop up on slower machines.

Then I realized that the same issue comes up if the camera is set to a CameraActor instead of blitz while he's teleported. Now whenever I teleport Blitz I make sure to Set Camera Actor with Player_0 as the target before I teleport. Sometimes you just have to do things and not ask questions.....

Moving

The get the plunger to move in the right direction I used RB_PrismaticActors, which are a type of Constraint. I used the same handle approach as in the RoboGuillotine example.

The plunger wasn't heavy enough on it's own to really pound the ball, so I welded a huge barrel above the plunger. This added the weight I needed. I turned off all the barrel's collision and checked both bOnlyOwnerSee and bOwnerNoSee so nothing could see or interact with the barrel. I also turned off all the lighting hoping that it might improve performance slightly. Even after all this, the ball wasn't going all the way up the tube.

I also put blocking volumes all around the plunger chute so the ball couldn't fly away.

Giving Up

After spending more time on the plunger than any other part of the map I decided continued tweaking wasn't worth it. Instead I placed 2 ForceTube volumes along the plunger railing and used them to accelerate the ball. This worked pretty well because it got the ball moving fast enough and pulling back the plunger still had an effect on how the ball behaved. Let this be a lesson to would be designers: People say they want realism, but they don't want realism. People want realistic looking magic.

Multipliers

I've seen a lot of multipliers in pinball games, so I wanted to include some in my table. My idea was that every time you hit a multiplier bumper you'd get a 1x multiplier added to your multiplier. That means if you have no bumpers lit, you get the normal score, if you have one bumper lit you get twice the normal score, if you have all 3 bumpers lit, you get 4 times the normal score.

Easy right? I'll just multiply any points I add to your score by a multiplier Named Variable and life will be good... except not... there is no multiply element in Kismet. I found out there isn't even a subtract element in Kismet. Doing Kismet Math isn't much fun.

I had to rig up a kinda crazy subsequence to do my multiplier. I kept track of each possible value that could be added to your score and each time a multiplier bumper is lit up, I add to that value. Each time a multiplier bumper is turned off, I subtract from it.

How did I subtract? Since I was adding a static number to a variable each time I turned on a multiplier, I could just add the negative of the static number to the variable. This meant that for every way to score on the table I needed three variables. The current point value of that scoring method, a base value that gets added to the current point value each time a multiplier gets turned on, and the negative of the base value that can be subtracted from the current point value each time a multiplier gets turned off. (Note: the current point value starts equal to the base value.)


Kismet Boundaries

One might assume that since you can place kismet elements as far as you want in any direction, that they will stay there... unfortunately this is not the case. Kismet has invisible boundaries along the top, sides and bottom. If you place Kismet elements outside of the invisible boundaries they all get moved back to the nearest boundary... and you get something like this:

Image:KismetWall.jpg


You've been warned.


Wrap up

After I had all the features implemented, the map needed a lot of testing. There were a lot of places where the ball could get stuck, and some of the objectives were near impossible. (I never once saw the ball go in the weapons compiler). I handed a few copies out around the office and played as much as I could in the remaining time in my schedule.

This is when I added a lot of the sounds, a few particle effects, and the side bumpers near the flippers. I also sank the Ice Cave into a pit and added some gravity around it so the ball would actually go in there. The frozen river worked well as a funnel to make the cave easier to hit.. The ball kept getting stuck behind the elevator, and I couldn't get the ball in the weapons compiler, so I shot one stone at two birds and turned getting stuck behind the elevator into a goal instead of a bug (Karl carries the ball from the elevator to the compiler now).

I actually allocated too little time to tracking down bugs for a map with this level of complexity. Kismet really puts a lot of amazing power in the hands of level designers, but that power also allows you to create more bugs. (And tempts you to aim higher -- imagine doing a pinball map in Unreal Tournament '99! Impossible!)


The Art Pass

Everyone around Naked Sky had gotten pretty interested in my map, so they decided to have some of the artists give it a one over. It's pretty funny how nervous I got handing my baby off to them. I had worked on it alone for almost 90 hours, and watching them hack away at geometry burned a hole in my soul.

It's also important to communicate your goals and requirements to anyone who's going to be working on your map. There was a lot of confusion about deadlines and my odd requirements for packages and changes in this map. It could have gone a bit smoother if I had communicated what I wanted more clearly.

I also learned that staying aware of what the artists were doing also helped prevent wasted work. I could comment on changes before while they were still in the prototype stage, and give advice and warnings about how various changes would effect gameplay. A simple stroll over to the art room every hour or so was definitely a good idea.

In the end I decided to let them replace some of my static meshes with BSP. This allowed them to make some more interesting shapes and do a lot better of a job texturing everything. I was disappointed to have sacrificed my design requirement of using only static meshes, but I had never taken advantage of the benefits of using static meshes (i.e, the ability to adjust the angle of the entire map all at once), so I figured it was an acceptable loss. (And the artists showed me how to rotate BSP anyway, so it came out roughly the same).

Final Cleanup

The artists did a beautiful job on my map. I especially loved the lighting they did. Even though they were careful to not change the way the table played, when they were done I had to clean up a few volumes and meshes. Switching from a static mesh table surface to a BSP table surface also required some changes in the terrain. These went in easily enough. I made sure to check for changes in all the objectives (someone accidentally filled the shredder with BSP) and test the map extensively. The artists had given me some feedback on gameplay, but most of their suggestions weren't able to make it in this late in development. And let me emphasize the need to retest extensively at this stage. Once I was confident that everything had been fixed up, I cleaned up my tutorials, zipped up the map, and out it went.

About me

I'm a 23 year old programmer who works for Naked Sky Entertainment. RBArenaPinball is my first map for the Unreal Engine, although I did have a little experience creating test maps in the course of my work. I'm graduating from UCSC this spring with a Computer Science Degree emphasizing Software Methodology and Game Design. I've never really been one for pinball, instead I prefer First Person Shooters, and Real-Time Strategies and I have a love/hate relationship with several MMORPGs. You can probably find me around the forums as Ecnassianer or Ecna.

Views