Unreal definitely has a problem with level-of-detail in their documentation.
If I had to summarize, Iâd say programming 101 boils down to four bullet points:
Logic
This is the obvious one: the if 'if this then that" part. Most people get this intuitively, and up to a point Blueprint helps with that â it looks kind of like a flowchart, so you can follow along a line and see âif this number is larger than 1, go here; if not, go thereâ
The slightly less obvious part of logic as flow control. Not everything is an âif thenâ â often you want to make something repeatedly. Thatâs usually known as looping â for example, you might âloop overâ a list of email address and send a spam message to everyone on the list. Or, you might loop over the list, check to see if they have bought something from your store in the last six months, and only then send them a coupon. In both cases your âflowchartâ now has a loop inside it. In blueprint that is represented by a foreach node.
Data
This is the stuff youâre working on â a list of numbers, an unreal object with properties, and so on. Youâve basically got many different ways of representing the ârealâ world data is how you present that to your program . Your logic operates on your data , using it to make decisions and either create new data or change existing data.
This all seems pretty obvious and in some ways it is. However much of the real work in programming is about finding the right way to turn the problem set into data. For example if you were writing a program to deal with customer data youâd need to store addresses in a way which handles zip codes and street address in the US, but districts and postal zones in Japan. If you making a decision about where to put effects in an unreal scene, you need data which lets you distinguish between good locations and bad ones â for example, you donât want to spawn your effects under the floor or inside walls.
Logic and data go hand in hand: if the logic and the data work well together, your program (or blueprint) will be short and clear. If they donât match up well the logic usually ends up being super complicated â which makes it very buggy. Youâre always looking for way to organize your data that makes the logic clearer.
Sometimes youâll break a problem up into stages where you collect data (say, looking at all the characters in your game and bucketing them into âalliesâ and âenemiesâ) then acting on that data in a second step ( âif the numbers of enemies is 2 times or more larger than the number of allies, run awayâ) . More often than not there are several steps along the way, but itâs good to break a problem down into simple steps with simple answers that you can understand easily. The most common source of problems in any programming is that people get overwhelmed by the complexity of trying to do everything at once.
A critical aspect of data is what programmers call âtypeâ â thatâs a term of art for that means âhereâs a bunch of data which always has these propertiesâ. Type is how you know that an object name contains letters and not numbers, or that an unreal light is a light (with properties for color and intensity etc) and not a vehicle or a physics collision mesh. Programs usually rely on type information to keep things organized; in blueprint that is why you canât connect anything to just anything else â when you run a wire into a âmultiplyâ node that wire has to represent some numbers.
Functions
Itâs very obvious if you look at blueprint examples that even a fairly simple bit of logic and is quickly hard to follow. Say you want to figure out where to shoot that missile â you need to:
- check your ammo supply
- If youâre out of ammo, play the âempty magazineâ sound and exit
- otherwise:
- get your own position
- find the right enemy
- Did we find any enemy? If not, exit
- get the enemies position
- check to see if thereâs something in the way
- if there is, go back to step #2 and try a different enemy
- create a missile object
- set the missiles destination using the position in #6
- play the fire sound
- deduct one from our ammo supply
- done! Now exit
That flow is complex enough â but most of my bullet point are not unreal built-in abilities. Each one probably takes several individual operations â my 13 logical steps might take 50 or 100 individual bits of blueprint, which would be both overwhelming to look at and also very hard to change or upgrade later.
To handle that, itâs a good idea to break up each of these logical tasks into what programmers call âfunctionsâ or âmethodsâ. In blueprint thatâs a single block that has some inputs and outputs . The inputs are the data that you need to do the job and the outputs are any new data that you want to pass along to some other function down the road.
Functions are useful for lots of reasons â they help you organize the layout of what youâre doing to make it easy to read and follow, which just as important as the actual technical inner workings of what you are doing; youâll spend way more time re-reading and trying to understand your code than you ever spend creating it!. But functions also help you spot what kind of data you need in different parts of what you are doing. One to the classic issues any programmer faces is managing data (see above!) â if you canât figure out what inputs and outputs you need for a function thatâs a sure sign you donât quite grasp the real problem yet.
Sometimes there are functions without inputs or without outputs (never without both, however!) A no-input function just does gives you some data back â for example, maybe it generates a random message text. A no-output function usually does something to existing objects - maybe it adds an item to a list, or sets a property on some Unreal actor.
State
Which gets us to the last big concept: state. State is the current status of all the data in a program. That might be something really simple â in a little program that grabs information from an http server the âstateâ might just be the address of the server, the name of a file on disk you want to dump the information to, and maybe an optional stored password that you might have given the program to access the website. In something big â like a character controller in Unreal â the state is all of the data that defines the situation â everything from the current game mode to the characterâs position in the world to the whether or not the character has a health bar over his head.
John Carmack â the guy behind Quake and Doom â once said in his understated way that âall bugs come from the state of the program not being quite what you think it isâ. Once you leave the realm of the trivial example, everything is about managing state. Some of that is simple stuff: When you spawn an enemy, you manage itâs âstateâ by positioning it in a good place, by making sure it has health and ammunition, by turning on its AI, and so on. But if you make some object that has to live for a while â say, you attach a blueprint of your own design to an object to make it rotate in place â then you have to make sure you understand the state of both the Unreal object youâre using and any data you are hanging on to. For example, you might want your thing to rotate slowly at first and then speed up â youâll need to save the current speed somewhere and then keep track of it. You might have a function that adds or removes speed from the rotation ⌠so what happens if the rotation speed gets set below zero? Does it just stop? Does it rotate in the other direction? Are you dividing a number by the speed â since math does not allow division by zero, that will be a problem.
Because confusion about state is the root of most bugs, you need to pay attention to both the data and the functions that use the data to make sure your state is as simple as possible. The more things youâre trying to manage, the harder life becomes. So making programs or blueprints is usually an iterative process of subdividing what youâre doing into small, simple chunks without a lot of state. At each level of what youâre doing you want to be able to see and understand the parts youâre looking at â once you are having trouble, itâs probably time to see if you can partition the problem a little bit.
A lot of the time the right way to break up the problem is to create a little sub-universe of data and functions that work on that data. Programmers usually call that a âclassâ or a âstructâ â basically itâs a way of grouping some information and some functions that work on that information together. Classes are an organizational tool â you can do most of what you need to do without them â but they are a big help in keeping the chaos at bay.
TLDR
Thereâs obviously a lot more: every environment â whether itâs a blueprint or a script running in Maya , or a huge monster program with 3 million lines of code like Unreal â has its own special rules and gotchas. But basically you need break things down to the four basic concepts. Youâve got logic that decides what to do and data that your logic uses. Typically you bundle that logic up into functions that do one job at a time to keep from going crazy. The sum total of all your data and the way your functions use that data is your state â changing any part of the state changes the behavior of the whole system.
Hope that helpsâŚ