⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aibot.cpp

📁 AI Game Programming Wisdom一书的源码
💻 CPP
字号:
//----------------------------------------------------------------------------------------------
// Sequential Prediction Demo: The positioning pattern
// 
// Author:  Fri Mommersteeg
// Date:    10-09-2001
// File:    AiBot.cpp
//----------------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------
// Include files
//----------------------------------------------------------------------------------------------

#include "stdafx.h"
#include "aibot.h"

//----------------------------------------------------------------------------------------------
// External declarations
//----------------------------------------------------------------------------------------------

extern LPDDS imgRedCross;

//----------------------------------------------------------------------------------------------
// PredictorFactory: Produces a predictor
//----------------------------------------------------------------------------------------------

CTennisPredictor * CAiBot::PredictorFactory() {
	// create string matching predictor
	CTennisPredictor * predictor = new CTennisPredictor;

	// set up string matching predictor
	predictor->Setup(WINDOW_SIZE, 2, MIN_PATTERN_SIZE);

	// return predictor
	return predictor;
}

//----------------------------------------------------------------------------------------------
// SetupAI(): Sets up the AI and registers the tennis ball
//----------------------------------------------------------------------------------------------

void CAiBot::SetupAI(CTennisBall * TennisBall, BOOL bTargeting) {
	pHorizontal = PredictorFactory();
	pVertical   = PredictorFactory();
	
	halfwidth = (field.right-field.left) / 2;
	halfheight = (field.bottom-field.top) / 2;
		
	nBounces = 0;
	this->bTargeting = bTargeting;

	ball = TennisBall;
	ball->RegisterObserver(this);
}

//----------------------------------------------------------------------------------------------
// EnableTargeting(): Enables or disables the bot targeting
//----------------------------------------------------------------------------------------------

void CAiBot::EnableTargeting(BOOL bEnabled) {
	bTargeting = bEnabled;
	if (!bTargeting) {
		rotation = 0;
	}
}

//----------------------------------------------------------------------------------------------
// Notify(): Observer notification handler (here the bot receives notifications from the ball)
//----------------------------------------------------------------------------------------------

BOOL CAiBot::Notify(int msg, DWORD param) {
	if (msg == HIT_GROUND_EVENT) {
		POINT pt;
		ball->GetPosition(pt);
		if (PtInRect(&field, pt)) {
			nBounces++;	
			
			// is this the first time that the ball bounces in this field?
			if (nBounces == 1) {
				// generate next elements for sequences
				int next_horizontal, next_vertical;
				
				// update "horizontal" sequence
				next_horizontal = pt.x > field.left + halfwidth;
				pHorizontal->Update(next_horizontal);
				
				// update "vertical" sequence
				next_vertical   = pt.y > field.top + halfheight;
				pVertical->Update(next_vertical);			
			}
		}
	}
	return TRUE;
}

//----------------------------------------------------------------------------------------------
// OnBallCollision(): Used to determine a new ball destination; overriden from CPaddle
//----------------------------------------------------------------------------------------------

void CAiBot::OnBallCollision() {
	
	int Destination;

	// randomly chooce a destination to play the ball to next time
	RandomPredictor.GetPrediction(Destination);

	BallDestination.x = field.left + OUTBOX_WIDTH + (Destination * (field.right-field.left-2*OUTBOX_WIDTH)) / PADDLE_ANGLES;
	BallDestination.y = (int)py + direction * (field.bottom-field.top);
}

//----------------------------------------------------------------------------------------------
// AdjustPaddleAngle(): Adjust paddle angle so that it is directed towards the ball destination
//----------------------------------------------------------------------------------------------

void CAiBot::AdjustPaddleAngle() {	
	float dy;
	float dist;
	
	dy = ((float)BallDestination.y - py);	
	dist = px + (dy*nx) / ny;

	if ((int)dist < BallDestination.x) {
		Rotate(-direction*ROTATE_SPEED);
	} else {
		Rotate(direction*ROTATE_SPEED);
	}
}

//----------------------------------------------------------------------------------------------
// SeekTarget(): Determines the target position to move the paddle to
//----------------------------------------------------------------------------------------------

