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

📄 tennisfield.cpp

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

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

#include "stdafx.h"
#include "tennisfield.h"
#include "soundbuffer.h"

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

extern LPDDS			imgField;
extern CSoundBuffer		sndHitBall;
extern CSoundBuffer		sndBounce;

//----------------------------------------------------------------------------------------------
// NetCollision(): checks for collisions between the ball and the tennis net (disabled here
//				   by setting the NET_HEIGHT to 0)	
//----------------------------------------------------------------------------------------------

void CTennisField::NetCollision() {
	RECT net;
	net.left = field.left;
	net.right = field.right;
	net.top = (field.top+field.bottom)/2 - NET_WIDTH;
	net.bottom = (field.top+field.bottom)/2 + NET_WIDTH;

	POINT pt;
	ball->GetPosition(pt);
	if (ball->GetHeight()<NET_HEIGHT && PtInRect(&net, pt)) {
		ball->SetVelocity(0,0,0);
	}
}

//----------------------------------------------------------------------------------------------
// SetupField(): sets up the tennis field and registers the game objects
//----------------------------------------------------------------------------------------------

void CTennisField::SetupField(LPRECT pField, CPaddle * Player1, CPaddle * Player2, CTennisBall * Ball) {
	// copy information into private structs
	CopyRect(&field, pField);
	player[0] = Player1;
	player[1] = Player2;
	ball = Ball;
	
	// set up bounce information
	player[0]->bounce = 0;
	player[1]->bounce = 0;

	// set up scores
	player[0]->score = 0;
	player[1]->score = 0;

	// register to subjects
	player[0]->RegisterObserver(this);
	player[1]->RegisterObserver(this);
	ball->RegisterObserver(this);

	// set up service
	SetupService(PLAYER1);
}

//----------------------------------------------------------------------------------------------
// ShowPlayerScore(): Displays the player score on the screen
//----------------------------------------------------------------------------------------------

void CTennisField::ShowPlayerScore(HDC dc, int x, int y, int PlayerId) {
	// displayed player score at (x, y)
	char s[20];	
	ltoa(player[PlayerId]->score,s,10);
    int length = strlen(s);
	SetTextColor(dc, player[PlayerId]->GetColor());
	TextOut(dc, x, y, s, length);
}

//----------------------------------------------------------------------------------------------
// ShowFPS(): Calculates the frames per second and displays the framerate on the screen.
//			  Note: all game speeds are relative to this framerate
//----------------------------------------------------------------------------------------------

void CTennisField::ShowFPS(HDC dc, int x, int y) {
	// calculate the new framerate
	nFrameCount++;
	g_FrameRate = (1000*nFrameCount) / (timeGetTime()-StartTime);
	
	// display the framerate on the screen
	char s[20] = "FPS: ";	
	ltoa(g_FrameRate,s+5,10);
    int length = strlen(s);
	TextOut(dc, x, y, s, length);	
}

//----------------------------------------------------------------------------------------------
// Update(): Updates the tennis field and all game objects registered with it
//----------------------------------------------------------------------------------------------

void CTennisField::Update() {

	Fill(NULL, 0, lpddss);
	Blit(imgField, lpddss, (SCREEN_WIDTH-FIELD_WIDTH) / 2, (SCREEN_HEIGHT-FIELD_HEIGHT) / 2);

	// update ball position
	ball->Update();

	// check for collisions between paddles and the ball
	player[0]->BallCollision(ball);
	player[1]->BallCollision(ball);

	// check for collisions between ball and net
	NetCollision();
	
	// update paddle positions
	player[0]->Update();
	player[1]->Update();
	
	// paint game objects
	player[0]->Paint(lpddss);
	player[1]->Paint(lpddss);
	ball->Paint(lpddss);

	HDC dc;
	lpddss->GetDC(&dc);

	// show scores
	SetBkColor(dc, RGB(0,0,0));
	SetTextColor(dc, RGB(255,255,255));
	TextOut(dc, 10, 140, "Score:", 6);

	// show frame rate
	ShowFPS(dc, SCREEN_WIDTH-80, SCREEN_HEIGHT-20);
	
	// show footer text
	TextOut(dc, 10, SCREEN_HEIGHT-20, "ESC - quit  F1 - (un)freeze game  F2 - toggle bot targeting  F3 - stop ball", 75);
	
	// show individual scores
	ShowPlayerScore(dc, 10, 160, 0);
	ShowPlayerScore(dc, 10, 175, 1);

	lpddss->ReleaseDC(dc);

	if (!Flip()){
		MessageBox(NULL,"flip failed","",MB_OK);
		exit(1);
	}
}

//----------------------------------------------------------------------------------------------
// BallInField(): Checks if the ball is in the play field of the specified player
//----------------------------------------------------------------------------------------------

BOOL CTennisField::BallInField(int index, POINT pt) {
	int opponent = (index+1) % 2;
	LPRECT lpRect = player[index]->GetField();

	if (PtInRect(lpRect, pt)) {
		if (ball->GetOwner() != OWNER_SERVICE) {
			player[index]->bounce++;
				
			if (player[index]->GetId()==ball->GetOwner()) {
				PlayerScores(opponent);
			} else {
				if (player[index]->bounce>1) {
					PlayerScores(opponent);
				}
			}
		}
		return TRUE;
	}
	return FALSE;
}

//----------------------------------------------------------------------------------------------
// Notify(): Observer notification handler; the tennis field can receive notifications from
//			 the ball and the players
//----------------------------------------------------------------------------------------------

BOOL CTennisField::Notify(int msg, DWORD param) {
	if (msg == HIT_GROUND_EVENT || msg == BALL_ROLLING_EVENT) {
		POINT pt;
		ball->GetPosition(pt);

		if (!BallInField(0, pt) && !BallInField(1, pt)) {

			for (int i=0; i<2; i++) {
				int opponent = (i+1) % 2;
				if (player[i]->GetId()==ball->GetOwner()) {
					if (player[opponent]->bounce>0) {
						PlayerScores(i); break;
					} else {
						PlayerScores(opponent); break;
					}
				}
			}

		}
		if (msg == HIT_GROUND_EVENT) {
			sndBounce.Play();
		}
	}

	if (msg == HIT_BALL_EVENT) {
		player[0]->bounce = 0;
		player[1]->bounce = 0;
		sndHitBall.Play();
	}
	return TRUE;
}

//----------------------------------------------------------------------------------------------
// SetupForService(): sets up the game for the service
//----------------------------------------------------------------------------------------------

void CTennisField::SetupService(int ServicePlayer) {
	// set player positions
	for (int i=0; i<2; i++) {
		player[i]->ResetForService(ServicePlayer == i);
		player[i]->bounce = 0;
	}

	// set ball position
	RECT field;
	CopyRect(&field, player[ServicePlayer]->GetField());
	ball->SetPosition((float)(field.right+field.left) / 2, (float)(field.top+field.bottom) / 2, 0);
	ball->SetVelocity(0,0,0);
	ball->SetOwner(OWNER_SERVICE);
}

//----------------------------------------------------------------------------------------------
// PlayerScores(): called when a player scores a point
//----------------------------------------------------------------------------------------------

void CTennisField::PlayerScores(int index) {
	player[index]->score++;
	SetupService(index);
}

⌨️ 快捷键说明

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