В данном уроке мы создадим простую игру, являющуюся внебрачным сыном арканоида и пинг-понга. Суть игры в том, чтобы отбить мячик до того как он коснется вашей стороны экрана. На другой стороне нам оппонирует компьютерный игрок, занимающийся аналогичным делом. Для этого нам понадобится создать 2 новых класса соответсвенно для нашего шарика и для платформы, представялющей игроков. Взаимодействие объектов будет определяться путем обнаружения столкновений между ними, меняя тем самым их поведение. Создаем новый класс, назовем его как-нибудь по оригинальнее, например Ball. Не забудем расширить его от класса Sprite. Данный класс во много напоминает собственный курсор из предыдущего урока, за одним исключением - для мячика мы применим радиальную градиентную заливку. Ball.as : Code package { import flash.display.*; import flash.geom.Matrix; public class Ball extends Sprite { public function Ball() { var matr:Matrix = new Matrix(); /// для задания одного из параметров заливки нам понадобиться матрица, тут мы ее создаем matr.createGradientBox(15, 15, 0, -5, -5); /// тут мы определям ее размеры, вращение и координаты this.graphics.lineStyle(1); /// тип градиента, массивы для цвета, прозрачности, расположения цветов, задание матрицы this.graphics.beginGradientFill(GradientType.RADIAL, [0xFF0000, 0xFFC000], [1, 1], [50, 255], matr, SpreadMethod.REFLECT); this.graphics.drawCircle(0, 0, 15); this.graphics.endFill(); } }
} Теперь создадим новый класс для "рокетки", назовем его Paddle. По скольку данный класс будет нами использован для задания как игрока таки его противника, у нас резонно возникает желание задать различный внешний вид рокеток. Сделать это можно используя параметы функции-конструкторв класса Paddle. Изменять таким образом можно все что душе угодно, но здесь мы ограничемся заданием цвета. Итак в параметрах функции public function Paddle() в круглых скобках пишем colors:Array. Мы используем массив в качестве типа параметра потому, что цвет градиентной заливки определяется массивом, элементами которого являются цвета. В нашем случаем мы используем 2 цвета для задания градиента, но прошу обратить внимание на то, что ряд других параметров функции beginGradientFill также представляет собой массивы. Количество элементов данных массивов одинаково и равно числу заданных цветов. Эти параметры связаны друг с другом и порядковый номер эелемента соответсвующего массива относится к цвету с точно таким же порядковым номером. Всего можно задать 15 цветов (то есть максимально массив может содержать 15 элементов). Paddle.as : Code package { import flash.display.*; import flash.geom.Matrix; public class Paddle extends Sprite { public function Paddle(colors:Array) { var matr:Matrix = new Matrix(); matr.createGradientBox(100, 20, 45, 0, 0); this.graphics.lineStyle(1); this.graphics.beginGradientFill(GradientType.LINEAR, colors, [1, 1], [0, 255], matr); /// для рокетки мы использовали линейный тип заливки, параметр colors задает цвета принятые функцией-конструтором во время создания экземпляра класса Paddle this.graphics.drawRect(0, 0, 100, 20); this.graphics.endFill(); } }
} Теперь открываем Main.mxml и пишем саму игру. Создаем глобальные переменные для нашей игры: Code private var ball:Ball; /// создаем мяч private var player:Paddle; /// создаем игрока private var enemy:Paddle; /// создаем компьютерного игрока private var xDir:int = 10; /// переменные задающие направление движения мячика по осям x и y private var yDir:int = -10; private var targetX:Number = 0; /// числовая переменная, обозначающая место куда мы ходим привести нашу рокетку (определяется движением мыши) private var easing:Number = 3; /// сглаживание движения Главная функция задающая игру после запуска приложения: Code private function init():void { Mouse.hide(); /// прячем курсор player = new Paddle([0x00FF00, 0x0000FF]); /// создаем экземпляр класса Paddle для игрока и задаем ему цвета. player.x = 200; player.y = 350; stage.addChild(player); enemy = new Paddle([0xFF0000, 0xFF00FF]); /// таже операция и для врага enemy.x = 200; enemy.y = 30; stage.addChild(enemy); player.addEventListener(Event.ENTER_FRAME, movePlayer); /// задаем функцию игрока вызываемую при каждом обновлении кадра enemy.addEventListener(Event.ENTER_FRAME, moveEnemy); /// то есть в дангой игре мы используем покадровую анимацию ball = new Ball(); /// создаем мячик ball.x = 250; ball.y = 200; stage.addChild(ball); ball.addEventListener(Event.ENTER_FRAME, moveBall); /// двигаем мяч } Далее сами функции движения объектов с подробными комментариями: Code private function moveBall(e:Event):void { /// если мяч уперся в какую либо из стен игрового экрана - меняем его направление на противоположное (отражаем) if (ball.x <= 0) { xDir *= -1; } else if (ball.x >= this.width - ball.width/2) { xDir *= -1; }
//// здесь иы используем функцию hitTestObject() объекта ball для проверки столкновения с объектами player и enemy. //// в случае обнаружения оного, функция возвращает значение [b]true[/b] и мы также как и в случае со стенкой отражаем мяч
if (ball.hitTestObject(player)) { yDir *= -1; } else if (ball.hitTestObject(enemy)) { yDir *= -1; }
if (ball.y <= 0) { yDir *= -1; } else if (ball.y >= this.height - ball.height/2) { yDir *= -1; } ball.x += xDir; //// двигаем мяч согласно определнному выше направлению по обоим осям ball.y += yDir; }
private function movePlayer(e:Event):void { if (this.mouseX < player.width/2) { //// если мышь левее точки равной половине рокетки, то не даем рокетке выйти за пределы экрана targetX = 0; } else if(this.mouseX > this.width - player.width/2) { //// тоже самое для правой границы targetX = this.width - player.width; } else { //// если куроср между этими двумя точками, то координаты цели движения равны положению мыши минус половина ширины рокетки targetX = this.mouseX - player.width/2; } player.x += (targetX/2 - player.x/2) / easing; //// координаты местоположения игрока опредеяются следующей формулой, где easing это параметр задающий плавность движения рокетки, своего рода энерции } private function moveEnemy(e:Event):void { //// функция движения компьютера очень похожа по механизму на функцию игрока, думаю тут все понятно //// иллюзия искусственного интеллекта здесь создается за счет постоянного следования рокетки за самим мячом, а не за курсором мыши как в случае с игроком //// однако выиграть у того ИИ вряд ли получится) у меня не вышло... хотя с увеличением энерции (easing) это становится все легче
var enemyTargetX:Number; enemyTargetX = ball.x - enemy.width / 2;
if (enemyTargetX <= 0) { enemyTargetX = 0; } else if (enemyTargetX >= this.width - enemy.width / 2) { enemyTargetX = this.width - enemy.width / 2; } enemy.x += (enemyTargetX / 2 - enemy.x / 2) / easing; } Полный код Main.mxml Code <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="500" height="400" applicationComplete="init()" frameRate="24"> <mx:Script> <![CDATA[ import flash.events.Event; import flash.events.MouseEvent; private var ball:Ball; private var player:Paddle; private var enemy:Paddle; private var xDir:int = 10; private var yDir:int = -10; private var targetX:Number = 0; private var easing:Number = 3; private function init():void { Mouse.hide(); player = new Paddle([0x00FF00, 0x0000FF]); player.x = 200; player.y = 350; stage.addChild(player); enemy = new Paddle([0xFF0000, 0xFF00FF]); enemy.x = 200; enemy.y = 30; stage.addChild(enemy); player.addEventListener(Event.ENTER_FRAME, movePlayer); enemy.addEventListener(Event.ENTER_FRAME, moveEnemy); ball = new Ball(); ball.x = 250; ball.y = 200; stage.addChild(ball); ball.addEventListener(Event.ENTER_FRAME, moveBall); } private function moveBall(e:Event):void { if (ball.x <= 0) { xDir *= -1; } else if (ball.x >= this.width - ball.width/2) { xDir *= -1; } if (ball.hitTestObject(player)) { yDir *= -1; } else if (ball.hitTestObject(enemy)) { yDir *= -1; } if (ball.y <= 0) { yDir *= -1; } else if (ball.y >= this.height - ball.height/2) { yDir *= -1; } ball.x += xDir; ball.y += yDir; } private function movePlayer(e:Event):void { if (this.mouseX < player.width/2) { targetX = 0; } else if(this.mouseX > this.width - player.width/2) { targetX = this.width - player.width; } else { targetX = this.mouseX - player.width/2; } player.x += (targetX/2 - player.x/2) / easing; } private function moveEnemy(e:Event):void { var enemyTargetX:Number; enemyTargetX = ball.x - enemy.width / 2; if (enemyTargetX <= 0) { enemyTargetX = 0; } else if (enemyTargetX >= this.width - enemy.width / 2) { enemyTargetX = this.width - enemy.width / 2; } enemy.x += (enemyTargetX / 2 - enemy.x / 2) / easing; } ]]> </mx:Script> </mx:Application> Компилим, играем. B1z ©
Сообщение отредактировал B1zDelKin - Суббота, 23.01.2010, 15:36 |