void CAiBot::SeekTarget() {

	if (ball->GetOwner() != OWNER_SERVICE || (ball->GetOwner() == OWNER_SERVICE && bHasService)) {
		int Prediction;
		
		// get ball position
		POINT pt;
		ball->GetPosition(pt);

		// if ball is not inside AI field, reset ball bounce count
		if (!PtInRect(&field, pt)) {
			nBounces = 0;
		}

		// is this bot the "owner" of the ball? from this we derive the general direction of the ball
		if (ball->GetOwner() != id) {
			if (nBounces == 0 && !(ball->GetOwner() == OWNER_SERVICE && bHasService)) {
				// interpolate the motion of the ball to where it will hit the ground
				ball->GetBouncePosition(target);					
				heuristic = INTERPOLATION;
			} else {
				// move straightly towards the ball
				target = pt;
				heuristic = TOWARDSBALL;
			}
		} else {
			heuristic = TOWARDSCENTER;

			// perform prediction for horizontal coordinate
			if (pHorizontal->GetPrediction(Prediction)) {

				// get the match size from the predictor
				int indicator = pHorizontal->GetMaxMatchSize();

				// limit the match size to the window size
				indicator = (indicator > WINDOW_SIZE) ? WINDOW_SIZE : indicator;

				// convert 0=left,1=right to -1=left,1=right
				Prediction = Prediction ? 1 : -1;

				// determine position
				target.x = field.left + halfwidth + (Prediction*indicator*halfwidth)/(2*WINDOW_SIZE);				
				heuristic = ANTICIPATION;
			} else {
				target.x = field.left + halfwidth;
			}

			// perform prediction for vertical coordinate
			if (pVertical->GetPrediction(Prediction)) {

				// get the match size from the predictor
				int indicator = pVertical->GetMaxMatchSize();

				// limit the match size to the window size
				indicator = (indicator > WINDOW_SIZE) ? WINDOW_SIZE : indicator;

				// convert 0=up,1=down to -1=up,1=down
				Prediction = Prediction ? 1 : -1;

				// determine position... yes, it's a long calculation
				target.y = field.top + halfheight - direction * halfheight / 2 + (Prediction*indicator*halfheight)/(4*WINDOW_SIZE);				
			} else {
				target.y = field.top + halfheight - direction * halfheight / 2;
			}		
		}
	} else {
		// do not move during service
		target.x = (int)px;
		target.y = (int)py;
	}
}

//----------------------------------------------------------------------------------------------
// AdvanceTarget(): Moves the paddle towards the target position
//----------------------------------------------------------------------------------------------

void CAiBot::AdvanceTarget() {
	// we use an extremely simple method to get to the target position

	long dx, dy;
	dx = target.x - (int)px;
	dy = target.y - (int)py;

	if (abs(dx)>abs(dy)) {
		if (dx<0) {			
			// if we can't move to the horizontal, then move vertical
			if (px<=field.left) {
				if (dy<0) {
					Up();
				} else {
					Down();
				}
			} else {
				Left();
			}
		} else {
			// if we can't move to the horizontal, then move vertical
			if (px>=field.right) {
				if (dy<0) {
					Up();
				} else {
					Down();
				}
			} else {
				Right();
			}
		}
	} else {
		if (dy<0) {
			// if we can't move to the vertical, then move horizontal
			if (py<=field.top) {
				if (dx<0) {
					Left();
				} else {
					Right();
				}
			} else {
				Up();
			}			
		} else if (dy>0) {
			// if we can't move to the vertical, then move horizontal
			if (py>=field.bottom) {
				if (dx<0) {
					Left();
				} else {
					Right();
				}
			} else {
				Down();
			}			
		}
	}
}

//----------------------------------------------------------------------------------------------
// Update(): Updates the status of the bot
//----------------------------------------------------------------------------------------------

void CAiBot::Update() {
	SeekTarget();
	AdvanceTarget();

	if (bTargeting) {
		AdjustPaddleAngle();
	}

	CPaddle::Update();
}

