ID:120721
 
In case you missed them, be sure to check out programming tips #1, #2, and #3

When you first start programming, the problem you're trying to solve is "how do I write code that'll do ______?". Initially you're happy just to get something working, who cares what the code looks like. But when you try to develop a complete game this indifference can become a problem. As your code gets messier and messier, the project becomes harder to work on - you're more likely to write code that has bugs and they become harder to track down and fix. Eventually it'll get to the point where you're wasting a lot of time, don't feel productive, and are more likely to stop working on the project.

As a more experienced programmer, instead of asking "how do I do ______?", you should start asking "what's the best way to do ______?". In this post we'll look at what benefits you can get from using datums.


In DM, the /datum type is the most basic object type. You can create custom datum types just like you can define custom sub-types of /mob or /turf. Their purpose might seem mysterious but really it's the same. Consider how you might implement a simple combat system with different kinds of weapons:

obj
weapon
proc
attack()

sword
attack()
// sword attack

shotgun
attack()
// shotgun attack

laser
attack()
// laser attack

mob
var
obj/weapon/weapon

proc
attack()
weapon.attack()

By making the player's weapon an object, you can easily switch which attack is performed by the mob's attack() proc by just switching their weapon var. Any type of mob can use any type of weapon. To avoid using objects you could do something like this:

mob
proc
attack()
// default attack

sword_user
attack()
// sword attack

shotgun_user
attack()
// shotgun attack

laser_user
attack()
// laser attack

But you don't want the mob's attack to depend on their type, you'll probably be using mob types for something else (ex: character classes, enemy types, etc.). The mob's type and weapon can vary independently. Overriding mob procs to create different attacks doesn't allow for this.

In this example weapons are a kind of /obj because you might have players be able to pick up and drop weapons. You want them to be objects that can be placed on the map. You can use datums to create a similar effect - functionality that is controlled by an object that's separate from the mob and can easily be changed - but for things that you wouldn't need to place on the map.

For example, you could put a mob's AI in a datum:

AI
proc
decide()
plan()
act()

mob
var
AI/ai

proc
go()
ai.decide()
ai.plan()
ai.act()

The AI datum contains the logic for how mobs make decisions, plan actions, and execute those actions. You can create different child types of /AI to create different behaviors or difficulty settings. One type of /AI object can more thoroughly analyze the situation and make better decisions, while a dumber /AI object might pick actions at random.

AI
// for each type implement the three procs (decide, plan,
// and act) to create varying levels of intelligence
smart
dumb
average

// somewhere in your code:
var/mob/m = new /mob/enemy/skeleton/warlock()

if(game_difficulty == HARD)
m.ai = new /AI/smart()
else
m.ai = new /AI/average()

To do this using only procs that belong to the mob, you'd have to do something like this:

mob
proc
smart_decide()
smart_plan()
smart_act()
dumb_decide()
dumb_plan()
dumb_act()
average_decide()
average_plan()
average_act()

Then you'd need if statements or something else to decide which set of procs is called.

Putting AI routines in a datum lets you use inheritance to extend AI behavior. For example:

AI
simple
var
range = 4

decide()
// pick a target
for(var/mob/m in oview(range, owner))
if(m.dead) continue

target = m
break

bigger_range
range = 7

biggest_range
range = 10

Because the simple AI routine uses the range var, you can create child types that have different values for the range var so you can easily customize and extend the same, simple behavior. You don't have to limit yourself to just using inheritance, you can do something like this:

AI
smart
dumb

all_or_nothing
var
AI/smart/smart = new()
AI/dumb/dumb = new()

decide()
if(prob(50))
smart.decide()
else
dumb.decide()

The "all or nothing" AI type doesn't inherit from the smart or dumb AI, but it does use them to give the AI a 50% chance of doing something smart and a 50% chance of doing something dumb. If you relied on inheritance you wouldn't be able to create something like this. With inheritance you can only call the parent proc or not - you can only make use of one other AI type (the parent type). In this example you're making use of two other AI types.


Having behavior that can vary is an indication you should use objects. It's really about organization. This isn't the only way to do things, it's just easier to manage. Look through your own projects and see what might work better as a datum.

This article doesn't describe all of the ways you can use objects to organize your code. Play around with these ideas and see what else you come up with. It might seem difficult at first and cleaning up existing projects to be more organized can take a while. But, once you get in the habit, writing clean, organized code will come much more easily.
You have an error in your 6th example.

for(var/mob/m in oview(range, src))

Since src in this case is a datum, oview() will likely crash and cause a runtime error.


Anyhow...

I really dislike the idea of putting AI routines in a datum.

It seems disorganized and inconvenient to have defined behaviors separated from the mob's attributes.

Programming unique behavior for unique mobs (example being a boss) would require the developer to constantly reference two separate segments of code: The boss's class definitions and the AI datum for that boss. These could also end up being in separate files, depending on how the developer likes to organize his code. Referencing different segments of code in separate files can be a pretty big headache at times, and would slow down development pretty significantly without really yielding a significant advantage in terms of robustness.

Your all or nothing example does make a good case for your implementation of AI datums, but ultimately it's not difficult to reproduce in a traditional state machine that isn't separated from the mob.

