Функция CalcVector() вычисляет вектор направления движения спрайта. Это направление выбирается случайным образом, и его в любой момент можно пересчитать заново.
Две последние функции, Hit() и Update(), уже упоминались выше. Они обеспечивают подтверждение и реакцию на столкновения.
В закрытой (private) секции объявляются переменные класса Sprite. Первая из них, surf, — указатель на интерфейс DirectDrawSurface, используемый для работы с поверхностью данного объекта Sprite. В переменных x, y, w и h хранятся положение и размеры поверхности. Переменные xinc и yinc служат для анимации спрайта. Как вы вскоре увидите, они инициализируются случайными величинами. Эти две переменные определяют направление, в котором движется спрайт.
В самом конце объявляются переменные collide и collideinfo. При обнаружении столкновения логической переменной collide присваивается значение TRUE, во всех остальных случаях она равна FALSE. Структура collideinfo содержит информацию о происшедшем столкновении. В данном случае нас интересует лишь положение второго спрайта, участвующего в столкновении.
Сейчас мы подробно рассмотрим все функции класса Sprite. Конструктор класса выглядит так:
Sprite::Sprite(LPDIRECTDRAWSURFACE s, int xx, int yy) {
DDSURFACEDESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwFlags=DDSD_WIDTH | DDSD_HEIGHT;
s->GetSurfaceDesc(&desc);
surf=s;
x=xx;
y=yy;
w=desc.dwWidth;
h=desc.dwHeight;
collide=FALSE;
CalcVector();
}
Конструктор получает в качестве аргументов указатель на поверхность DirectDraw и исходное положение спрайта. Сохранить эти значения в переменных класса нетрудно, однако мы еще должны инициализировать переменные ширины и высоты (w и h). Для этого необходимо запросить у поверхности DirectDraw ее размеры. С помощью структуры DDSURFACEDESC и функции GetSurfaceDesc() мы узнаем размеры и присваиваем нужные значения переменным. Переменной collide присваивается значение FALSE (потому что столкновение еще не было обнаружено). Наконец, мы вызываем функцию CalcVector(), которая определяется так:
void Sprite::CalcVector() {
xinc=(rand()%7)-3;
yinc=(rand()%7)-3;
}
Функция CalcVector() инициализирует переменные xinc и yinc с помощью генератора случайных чисел rand(). Полученное от rand() значение преобразуется так, чтобы оно принадлежало интервалу от –3 до 3. Эти значения будут использоваться для перемещения спрайта при очередном обновлении экрана. Обратите внимание — одна или обе переменные вполне могут быть равны нулю. Если нулю равна только одна переменная, перемещение спрайта ограничивается осью X или Y. Если нулю равны обе переменные, спрайт вообще не двигается.
Функция GetRect() инициализирует объект CRect() данными о положении и размерах спрайта. Эта функция определяется так:
CRect Sprite::GetRect() {
CRect r;
r.left=x;
r.top=y;
r.right=x+w;
r.bottom=y+h;
return r;
}
Перейдем к функции Hit(). Напомню, что эта функция вызывается при обнаружении столкновения. Функции Hit() передается один аргумент — указатель на спрайт, с которым произошло столкновение. Она выглядит так:
void Sprite::Hit(Sprite* s) {
if (!collide) {
collideinfo.x=s->GetCenterX();
collideinfo.y=s->GetCenterY();
collide=TRUE;
}
}
Функция Hit() реализует стадию подтверждения столкновений. В нашем случае она сохраняет положение каждого из столкнувшихся спрайтов и присваивает логической переменной collide значение TRUE. Обратите внимание — сохраняется лишь положение спрайта, а не указатель на сам спрайт. Это сделано намеренно, чтобы мы не смогли обратиться к спрайту во время реакции на столкновение (о ней говорится ниже). Следовательно, если вам потребуется другая информация о столкнувшемся спрайте, кроме его положения (например, тип спрайта или уровень его «здоровья» для компьютерной игры), ее необходимо сохранить в функции Hit(). Эту информацию следует получить немедленно, не дожидаясь стадии реакции, потому что к этому времени статус другого спрайта может измениться.
Функция Sprite::Update() выполняет две задачи: обновляет положение спрайта и, в случае столкновения, изменяет переменные, определяющие направление его перемещения (xinc и yinc). Функция Update() приведена в листинге 9.2.
Листинг 9.2. Функция Sprite::Update()
void Sprite::Update() {
if (collide) {
int centerx=GetCenterX();
int centery=GetCenterY();
int xvect=collideinfo.x-centerx;
int yvect=collideinfo.y-centery;
if ((xinc>0 && xvect>0) || (xinc<0 && xvect<0)) xinc=-xinc;
if ((yinc>0 && yvect>0) || (yinc<0 && yvect<0)) yinc=-yinc;
collide=FALSE;
}
x+=xinc;
y+=yinc;
if (x>640-w/2) {
xinc=-xinc;
x=640-w/2;
}
if (x<-(w/2)) {
xinc=-xinc;
x=-(w/2);
}
if (y>480-h/2) {
yinc=-yinc;
y=480-h/2;
}
if (y<-(h/2)) {
yinc=-yinc;
y=-(h/2);
}