//----------------------------------------------------------------------------------------------
// PaintSequence(): Displays sequence information on the screen
//----------------------------------------------------------------------------------------------

void CAiBot::PaintSequence(HDC dc, int x, int y, char * szA, char * szB, CTennisPredictor * pPredictor, int Width) {
	int nWindowSize;
	int nPatternSize;
	int nPatternStart;
	int nPatternEnd;
	int element;
	int i;

	nWindowSize = pPredictor->GetWindowSize();
	nPatternSize = pPredictor->GetMaxMatchSize();
	nPatternEnd = pPredictor->GetMaxMatchPosition()+1;
	nPatternStart = nPatternEnd-nPatternSize;
	for (i = 0; i<nWindowSize; i++) {		
		if (i >= nPatternStart && i < nPatternEnd) {
			SetTextColor(dc, RGB(255, 255, 0));
		} else if (i == nPatternEnd && nPatternSize >= MIN_PATTERN_SIZE) {
			SetTextColor(dc, RGB(0, 255, 0));		
		} else {
			SetTextColor(dc, RGB(255,255,255));
		}
		element = pPredictor->GetWindowEntry(i);
		if (element == 0) {
			TextOut(dc, x+i*Width,y, szA, 1);
		} else {
			TextOut(dc, x+i*Width,y, szB, 1);
		}
	}
}

//----------------------------------------------------------------------------------------------
// ShowStatistics(): Shows AI statistics on the screen
//----------------------------------------------------------------------------------------------

void CAiBot::ShowStatistics(HDC dc) {
	SetBkColor(dc, RGB(0,0,0));
	SetTextColor(dc, RGB(255,255,255));
	TextOut(dc, 10, 10, "Horizontal Predictor:    ", 25);
	TextOut(dc, 10, 30, "Vertical Predictor:      ", 25);

	PaintSequence(dc, 200, 10, "L", "R", pHorizontal);
	PaintSequence(dc, 200, 30, "A", "B", pVertical);
	
	SetTextColor(dc, RGB(255,255,255));
	TextOut(dc, 10, 80, "Positioning strategy: ", 21);

	switch (heuristic) {
	case ANTICIPATION:
		TextOut(dc, 10, 100, "ANTICIPATION   ", 15);
		break;
	case INTERPOLATION:
		TextOut(dc, 10, 100, "INTERPOLATION  ", 15);
		break;
	case TOWARDSBALL:
		TextOut(dc, 10, 100, "TOWARDS BALL   ", 15);
		break;
	case TOWARDSCENTER:
		TextOut(dc, 10, 100, "TOWARDS CENTER ", 15);	
		break;
	}
}

//----------------------------------------------------------------------------------------------
// Paint(): Paints the AI paddle; overriden from CPaddle
//----------------------------------------------------------------------------------------------

void CAiBot::Paint(LPDDS lpdds) {
	
	// display a red cross in case the bot uses anticipation
	if (heuristic == ANTICIPATION) {
		RECT source, dest;
		GetSurfaceSize(imgRedCross, &source);
		CopyRect(&dest, &source);
		OffsetRect(&dest, target.x - CROSS_WIDTH / 2, target.y - CROSS_HEIGHT / 2);
		Blit(imgRedCross, &source, lpddss, &dest, 0);
	}

	// call parent paint 
	CPaddle::Paint(lpdds);

	// show AI statistics
	HDC dc;
	lpdds->GetDC(&dc);
	ShowStatistics(dc);		
	lpdds->ReleaseDC(dc);
}

//----------------------------------------------------------------------------------------------
// ResetForService(): Resets the AI bot for the service
//----------------------------------------------------------------------------------------------

void CAiBot::ResetForService(BOOL HasService) {
	// call default implementation
	CPaddle::ResetForService(HasService);

	// reset predictors
	if (pHorizontal != NULL) {
		pHorizontal->Reset();
	}
	if (pVertical != NULL) {
		pVertical->Reset();
	}

	bHasService = HasService;
	heuristic = TOWARDSCENTER;

	OnBallCollision();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -