Мяч и бита

Исходный файл: Paddleball.fla

Хотя предыдущая игра веселая, у нее есть один недостаток: нет никакой возможности выиграть. Вы просто играете до тех пор, пока не надоест или пока не проиграете.
Игра станет более интересной, если позволить игроку управлять одной битой в то время, как компьютер будет управлять другой. Игрок попытается не пропустить мяч, надеясь на то, что его пропустит компьютер.

На рис. 11.3 показан кадр из игры. Игрок управляет левой битой, а компьютер - правой.

Задача проекта

Цель игры состоит в том, чтобы создать противника, обладающего искусственным интеллектом, с которым будет соревноваться игрок. Левая бита будет управляться игроком, а правая - воссоздавать возможную реакцию человека с помощью компьютерных расчетов.
Мяч будет отскакивать от верхней и нижней стен, и только от действий игрока и компьютера будет зависеть, вылетит ли он за пределы экрана.
Когда мяч пролетает мимо одной из бит игроков, игра приостанавливается до тех пор, пока пользователь не щелкнет по кнопке "serve". Затем мяч снова появится в середине экрана. Счет игры сохранится. Игра заканчивается в том случае, если один из игроков наберет 7 очков.

Подход

Искусственный интеллект для этой игры можно создать разными способами. Один из них - сделать так, чтобы бита всегда следовала за мячом. Однако в этом случае у компьютера просто не будет возможности пропустить мяч.
Лучше, если бита компьютера будет медленно двигаться в направлении мяча. Если мяч будет лететь слишком быстро, компьютер может не успеть переместить биту в правильное положение. Кроме того, бита будет двигаться только тогда, когда мяч летит в искусственного противника.

Словосочетание "искусственный интеллект" звучит таинственно. Однако для игр не так важно, чтобы противник был умным. Компьютер должен только способствовать захватывающей игре. Конечно, в большинстве игр гораздо проще создать безупречного противника. Однако в таком случае игра для компьютера становится беспроигрышной, что не интересно для игрока. Трудность состоит в том, чтобы создать противника, обладающего некими навыками (это сделает игру непростой), но чтобы имеющихся навыков не хватало для беспроигрышной игры.

Для того чтобы счет игры был сохранен, нужны несколько переменных. Однако создать паузу в игре между подачами мяча довольно сложно, поэтому в игре будет два кадра: в первом программа ждет, когда игрок щелкнет по кнопке "serve", а во втором разворачивается само действие игры. Этот второй кадр начинается с установки произвольного начального положения мяча.

Подготовка ролика

В общих чертах ролик аналогичен предыдущему. Вместо трех кадров вам понадобятся четыре: "start game", "start level", "play" и "game over". Перед каждой подачей мяча будет виден кадр "start level". Кадр же “game over" станет отображаться только тогда, когда будет пропущен последний мяч.
Как и в предыдущей игре, вам нужен один клип под названием "paddle» и еше один с именем "computerPaddle". Поведение второй биты будет запрограммировано с помощью языка ActionScript. Так как бита компьютера будет располагаться справа, необходимо убрать правую стенку. При этом верхняя и нижняя стены останутся.

Создание кода

В сценарий предыдущего ролика необходимо внести некоторые изменения. Изменить существующие функции и добавить одну новую. Приведем сценарий клипа "actions", который вызывает новую функцию moveComputerPaddle:

onClipEvent(load) {
_root.startLevel();
}
onClipEvent(enterFrame) {
_root.moveBall ();
_root.movePaddle() ;
_root.moveComputerPaddle();
}

Вместо функции startGame в этой игре используется функция startLevel, которая обладает всеми возможностями функции startGame и в дополнение к ним указывает, что мяч будет двигаться в произвольном направлении. Достичь этого можно, определив, что мяч в 50% случаев подается вверх, в 50% случаев - вниз, также в 50% случаев - влево и в 50% случаев - вправо. То есть вы получаете четыре возможных направления движения мяча по диагонали.

function startLevel() {
// Определяем начальное положение мяча,
х = ball._x;
у = ball._y;
// Указываем начальную скорость и одно из четырех
// произвольных направлений по диагонали,
dx = 5;
dy = 5;
if (Math.random() < .5) dx *= -1;
if (Math.random() < .5) dy *= -1;
// Прячем курсор. Mouse.hide();
// Устанавливаем значения констант.
rightWall = 550;
leftWall = 0;
topWall = 0;
bottomWall = 400;
ballRadius = ball._width/2;
passedPaddle = false;
}

Теперь в функцию moveBall включен код для определения, пролетел ли мяч мимо биты компьютера или нет (10). Он похож на код, обрабатывающий биту игрока (9), и идентичен соответствующему фрагменту кода предыдущей игры.
Когда мяч пролетает с правой (11) или с левой (12) стороны, обычно игра возвращается к кадру "start level". Однако если не осталось больше мячей, программа переходит к кадру завершения игры, "game over". В зависимости от того, кто пропустил мяч, очко записывается либо игроку, либо компьютеру (переменной playerScore или computerScore).

