Hello,
In this post I'd like to talk about a basic programming concept, the state machine. State machine's are used all over the place in various areas of programming. In games, they are heavily used by AI (and other things, however this post will deal mostly with AI). So let's get right down to it.
What is a state machine? It can essentially be boiled down into a giant list of if/else statements of potential tasks. For instance, I might have a boolean for isTired, isReadyToFight, or isFighting associated with a warrior. So my state machine might look something like this
class Warrior : GameObject
{
bool isTired = true;
bool isReadyToFight = false;
bool isFighting = false;
void Update()
{
if(isTired)
{
isReadyToFight = isFighting = false;
isTired = true;
Rest();
}
else if(isReadyToFight)
{
isFighting = true;
Fight();
}
}
//Rest of implementation omitted
}
Phew. That took a while to type. Let's look at this. So we can see we have two real states here. Resting and Fighting. We start off with isTired = true, so Resting is our Initial State or Starting Point in our state machine. We rest till we're ready to fight, then we fight till we need to rest. Pretty simple. Let's assume we needed another state, such as retreat. Then we would need another bool, and more if/else statements. Then we add states like MoveIntoRange, Heal, DefendTarget...oh my. This code is turning into a disaster! But you probably already know the solution..
We could use enumerators to traverse our state machine. Let's take a minute and see what this might look like:
class Warrior : GameObject
{
enum State {Resting, Fighting}
State currState = State.Resting;
void Update()
{
switch(currState)
{
case State.Resting:
Rest();
if(canFight)
SetCurrentState(State.Fighting);
break;
case State.Fighting:
Fight();
if(!canFight)
SetCurrentState(State.Resting);
break;
default:
break;
}
}
void SetCurrentState(State newState)
{
switch(currState)
{
case State.Resting:
//Do some exit resting stuff: make the bed, get dressed, etc.
break;
case State.Fighting:
//Do some exit fighting stuff: Put away sword, Report to commander, etc.
break;
default:
break; }
switch(newState)
{
case State.Resting:
//Do some enter resting stuff, put on pajamas, drink warm milk etc.
break;
case State.Fighting:
//Do some exit fighting stuff: Take out weapons, say goodbye to your mom, etc.
break;
default:
break; }
currState = newState;
}
//Rest is omitted
}
Phew. Lots of code again. Well, we've cleaned up alot from last time. We even added some enter/exit state functionality, which is great! States could even have their own sub-states like this. But, our code is still very challenging to add states to. Every time we want to add a state, we'll need to extend the switch state in Update, and most likely both witch statements in SetCurrentState. Also, there's something else we need to worry about. In the Resting state, we check to see if we can fight. But what if we need to check for more things, such as go to work, or do chores? The resting state will continue to grow as we add more states that can be reached from the resting state. True, we could modulate this and put the Resting state in its own function ExecuteResting(), but the warrior class itself is now becoming huge and messy with lots of complicated functions and confusing state connections. Plus we have to watch out for things like going into states we shouldn't be. For instance, if we're in a Retreat state, it doesn't make alot of sense to be able to go into the Rest state just cause its time to rest. So, onto the actual solution used today.
First off, we make an actual State abstract state class that looks something like this.
template <class T>
abstract class State
{
public virtual void Execute(T owner) {}
public virtual void Enter(T owner) {}
public virtual void Exit(T owner) {}
//You can easily add more like this if you need to
}
Then we can make a state machine as such
template <class T>
class StateMachine
{
State<T> currState;
T m_owner;
StateMachine(T owner) {m_owner = owner;}
//Hiding the default constructor
private StateMachine() {}
public void Update()
{
if(currState != NULL)
currState.Execute(m_owner);
}
public void SetNewState(State<T> newState)
{
if(currState != NULL)
currState.Exit(owner);
currState = newState;
currState.Enter(owner);
}
}
At this point, we can make our warrior class look like this
class Warrior : GameObject
{
StateMachine<Warrior> m_stateMachine;
Warrior() {m_StateMachine.SetNewState(new WarriorResting(); }
void Update() {m_stateMachine.Update(); }
void Rest() {/*Rest omitted*/}
void Fight() {/*Fight omitted*/}
}
Then we can make our Rest state
class WarriorRest : State<Warrior>
{
public virtual void Enter(Warrior owner) {/*Put on pajamas, drink milk, etc*/}
public virtual void Exit(Warrior owner) {/*Make bed, get dressed, etc*/}
public virtual void Execute(Warrior owner)
{
owner.Rest();
if(owner.isReadyToFight)
owner.m_stateMachine.SetNewState(new WarriorFight());
}
}
The WarriorFight class would be of similar nature. Let's look at some of the many advantages of doing this.
1. Very easy to maintain and add new states. If we want to add say, a retreat class, its very easy to do that. We just make a new WarriorWhatever class. Then wherever we should be able to enter that class from we can make the appropriate checks to do so. We still have to go to each of our states and put the checks in, however we don't have to search through nasty switch statements to do it. We know right where ALL of our Rest logic is contained and can easy add it there.
2. Separation of AI Logic and function. So, what if we wanted to make the player a warrior as well? With this functionality we notice that a player could easy control the warrior class. All the functionality is there-Rest, Fight, Retreat, etc- its just a matter of how its called. With the previous solutions, it would be much more challenging to separate the two to re-use Warrior for any other purpose.
3. Easy to modify. What if we want some global check going on? Such as, at any given point in time, we want to be able to Retreat. We could easily modify the StateMachine class to support this.
State<T> globalState;
public void Update(){
if(currState != NULL)
currState.Execute(m_owner);
if(globalState != NULL)
globalState.Execute(m_owner);
}
Now we have two states running simultaneously. Our global state could be something like
class CheckRetreat : State<Warrior>
{
public virtual Execute(Warrior owner)
{
if(!owner.isRetreating && BattleManager.shouldRetreat)
{
owner.m_stateMachine.SetNewState(new WarriorRetreat());
}
}
}
In fact, you could even modify your state machine to maintain a list of states to update all at once! (Careful if you actually do that though, not as good as an idea as it sounds). Some common state machine modifications include keeping track of the previous state to revert to at any time, having a static state shared by all people who would use it, making the state machine itself static for many Warriors to use. The possibilities are pretty endless.
4. Easy on memory.
If you look at it, you pretty much see that all the states work with any owner. So, is there any real reason for each state machine have its own instance of every state? Not really, no. All of your states could be made into singletons. Then instead of doing
m_stateMachine.SetNewState(new WarriorRest());
We could do
m_stateMachine.SetNewState( WarriorRest.Instance());
You could even make a StateManager to keep track of states and delete ones least recently used and keep the frequent ones in memory as much as possible.
There are many other advantages to this approach, but since this is getting pretty long as it is, I'm going to cut it short here. I hope this opened some doors or at least served as a useful refresher. Oh, and as for the mashed up C#/C++ code I was using in my examples, I was just trying to use what seemed most readable for the given instance. Sorry if you were looking for really specific coding examples.
PS, all AI in this game was made using the state machine algorithms above, just to show you that this stuff can work and be pretty useful.
http://class.cas.msu.edu/tc455/project2/group1/index.html
If you wanna talk more states or more game AI in general, shoot me an email at warddav16@gmail.com or leave a comment below!
--daviD Ward
Adventures of daviD
Sunday, May 12, 2013
Saturday, March 2, 2013
Object Orient All The Things
Hello again,
This post is going to be slightly different. Its about porting what you learn in your object oriented design class to the real world: where it works and where it doesn't. Lets get started.
My latest game I'm working on is a retro 2D style game, mostly inspired by Legend Of Zelda : Link to the Past. Since its a 5 week project, we're not doing any dungeon crawling, but what we are doing are boss fights. And since I have another programmer, I get to do all the boss AI! Dream come true. Now, I sought out to make some simple, re-usable code from my favorite AI book (and one of my favorite game programming books in general), Programming Game AI by Example, by Mat Buckland.
http://www.amazon.com/Programming-Game-Example-Mat-Buckland/dp/1556220782
Its a great intro to AI book, go read it! Really, its way better than this post. Go read it!
...You read it? Awesome! Lets continue.
So after watching some LOZ Link to the Past boss videos on youtube, I noticed all bosses are pretty state driven. 1st chapter of that awesome book I know you just read is about state driven AI, so that's pretty fantastic. I made a StateMachine class and an abstract State class and was all set to go! I made an EnemyBase class who owned its own StateMachine and I was pumped to start making state based behaviors, everything was so awesome and cool there, and I started on the first boss. Here's where my super object oriented world crashed.
Spoiler alert, first boss is going to be a wizard who shoots fireballs in random directions. Also, before the fight, there are going to be archers who shoot arrows. Awesome! I'll just make a shoot arrow state and...oh wait. Let's look at our abstract state class in C#
public abstract class State<T>
{
public virtual Enter(T owner){}
public virtual Execute(T owner){}
public virtual Exit(T owner){}
}
So what if I made a State called ShootArrow?
public class ShootArrow : State<EnemyBase>
{
public override Enter(EnemyBase owner)
{
owner.ShootArrow();
}
}
There's a huge issue with this approach, and that is EnemyBase doesn't have a ranged attack! Sure, I could've made one, but not every enemy needs a ranged attack, so that's not very object oriented to put one there...they could have a virtual ranged attack that's only implemented in classes that need to have a ranged attack, but what if two classes need to implement it that exact same way (like Archer and Boss1)? Then both classes would have duplicate code...no no no. Never think copied code. Always wrong. Not object oriented. You will get and F on the project. Bad bad bad.
But even here I had already jumped ahead of myself. Without putting all functionality for every enemy I ever want to have in my base class, I can't have any state inherit from State<EnemyBase> as it won't be able to call any functions it doesn't have. So, each thing inherited from EnemyBase will need to have its own state machine, so states can call the functions they'll need. I'll need things like
public class ShootBolt : State<Boss1>
{
public override Enter(Boss1 owner)
{
owner.ShootBolt();
}
}
instead. Then Boss1 can have a function that shoots bolts! Hooray! Oh wait....have you seen the problem yet? Archer needs to shoot arrows too...but I can't give the archer a state made for Boss1, the compiler would never allow it. So what if I made a class inbetween EnemyBase and Boss1 and archer called EnemyCanShoot : EnemyBase and then do Boss1 : EnemyCanShoot and Archer : EnemyCanShoot? Then my state could be public class ShootBolt : State<EnemyCanShoot> instead? That could work....if shooting a bolt was the only thing I ever needed to share between classes. What happens if Boss1 and BasicWizard need to teleport as well? Boss1 can't inherit from EnemyCanShoot AND EnemyCanTeleport, this is C# (oh yeah, this projects being made in C# and Unity3D), multiple inheritance isn't allowed. Even if it were C++ and we could do MI, that could start to really lead to some super sloppy code.
class Boss1 : public EnemyCanShoot, public EnemyCanTeleport, public EnemyCanSlash, public EnemyCanDie, public EnemyCanBreatheFire, public EnemyCanSwim, public EnemyDropsPickup
etc...yikes. So this doesn't seem like a good idea, especially when all those EnemyCan's all inherit from from the same EnemyBase and would be overriding different functions at the same time and trying to figure out which fricking Move function you actually wanna call like the one that swims or flies or teleports or asdfbgrwhrtw. Messy. More like EnemyCant. Ha. Jokes.
But really, maybe we could do something like an interface? Yeah, that could work, public class Boss1 : ICanShoot and public class Archer : ICanShoot that just have some sort of functionality to shoot. Problem is, interfaces can't have anything really in them, like variables or function definitions. So if Boss1 and Archer need to shoot the exact same way, you end up with redundant code. Insert Luke Skywalker "Nooooo" here.
Is there any hope out there? Is this super StateMachine not as awesome as I originally thought? Can I not have re-usable states everywhere? What to do? Ultimately, I had to face some kinda rough truths (at least for me). Sometimes, its okay to not object orient all the things. This idea of an abstract state machine presented in the book wasn't meant for what I was trying to use it for. That's not to say its not still awesome, it takes code away from your Boss1 code and breaks it down and makes it much more manageable and readable without alot of nasty switch statements. Which is wonderful. But I had to accept it, without a major code re-structure (which I really didn't want to do), I was going to have either some duplicate code or some enemies that had (potentially alot of) un-needed functionality. If I were to start this project over, I probably would've done things a bit differently. I might not have used this StateMachine approach as such a godlike over any other AI approach and make it so every enemy HAS to use it.
And you might be wondering "why didn't he just do this" or "why didn't he just do that" or some super thing that I didn't think of that magically does everything I was just trying to do. First, let me say I tried alot of things that I didn't even really mention in this article to get this approach of re-usable states to work that failed, so I may have attempted it. Secondly, this is a 5 week project where I have quite alot of other things to do, both in this project and outside of it too, so spending a week trying to get this perfect for all cases just wasn't in the cards. That being said, if someone has some way or technique that does let this work the way I was trying to, please share!!!! I'm very curious, and I'm sure there's a solution out there I didn't have time to try that works great and is magical and awesome and lovely. But that being said, here's how my story ends now:
There are 5 lines of duplicate code copied and pasted in my project now. It happened. And you know, I'm pretty okay with that. I made alot of object oriented code in this that I'm quite proud of (next post maybe) and some AI that's working nicely. And if the alternative is spending hours and hours getting an approach to do something its probably not truly meant for, only 5 line is great to me. Spending the time to completely object orient (assuming you are doing an object oriented approach, not something like data oriented) is usually worth it, but if you don't do it to its fullest because the game needs to get done, or because the approach you took is awesome and perfect except for one or two little instances, trust me: its not the end of the world, and your teacher isn't going to give you an F if your game is awesome.
--daviD Ward
This post is going to be slightly different. Its about porting what you learn in your object oriented design class to the real world: where it works and where it doesn't. Lets get started.
My latest game I'm working on is a retro 2D style game, mostly inspired by Legend Of Zelda : Link to the Past. Since its a 5 week project, we're not doing any dungeon crawling, but what we are doing are boss fights. And since I have another programmer, I get to do all the boss AI! Dream come true. Now, I sought out to make some simple, re-usable code from my favorite AI book (and one of my favorite game programming books in general), Programming Game AI by Example, by Mat Buckland.
http://www.amazon.com/Programming-Game-Example-Mat-Buckland/dp/1556220782
Its a great intro to AI book, go read it! Really, its way better than this post. Go read it!
...You read it? Awesome! Lets continue.
So after watching some LOZ Link to the Past boss videos on youtube, I noticed all bosses are pretty state driven. 1st chapter of that awesome book I know you just read is about state driven AI, so that's pretty fantastic. I made a StateMachine class and an abstract State class and was all set to go! I made an EnemyBase class who owned its own StateMachine and I was pumped to start making state based behaviors, everything was so awesome and cool there, and I started on the first boss. Here's where my super object oriented world crashed.
Spoiler alert, first boss is going to be a wizard who shoots fireballs in random directions. Also, before the fight, there are going to be archers who shoot arrows. Awesome! I'll just make a shoot arrow state and...oh wait. Let's look at our abstract state class in C#
public abstract class State<T>
{
public virtual Enter(T owner){}
public virtual Execute(T owner){}
public virtual Exit(T owner){}
}
So what if I made a State called ShootArrow?
public class ShootArrow : State<EnemyBase>
{
public override Enter(EnemyBase owner)
{
owner.ShootArrow();
}
}
There's a huge issue with this approach, and that is EnemyBase doesn't have a ranged attack! Sure, I could've made one, but not every enemy needs a ranged attack, so that's not very object oriented to put one there...they could have a virtual ranged attack that's only implemented in classes that need to have a ranged attack, but what if two classes need to implement it that exact same way (like Archer and Boss1)? Then both classes would have duplicate code...no no no. Never think copied code. Always wrong. Not object oriented. You will get and F on the project. Bad bad bad.
But even here I had already jumped ahead of myself. Without putting all functionality for every enemy I ever want to have in my base class, I can't have any state inherit from State<EnemyBase> as it won't be able to call any functions it doesn't have. So, each thing inherited from EnemyBase will need to have its own state machine, so states can call the functions they'll need. I'll need things like
public class ShootBolt : State<Boss1>
{
public override Enter(Boss1 owner)
{
owner.ShootBolt();
}
}
instead. Then Boss1 can have a function that shoots bolts! Hooray! Oh wait....have you seen the problem yet? Archer needs to shoot arrows too...but I can't give the archer a state made for Boss1, the compiler would never allow it. So what if I made a class inbetween EnemyBase and Boss1 and archer called EnemyCanShoot : EnemyBase and then do Boss1 : EnemyCanShoot and Archer : EnemyCanShoot? Then my state could be public class ShootBolt : State<EnemyCanShoot> instead? That could work....if shooting a bolt was the only thing I ever needed to share between classes. What happens if Boss1 and BasicWizard need to teleport as well? Boss1 can't inherit from EnemyCanShoot AND EnemyCanTeleport, this is C# (oh yeah, this projects being made in C# and Unity3D), multiple inheritance isn't allowed. Even if it were C++ and we could do MI, that could start to really lead to some super sloppy code.
class Boss1 : public EnemyCanShoot, public EnemyCanTeleport, public EnemyCanSlash, public EnemyCanDie, public EnemyCanBreatheFire, public EnemyCanSwim, public EnemyDropsPickup
etc...yikes. So this doesn't seem like a good idea, especially when all those EnemyCan's all inherit from from the same EnemyBase and would be overriding different functions at the same time and trying to figure out which fricking Move function you actually wanna call like the one that swims or flies or teleports or asdfbgrwhrtw. Messy. More like EnemyCant. Ha. Jokes.
But really, maybe we could do something like an interface? Yeah, that could work, public class Boss1 : ICanShoot and public class Archer : ICanShoot that just have some sort of functionality to shoot. Problem is, interfaces can't have anything really in them, like variables or function definitions. So if Boss1 and Archer need to shoot the exact same way, you end up with redundant code. Insert Luke Skywalker "Nooooo" here.
Is there any hope out there? Is this super StateMachine not as awesome as I originally thought? Can I not have re-usable states everywhere? What to do? Ultimately, I had to face some kinda rough truths (at least for me). Sometimes, its okay to not object orient all the things. This idea of an abstract state machine presented in the book wasn't meant for what I was trying to use it for. That's not to say its not still awesome, it takes code away from your Boss1 code and breaks it down and makes it much more manageable and readable without alot of nasty switch statements. Which is wonderful. But I had to accept it, without a major code re-structure (which I really didn't want to do), I was going to have either some duplicate code or some enemies that had (potentially alot of) un-needed functionality. If I were to start this project over, I probably would've done things a bit differently. I might not have used this StateMachine approach as such a godlike over any other AI approach and make it so every enemy HAS to use it.
And you might be wondering "why didn't he just do this" or "why didn't he just do that" or some super thing that I didn't think of that magically does everything I was just trying to do. First, let me say I tried alot of things that I didn't even really mention in this article to get this approach of re-usable states to work that failed, so I may have attempted it. Secondly, this is a 5 week project where I have quite alot of other things to do, both in this project and outside of it too, so spending a week trying to get this perfect for all cases just wasn't in the cards. That being said, if someone has some way or technique that does let this work the way I was trying to, please share!!!! I'm very curious, and I'm sure there's a solution out there I didn't have time to try that works great and is magical and awesome and lovely. But that being said, here's how my story ends now:
There are 5 lines of duplicate code copied and pasted in my project now. It happened. And you know, I'm pretty okay with that. I made alot of object oriented code in this that I'm quite proud of (next post maybe) and some AI that's working nicely. And if the alternative is spending hours and hours getting an approach to do something its probably not truly meant for, only 5 line is great to me. Spending the time to completely object orient (assuming you are doing an object oriented approach, not something like data oriented) is usually worth it, but if you don't do it to its fullest because the game needs to get done, or because the approach you took is awesome and perfect except for one or two little instances, trust me: its not the end of the world, and your teacher isn't going to give you an F if your game is awesome.
--daviD Ward
Thursday, December 13, 2012
To Lose One's Self Technical Postmortem
Hello again,
This past semester I took TC 445 at Michigan State University. I'm proud to present my final from this class, To Lose One's Self, which can be played here:
http://class.cas.msu.edu/tc445/level4/group3/
http://class.cas.msu.edu/tc445/level4/group3/
I wanted to talk about some of the coding design and implementation decisions I made in this project. The premise of the main mechanic is pretty simple. You are in an unbeatable maze. You must find your way to the exit. You have the ability to make the walls of the maze disappear for a time, however there is an enemy hunting you. When you walls are down, you can go right to the exit, but he can go right to you. You must balance dropping the walls in such a way as to avoid the enemy, but still reach the exit before he gets you. Along the way, there are objects you can collect that will make him slower. If you collect all 6 and beat it, you get the happy ending. If you beat it without getting all 6, you get the not so happy ending. The game was made in Unity3D version 3.5 in a time period of roughly 5 weeks. That's all I'll say about the game itself, check it out!!
I was the only programmer on this project, in fact I was the only one who had much coding knowledge at all. I was very fortunate to work with some really great, smart, passionate artists and designers on this project as well, which worked out great. As the only programmer, I pretty much had alot power to do things how I wanted.
The game pretty much has two main states, walls and no walls. When the walls are up, the enemy should be navigating the maze to try to find you, and the walls of the maze should all be there with colliders turned on and we have a certain skybox. When the walls are down, the walls should animate them into the ground, the enemy should run straight towards you, and the skybox should change as well as some visual FX should be applied. I made a GameManager class to keep track of this state. When the "F" key is pressed, the transition occurs and the walls go down. Then after a random amount of time (from about 3 to 5 seconds) the walls go back up and the state is changed. This is all handled by the GameManager. It seemed really, really impractical to me to have the GameManager actually set all the walls and the enemy. Thats alot of work to do in one frame and could easily cause some lag do to looping through all the walls and other object and turning them off or changing their settings. Instead, I made GameManager a singleton that each object affected by the game state constantly asks the manager what they should be doing. Here's some pseudo-code to demonstrate what I mean.
public class Wall
{
void Update()
{
if(GameManager.Instance().AreWallsDown())
{
//Do set walls down
}
else
{
//Do set walls up
}
}
//Rest of implementation
}
By having this concept, everything in the game was consistent, there were no spikes in lag (at least not from code..) when the walls went from up to down visa versa. Everything ran pretty smoothly.
The enemy was a little different, however. He's probably the most interesting piece in this post, so I'll spend some time on him now.
When the walls are down, he should sprint right at you. That's pretty easy to accomplish with a simple seek behavior. But when the walls are up, he should wander around and try to find you. Not so simple now. Any AI programmer's first inclination in this case would be to use an A* algorithm and indeed, it was mine as well. However after thinking about it, the maze is unbeatable. True I can give him a point and make him find his way there as fast as possible, but there are two big issues with this.
1. Where do we tell him to go? Do we just give him random points from our node tree and have him head there? Do we give him the player's position? What if he can't get there (remember the maze is unbeatable..everything is sectioned with no way to get from one to another without the player dropping the walls)
2. Even if we knew what to tell our AI and how to get to the player, we don't want to. An AI that apparently knows the maze and can always find its way to you while you're still trying to figure out which way to go? Not very fair to the player...the AI should technically be as "lost" as the player is. It should maybe know where the player kinda is, and work its way towards him as best as it can, but it should never be able to just magically "go" to the player, even if it can.
So now, what are we left with? The answer is really quite simple, we chunk A* all together and go with a more Unity styled solution, RayCasts. A raycast is essentially shooting a ray out of a point in a direction and seeing if you hit anything. A full reference can be found here
Using this, we can pretty much do everything we want to. And if we use layering in a smart manner, we can use it pretty efficiently with not a ton of overhead. With this in mind, we can do some simple obstacle avoidance
void AvoidObstacles(Vector3 dir /*the direction I want to go*/)
void AvoidObstacles(Vector3 dir /*the direction I want to go*/)
{
RaycastHit hit;
if(Physics.Raycast(transform.position, transform.forward, out hit, ObjectDetectionRange))
{
if(hit.transform != transform)
{
dir += hit.normal;
}
}
var newRot = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.Slerp(transform.rotation, newRot, Time.deltaTime * Speed);
transform.position += transform.forward * Speed * Time.deltaTime;
}
By simply adding the normal of whatever we hit, our enemy will essentially avoid walls. Its not quite this simple, you'll need to shoot more rays to ensure his sides don't clip the walls, but you get the basic idea. Now we need to decide what direction we want to go. When the walls are down, this direction is the direction towards the player. But what about when the walls are up? Well...its just his current forward. He just wants to go forward. He doesn't really know much about whats going on, so if he doesn't know where the player is and he can't see him, he'll just kinda wander forward an avoid the walls of the maze.
void Update()
{
Vector3 dir;
if(GameManager.Instance().AreWallsDown()) dir = Seek(Player.transform.position);
else dir = Wander(); //returns transform.forward
AvoidObstacles(dir);
}
That's really about it. Now, there are two special cases to this to make him smarter.
1. The walls are up and I can see the player. I shouldn't just wander around, I should kill him! (Or get him or...whatever it is I do).
2. I can't see him right now, but I did see him recently. Rather than wander forward aimlessly, I should try to (without an A*) get to where I last saw him.
The second one is pretty easy to make look natural. Everytime the enemy sees the player, whether the walls are up or down, he stores the point where he saw him/her. Then next time he can't see the player, rather than just go forward, he does a Seek(LastKnowPosisition). He does till he either times out (he got stuck or he can't get there as the maze won't allow it), or he reaches the point where he last the saw the player. Lets he times out, its possible he took a stupid route and didn't end up where he wanted to go. Or he's not in the same section as his target and he's not gonna be able to get there. Or he was still on his way there. In any case, when he comes to a fork, he ALWAYS take the way towards where he thinks the player is (very natural seeming). And if he didn't get all the way there, then now, as he goes back to wandering, he's alot closer to the player than he would've been otherwise, keeping some tension on the player to not drop those walls so fast again.
The first one is a bit more tricky, but not completely terrible. Basically we need to know two things to know if we can see the player, am I facing the player, and is there anything between us that would obstruct my vision (such as, oh, I don't know, millions of maze walls). If both these conditions are met, I can see the player and should seek him rather than wander forward aimlessly. But how do we know these two things are true? If there's anything obstructing our vision, a raycast will pick that up pretty easily so that's not so bad. As for if I'm facing the player, we will turn to some Vector Calculus.
bool DoISeeThePlayer()
{
Vector3 directionTowardsPlayer = (Player.transform.position - transform.position).normalized;
//If the dot product between my forward and the direction from me that the player lies is greater than
// zero, I can see him. Instead of zero, we'll use some vision range variable that the designer can set
//A typical human vision range would be from about 15-30
if (Vector3.Dot (transform.forward, directionTowardsPlayer) > VisionRange)
{
//I can see the player, now do a raycast to make sure there's no objects between me and him/her
if (Physics.Raycast (transform.position, directionTowardsPlayer, out hit))
{
if (hit.transform == Player.transform)
{
UpdateLastKnowPositionOfPlayer();
return true;
}
}
}
return false;
}
With this logic, I can detect in-maze whether or not I should go after the player.
Well that about wraps this one up, if you have any questions about anything else in the game, feel free to comment or shoot me an email at warddav16@gmail.com. Till next time.
--daviD Ward
Saturday, September 29, 2012
Some Fun Web Development Technologies
Well, I've missed my one post a week mark hardcore...more like one post every month (and even missing that sometimes). Oh well, such is life.
Thought it'd be good to talk about some projects I've been doing. I'm currently working on my capstone project, which can be as of 9/29/2012 can be viewed here
http://www.cse.msu.edu/~cse498/2012-08/projects/auto-owners/
Working with two really great guys on this one, its been pretty rough but its gone well so far. I've been mostly working on front end web development for it, and helping with the server and database work as needed. I've only ever dabbled with web development till now, plus a little work at Techsmith on some of their sites, so its been a bit of a learning curve. We've been utilizing jQuery mobile which can be found here
http://jquerymobile.com/
jQuery mobile is pretty awesome. You can make websites that look good on both mobile and desktop browsers pretty easily, and its been alot of fun. A really nice feature they have on their home page is a drag and drop window. Once you drag and drop elements in it, you can click on the element to make it show the HTML behind it. You can even build a page and export the HTML to your computer. Its been a great way to make pages quickly and prototype. I would strongly recommend it to anyone making a website that should support mobile.
Another utility we've been using alot is Ember.js. Its pretty new and lacking in documentation, but it lets you do some pretty neat things. It can be found here
http://emberjs.com/
Ember.js is a javascript library that essentially lets you do more object oriented coding for web development. With a protocol they refer to as handlebars, you can control all of the javascript right from your HTML. It's quite a learning curve to start using, which I am still definitely in the middle of. A really good break down of Ember.js and how to use it can be viewed here
http://www.adobe.com/devnet/html5/articles/flame-on-a-beginners-guide-to-emberjs.html
Sorry for the short post after not having one for so long. Gonna talk about some other (and actual game related) projects soon!
--daviD
Thought it'd be good to talk about some projects I've been doing. I'm currently working on my capstone project, which can be as of 9/29/2012 can be viewed here
http://www.cse.msu.edu/~cse498/2012-08/projects/auto-owners/
Working with two really great guys on this one, its been pretty rough but its gone well so far. I've been mostly working on front end web development for it, and helping with the server and database work as needed. I've only ever dabbled with web development till now, plus a little work at Techsmith on some of their sites, so its been a bit of a learning curve. We've been utilizing jQuery mobile which can be found here
http://jquerymobile.com/
jQuery mobile is pretty awesome. You can make websites that look good on both mobile and desktop browsers pretty easily, and its been alot of fun. A really nice feature they have on their home page is a drag and drop window. Once you drag and drop elements in it, you can click on the element to make it show the HTML behind it. You can even build a page and export the HTML to your computer. Its been a great way to make pages quickly and prototype. I would strongly recommend it to anyone making a website that should support mobile.
Another utility we've been using alot is Ember.js. Its pretty new and lacking in documentation, but it lets you do some pretty neat things. It can be found here
http://emberjs.com/
Ember.js is a javascript library that essentially lets you do more object oriented coding for web development. With a protocol they refer to as handlebars, you can control all of the javascript right from your HTML. It's quite a learning curve to start using, which I am still definitely in the middle of. A really good break down of Ember.js and how to use it can be viewed here
http://www.adobe.com/devnet/html5/articles/flame-on-a-beginners-guide-to-emberjs.html
Sorry for the short post after not having one for so long. Gonna talk about some other (and actual game related) projects soon!
--daviD
Wednesday, July 4, 2012
Unity Coding Tutorial pt 2
Hello again,
Welcome to Unity Coding Tutorial pt 2. As I noted in pt 1, this time I would like to discuss some tricks I've found in Unity. Due to the length of this tutorial already, I have decided to move GUI elements to a later date.
Communicating across scripts.
This is a huge part of Unity. You never want a vastly complicated script that can do alot of things, in my opinion the smaller the script the better. However, this creates an issue as, often times, one script will keep track of things that another will want to depend on. There are a couple ways to fix this, each with its own advantages. The simplest way is with static functions and variables.
Static power.
Its easy to make a static variable. All you have to do is
public static int /*or whatever kind of type*/ MyVariable;
Then, anywhere else in your code, you can read and write to that variable by doing something like
className.MyVariable++;
You can also do the same with functions.
private static int myVariable;
public static void IncVariable()
{
myVariable++;
}
You can access functions by doing something like
className.IncVariable();
Notice that in order for myVariable to be accessed inside of the IncVariable function, it needs to be declared as static. Why? Static variables (and functions) essentially exist everywhere. They are created at the beginning of your program, and destroyed at the end. In a way, they have global scope. Therefore, since they are not bound to to a particular instance of a class, they can only access items that have similar scope. They don't "know" about any variables tied to an instance of a class. There are some work arounds that can be applied to certain situations, such as giving static functions some arguments and passing it the data it would need. But, since other scripts don't always have the variables needed, there aren't very many cases where this is practical.
Another draw backs to static variables is, well, they exist everywhere. This means from the start of your program to the end of your program, they are alive and have a value. Even across scenes. This has caused hundreds of programmers to run into issues. Data from one scene is still exactly as it was in the old scene, it doesn't get reset. There are advantages to this, one of them being a great way to carry data over from scene to scene in your game. A work around to this issue is to initialize all your static variables in Start() or Awake() to whatever they should be at the start of a scene. This will reset data before every scene and ensure you never run into any weird issues with data from old scenes. However, there are other ways to share data across scripts.
Singletons And Member Variables.
Singleton patterns are a favorite of mine. Of course, like anything else, they can be overused. The pattern essentially goes as such.
class myClass
{
private static myClass mInstance = null;
public static myClass mInstance Instance()
{
if(mInstance == null ) mInstance = new myClass();
return myInstance;
}
private myClass(){}
}
If you want your MonoBehaviour to be an singleton, you need to do some variation of this.
class myClass : MonoBehaviour
{
private static myClass mInstance = null;
public static myClass mInstance Instance() {return mInstance;}
void Awake()
{
if(!mInstance) mInstance = this;
}
}
All the singleton pattern does is make your one class available anywhere in any script. It contains a pointer to an Instance of itself. And since this instance has a scope of the scene it is in, it won't ever carry over data from old scenes! It will be created and destroyed in every scene it is in. You can access data from this script by doing something like this.
var inst = myClass.Instance();
if(inst) /*If there is one in this scene*/ inst.anyPublicFunctionOrVariable;
This pattern, of course, can only be applied to things that there can only ever be one of per scene. If you have multiple objects of a type in a scene, you may need to make that script have a variable of whatever script it needs to know about. Something like
myClass1 : MonoBehaviour
{
public myClass2 thingsINeed;
void Update()
{
thingsINeed.anyPublicFunctionOrVariable;
}
}
In the editor, you can then drag on drop the object that has the script you need attached, and it will automatically declare it for you.
Making Objects move.
By editing an objects transform.position, you can essentially make the object move. A full reference of transform and all the things you can do with it can be found here :
http://docs.unity3d.com/Documentation/ScriptReference/Transform.html
You can receive input from from the keyboard, mouse, joystick, or touch screen using the input class. A full reference can be found here :
http://docs.unity3d.com/Documentation/ScriptReference/Input.html
With this knowledge, lets look at a simple 2D controller.
//This should be attached to the object it is supposed to move
//We'll also assume the object is also always facing forward
class Controller2D : MonoBehaviour
{
public float Speed = 1;
void Update()
{
if(Input.GetKey("d"))
{
transform.position += transform.forward * Speed * Time.deltaTime;
}
if(Input.GetKey("a"))
{
transform.position -= transform.forward * Speed * Time.deltaTime;
}
}
}
Even though the code is pretty self explanatory and this is the simplest controller ever, let's break it down. Feel free to skip over this if you already understand everything that's happening.
First thing's first, as the comments say, this must be on the gameObject it is going to move. It also assumes that the gameObejct is always facing in the "correct" forward direction. On Update() (which we remember is called every frame), it will check Input to see if the "d" key is currently being pushed. If it is, it will update its position based on its forward position, Speed, and something called Time.deltaTime. transform.forward is just the direction we want to move in. This will often not be its own forward direction, but for this simple example it works fine. Speed is a variable just to tweak the speed, it is set to 1 by default. Since its public, a designer could easily tweak this variable and make this object faster or slower. Time.deltaTime is a variable that keeps track of the time between this Update call and the Update call before it. It essentially will make your object move smoothly on any computer, since every call to Update will not always be after the same amount of time for every computer (or even on the same computer). We see that the rest of the code is exactly the same for when "a" is pushed, only the minus sign will make the gameObject move backwards (still facing forward though).
Lets look at a (very) simple enemy AI. Notice its very similar to the code above.
class Enemy : MonoBehaviour
{
public GameObject Player;
public float Speed = 1;
void Start()
{
if(!Player) /*Player was not set up in the editor*/
Player = FindWithTag("Player");
}
void Update()
{
Seek(Player.transform.position);
}
void Seek(Vector3 target)
{
Vector3 direction = transform.position - target;
transform.forward = direction;
transform.position += transform.forward * Speed * Time.deltaTime;
}
}
Again, we're moving by our own forward direction time Speed time Time.deltaTime. Here however, we are not waiting for any input. Instead, we set our own forward direction based on where our target is, which for this enemy is whatever is tagged as "Player." We then move according to the new forward direction.
An annoying (although necessary) aspect of transform (and many other things like transforms in Unity) is that you cannot simply edit a transform x, y, or z. You will have to create an entirely new Vector3 and assign it into position.
Well, hope you got some good ideas from this tutorial. If you think you got a good grasp on all of the above, try this for practice:
-Make a 2D controller that actually changes the forward direction when they move backfowards and forwards.
-Make the Controller into two different scripts: An InputHandler and a Motor. The InputHandler should detect input and call the appropriate function in the Motor. The Motor should actually move the player.
-Make an enemy that runs away from the player instead of towards it.
Best of luck.
--daviD Ward
Welcome to Unity Coding Tutorial pt 2. As I noted in pt 1, this time I would like to discuss some tricks I've found in Unity. Due to the length of this tutorial already, I have decided to move GUI elements to a later date.
Communicating across scripts.
This is a huge part of Unity. You never want a vastly complicated script that can do alot of things, in my opinion the smaller the script the better. However, this creates an issue as, often times, one script will keep track of things that another will want to depend on. There are a couple ways to fix this, each with its own advantages. The simplest way is with static functions and variables.
Static power.
Its easy to make a static variable. All you have to do is
public static int /*or whatever kind of type*/ MyVariable;
Then, anywhere else in your code, you can read and write to that variable by doing something like
className.MyVariable++;
You can also do the same with functions.
private static int myVariable;
public static void IncVariable()
{
myVariable++;
}
You can access functions by doing something like
className.IncVariable();
Notice that in order for myVariable to be accessed inside of the IncVariable function, it needs to be declared as static. Why? Static variables (and functions) essentially exist everywhere. They are created at the beginning of your program, and destroyed at the end. In a way, they have global scope. Therefore, since they are not bound to to a particular instance of a class, they can only access items that have similar scope. They don't "know" about any variables tied to an instance of a class. There are some work arounds that can be applied to certain situations, such as giving static functions some arguments and passing it the data it would need. But, since other scripts don't always have the variables needed, there aren't very many cases where this is practical.
Another draw backs to static variables is, well, they exist everywhere. This means from the start of your program to the end of your program, they are alive and have a value. Even across scenes. This has caused hundreds of programmers to run into issues. Data from one scene is still exactly as it was in the old scene, it doesn't get reset. There are advantages to this, one of them being a great way to carry data over from scene to scene in your game. A work around to this issue is to initialize all your static variables in Start() or Awake() to whatever they should be at the start of a scene. This will reset data before every scene and ensure you never run into any weird issues with data from old scenes. However, there are other ways to share data across scripts.
Singletons And Member Variables.
Singleton patterns are a favorite of mine. Of course, like anything else, they can be overused. The pattern essentially goes as such.
class myClass
{
private static myClass mInstance = null;
public static myClass mInstance Instance()
{
if(mInstance == null ) mInstance = new myClass();
return myInstance;
}
private myClass(){}
}
If you want your MonoBehaviour to be an singleton, you need to do some variation of this.
class myClass : MonoBehaviour
{
private static myClass mInstance = null;
public static myClass mInstance Instance() {return mInstance;}
void Awake()
{
if(!mInstance) mInstance = this;
}
}
All the singleton pattern does is make your one class available anywhere in any script. It contains a pointer to an Instance of itself. And since this instance has a scope of the scene it is in, it won't ever carry over data from old scenes! It will be created and destroyed in every scene it is in. You can access data from this script by doing something like this.
var inst = myClass.Instance();
if(inst) /*If there is one in this scene*/ inst.anyPublicFunctionOrVariable;
This pattern, of course, can only be applied to things that there can only ever be one of per scene. If you have multiple objects of a type in a scene, you may need to make that script have a variable of whatever script it needs to know about. Something like
myClass1 : MonoBehaviour
{
public myClass2 thingsINeed;
void Update()
{
thingsINeed.anyPublicFunctionOrVariable;
}
}
In the editor, you can then drag on drop the object that has the script you need attached, and it will automatically declare it for you.
Making Objects move.
By editing an objects transform.position, you can essentially make the object move. A full reference of transform and all the things you can do with it can be found here :
http://docs.unity3d.com/Documentation/ScriptReference/Transform.html
You can receive input from from the keyboard, mouse, joystick, or touch screen using the input class. A full reference can be found here :
http://docs.unity3d.com/Documentation/ScriptReference/Input.html
With this knowledge, lets look at a simple 2D controller.
//This should be attached to the object it is supposed to move
//We'll also assume the object is also always facing forward
class Controller2D : MonoBehaviour
{
public float Speed = 1;
void Update()
{
if(Input.GetKey("d"))
{
transform.position += transform.forward * Speed * Time.deltaTime;
}
if(Input.GetKey("a"))
{
transform.position -= transform.forward * Speed * Time.deltaTime;
}
}
}
Even though the code is pretty self explanatory and this is the simplest controller ever, let's break it down. Feel free to skip over this if you already understand everything that's happening.
First thing's first, as the comments say, this must be on the gameObject it is going to move. It also assumes that the gameObejct is always facing in the "correct" forward direction. On Update() (which we remember is called every frame), it will check Input to see if the "d" key is currently being pushed. If it is, it will update its position based on its forward position, Speed, and something called Time.deltaTime. transform.forward is just the direction we want to move in. This will often not be its own forward direction, but for this simple example it works fine. Speed is a variable just to tweak the speed, it is set to 1 by default. Since its public, a designer could easily tweak this variable and make this object faster or slower. Time.deltaTime is a variable that keeps track of the time between this Update call and the Update call before it. It essentially will make your object move smoothly on any computer, since every call to Update will not always be after the same amount of time for every computer (or even on the same computer). We see that the rest of the code is exactly the same for when "a" is pushed, only the minus sign will make the gameObject move backwards (still facing forward though).
Lets look at a (very) simple enemy AI. Notice its very similar to the code above.
class Enemy : MonoBehaviour
{
public GameObject Player;
public float Speed = 1;
void Start()
{
if(!Player) /*Player was not set up in the editor*/
Player = FindWithTag("Player");
}
void Update()
{
Seek(Player.transform.position);
}
void Seek(Vector3 target)
{
Vector3 direction = transform.position - target;
transform.forward = direction;
transform.position += transform.forward * Speed * Time.deltaTime;
}
}
Again, we're moving by our own forward direction time Speed time Time.deltaTime. Here however, we are not waiting for any input. Instead, we set our own forward direction based on where our target is, which for this enemy is whatever is tagged as "Player." We then move according to the new forward direction.
An annoying (although necessary) aspect of transform (and many other things like transforms in Unity) is that you cannot simply edit a transform x, y, or z. You will have to create an entirely new Vector3 and assign it into position.
Well, hope you got some good ideas from this tutorial. If you think you got a good grasp on all of the above, try this for practice:
-Make a 2D controller that actually changes the forward direction when they move backfowards and forwards.
-Make the Controller into two different scripts: An InputHandler and a Motor. The InputHandler should detect input and call the appropriate function in the Motor. The Motor should actually move the player.
-Make an enemy that runs away from the player instead of towards it.
Best of luck.
--daviD Ward
Friday, June 22, 2012
Unity Coding Tutorial pt 1
Well, I've missed my one post a week deadline pretty hard core. Well that's something.
I wanted to do a couple brief Unity tutorials, since I really had a hard time searching the internet to find one that I liked and taught the things I wanted to learn. This tutorial assumes you know at least a little bit about Unity (how to open a script, attach it to an object, what a scene is, etc) and some general things about coding and C#.
Let's begin.
MonoBehaviour.
When you create a new C# script, you'll notice that it comes automatically inherited from MonoBehaviour, and has two functions created, Start and Update. Unless a script is inherited from MonoBehaviour, it cannot be attached to an object, so keep that in mind. Of course, if you're doing a larger project, you'll have many scripts that do not inherit from MonoBehaviour, but in general most of your scripts will ultimately want to be derived from it. At the beginning of every scene, Unity will go through all MonoBehaviours that are active in the scene (and whose gameObjects that its attached to is active) and will call Start() on them. It will also call a function called Awake() before it calls Start(), so keep that in mind if you have some pre-setup you ever need to do in a sequential manner. Then, ever frame of the scene, it will also call Update() on every single active MonoBehaviour in the scene. There are many other over loadable functions in MonoBehaviour that you can use and are called at different times, most of which you can view here:
http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.html
Now, since Update() is called once per frame for every active MonoBehaviour, its a good idea to try to keep this as simple as possible. Its easy to bog this function down and slow your game drastically to the point of being unplayable. Try to declare any complicated variables in Start() or Awake(), so that way in Update you don't have to keep building something every time to use it, it will already be there for you to use. Keep in mind, these functions will only be called for scripts that are attached to gameObjects int the scene.
Variables.
Unity is very nice about variables. By making a variable public in your C# script, you can actually change its value in the editor! This include strings, integers, floating point numbers, and more. Even gameObjects and transforms can be assigned. If you make a variable called public GameObject publicObj, this will appear in the inspector, and you can drag and drop the object that you want to be able to access in your code! You can even give your variables a default value, but the game will use whatever value is in the editor over whats in code. This is a very powerful strategy to use when you code. It is assigned and created and able to be referenced and you don't even have to worry about your game being bogged down to have to go and find it, it will have the object from the get go.
public GameObject myObj;
void Awake()
{
if(myObj != null)
Debug.Log(myObj.name);
else
Debug.Log("You forgot to assign myObj!");
}
It is very nice. Another thing you can do which is very powerful is to instantiate a prefabbed object. You can do that the function Instantiate.
public GameObject bullet;
public GameObject firingLocation;
void Update()
{
if(Input.GetKeyDown("space")
Instantiate(bullet, firingLocation.transform.position, firingLocation.transform.rotation);
}
This code will instantiate whatever gameObject bullet is at firingLocation's position and with firingLocation's rotation (i,e., facing the same way). There is a way to make your own classes able to be setup in the main menu, however this is a little more advanced so I'll save it for a later tutorial.
Another very powerful aspect of variables is public arrays. If you say public string[] Messages, this will an editable variable called Messages in the editor that you can even specify the size of! Say you wanted to play a random audio clip at the start of a scene.
public AudioClip[] playAtStart;
void Start()
{
if(playAtStart.Length > 0)
audio.PlayOneShot(playAtStart[Random.Range(0, playAtStart.Length)]);
else
Debug.Log("You didn't set up playAtStart");
}
Some objects though, you can't set up in the editor (or it's very impractical to). There is a very convenient (although very slow) function called GameObject.Find. There are a couple different versions of this function, but the only one I would ever use is FindGameObjectsWithTag(string tagname). This will return an array of GameObjects who have a tag that matches the given argument. DON'T EVER USE THIS FUNCTION OR ANY OTHER FIND FUNCTIONS OUTSIDE OF START OR AWAKE. It will bog down your program to unusable with even the simplest of scenes. If you don't know what a tag is or how to give one to an object, here's a good reference :
http://unity3d.com/support/documentation/Components/Tags.html
Collisions.
Collisions are a very important part of almost any game. MonoBehaviour has two very nice functions for collisions, OnCollisionEnter and OnTriggerEnter. But first, let's learn how to trigger these functions. In order for a MonoBehaviour have one of these functions called, there must a Collider on the object. In the editor, you'll notice a trigger checkbox. If you check it, the collider essentially becomes a trigger. A trigger is not actually a physical object like a wall or anything else. You can go right through it, however it will still recognize that you entered it. Triggers are useful for a broad spectrum of things, such as detecting which lane a player entered, when to trigger an audio clip, and thousands more. Both objects will need a collider attached to them and (in almost every case) a RigidBody. If its a custom that you made in Maya or Blender another software, it will most likely need to be checked "Convex" as well. If for some reason you OnCollisionEnter is not working, out a Debug.Log("Here") at the start of the function and play with these settings on both objects till you get it working. Let's re-visit that bullet example. Since OnCollisionEnter will be called for any object that interacts with it, chances are we wanna only do certain thing's for certain objects. Tags are a great way to do this.
class Enemy : MonoBehaviour {
void OnCollisionEnter(Collision col)
{
Debug.Log("Collision Detected");
if(col.gameObject.tag == "Bullet")
Destroy(gameObject);
}
}
This code will destroy whatever gameObject is attached to when it collides with an object with a tag "Bullet." You can easily set up a trigger as well.
class PlayAudio : MonoBehaviour {
public AudioClip enterRoomSound;
void OnTriggerEnter(Collider col)
{
Debug.Log("Trigger Detected");
if(col.gameObject.tag == "Player" && enterRoomSound)
{
audio.PlayOneShot(enterRoomSound);
}
}
You could use this to play enemy noise when you enter the room to let the player know that there are enemies here. Notice that OnCollisionEnter takes a Collision as an argument and OnTriggerEnter takes a Collider. If you don't have these arguments, Unity will complain. Obviously, OnTriggerEnter will be called for objects whose collider is marked as a trigger, and OnCollisionEnter otherwise.
I hope this helped a few people get a start in Unity and get them making games. Practice makes perfect, try to do a couple test scenes on your own. Next tutorial, I would like to go over a couple tricks I've learned, as well as maybe some GUI elements.
--daviD Ward
I wanted to do a couple brief Unity tutorials, since I really had a hard time searching the internet to find one that I liked and taught the things I wanted to learn. This tutorial assumes you know at least a little bit about Unity (how to open a script, attach it to an object, what a scene is, etc) and some general things about coding and C#.
Let's begin.
MonoBehaviour.
When you create a new C# script, you'll notice that it comes automatically inherited from MonoBehaviour, and has two functions created, Start and Update. Unless a script is inherited from MonoBehaviour, it cannot be attached to an object, so keep that in mind. Of course, if you're doing a larger project, you'll have many scripts that do not inherit from MonoBehaviour, but in general most of your scripts will ultimately want to be derived from it. At the beginning of every scene, Unity will go through all MonoBehaviours that are active in the scene (and whose gameObjects that its attached to is active) and will call Start() on them. It will also call a function called Awake() before it calls Start(), so keep that in mind if you have some pre-setup you ever need to do in a sequential manner. Then, ever frame of the scene, it will also call Update() on every single active MonoBehaviour in the scene. There are many other over loadable functions in MonoBehaviour that you can use and are called at different times, most of which you can view here:
http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.html
Now, since Update() is called once per frame for every active MonoBehaviour, its a good idea to try to keep this as simple as possible. Its easy to bog this function down and slow your game drastically to the point of being unplayable. Try to declare any complicated variables in Start() or Awake(), so that way in Update you don't have to keep building something every time to use it, it will already be there for you to use. Keep in mind, these functions will only be called for scripts that are attached to gameObjects int the scene.
Variables.
Unity is very nice about variables. By making a variable public in your C# script, you can actually change its value in the editor! This include strings, integers, floating point numbers, and more. Even gameObjects and transforms can be assigned. If you make a variable called public GameObject publicObj, this will appear in the inspector, and you can drag and drop the object that you want to be able to access in your code! You can even give your variables a default value, but the game will use whatever value is in the editor over whats in code. This is a very powerful strategy to use when you code. It is assigned and created and able to be referenced and you don't even have to worry about your game being bogged down to have to go and find it, it will have the object from the get go.
public GameObject myObj;
void Awake()
{
if(myObj != null)
Debug.Log(myObj.name);
else
Debug.Log("You forgot to assign myObj!");
}
It is very nice. Another thing you can do which is very powerful is to instantiate a prefabbed object. You can do that the function Instantiate.
public GameObject bullet;
public GameObject firingLocation;
void Update()
{
if(Input.GetKeyDown("space")
Instantiate(bullet, firingLocation.transform.position, firingLocation.transform.rotation);
}
This code will instantiate whatever gameObject bullet is at firingLocation's position and with firingLocation's rotation (i,e., facing the same way). There is a way to make your own classes able to be setup in the main menu, however this is a little more advanced so I'll save it for a later tutorial.
Another very powerful aspect of variables is public arrays. If you say public string[] Messages, this will an editable variable called Messages in the editor that you can even specify the size of! Say you wanted to play a random audio clip at the start of a scene.
public AudioClip[] playAtStart;
void Start()
{
if(playAtStart.Length > 0)
audio.PlayOneShot(playAtStart[Random.Range(0, playAtStart.Length)]);
else
Debug.Log("You didn't set up playAtStart");
}
Some objects though, you can't set up in the editor (or it's very impractical to). There is a very convenient (although very slow) function called GameObject.Find. There are a couple different versions of this function, but the only one I would ever use is FindGameObjectsWithTag(string tagname). This will return an array of GameObjects who have a tag that matches the given argument. DON'T EVER USE THIS FUNCTION OR ANY OTHER FIND FUNCTIONS OUTSIDE OF START OR AWAKE. It will bog down your program to unusable with even the simplest of scenes. If you don't know what a tag is or how to give one to an object, here's a good reference :
http://unity3d.com/support/documentation/Components/Tags.html
Collisions.
Collisions are a very important part of almost any game. MonoBehaviour has two very nice functions for collisions, OnCollisionEnter and OnTriggerEnter. But first, let's learn how to trigger these functions. In order for a MonoBehaviour have one of these functions called, there must a Collider on the object. In the editor, you'll notice a trigger checkbox. If you check it, the collider essentially becomes a trigger. A trigger is not actually a physical object like a wall or anything else. You can go right through it, however it will still recognize that you entered it. Triggers are useful for a broad spectrum of things, such as detecting which lane a player entered, when to trigger an audio clip, and thousands more. Both objects will need a collider attached to them and (in almost every case) a RigidBody. If its a custom that you made in Maya or Blender another software, it will most likely need to be checked "Convex" as well. If for some reason you OnCollisionEnter is not working, out a Debug.Log("Here") at the start of the function and play with these settings on both objects till you get it working. Let's re-visit that bullet example. Since OnCollisionEnter will be called for any object that interacts with it, chances are we wanna only do certain thing's for certain objects. Tags are a great way to do this.
class Enemy : MonoBehaviour {
void OnCollisionEnter(Collision col)
{
Debug.Log("Collision Detected");
if(col.gameObject.tag == "Bullet")
Destroy(gameObject);
}
}
This code will destroy whatever gameObject is attached to when it collides with an object with a tag "Bullet." You can easily set up a trigger as well.
class PlayAudio : MonoBehaviour {
public AudioClip enterRoomSound;
void OnTriggerEnter(Collider col)
{
Debug.Log("Trigger Detected");
if(col.gameObject.tag == "Player" && enterRoomSound)
{
audio.PlayOneShot(enterRoomSound);
}
}
You could use this to play enemy noise when you enter the room to let the player know that there are enemies here. Notice that OnCollisionEnter takes a Collision as an argument and OnTriggerEnter takes a Collider. If you don't have these arguments, Unity will complain. Obviously, OnTriggerEnter will be called for objects whose collider is marked as a trigger, and OnCollisionEnter otherwise.
I hope this helped a few people get a start in Unity and get them making games. Practice makes perfect, try to do a couple test scenes on your own. Next tutorial, I would like to go over a couple tricks I've learned, as well as maybe some GUI elements.
--daviD Ward
Tuesday, May 1, 2012
From Hello World to Ray Tracing
Hello again,
This week I'd like to talk more about my background in computer science, and maybe some up-and-coming programmers may get some good pointers out of it. First off, I'm just finishing my sophomore year at Michigan State University. This past year I took the senior level graphics programming course (hence the ray tracing comment in the title), as well as the junior level algorithms course. But I wasn't always in such courses. I wrote my first line of code,
print "Hello World"
in Python version 2.6 in the fall of 2010. For those of you who haven't taken calculus yet, I'll break down the math for you: I've only been programming for slightly over 1 and 1/2 years. And while I admit to be no programming genius, I've accomplished more in this one and a half years than many people do in all four of their college education, and not just in the class room. And don't take this the wrong way, I'm not proclaiming myself to be some super genius who can fly through the curriculum like its nothing, I struggled all the way through just as everyone else. I will say that I worked incredibly hard, and made sure I got myself out there everyway I could (even including starting this blog). I will also say I made my class schedule pretty cleverly, making sure I was in the courses I needed to be as to not waste time with a bunch of classes I didn't care about.
I guess I should start from before college. I was homeschooled first through 12th grade, which gave me virtually no computer classes or programming experience. Not all homeschoolers are in such a situation, many do have chances to code. I, sadly, was not one. I always wondered what would have happened if I started coding years back, but sports and other highschool activities took priority. I did do two things right though, I took advanced math at Lansing Community College and always kept designing games, even though I had no knowledge of how to make them. I've pretty much been designing games since I was four years old, but only seriously thought of going into them as a career at about age 14. I had no desire to ever become and engineer, but as I researched more and more into the games industry, I realized how difficult it was to go into the industry as a designer who could do nothing else. By difficult, I mean impossible. Even students with resumes vastly more impressive than mine are often never make it into the industry. Around that summer when I was 14, I took a game design camp at Michigan State offered by the group Spartasoft, a group I would become far more familiar with years later. I was pretty much set on MSU at that point, especially being so close to home. But lets fast-forward to school.
College, year one.
I had decided to major in Computer Science Engineering, hoping to break into the industry as a programmer since I was good at math, and couldn't draw a stick figure to save my sorry life. It was in this first week I heard about Spartasoft, and was eager to join. I began attending meetings and making friends in that group, and tried to do a game jam or two (in Spartasoft, we have what are called game james, where we get together and make a game from start to finish as best we can in 48 hours), although I was pretty useless in them. I learned alot through meetings though, and was introduced to the Unity game engine, although again, I was near usless at using it. I took my first programming course which, as mentioned before, taught programming and basic CS concepts through the Python programming language. I loved projects, I loved the professors and the material, and because I enjoyed it so much I was also very good at it. The next semester I decided I wanted to take as many CSE courses as I could, these university required ones were far too boring and useless, I thought. As a result of this mindset, I currently still have very few of my university requirements met. While writing and researching have their place and are very useful, taking more CSE courses sooner gave me more time to refine my skills longer while in school and work at better jobs faster.
The next semester I took C++ and data types, as well as discrete mathematics. C++ was an incredibly fun course, and taught me a "real" programming language as well some usefull algorithms (linked lists, some sorting, etc.). Suddenly I wasn't as useless in game jams, which we primarily use C# for. I was still lacking in my skills with Unity, a thing I would shortly rectify. I also got a decent job working at one of the technical helpdesks at MSU. This gave me a decent amount of technical experience I could put on my resume, and also was a pretty cool job. I got this job by pretty much applying everywhere I possible could, even if I seemed unqualified. From this I learned never to say "They probably won't even look at me." and not apply. They might not, but what if they do? Better than flipping burgers if you can help it (if not, jobs a job, and no job is easy to come by these days).
Over the summer, I was bound and determined to learn Unity. I set out to make a number of simple games, and while I didn't finish any of them, I learned alot and gained a bit of confidence in making future games. I also kept my helpdesk job, and finished up what was left of my calc requirements. I also saught out a better job, and once again applied everywhere without any thought of mopy "they won't look at me, because I'm still a sophomore" thoughts. I was also eager to prove how much I had learned, and take a job where I could actually program. I contacted my old Python professor who thankfully remembered me, and was able to get a job as a teaching assistant for him that fall. I was also able to secure an internship at Techsmith Corporation for the following spring semester, which I am now finishing up. The interview was pretty difficult for that, and it involved whiteboarding, which I had never done before. My advice for first time whiteboarders would be to bascally find some problems online, and work them out in front of your friend while they watch. Also, always say what you're thinking while to whiteboard (assuming its in person). They really don't expect you to answer all the problems perfectly, but are looking for your thought process. But I could ramble on about interviwing forever, maybe a future article on the subject.
Fall of Sophomore year.
Well this fall I took CSE 335, software design. This was the hardest class I've ever taken. It was also the funnest class, as well as the class I learned the most in. While I spend 20+ hours a week on this class alone, and barely scathed through my other classes because of it, it was worth it. I don't know about the spring semester of the class, I've heard mixed things. But I can attest to the greatness of the fall version of this class with Dr. Owen. To any MSU CSE students, take this class in the fall! And one year after taking the class, I found myself as a teaching assistant for the Python programming class. It was wierd, I admit, remembering all the projects I had done not so long ago compared to where I was now, but I enjoyed it. Hopefully I taught some people some things too! More importantly, I was useful, and even team lead, in game jams. I made some decent games that are now online (which I will put on my web site, which I will make soon..). But game jam games weren't enough, I wanted more game dev. I made an announcement at Spartasoft that I was starting a game design team. Many showed interest in joining, and over fall we designed a game that barely ever got started. We overscoped, but in the process I learned much about leading a team and established workflow patterns, and made some good friends in the process. In the fall I was also able to take IPhone game design, which, while being new course with many kinks to be worked out, gave me a pretty decent understanding of IOS games and Objective C. Being so young in all these advanced courses started becoming apparent though, as my classmates began inviting me to the bars with them, only to realize that not only could I not go, but was not going to be able to go in the near future.
Spring.
Spring saw the return of my game team, which got far more awesome and productive. We named ourselves Slightly Serious Games, and I took the role of AI programmer and team lead. I also assigned more definitive roles for all of the team. We should be making a website soon and putting our current work up. We would someday like to start ourselves as a startup company, but we'll see how that goes. My next article may be more about my team and our challenges, so I won't go too deeply in depth with that now. I also took the senior level graphics course and loved it, especially since it was taught by Dr. Owen again. I hope to take more classes with him. This semester also saw me in my first internship at Techsmith, a job I thoroughly enjoyed. I learned alot, especially about using C# (current favorite language). I also had alot of opportunity to practice my web and server skills, as well as more Objective C and some Android dev.
My contacts through Spartasoft have helped me secure my first real game design job this year for the MSU GEL lab. I will be making games for various contractors. I was also elected into Spartsoft's eboard as secretary, a chance to give back to new game designers to help them enjoy school and learn as much as I have. I'm also taking operating systems over summer, and taking the grad school computer graphics class in the fall. I hope to continue working with Slightly Sirius over fall, and plan on taking the CSE Capstone this spring as well as more CSE grad school classes next fall. I hope this article showed that with alot of work and some decent planning, how far someone can go in a year. I hope to keep accelerating at the same pace I have been, and making better and better games as I go.
--daviD Ward
This week I'd like to talk more about my background in computer science, and maybe some up-and-coming programmers may get some good pointers out of it. First off, I'm just finishing my sophomore year at Michigan State University. This past year I took the senior level graphics programming course (hence the ray tracing comment in the title), as well as the junior level algorithms course. But I wasn't always in such courses. I wrote my first line of code,
print "Hello World"
in Python version 2.6 in the fall of 2010. For those of you who haven't taken calculus yet, I'll break down the math for you: I've only been programming for slightly over 1 and 1/2 years. And while I admit to be no programming genius, I've accomplished more in this one and a half years than many people do in all four of their college education, and not just in the class room. And don't take this the wrong way, I'm not proclaiming myself to be some super genius who can fly through the curriculum like its nothing, I struggled all the way through just as everyone else. I will say that I worked incredibly hard, and made sure I got myself out there everyway I could (even including starting this blog). I will also say I made my class schedule pretty cleverly, making sure I was in the courses I needed to be as to not waste time with a bunch of classes I didn't care about.
I guess I should start from before college. I was homeschooled first through 12th grade, which gave me virtually no computer classes or programming experience. Not all homeschoolers are in such a situation, many do have chances to code. I, sadly, was not one. I always wondered what would have happened if I started coding years back, but sports and other highschool activities took priority. I did do two things right though, I took advanced math at Lansing Community College and always kept designing games, even though I had no knowledge of how to make them. I've pretty much been designing games since I was four years old, but only seriously thought of going into them as a career at about age 14. I had no desire to ever become and engineer, but as I researched more and more into the games industry, I realized how difficult it was to go into the industry as a designer who could do nothing else. By difficult, I mean impossible. Even students with resumes vastly more impressive than mine are often never make it into the industry. Around that summer when I was 14, I took a game design camp at Michigan State offered by the group Spartasoft, a group I would become far more familiar with years later. I was pretty much set on MSU at that point, especially being so close to home. But lets fast-forward to school.
College, year one.
I had decided to major in Computer Science Engineering, hoping to break into the industry as a programmer since I was good at math, and couldn't draw a stick figure to save my sorry life. It was in this first week I heard about Spartasoft, and was eager to join. I began attending meetings and making friends in that group, and tried to do a game jam or two (in Spartasoft, we have what are called game james, where we get together and make a game from start to finish as best we can in 48 hours), although I was pretty useless in them. I learned alot through meetings though, and was introduced to the Unity game engine, although again, I was near usless at using it. I took my first programming course which, as mentioned before, taught programming and basic CS concepts through the Python programming language. I loved projects, I loved the professors and the material, and because I enjoyed it so much I was also very good at it. The next semester I decided I wanted to take as many CSE courses as I could, these university required ones were far too boring and useless, I thought. As a result of this mindset, I currently still have very few of my university requirements met. While writing and researching have their place and are very useful, taking more CSE courses sooner gave me more time to refine my skills longer while in school and work at better jobs faster.
The next semester I took C++ and data types, as well as discrete mathematics. C++ was an incredibly fun course, and taught me a "real" programming language as well some usefull algorithms (linked lists, some sorting, etc.). Suddenly I wasn't as useless in game jams, which we primarily use C# for. I was still lacking in my skills with Unity, a thing I would shortly rectify. I also got a decent job working at one of the technical helpdesks at MSU. This gave me a decent amount of technical experience I could put on my resume, and also was a pretty cool job. I got this job by pretty much applying everywhere I possible could, even if I seemed unqualified. From this I learned never to say "They probably won't even look at me." and not apply. They might not, but what if they do? Better than flipping burgers if you can help it (if not, jobs a job, and no job is easy to come by these days).
Over the summer, I was bound and determined to learn Unity. I set out to make a number of simple games, and while I didn't finish any of them, I learned alot and gained a bit of confidence in making future games. I also kept my helpdesk job, and finished up what was left of my calc requirements. I also saught out a better job, and once again applied everywhere without any thought of mopy "they won't look at me, because I'm still a sophomore" thoughts. I was also eager to prove how much I had learned, and take a job where I could actually program. I contacted my old Python professor who thankfully remembered me, and was able to get a job as a teaching assistant for him that fall. I was also able to secure an internship at Techsmith Corporation for the following spring semester, which I am now finishing up. The interview was pretty difficult for that, and it involved whiteboarding, which I had never done before. My advice for first time whiteboarders would be to bascally find some problems online, and work them out in front of your friend while they watch. Also, always say what you're thinking while to whiteboard (assuming its in person). They really don't expect you to answer all the problems perfectly, but are looking for your thought process. But I could ramble on about interviwing forever, maybe a future article on the subject.
Fall of Sophomore year.
Well this fall I took CSE 335, software design. This was the hardest class I've ever taken. It was also the funnest class, as well as the class I learned the most in. While I spend 20+ hours a week on this class alone, and barely scathed through my other classes because of it, it was worth it. I don't know about the spring semester of the class, I've heard mixed things. But I can attest to the greatness of the fall version of this class with Dr. Owen. To any MSU CSE students, take this class in the fall! And one year after taking the class, I found myself as a teaching assistant for the Python programming class. It was wierd, I admit, remembering all the projects I had done not so long ago compared to where I was now, but I enjoyed it. Hopefully I taught some people some things too! More importantly, I was useful, and even team lead, in game jams. I made some decent games that are now online (which I will put on my web site, which I will make soon..). But game jam games weren't enough, I wanted more game dev. I made an announcement at Spartasoft that I was starting a game design team. Many showed interest in joining, and over fall we designed a game that barely ever got started. We overscoped, but in the process I learned much about leading a team and established workflow patterns, and made some good friends in the process. In the fall I was also able to take IPhone game design, which, while being new course with many kinks to be worked out, gave me a pretty decent understanding of IOS games and Objective C. Being so young in all these advanced courses started becoming apparent though, as my classmates began inviting me to the bars with them, only to realize that not only could I not go, but was not going to be able to go in the near future.
Spring.
Spring saw the return of my game team, which got far more awesome and productive. We named ourselves Slightly Serious Games, and I took the role of AI programmer and team lead. I also assigned more definitive roles for all of the team. We should be making a website soon and putting our current work up. We would someday like to start ourselves as a startup company, but we'll see how that goes. My next article may be more about my team and our challenges, so I won't go too deeply in depth with that now. I also took the senior level graphics course and loved it, especially since it was taught by Dr. Owen again. I hope to take more classes with him. This semester also saw me in my first internship at Techsmith, a job I thoroughly enjoyed. I learned alot, especially about using C# (current favorite language). I also had alot of opportunity to practice my web and server skills, as well as more Objective C and some Android dev.
My contacts through Spartasoft have helped me secure my first real game design job this year for the MSU GEL lab. I will be making games for various contractors. I was also elected into Spartsoft's eboard as secretary, a chance to give back to new game designers to help them enjoy school and learn as much as I have. I'm also taking operating systems over summer, and taking the grad school computer graphics class in the fall. I hope to continue working with Slightly Sirius over fall, and plan on taking the CSE Capstone this spring as well as more CSE grad school classes next fall. I hope this article showed that with alot of work and some decent planning, how far someone can go in a year. I hope to keep accelerating at the same pace I have been, and making better and better games as I go.
--daviD Ward
Subscribe to:
Comments (Atom)