need advice implementing AI in game.
Hello again
I've been trying to get some AI working. I would like to know if you guys have any advice on where to go or things to avoid in the process.
I've though about stuff like "Objectives, task, actions, etc"
Any advice would be great .
thanks
I've been trying to get some AI working. I would like to know if you guys have any advice on where to go or things to avoid in the process.
I've though about stuff like "Objectives, task, actions, etc"
Any advice would be great .
thanks
The Mac Game Programming book has a lot of good AI info in it. Basic logic stuff, and a good deal on path finding (a little broken). The page below has a ton of good info also.
http://www.gameai.com/
http://www.gameai.com/
NYGhost Wrote:Hello again
I've been trying to get some AI working. I would like to know if you guys have any advice on where to go or things to avoid in the process.
I've though about stuff like "Objectives, task, actions, etc"
Any advice would be great .
thanks
well, do you want learning? no learning?
simple Finite State Machine or real time agent?
I'm currently taking an AI class right now at college. I really should post all my programs and homeworks as they come
For the ship and station AI in Oolite, I used an Objective-C class to implement simple finite state machines for decision making, but hardcoded simple behaviours, so that for example, a pirate's AI determines who and what to attack, but the direct flight control for the attack is handled by the code itself.
This can be thought of in terms of a simple animal analogy: the AI provides higher brain functions ('I'll eat that gazelle'), the coded behaviours the instincts ('legs: run, paws:snatch, jaws:bite').
The AI class is fairly simple, a page or two of code, which uses Apple property lists to store the state machine descriptions and leverages Objective-C's ability to turn strings into method selectors. I wrote it after reading, understanding and disliking the implementation of FSM's in Game Programming Gems (1).
If you like, I could post it here, it'd be easire than downloading all 30Mb of Oolite's source.
This can be thought of in terms of a simple animal analogy: the AI provides higher brain functions ('I'll eat that gazelle'), the coded behaviours the instincts ('legs: run, paws:snatch, jaws:bite').
The AI class is fairly simple, a page or two of code, which uses Apple property lists to store the state machine descriptions and leverages Objective-C's ability to turn strings into method selectors. I wrote it after reading, understanding and disliking the implementation of FSM's in Game Programming Gems (1).
If you like, I could post it here, it'd be easire than downloading all 30Mb of Oolite's source.
That may be helpful, post code please
On this one I would like flexible approach I've read a bit about state machine.
but know nothing about "real time agent".
but know nothing about "real time agent".
thank you!
http://sky289hawk1.dyndns.org:8080/Intel...Agents.ppt
lecture 2 in AI
lecture 2 in AI
There's a fair amount of debugging code in there, but here ya go. AI.h AI.m and a typical AI property list for Oolite.
AI.h
AI.m
missileAI.plist
AI.h
Code:
//
// AI.h
/*
*
* Oolite
*
* Created by Giles Williams on Sat Apr 03 2004.
* Copyright (c) 2004 for aegidian.org. All rights reserved.
*
Copyright (c) 2004, Giles C Williams
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
ï Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
ï Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
ï Neither the name of aegidian.org nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.
ï Neither this product nor its source code nor any products derived from them may
be offered for sale.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#import <Foundation/Foundation.h>
#import "entities.h"
#define AI_THINK_INTERVAL 0.125
@interface AI : NSObject {
ShipEntity *owner; // the object this is the AI for
NSString *owner_desc; // describes the object this is the AI for
NSDictionary *stateMachine;
NSString *currentState;
NSMutableArray *pendingMessages;
NSMutableArray *ai_stack;
NSLock *aiLock;
double nextThinkTime;
double thinkTimeInterval;
}
- (id) initWithStateMachine:(NSString *) smName andState:(NSString *) stateName;
- (void) setOwner:(ShipEntity *)ship;
- (void) preserveCurrentStateMachine;
- (void) restorePreviousStateMachine;
- (void) exitStateMachine;
- (void) setStateMachine:(NSString *) smName;
- (int) ai_stack_depth;
- (void) setState:(NSString *) stateName;
- (void) reactToMessage:(NSString *) message;
- (void) takeAction:(NSString *) action;
- (void) think;
- (void) message:(NSString *) ms;
- (void) setNextThinkTime:(double) ntt;
- (double) nextThinkTime;
- (void) setThinkTimeInterval:(double) tti;
- (double) thinkTimeInterval;
@endCode:
//
// AI.m
/*
*
* Oolite
*
* Created by Giles Williams on Sat Apr 03 2004.
* Copyright (c) 2004 for aegidian.org. All rights reserved.
*
Copyright (c) 2004, Giles C Williams
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
ï Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
ï Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
ï Neither the name of aegidian.org nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.
ï Neither this product nor its source code nor any products derived from them may
be offered for sale.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#import "AI.h"
#import "entities.h"
#import "ResourceManager.h"
@implementation AI
- (id) init
{
self = [super init];
//
ai_stack = [[NSMutableArray alloc] initWithCapacity:8];
//
pendingMessages = [[NSMutableArray alloc] initWithCapacity:16]; // alloc retains
//
nextThinkTime = 0.0;
//
aiLock = [[NSLock alloc] init];
//
thinkTimeInterval = AI_THINK_INTERVAL;
//
return self;
}
- (void) dealloc
{
if (owner_desc) [owner_desc release];
if (ai_stack) [ai_stack release];
if (stateMachine) [stateMachine release];
if (currentState) [currentState release];
if (pendingMessages) [pendingMessages release];
if (aiLock) [aiLock release];
[super dealloc];
}
- (id) initWithStateMachine:(NSString *) smName andState:(NSString *) stateName
{
self = [super init];
//
pendingMessages = [[NSMutableArray alloc] initWithCapacity:16]; // alloc retains
//
aiLock = [[NSLock alloc] init];
//
[self setStateMachine:smName];
//
currentState = [stateName retain];
//
return self;
}
- (void) setOwner:(ShipEntity *)ship
{
owner = ship; // now we assume this is retained elsewhere!
if (owner_desc) [owner_desc release];
owner_desc = [[NSString stringWithFormat:@"%@ %d", [owner name], [owner universal_id]] retain];
}
- (void) preserveCurrentStateMachine
{
NSMutableDictionary *pickledMachine = [NSMutableDictionary dictionaryWithCapacity:3];
[pickledMachine setObject:stateMachine forKey:@"stateMachine"];
[pickledMachine setObject:currentState forKey:@"currentState"];
[pickledMachine setObject:pendingMessages forKey:@"pendingMessages"];
if (!ai_stack)
ai_stack = [[NSMutableArray alloc] initWithCapacity:8];
[ai_stack insertObject:pickledMachine atIndex:0]; // PUSH
}
- (void) restorePreviousStateMachine
{
if (!ai_stack)
return;
if ([ai_stack count] < 1)
return;
NSMutableDictionary *pickledMachine = [ai_stack objectAtIndex:0];
//debug
//NSLog(@"restoring pickled ai :\n%@",[pickledMachine description]);
[aiLock lock];
if (stateMachine) [stateMachine release];
stateMachine = [[NSDictionary dictionaryWithDictionary:(NSDictionary *)[pickledMachine objectForKey:@"stateMachine"]] retain];
if (currentState) [currentState release];
currentState = [[NSString stringWithString:(NSString *)[pickledMachine objectForKey:@"currentState"]] retain];
if (pendingMessages) [pendingMessages release];
pendingMessages = [[NSMutableArray arrayWithArray:(NSArray *)[pickledMachine objectForKey:@"pendingMessages"]] retain]; // restore a MUTABLE array
//NSLog(@"debug restorePreviousStateMachine");
[aiLock unlock];
[ai_stack removeObjectAtIndex:0]; // POP
}
- (void) exitStateMachine
{
if ([ai_stack count] > 0)
{
if ((owner)&&([owner reportAImessages])) NSLog(@"Popping previous state machine for %@",self);
[self restorePreviousStateMachine];
[self reactToMessage:@"RESTARTED"];
}
}
- (void) setStateMachine:(NSString *) smName
{
//NSString *filepath;
//
//filepath = [[[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents"] stringByAppendingPathComponent:@"Resources"] stringByAppendingPathComponent:smName];
//
//NSLog(@"Loading AI data from %@",filepath);
//
[aiLock lock];
//
if (stateMachine)
{
[self preserveCurrentStateMachine];
[stateMachine release];
}
stateMachine = [[ResourceManager dictionaryFromFilesNamed:smName inFolder:@"AIs" andMerge:NO] retain];
//stateMachine = [[NSDictionary alloc] initWithContentsOfFile:filepath]; // alloc retains
//
[aiLock unlock];
//
[self setState:@"GLOBAL"];
//
//NSLog(@"AI Loaded:\n%@",[stateMachine description]);
//
// refresh name
//
if (owner_desc) [owner_desc release];
owner_desc = [[NSString stringWithFormat:@"%@ %d", [owner name], [owner universal_id]] retain];
}
- (int) ai_stack_depth
{
return [ai_stack count];
}
- (void) setState:(NSString *) stateName
{
if ([stateMachine objectForKey:stateName])
{
//if ((owner)&&([owner universal_id])&&([owner reportAImessages])) NSLog(@"AI for %@ enters state %@", owner_desc, stateName);
//
[self reactToMessage:@"EXIT"];
if (currentState) [currentState release];
currentState = [stateName retain];
[self reactToMessage:@"ENTER"];
}
}
- (void) reactToMessage:(NSString *) message
{
int i;
NSArray* actions;
NSDictionary* messagesForState;
if ([owner universal_id] == NO_TARGET) // don't think until launched
return;
//
[aiLock lock];
//
messagesForState = [NSDictionary dictionaryWithDictionary:[stateMachine objectForKey:currentState]];
//
if ((currentState)&&(![message isEqual:@"UPDATE"])&&((owner)&&([owner reportAImessages])))
NSLog(@"AI for %@ in state '%@' receives message '%@'", owner_desc, currentState, message);
//
actions = [NSArray arrayWithArray:[messagesForState objectForKey:message]];
//
[aiLock unlock];
if ((actions)&&([actions count] > 0))
{
//
for (i = 0; i < [actions count]; i++)
[self takeAction:[actions objectAtIndex:i]];
//
}
else
{
if (currentState)
{
SEL _interpretAIMessageSel = @selector(interpretAIMessage:);
//if ((owner)&&([owner reportAImessages])&&(![message isEqual:@"UPDATE"]))
// NSLog(@"AI for %@ has no response to '%@' in state '%@'", owner_desc, message, currentState);
//if ([owner respondsToSelector:NSSelectorFromString(@"interpretAIMessage:")])
if ([owner respondsToSelector:_interpretAIMessageSel])
[owner performSelector:_interpretAIMessageSel withObject:message];
}
return;
}
}
- (void) takeAction:(NSString *) action
{
NSArray* tokens = [action componentsSeparatedByString:@" "];
NSString* dataString = nil;
NSString* my_selector;
SEL _selector;
if ((owner)&&([owner reportAImessages])) NSLog(@"%@ to take action %@", owner_desc, action);
if ([tokens count] < 1)
{
if ([owner reportAImessages]) NSLog(@"No action '%@'",action);
return;
}
my_selector = (NSString *)[tokens objectAtIndex:0];
if ([tokens count] > 1)
{
dataString = (NSString *)[tokens objectAtIndex:1];
}
_selector = NSSelectorFromString(my_selector);
if (![owner respondsToSelector:_selector])
{
if ([my_selector isEqual:@"setStateTo:"])
[self setState:dataString];
else
NSLog(@"***** %@ does not respond to %@",owner_desc, my_selector);
}
else
{
if (dataString)
[owner performSelector:_selector withObject:dataString];
else
[owner performSelector:_selector];
}
}
- (void) think
{
NSArray *ms_list = nil;
if ([owner universal_id] == NO_TARGET) // don't think until launched
return;
//
[self reactToMessage:@"UPDATE"];
[aiLock lock];
if (pendingMessages)
{
//NSLog(@"debug1");
ms_list = [NSArray arrayWithArray:pendingMessages];
//NSLog(@"debug2");
[pendingMessages removeAllObjects];
}
[aiLock unlock];
if (ms_list)
{
int i;
for (i = 0; i < [ms_list count]; i++)
[self reactToMessage:(NSString *)[ms_list objectAtIndex:i]];
}
}
- (void) message:(NSString *) ms
{
if ([owner universal_id] == NO_TARGET) // don't think until launched
return;
//
[pendingMessages addObject:ms];
//[self think];
}
- (void) setNextThinkTime:(double) ntt
{
nextThinkTime = ntt;
}
- (double) nextThinkTime
{
return nextThinkTime;
}
- (void) setThinkTimeInterval:(double) tti
{
thinkTimeInterval = tti;
}
- (double) thinkTimeInterval
{
return thinkTimeInterval;
}
@endCode:
{
"ATTACK_SHIP" = {
"DESIRED_RANGE_ACHIEVED" = ("setStateTo: DETONATE");
ENTER = ("setDesiredRangeTo: 25.0", performIntercept);
EXIT = ();
"TARGET_DESTROYED" = ("setStateTo: EXPLODE");
"TARGET_LOST" = ("setStateTo: EXPLODE");
"ECM" = ("setStateTo: EXPLODE");
"GONE_BEYOND_RANGE" = ("setStateTo: EXPLODE");
UPDATE = ("setDesiredRangeTo: 30000.0", checkDistanceTravelled, "setDesiredRangeTo: 25.0", "pauseAI: 5.0");
};
DETONATE = {
ENTER = ("setDesiredRangeTo: 250.0", dealEnergyDamageWithinDesiredRange, becomeExplosion);
EXIT = ();
UPDATE = ();
};
EXPLODE = {
ENTER = (becomeExplosion);
EXIT = ();
UPDATE = ();
};
GLOBAL = {
ENTER = ("setSpeedFactorTo: 1.0", "setStateTo: ATTACK_SHIP");
EXIT = ();
UPDATE = ();
};
}
that was good skyhawk! :o
it really helps map out thet things I may need, although it may be more than what I can implement on my own.
it really helps map out thet things I may need, although it may be more than what I can implement on my own.
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Advice regarding Views & Touches for iPhone game | Elphaba | 5 | 2,884 |
Jul 17, 2009 01:54 PM Last Post: Frank C. |
|
| Implementing audio in games | sammyitch | 3 | 2,297 |
Dec 21, 2005 06:27 AM Last Post: unknown |
|
| Implementing sound | Muffinking | 25 | 8,012 |
Nov 4, 2003 05:22 AM Last Post: MattDiamond |
|