function moveBall() {
// Изменяем координаты х и у.
х += dx;
y += dy;
// Проверяем, попал ли мяч в нижнюю стену,
if (y+ballRadius > bottomWall) {
overshoot = (y+ballRadius) - bottomWall;
у -= overshoot*2;
dy *= -1;
}
// Проверяем, попал ли мяч в верхнюю стену, if (y-ballRadius < topWall) {
overshoot = topWall - (y-ballRadius);
у += overshoot*2;
dy *= -1;}

(9) // Находится ли мяч там, где по нему должна ударить бита?

paddleRight = paddle._x+(paddle._width/2);
if ((x-ballRadius < paddleRight) and ipassedPaddle) {
// Находится ли там бита?
paddleTop = paddle._y-(paddle._height/2);
paddleBottom = paddle._y+(paddle._height/2);
if ((y > paddleTop) and (y < paddleBottom)) {
overshoot = paddleRight - (x-ballRadius)
// Удар битой,
x += overshoot*2;
dx += -1;
// Увеличиваем скорость мяча,
dx *= 1.05;
dy *= 1.05;
} else {
// Мяч пропущен, больше ничего не проверяем.
passedPaddle = true;}
}

(10) // Находится ли мяч там,

// где должен столкнуться с битой компьютера?
paddleLeft = computerPaddle._x-(computerPaddle._width/2);
if ((x+ballRadius > paddleLeft) and !passedPaddle) {
// Находится ли тем бита?
paddleTop = computerPaddle._y-(computerPaddle._height/2);
paddleBottom = computerPaddle_>y+
(computeerPaddle._height/2);
if ((y > paddleTop) and (y < paddleBottom)) {
// Удар битой.
oveershoot = (x+ballRadius) - paddleLeft;
x -= overshoot *2; dx *= -1;
// Увеличиваем скорость мяча,
dx *= 1.05;
dy *= 1.05;
} else {
// Мяч пропущен, ничего больше не проверяем.
passedPaddle = true;
}}

(11) // Проверяем, попал ли мяч в левую стену.

if ((x-ballRadius < leftWall) and passedPaddle) {
Mouse.show();
computerScore++;
if (numBalls == 0) {
gotoAndPlay("game over");
} else {
numBalls--;
gotoAndPlayf"start level");}}

(12) // Выполняем аналогичную проверку для правой стены,

if ((x+ballRadius > rightWall) and passedPaddle) {
Mouse.show();
playerScore++;
if (numBalls == 0) {
gotbAndPlay("game over");
} else {
numBalls-;
gotoAndPlay("start level");
// Устанавливаем новое положение мяча.
ball._x = х;
ball._y = у;
}

Функция movePaddle идентична одноименной функции предыдущей игры. Однако необходимо добавить функцию moveComputerPaddle, управляющую правой битой, которая будет перемещать биту только в том случае, если мяч летит вправо. Бита будет перемещаться вверх, если мяч расположен выше нее, и вниз, если ниже.
Скорость передвижения биты устанавливается в начале функции. Чем выше это значение, тем быстрее бита будет реагировать на перемещения мяча.

function moveComputerPaddle() {
// Устанавливаем скорость биты, управляемой компьютером.
moveAmount = 8;
// Выясняем, движется ли мяч в этом направлении,
if (dx > 0) {
// Перемещаем биту вверх.
if (у < computerPaddle._y-moveAmount) {
computerPaddle._y -= moveAmount;
,// Перемещаем биту вниз.
} esle if (у > computerPaddle._y+moveAmount) {
computerPaddle._y += moveAmount;
}}}

Еще один важный фрагмент кода входит в кадр "start game" и устанавливает исходные значения количества мячей и очков. Эти переменные не могут быть вставлены в функцию startLevel, так как они должны быть установлены только в начале игры, а не перед тем, как подается мяч.

numBalls = 7;
computerScore = 0;
playerScore = 0;
stop();

К сведению

В дополнение к уже описанным элементам необходимо создать текстовые поля playerScore и computerScore и поместить их на рабочее поле. Они должны быть расположены во всех кадрах, кроме "start game", таким образом, чтобы были видны между подачами мяча и в конце игры.

Другие возможности

Изменить количество мячей просто: достаточно изменить только одно значение в кадре "start game". Изменяя другие параметры, можно продлить или усложнить игру. Есть и другие варианты усовершенствования игры - например, увеличить скорость биты компьютера, поменяв одно значение в функции moveComputerPaddle.
Также можно сделать компьютер "умнее". Например, написать код, который будет предугадывать место, куда прилетит мяч, и передвигать туда биту вместо того, чтобы просто перемешать ее вслед за мячом. При пересечении границ игрового поля мяч будет ударяться о верхнюю или нижнюю стенку только один раз, так что определить предполагаемое место можно с помощью простых математических расчетов, если вы хорошо владеете математикой.