NPCs can be just 1 frame with a person on it that does nothing other than to stand and look amusing on the screen. Or with a little bit of programming magic, an NPC can be fully animated from all angles, can walk and interact, and in a sense seem more like a real person. The difference is the static, simplistic, (probably boring) NPC types from my game, Dark Ages I, to the complex and intricate NPCs of the later Ultima games who all walk, talk, follow meal and sleeping agendas, and even manipulate their environment to their own personal needs!
I don't know how Origin manages such detailed NPCs, but at least I can get everyone started on making complex NPCs. Under my method, each NPC has simple number variables that control where and when he can move and what picture to use. All the variables for all the NPCs in the current map are stored in one array using the TYPE command. For those who don't know how to use it, I'll give a brief explanation.
Imagine you have made an NPC and wish to store his map coordinates and name. You may do so using these variables:
x1 = 10 y1 = 37 name1$ = "Rhoeyce"Now let's say you wanted more than one NPC for the map, so you create 3 more variables:
x2 = 45 y2 = 7 name2$ = "Hans-Dirk"What if you want more than 2 NPCs? Suddenly you are swamped with variables! Well all that can be reduced to just one array with the TYPE command:
TYPE NPC x as integer y as integer name as string*15 END TYPE DIM SHARED People(1 to 10) AS NPCWith that simple little blurb of code, you can now store 10 NPCs in the array People. By changing the number from 1 to 10 to 1 to whatever, you can have as many NPCs as you want in the map. You can store the individual aspects of data in this manner:
People.x(1) = 10 People.y(1) = 37 People.name(1) = "Rhoeyce" People.x(2) = 45 People.y(2) = 7 People.name(2) = "Hans-Dirk"You access the information the same way, such as
newx = People.x(2) PRINT People.name(1) etc.There, TYPEs in a nutshell. Back to NPCs. What should be stored in the TYPE? I store information such as name, x and y boundaries, picture, and temporary variables such as whether or not the person is currently moving. It could look something like this:
TYPE NPC X as integer Y as integer MaxX as integer MaxY as integer MinX as integer MinY as integer Name as string*12 PictureSet as integer Frame as integer Direction as integer InMotion as integer END TYPEIt probably seems like a lot; well, it is. But the results are beautiful. By now creating a simple loop, you can run through your entire NPC array and determine whether or not they move and if they do, what direction, how long, and what picture to use. I'll try to make a pseudo-loop so you can see how it works.
First, check to see if the NPC is already in motion (InMotion variable).
If yes, then move it based on Direction, and show it's picture based on PictureSet, Direction, and Frame.
If no, then randomly select whether or not it wants to move with a random number generator.
If it was not moving and it randomly generated that it would move, have another random generator select a direction and have it stored in Direction. Then check the current X and Y coordinates. Let's say that you randomly generated a 1 for direction, which you make "up" or "north". You would now check Y-1 to make sure it was not less than MinY. If it IS less, you have to randomly select a new direction. If it is ok, that means the NPC can move north. Change the InMotion variable so that the next time the NPC loop is run, the NPC will continue to move in this direction.
That's it, run through the loop for every NPC you have on the map and it's done. Simple, isn't it? Anyway, let me explain some of the variables barely mentioned above. The first is PictureSet. If you're going to use moving NPCs, you need to have a set of frames showing movement. I like using 4 frames for each direction, for a total of 16 frames per PictureSet. Since I store all the NPC frames in one array, I need to specify where in the array the set is located. Therefore, if I have 3 NPC picture sets, I store them in an array such as this: NPCPics(1 to 48) and then qualify which picture set I am using with the numbers 1, 17, and 33.
Now that I have each NPC locked into a set of pictures, I need to find out which frame to use in the set. I can do that with Direction. Note that before it was used to determine where the NPC will move, but since the frame you will see depends on the direction the NPC is moving, it MUST also be used to determine which frame. Furthermore, the Frame variable must be used to determine which of the 4 pics per direction will be displayed. Every time I run through the loop, I have
Frame = Frame + 1 If Frame > 4 then Frame = 1That way it cycles through the pictures for the direction. Now, let's say for example that the NPC is the second picture set (PictureSet = 17), he's moving south (Direction = 3), how would you determine the right picture?
Picture = NPCPics (PictureSet + (Direction * 4) + Frame)That's it and the animation is made by cycling through the frames as shown a few lines above. We'll say we're currently at Frame = 1, so the picture drawn would be 17+12+1 or 30. The next time the loop is run, Frame will equal Frame + 1 or 2, so the new picture would be 17+12+2 or 31. The loop continues and once Frame equals 5, the code will change it back to 1 and the cycle will start over giving that look of fluid animation.
And finally, what about the InMotion variable? What I do, since I work with pixel scrolling, is I set this number to the number of pixels per tile. If I use 32x32 pixels per tile, I set InMotion to 32. Then each time I run through the loop, I subtract 1 from InMotion. When it hits 0, the NPC stops moving. That way the NPC only moves 1 tile at a time before having to go through the random number generator to determine if it wants to move again. Of course, you can set this number however you want based on how near or far you want the NPC to move.
This will give you in my opinion a nice way to manage a bunch of NPCs moving at the same time. But it's still not finished. What about collisions? After all you can't have NPCs walking through walls. This part is simple. Up above where I showed how to check the direction to see if it is beyond the Max or Min coordinates, you could also check the collision. Simple check X-1 or X+1 or Y-1 or Y+1 for a solid tile. If yes, have it choose a new direction. You can do a similar check to make sure the NPC doesn't walk into another NPC.
That's it for my tutorial. Perhaps sometime I'll add an actual demo program (don't hold me to it!!) In any case, this still doesn't explain how Origin manages personal agendas, sleep schedules, etc. Nor do I claim this to be the best or only way, just the way I decided to do it. In any case, good luck with your NPCs!