Hey, I'm just some kid who makes games for fun :)
SHello, and welcome back. I'm here again for another little (or rather large) blog entry. This one, like the last one, is also related to Half-Life 2 modding, specifically NPCs.
Now, before I go on I'd like to say something. I realize it has been months since I've posted anything here (I wonder if anybody reads this?). I haven't been modding the entire time. In fact, I basically just got back into it again (now that I understand C++ more thoroughly).
This time around I went ahead and followed the basic entity tutorials on the Valve Developer Community (Very good resource for all Half-Life 2 modding) again, to get myself back into gear with Half-Life's coding ways.
After I figured those out (didn't take long at all this time c:), I went ahead and started on another little "project": Make an NPC that follows the player around. Sounds simple right? Well, it actually is pretty simple, once you get the hang of how NPCs work in Half-Life 2 (In HL2 NPCs include zombies, combine, headcrabs, citizens, etc..).
First up was to figure out how exactly do NPCs work in HL2. I would say this was the biggest hurdle of all. I was pretty intimidated when I looked at how VALVe made the zombie, combine and other NPCs. So mcuh code! I didn't even know where to start at all! So what did I do? Went back to ye good ol' VDC!And sure enough, they bascially had a full tutorial on how to code your very own NPC (You can find it here).
Although at the time, when I read through that, I basically understoon nothing. I was still pretty confused on how exactly I would make an NPC work. So I started experimenting and looking around the files that came with the SDK, and I found a file called "monster_dummy.cpp" (For those who don't know, cpp files are C++ files). VALVe was nice enough to provide some explination at the top on what exactly that file was.
Turns out that was an NPC template! How convinient. All I needed to do was flesh it out.
The first thing I did was make my own cpp file for my new npc (I called it npc_box), copy and pasted the monster_dummy code into the new CPP file, changed all the class names to my own class name, etc etc...
Saved, compiled, started the mod, loaded up a map, spawned one of the new NPCs, and lo' and behold, it worked! Granted all it did was turn to look at you as soon as you walked up to it (and turned back a second later). But it still worked, and that's what matters right? .. Of course.. *sigh*
Anyways, now it was time to try and understand how NPCs worked. Well, needless to say I was pretty overwhelmed with all the NPC gibberish (schedules, tasks, conditions?? What is all this?!), I decided that something so simple as an entity that would follow the player couldn't be THAT hard right? Why would I need a complicated NPC?
So I ditched the NPC idea and went back to the model entity (which I created using this tutorial), and started tinkering with how it moved, behaved etc..
Well it basically got me nowhere at all. So I headed over to the Steam forums, more specifically the Source Coding forum, and made my topic asking for help (You can read through that topic right here), and asked for help. Long story short, they basically told me "you'll need NPCs to do that". So I was k', I guess I really am going to have to learn how NPCs worked.
Now, I told them how I thought an NPC worked. Here's what I said:
The appropriate schedule, which is a list of tasks, is executed. It will continue to execute until it's either interrupted (by a defined interruption) or until it ends.. then it picks something else to do..
So.. am I right?
And this guy told me:
Alrighty! So I at least had SOME idea as to how this all worked. Now, I'll say right now that I was basically summarizing what the VDC told me (the wiki.. remember?). This basically just told me "I'm right, stop doubting myself". (:
Anyways, so then it was time to really figure out how it all worked, code-wise. I followed this tutorial, read it all twice (or maybe three.. twelve times c:) until I had a pretty solid idea of how to code my NPC.
Another long-story short, I figured out how to get the NPC to work with all of it's schedules, tasks, conditions, etc.. Surprisingly, it really isn't that hard at all! It just seemed very confusing at first, but once I got the grasp of it, I was basically an exper- Ok, I'm still pretty noobish when it comes to this, but hey, give me some credit! ;)
Anyways! The fact that you are reading this makes me happy. Why don't you comment, and TELL me that you're reading this? ;)
Ok, ok, back on topic. So now that I knew how the NPC worked (sort-of), I then needed to give the NPC a schedule that said "follow the player". Well, technically the schedule says "turn to face the player, then find a path to the player, then follow that path", but that's for another time.
Now, at this point the NPC would basically just sit there and do absolutley nothing. This pretty much bothered me, since I specifially said in the schedule he should find a path to the player, then follow it.
Now, an odd quirk. Whenever I spawned an NPC, he would just sit there, but there would also be sparks coming from the top of his head. I had absolutley NO idea what that meant, and since there were no console messages I was REALLY stumped.. back to the Source Coding on the Steam forums for me!
Sormii was kind enough to post one of his own problems (and the solution) in my topic, so went and read through the topic. Now that I look back at it, it really didn't help me THAT much, it basically just told me that I KNOW that the problem is somewhere within the schedule, not making the NPC know that that's the schedule it should follow.
Basically the problem was somewhere within all the tasks within the schedule. The NPC knew that it should follow the schedule, but it didn't know HOW! Ok, two steps forward, one step back. Great.
Ok, so I said "screw this" and I went to bed. Next morning, I wake up, check the topic and voila! Sormii has come to my aid once more, with this very simple piece of code:
It's funny, really. If you ever did read my other blog post (the one talking about the swimming engines), you'll know that I spent at least 3 hours (or an hour?) looking for one line of code. Granted, I wasn't looking for one line of code to fix my problem, I was looking for a solution in general.
But it seemed that this ONE piece of code solved all my problems! So, SUPER SPECIAL THANKS TO SORMII! (Along with Winston, and everybody else who helped me in my topic c:)
Ok, so now the NPC was "jumpy". Here's what happened. The NPC would turn to face you (like it should), then it would start towards you in a "lumpy" fasion. Think Zombie on crack. It would step forward, then stop for half a millisecond and begin again. It looked like it was limping. However, it did eventually make it to me, so I at least knew that it was finding a path to me and moving towards me. At least I had something going for me ;p
Well that was a pretty simple fix really. My schedule said this:
Task 1: Face player
Task 2: Find path to player
Task 3: Walk path
The problem? It wouldn't wait until it was at the end of the path to repeat the tasks. It had to continually stop, face player, find the path again, walk the path. This is not only not efficient, it gave me odd results.
Of course, there was a simple fix, add another task.
Task 4: Wait until all movement is complete to continue tasks
Well, that fixed that, didn't it? Now my NPC worked just as it should!
Although this is kind of off topic, I did some more experimenting with the NPC. I used some conditions to check wheter or not the NPC was within 128 units of the player. If it was farther, go through the process of getting to the player. Otherwise stand there. I won't bore you with that (plus it was relativly simple ;p).
And that basically concludes my adventures on finding out how to make a simple NPC, and how to get it to follow the player on Half-Life 2.
Who knows, one day I may write a tutorial on this! Actually, that isn't such a bad idea.. and it would include all code and stuff.. I know this blog post is not for those who are not very familiar with HL2 coding ;p
Until next time,