Advertisement

Producing intelligence on meters?

Started by November 05, 2005 01:57 PM
22 comments, last by Steadtler 19 years ago
Good idea, thanks.

For the most part, everything is working fine. Although the time is extremely fast, every 15 seconds, a new message pops up. The NPC says the following...

I'm eating now.
I'm eating now.
I'm taking a shower now.
I'm watching TV.
I'm eating now.
I'm taking a shower now.
I'm watching TV.
.
.
.

Okay, so that's improvement with meters, I guess. Every frame, or after every input in a console window, I don't want him/her to be off to another task. What's the next step?
You want to slow down the rate at which the NPC changes task?
Advertisement
This does it pretty much:

	for (;;)	{		int start_time = System::Environment::TickCount; 		for (int i = 0; i < 3; i++) 			N.update(); 		while ((System::Environment::TickCount - start_time) < 3);	} 


Each update is around 3 seconds. In games, they usually do one task for 1-5 minutes, though, semitaniously. So I'm confused on how to extend this.
Mistake - see post below
Yea you really don't want delays in there at all. You want to update each NPC as fast as possible and the update decides whether they have finished the task. To do this the NPC has to keep track of what task they are doing.

For example you can use two thresholds depending on whether the NPC is eating or not:

update(){  if (task==EATING)  {    hunger-=0.4; //im eating so my hunger is decreasing quite quickly    if (NPC.hunger < 5)  //if I am not very hungry..      task=NONE; //..then I stop eating  }  else  {    hunger+=0.1; //im not eating so my hunger is growing slowly    if (NPC.hunger > 95)  //if I get too hungry then..      task=EATING; //..I start eating  }}


This behaviour will mean the NPC will slowly get hungry, when their hunger reaches a certain point they will start eating. As they eat their hunger will slowly decrease. They will stop eating when their hunger drops to a certain level, and the cycle starts again.

Similarly with showering. If the NPC is not showering it gets dirty very slowly, and when it reaches a certain level of dirty the NPC sets its task to "showering". While showering the NPC's dirtiness decreases rapidly. Once it goes below a certain level the NPC stops showering.

You will find that you get complex conflicts happening. For example what does the NPC do if he gets hungry in the middle of showering? Does he stop showering and start eating? Or does he wait until he's finished showering? At that point you have to introduce priorities. This could get very complicated.

Anyway good luck for now, I have to sleep (my tiredness meter just reached 99 and it's 3:15am)
haha thanks for the help :) That totally makes sense to me now. I don't know if there should be a while(i'm eating) so it doesn't trail off into taking a shower 1 second later, though. Thoughts?

[Edited by - dxFoo on November 5, 2005 9:19:47 PM]
Advertisement
Here's my final code for the night. If you can please compile this and tell me what you think, it can only help this get better. One thing I'd like to improve on is conditions in NPC::update(). If TASK == SLEEPING && Time > 5pm, TASK = NONE. etc. Thanks for looking at this...

Also, while looking at this code, I find that it's more behavioral than intelligent. But that's often obvious in noob AI code I guess.

#include <iostream>#include <string>#include <cstdlib>#include <ctime>using namespace std;class Utilities{public:	int randNum(int min, int max)	{		return (((double) rand() / (double) RAND_MAX) * max + min);	}} util;class NPC{private:	std::string name;	// NPC's name	int age;			// NPC's age	struct Memory	{		double swordSkill;		double arrowsShot;	};	struct Needs	{		double dirty;		double hunger; 		double entertainment; 		double tired;	};public:	Memory memory;	// The NPC's memory box.	Needs needs;	// The NPC's daily needs.	enum Task	{		NONE, EAT, SLEEP, SHOWERING	} task; // current task	// NPC Constructor	NPC(std::string name, int age)	{		this->name = name;		this->age = age;		// Clear memory like a newborn baby!		memory.arrowsShot = 0;		memory.swordSkill = 0;		// Initialize needs with random starting values.		needs.dirty = util.randNum(1, 100);		needs.entertainment = util.randNum(1, 100);		needs.hunger = util.randNum(1, 100);				needs.tired = util.randNum(1, 100);	}	// Show current NPC stats.	void showStats()	{ 		cout << "\nName: " << name << endl;		cout << "Age:  " << age  << endl;		cout << "\nMemory:\n-------" << endl;		cout << "Arrows Shot:   " << memory.arrowsShot << endl;		cout << "Sword Skill:   " << memory.swordSkill << endl;		cout << "\nNeeds:\n------" << endl;		cout << "Entertainment: " << needs.entertainment << "%" << endl;		cout << "Hunger:        " << needs.hunger << "%" << endl;		cout << "Tired:         " << needs.tired << "%" << endl;		cout << "Dirty:         " << needs.dirty << "%" << endl;	} 	void update()	{		// Sleep		if (task == SLEEP)		{			needs.tired -= 0.4;  // Sleep reduces tiredness.			cout << "Sleeping..." << endl;	// Display current status.			if (needs.tired < 5) 				task = NONE; 		} 		else		{			needs.tired += 0.1;			cout << "Awake" << endl;	// Display current status.			if (needs.tired > 95) 				task = SLEEP; 		}		// Shower		if (task == SHOWERING)		{			needs.dirty -= 0.4;  // Sleep reduces tiredness.			cout << "Showering..." << endl;	// Display current status.			if (needs.dirty < 5) 				task = NONE; 		} 		else		{			needs.dirty += 0.1;			// Gets dirtier as time continues.			cout << "Clean" << endl;	// Display current status.			if (needs.dirty > 95) 				task = SHOWERING; 		}	}	};int main(){	srand((unsigned) time(NULL));	// seed time	NPC N1("Kylena", 18); 	N1.showStats();	N1.task = NPC::SLEEP;	for (int i = 0; i < 5000; i++) 		N1.update(); 	system("pause");	return 0;}
Also toss in randomness so each NPC doesn't stop showering at the same point. Some can tolerate being dirtier then others (thus get out of the shower sooner) while others need to shower longer. You also don't need to update an NPC every frame. It's like real life, every few seconds should be more then fine, plus saves you CPU cycles.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

The NPC now has an idea of what task it is doing, but it is purely reactive. You are right that it's more behavoral than intelligent, but the next step will introduce basic intelligence.

The main problem at the moment is the NPC cannot handle having more than one task to do. For example if the NPC is both tired and dirty it will enter a loop switching between showering and sleeping. What an intelligent NPC should do is know which tasks need to be done, and decide which task to do first.

So what your NPC needs now is a decision making process. The NPC should store a list of tasks that need to be done, and choose which one to carry out first.

For example when the NPC is tired he stores "sleep" in his tasks to-do list. If he is dirty he stores "shower" in the list too. If the NPC isn't doing anything, and there are multiple tasks to do then the NPC decides which task from the to-do list to do first, and carries it through until complete, at which point the task is removed from the list, and then the NPC can work out the next task to do.

The decision making process can be based on quantifying each task based on how much the NPC reckons it needs to be done. For example:

need_to_sleep = tiredness * tiredness_weight;
need_to_eat = hunger * hunger_weight;

Then the NPC will decide to do the task with the highest need.

Different NPC's might have different weights based on their personality, and so they will make different decisions in the same situtation. For example if the average hunger_weight of NPC's is 1, then an NPC with a hunger_weight of 5 will tend to have a lower hunger threshold and will tend to treat eating as a priority over other tasks like sleeping.
>> "[Jeff Hawkins] teaches a new theory on how we can't build intelligent machines until we figure out how the brain works"

I've also read Hawkins's book, and although it was very optimistic (and you could even say inspiring), unfortunately in my opinion it did not portray either a NEW theory or a FRAMEWORK for building intelligent machines. As most brain theories, in fact, his descriptions are so vague that they are practically unimplementable (for instance, along the lines of "The brain continually makes predictions."). His tenets of brain theory are actually not new at all, but they are decently accepted in the cognitive psychology community (even as far back as Grossberg's neural network papers in the 1970s, where he states Hawkins' prediction hypothesis almost exactly). If anything, he's communicating these ideas to a wider public.

Further, his ideas do not seem to constitute a framework for studying the brain. Many appealing frameworks have been proposed, all saying that theirs is correct -- Godel Escher Bach provides a logical framework, Rumelhart proposed one based on neural networks, and now Hawkins is proposing one even more vague than the latter two. His "biological explanations" are rather weak (relying on purely anatomical distinctions), although in his credit he attempts to make "predictions" of future experimental studies which would bolster his theory. In short, it's a good try, but it just doesn't cut it as a framework.
h20, member of WFG 0 A.D.

This topic is closed to new replies.

Advertisement