If these AI datums managed the behaviors of a group of mobs, like say a group of ants, then it would make much more sense to use them.

[EDIT]: Your solution would be a very robust one if defined behaviors were reused in multiple unrelated types of mobs. I suppose it just comes down to the designs for the mobs that will inhabit the game.
Just a piece of advice: you really ought to consider giving your blog posts better titles. Having a descriptive and eye catching title is important, both for initial readership and future search results.

It may seem like a trivial thing, but when it comes to drawing in readers the title of a post like this is almost as important as the content.
D4RK3 54B3R wrote:
Your all or nothing example does make a good case for your implementation of AI datums, but ultimately it's not difficult to reproduce in a traditional state machine that isn't separated from the mob.

The article shows the benefits you can get from using datums to separate functionality from the mob types. If you don't need those benefits you obviously don't need to do things that way (the previous article is about that very topic), but you can't say "that's a bad way to do things because people might not always need to do things that way". The example has to assume that the benefit is desirable.

I thought this made it pretty clear: "Having behavior that can vary is an indication you should use objects. It's really about organization. This isn't the only way to do things, it's just easier to manage."

SilkWizard wrote:
Just a piece of advice: you really ought to consider giving your blog posts better titles. Having a descriptive and eye catching title is important, both for initial readership and future search results.

No matter what, the BYOND website does a bad job of helping people find things. To find something you often have to know it exists. Without some type of rating system to help better articles/resources float to the top of search results, there's a slim chance anyone will read this article after it drops off the front page.

I'd also like to ultimately have a larger tutorial or article that links to these smaller ones.
Forum_account wrote:
No matter what, the BYOND website does a bad job of helping people find things. To find something you often have to know it exists. Without some type of rating system to help better articles/resources float to the top of search results, there's a slim chance anyone will read this article after it drops off the front page.

Some things are inside of your control, others aren't. That the nature of systems like this. All that you can do is try to make what you're putting out there as good as it can be, and by putting some thought into your titles you'll get a heck of a lot more clicks while you're featured on the front page, listed in the recent comments section, or when users use the search to find how-to articles in the future.
I wouldn't hurt to ask Tom about moving this over to the main BYOND blog.
The real solution is to display content that's relevant to developers inside the Dream Maker program. Anything based on the website will have limited exposure because the website isn't widely used. I've got the developer page covered, it just seems like most people don't actively look for content related to DM development.

I did change the titles of these. I want it to be clear that they're a set, but having better titles will help to keep it organized.
Thank you greatly for these articles; this one being my favorite. I had some problems with datums before and others helped me get started, but this also explained in a very easy to understand way.
I've said it once, and I'll say it again, oh you sly bugger ;)


The last two articles wouldn't even exist without me! I demand credit!
El Wookie wrote:
I've said it once, and I'll say it again, oh you sly bugger ;)


The last two articles wouldn't even exist without me! I demand credit!

I try to base a lot of the things I do on what I see other people doing. If datums weren't a topic of interest I wouldn't have written this. Obviously this article comes more directly from a reply of mine to a forum post of yours, but really everyone deserves a little credit =)
Mate. You're one cool kangaroo! :)
I have two more of these articles in the works, but if anyone has ideas for additional topics I could cover I'd like to hear.

One of the articles is about organization - how to organize files, how to name things, etc. The other article is sort of about organization too, but more about code and procs - how to split code between procs, how to go about implementing the features your game will need.

I also have a rough idea for an article about creating maps, but I need more ideas for that.
Sounds familiar too! =P

I'd love an article covering some proper mouse control, I've searched for one multiple times but never found one. :(
Forum_account wrote:
I have two more of these articles in the works, but if anyone has ideas for additional topics I could cover I'd like to hear.

Turning a rough demo into an actual game. A lot of people make neat little sandboxes but they have a hard time adding the meta-game stuff to turn it into a full game.

The topic could probably broken down into a few subgroups:
- How should you have players/teams rack up points?
- How do you make a server run itself without host intervention?
- What to do with people logging in before, during, or when a match is ending.
- How do you separate single player from multiplayer?
SuperAntx wrote:
Forum_account wrote:
I have two more of these articles in the works, but if anyone has ideas for additional topics I could cover I'd like to hear.

Turning a rough demo into an actual game. A lot of people make neat little sandboxes but they have a hard time adding the meta-game stuff to turn it into a full game.

The topic could probably broken down into a few subgroups:
- How should you have players/teams rack up points?
- How do you make a server run itself without host intervention?
- What to do with people logging in before, during, or when a match is ending.
- How do you separate single player from multiplayer?

I think that the organization articles (one of them at least) is closely related to that. It takes a lot of details to turn a demo into a game so you can get away with being disorganized if you leave those details out.

I'll probably split that article into two parts and make one more focused on games - some of these articles are more about general programming than game development.

El Wookie wrote:
I'd love an article covering some proper mouse control, I've searched for one multiple times but never found one. :(

I'm not entirely sure what you mean, I tend to avoid using the mouse in games so I'm not too sure what you'd need or want to do with the mouse. I should be able to fit this into an article, it also relates to the code organization article.