Четверг, 28 Марта 2024, 22:21

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 2 из 2
  • «
  • 1
  • 2
Форум игроделов » Записи участника » B1zDelKin [31]
Результаты поиска
B1zDelKinДата: Понедельник, 25 Января 2010, 20:07 | Сообщение # 21 | Тема: FlashDevelop
частый гость
Сейчас нет на сайте
Ктулху ты Боже мой... ну, читать научитесь уже. Секрет успешного решения проблем в том, чтобы читать ВСЕ посты, а не только те, что являются ответом на ваши собственные.

Quote (kALIFE)
кто нить поможет исправить проблему
ВСЕ Я РЕШИЛ ЭТУ ПРОБЛЕМУ...
если че я кинул эти файлы FlexDesignView в папку где FD
и в папку C:documents and settings/user/local settings/application data/flashdevelop

Скопируйте туда Data и Plugins и все, счастье настало.

B1zDelKinДата: Понедельник, 25 Января 2010, 11:59 | Сообщение # 22 | Тема: Flash Level Editor
частый гость
Сейчас нет на сайте
ActionScript for Multiplayer Games and Virtual Worlds by Jobe Makar

В иходных файлах для данной книги есть примеры редакторов уровней, в том числе для изометричских мморпг.

B1zDelKinДата: Понедельник, 25 Января 2010, 11:50 | Сообщение # 23 | Тема: Flex и ActionScript 3.0 для создания мини-флеш игр. Часть 3
частый гость
Сейчас нет на сайте
В данном уроке мы расширим возможности созданной в предыдущем уроке игры. А именно:
- Разнообразим отскок от рокетки в зависимости от места попадания мячом
- Сделаем ведение счета игры 2-мя способами: средствами среды Flex и AS3
- Добавим эффект свечения при ударе мяча

Открываем наш проект. В файле Main.mxml находим функцию движения мяча moveBall.
Находим строчку

Code

if (ball.hitTestObject(player)) {
  yDir *= -1;
}

Для того, чтобы добавить особое поведение мячу при столкновении с рокеткой, мы добавим новую функцию, призванную просчитать место столкновения и в зависимости от этого места изменять скорость и угол отражения:

Code

if (ball.hitTestObject(player)) {
  yDir *= -1;
  [b]checkHitPosition(player);[/b] /// параметром данной функции является рокетка стлокновения с которой мы анализируем. в данном случае это игрок
}

Теперь подробно рассмотрим функцию проверки места столкновения:

Code

private function checkHitPosition(paddle:Paddle):void
{
  var hitPercent:Number;

                 /*переменная hitPercent отражает место в которое ударился мяч, 0 - это левый край рокетки, 50 - это ее середина, 100 - правый край

  var ballPosition:Number = ball.x - paddle.x; /// эта переменная отражает положение мяча относительно положения рокетки
     
  hitPercent = (ballPosition / (paddle.width - ball.width)) - .5; //// данная формула вычисляет место удара
  xDir = hitPercent * 20;  /// тут мы выбираем под каким углом отразится мяч, мне понравился коэффициент 20, можете поперебирать и выбрать понравившийся себе вариант
  yDir *= 1.04; /// добавляем ускорение мячу
}

Те же самые действия необходимо повторить и для столкновения с рокеткой соперника.

Теперь давайте сделаем игру более осмысленной добавим ведение счета, дав, таким образом, возможность выигрывать. Я решил продемонстрировать 2 альтернативных способа сделать это. На то есть 2 причины:
- Знать надо оба способа, в процессе работы во Флекс, у Вас рано или поздно возникнет ситуация, когда стандартные средства (кнопки, картинки, лайбелы) перестанут удовлетворять Вашим целям, и лучшим выходом будет создание нужного элемент лично.
- В процессе планирования Вы сможете, четко представив назначение данного элемента, выбрать верную реализацию. Использовать встроенные элементы флекса легче, и если они удовлетворяют нужной функциональности, то использовать лучше именно их.

К делу. Переходим в Main.mxml к Disign View. Находим вкладку Components -> Controls и перетаскиваем оттуда на сцену компонент label. Возвращаемся в Source View и приводим наш компонент к следующему виду:

Code

<mx:Label id="escore" text="{enemyScore.toString()}" fontFamily="Arial" fontSize="24" x="15" y="15" width="60" height="35"/>

Обратите внимание на строку text="{enemyScore.toString()}" здесь мы используем привязку данных для атрибута text компонента label. Это означет, что в качестве строкового значения будет использоваться значение переменной enemyScore и любоей изменение ее значения повлечет изменение текста.

Самое время теперь добавить эту глобальную переменную:

Code

[Bindable]  /// данный тег указывает на то, что переменная используется в привязке данных (data binding)
private var enemyScore:int = 0;

Это пример использования средств Флекс. Теперь рассмотрим использование AS3 для данной цели. Нам нужно создать новый класс, выполняющий те же самые функции. Создаем новый класс, назовем его ScreenText и расширим его от класса Sprite.

Вот полный код ScreenText.as с комментариями:

Code

package   
{
  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.text.TextFormat;
   
public class ScreenText extends Sprite
{
  protected var displayText:TextField;  //// экземпляр класса текст
  protected var format:TextFormat;     //// экземпляр клааса форматирования класса
    
  public function ScreenText()  
  {
   displayText = new TextField();
   displayText.text = "0";                  //// задаем первоначальный текст счета "0"
   displayText.selectable = false;       //// делаем текст "невыбираемым"
   displayText.autoSize;                    //// авторазмер
   displayText.x = 0;
   displayText.y = 0;
     
   format = new TextFormat("Arial", 24);    //// задаем шрифт и размер
   displayText.setTextFormat(format);       //// атачим созданный формат текстовому полю
     
   addChild(displayText);
  }
    
  public function setScore(newscore:String):void    //// здесь мы создадим публичную (общедоступную) функцию изменения текста
  {
   this.displayText.text = newscore;
   format = new TextFormat("Arial", 24);
   displayText.setTextFormat(format);
  }
    
}

}

Теперь осталось добавить экземпляр ScreenText'а в нашу игру:

Code

private var scoreLabel:ScreenText;    /// создаем компоненту
private var playerScore:int = 0;        /// создаем переменную счета для игрока

private function init():void
{
  Mouse.hide();
     
  player = new Paddle([0x00FF00, 0x0000FF]);
  player.x = 300;
  player.y = 430;
  stage.addChild(player);
     
  enemy = new Paddle([0xFF0000, 0xFF00FF]);
  enemy.x = 300;
  enemy.y = 50;
  stage.addChild(enemy);
     
  player.addEventListener(Event.ENTER_FRAME, movePlayer);
  enemy.addEventListener(Event.ENTER_FRAME, moveEnemy);
     
  ball = new Ball();
  ball.x = 350;
  ball.y = 410;
  stage.addChild(ball);
     
  [b]scoreLabel = new ScreenText(); /// инициируем
  scoreLabel.x = 15;                         /// задаем местоположение
  scoreLabel.y = 450;
  stage.addChild(scoreLabel);           /// обратите внимание на то что счет должен находить в самом верху списка отображения и перекрывать все игровые элементы, поэтому мы добавляем его на сцену последним[/b]
     
  ball.addEventListener(Event.ENTER_FRAME, moveBall);
}

Теперь мы имеем совершенно идентичные стороннему человеку компоненты созданные и работающие по-разному.
Осталось только добавить возможности прогирывать и выигрывать "сеты".

Для этого возвращаемся к функции движения мяча moveBall и меняем

Code

if (ball.y <= 0) {
  yDir *= -1;
}
else if (ball.y >= this.height - ball.height/2) {
  yDir *= -1;
}

на

Code

if (ball.y <= 0) {                            //// если мяч коснулся верхней части экрана
  ++playerScore;            //// увеличиваем счет игрока
  scoreLabel.setScore(playerScore.toString());   //// вызываем публичную функцию класса ScreenText и задем ей в качесвте параметра новый счет игрока
  resetBallPosition();     //// теперь надо начать новый "сет" при помощи вызова данной функции
}
else if (ball.y >= this.height - ball.height/2) {     //// если мяч коснулся нижней части экрана
  ++enemyScore;        //// увеличиваем лицевой счет компьютера, из-за привязки данных, увеличения значения переменной автоматически повлечет за собой увеличение значения тесктового поля созданой нами компаненты Label
  resetBallPosition();
}

Ну и простая функция новой игры, просто возвращающей первоначальные позиции элемнтам игры:

Code

private function resetBallPosition():void
{
  enemy.x = 300;
  ball.x = 350;
  ball.y = 410;
  xDir = 10;
  yDir = -10;
}

Ну и напоследок давайте добавим в нашу игру спецэффектов))

Откроем файл Ball.as и внесем ряд изменений в наш класс. Добавим 2 внутренние функции:

Code

public function glowBall(color:Array):void               /// в параметр функции подсветки мяча добавим массив цветов, для того чтобы иметь возможности присваивать различные цвета в зависимости от наших целей
{
  var gradientGlow:GradientGlowFilter = new GradientGlowFilter();  /// создаем новый экземпляр класса градиентного свечения
  gradientGlow.distance = 0;                    /// задаем различные параметры, поиграейте с ними, чтобы понять, что есть что  
  gradientGlow.angle = 45;
  gradientGlow.colors = color;
  gradientGlow.alphas = [0, 1];
  gradientGlow.ratios = [0, 255];
  gradientGlow.blurX = 50;
  gradientGlow.blurY = 50;
  gradientGlow.strength = 4;
  gradientGlow.quality = BitmapFilterQuality.MEDIUM;
  gradientGlow.type = BitmapFilterType.OUTER;
  this.filters = [gradientGlow];                    //// эффекты добавляются во внутренний маасив класса Sprite [b]filters[/b]
     
  var timer:Timer = new Timer(100, 1);                        //// создаем таймер отсчитывающий 100 милисекунд один раз
  timer.addEventListener(TimerEvent.TIMER_COMPLETE, unGlowBall);  //// по завершению таймера вызываем функцию затухания
  timer.start();   //// стартуем
}
    
protected function unGlowBall(e:TimerEvent):void
{
  this.filters = null;    //// "нуллим" массив тем самым убирая все эффекты
}

Обратите внимание на то, как осуществляется анимация свечения в данном случае. По скольку положение мяча просчитывается каждый кадр, то столкновение длиться не больше чем 1 секунда / 24 кадра в секунду. "Маловато будет!" (С). Поэтому мы используем анимацию по времени. Свечение в данном случае пропадет через 100 милисекунд после появления. Это обеспечит созданный нами таймер.

Теперь непосредственно добавим подсветку при столкновении мяча с препятствиями внутри функции moveBall:

Code

if (ball.x <= 0) {
  xDir *= -1;
  ball.glowBall([0x000000, 0x0000FF]); /// синяя подсветка для столкновения со стенками
}
else if (ball.x >= this.width - ball.width/2) {
  xDir *= -1;
  ball.glowBall([0x000000, 0x0000FF]);
}
if (ball.hitTestObject(player)) {
  yDir *= -1;
  ball.glowBall([0x000000, 0x00FF00]);  /// зеленая подсветка для столкновения с рокеткой игрока
  checkHitPosition(player);
}
else if (ball.hitTestObject(enemy)) {
  yDir *= -1;
  ball.glowBall([0x000000, 0xFF0000]);  /// красная подсветка для столкновения с рокеткой компьютера
  checkHitPosition(enemy);
}

Полный код Main.mxml (с измененными размерами экрана):

Code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application layout="absolute" width="700" height="500" frameRate="24" applicationComplete="init()" xmlns:mx="http://www.adobe.com/2006/mxml">
     <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 var scoreLabel:ScreenText;
   private var playerScore:int = 0;
   [Bindable]
   private var enemyScore:int = 0;
    
   private function init():void
   {
    Mouse.hide();
     
    player = new Paddle([0x00FF00, 0x0000FF]);
    player.x = 300;
    player.y = 430;
    stage.addChild(player);
     
    enemy = new Paddle([0xFF0000, 0xFF00FF]);
    enemy.x = 300;
    enemy.y = 50;
    stage.addChild(enemy);
     
    player.addEventListener(Event.ENTER_FRAME, movePlayer);
    enemy.addEventListener(Event.ENTER_FRAME, moveEnemy);
     
    ball = new Ball();
    ball.x = 350;
    ball.y = 410;
    stage.addChild(ball);
     
    scoreLabel = new ScreenText();
    scoreLabel.x = 15;
    scoreLabel.y = 450;
    stage.addChild(scoreLabel);
     
    ball.addEventListener(Event.ENTER_FRAME, moveBall);
   }
    
   private function resetBallPosition():void
   {
    enemy.x = 300;
    ball.x = 350;
    ball.y = 410;
    xDir = 10;
    yDir = -10;
   }
    
   private function checkHitPosition(paddle:Paddle):void
   {
    var hitPercent:Number;
    var ballPosition:Number = ball.x - paddle.x;
     
    hitPercent = (ballPosition / (paddle.width - ball.width)) - .5;
    xDir = hitPercent * 20;
    yDir *= 1.04;
   }
    
   private function moveBall(e:Event):void
   {
     
    if (ball.x <= 0) {
     xDir *= -1;
     ball.glowBall([0x000000, 0x0000FF]);
    }
    else if (ball.x >= this.width - ball.width/2) {
     xDir *= -1;
     ball.glowBall([0x000000, 0x0000FF]);
    }
    if (ball.hitTestObject(player)) {
     yDir *= -1;
     ball.glowBall([0x000000, 0x00FF00]);
     checkHitPosition(player);
    }
    else if (ball.hitTestObject(enemy)) {
     yDir *= -1;
     ball.glowBall([0x000000, 0xFF0000]);
     checkHitPosition(enemy);
    }
    if (ball.y <= 0) {
     ++playerScore;
     scoreLabel.setScore(playerScore.toString());
     resetBallPosition();
    }
    else if (ball.y >= this.height - ball.height/2) {
     ++enemyScore;
     resetBallPosition();
    }
     
    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:Label id="escore" text="{enemyScore.toString()}" fontFamily="Arial" fontSize="24" x="15" y="15" width="60" height="35"/>
</mx:Application>

Полный код ScreenText.as:

Code

package   
{
  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.text.TextFormat;
   
  public class ScreenText extends Sprite
  {
   protected var displayText:TextField;
   protected var format:TextFormat;
    
   public function ScreenText()  
   {
    displayText = new TextField();
    displayText.text = "0";
    displayText.selectable = false;
    displayText.autoSize;
    displayText.x = 0;
    displayText.y = 0;
     
    format = new TextFormat("Arial", 24);
    displayText.setTextFormat(format);// .defaultTextFormat = format;
     
    addChild(displayText);
   }
    
   public function setScore(newscore:String):void
   {
    this.displayText.text = newscore;
    format = new TextFormat("Arial", 24);
    displayText.setTextFormat(format);
   }
    
  }

}

Полный код Ball.as:

Code

package   
{
  import flash.display.*;
  import flash.events.TimerEvent;
  import flash.geom.Matrix;
  import flash.filters.BitmapFilterQuality;
  import flash.filters.BitmapFilterType;
  import flash.filters.GradientGlowFilter;
  import flash.utils.Timer;
   
  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();
   }
    
   public function glowBall(color:Array):void
   {
    var gradientGlow:GradientGlowFilter = new GradientGlowFilter();
    gradientGlow.distance = 0;
    gradientGlow.angle = 45;
    gradientGlow.colors = color;
    gradientGlow.alphas = [0, 1];
    gradientGlow.ratios = [0, 255];
    gradientGlow.blurX = 50;
    gradientGlow.blurY = 50;
    gradientGlow.strength = 4;
    gradientGlow.quality = BitmapFilterQuality.MEDIUM;
    gradientGlow.type = BitmapFilterType.OUTER;
    this.filters = [gradientGlow];
     
    var timer:Timer = new Timer(100, 1);
    timer.addEventListener(TimerEvent.TIMER_COMPLETE, unGlowBall);
    timer.start();
   }
    
   protected function unGlowBall(e:TimerEvent):void
   {
    this.filters = null;
   }
    
  }

}

Компилим, играем.

B1z ©

B1zDelKinДата: Суббота, 23 Января 2010, 15:32 | Сообщение # 24 | Тема: Flex и ActionScript 3.0 для создания мини-флеш игр. Часть 2
частый гость
Сейчас нет на сайте
В данном уроке мы создадим простую игру, являющуюся внебрачным сыном арканоида и пинг-понга.
Суть игры в том, чтобы отбить мячик до того как он коснется вашей стороны экрана. На другой стороне нам оппонирует компьютерный игрок, занимающийся аналогичным делом.

Для этого нам понадобится создать 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 Января 2010, 15:36
B1zDelKinДата: Пятница, 22 Января 2010, 11:22 | Сообщение # 25 | Тема: Flex и ActionScript 3.0 для создания мини-флеш игр. Часть 1
частый гость
Сейчас нет на сайте
Для создания игр ака Братья Марио, Пэкмен, Паззл или Мемория в среде Flash в основном использутся программы Flash CS*вписать нужное число* и ей подобные. Разумеется, среда Flex обладает не меньшим (а значительно большим) потенциалом для такой работы.

Однако, исследуя данный вопрос на бескрайних просторах интернета, обнаружил, что тема освещена достаточно неважно. Между тем, использование этих знаний существенно повысит мощь создаваемых Вами Flex-приложений. Раз мы здесь говорим о ГемДев'е... то это могут быть и мини-игры для ващей браузерной игры, чтобы игрокам не было скучно во время каких-то действий, или даже основой для вашей игры.

В данной серии уроков, будет пройден путь от простой экранной стрелялки до простой карты-квеста для создаваемой в данном разделе Ассасином игры (с его согласия ессно).

Для работы будет использоваться бесплатная оболочка для среды Flex - Flash Develop.
Вся графика в уроках будет создаваться программным путем, но Вы вправе пользоваться чем угодно.

Настоятельно рекомендую перед чтением данных (да и вообще любых уроков по AS3) уроков прочитать хоть что-нибудь про ActionScript 3.0. Литература представленна в соответсвующей прикрепленной теме данного раздела. И дело тут не в том, что я не собираюсь объяснять каждую запятую, просто мое ИМХО говорит мне, что человеку поленившемуся потратить день на прочтение нужной книги, данные уроки не нужны, не помогут, да и в вообще игроделательная лихорадка у него пройдет вместе с подростковыми прыщами.

От себя порекомендую ознакомиться с трудами Джоба Макара (Jobe Makar) и посетить блог Метью Касперсона (Matthew Casperson).

В самом первом уроке мы создадим экранную стрелялку. Сначала нужно четко представить суть игры. Наша игра будет заключаться в следующем:

На экране в рандомном порядке будут появляться враги, которых нам нужно будет "убить" кликом мыши. Довольно просто.
Теперь подумаем, что нам для этого понадобиться?

Итак, вопрос на миллион рублей! "Что нам понадобиться для создания задуманной стрелялки?"
A ) - Уличная магия
B ) - Загадочный Бурундук
C ) - Два своих класса для курсора и врага
D ) - 2 билета на "Аншлаг-Аншлаг"

Если Вы ответили "С", то можете читать далее (остальным начать сначала).

Итак приступим. Открываем FD, создаем новый проект Flex, как нибудь его называем (н-р, ShootEmAll).
Теперь ПКМ на папке src и выбираем Add -> New Class.

В появившемся окне в поле Name пишем название нашего будущего класса, пусть это будет Cursor.
Далее напротив поля Base Class жмем на Browse и вписываем туда Sprite.

Жмем ок. FD автоматически создаст тело нашего будущего класса.
Класс Sprite - это базовый визуальный класс Flash. Поскольку наш курсор будет графическим объектом, он должен его раширять. На это указывает ключевое слово extends.

Теперь мы зададим внешний вид нашего курсора, это будет простой красный кружок.
Для этого в функции-конструкторе класса public function Cursor() вписываем следующий код:

Code

this.graphics.lineStyle(1);
this.graphics.beginFill(0xFF0000);
this.graphics.drawCircle(0, 0, 10);
this.graphics.endFill();

Курсор готов к использованию. Теперь повторим предыдущие шаги и создадим новый класс Enemy, символизирующий наего будущего врага (не забудем добавить ему расширение класса Sprite).

Теперь надо подумать о будущей логике нашего врага. Что мы от него хотим?
Прежде всего мы хотим, чтобы при клике враг "умирал", то есть исчезал со сцены.
Также мы добавим определенное поведение при наведении и уводе мыши на врага.

Но сначала нам так же, как и в случае с курсором нужно отобразить его:

Code

this.graphics.lineStyle(1);
this.graphics.beginFill(0x0000FF);
this.graphics.drawCircle(0, 0, 50);
this.graphics.beginFill(0x00FF00);
this.graphics.drawCircle(0, 0, 30);
this.graphics.beginFill(0xFFC000);
this.graphics.drawCircle(0, 0, 15);
this.graphics.endFill();

Теперь мы добавим оговоренные выше обработчики событий в конец функции-конструтора:

Code

this.addEventListener(MouseEvent.CLICK, killEnemy);
this.addEventListener(MouseEvent.MOUSE_MOVE, overEnemy);
this.addEventListener(MouseEvent.MOUSE_OUT, outEnemy);

Первый обработчик вызывает функцию killEnemy при обнаружении клика на себе данного экземпляра класса Enemy.
При этом происходит удаление экземпляра из списка отображения родительского объекта:

Code

protected function killEnemy(e:MouseEvent):void
{
  this.parent.removeChild(this);
}

Два других обработчика срабатывают при наведении и "уведении" мыши на врага и просто меняют степень его прозрачности:

Code

protected function overEnemy(e:MouseEvent):void
{
  this.alpha = .4;
}
    
protected function outEnemy(e:MouseEvent):void
{
  this.alpha = 1;
}

Теперь возьмемся за саму игру. Открываем наш Main.mxml и добавим созданный нами курсор:

Code

private var cursor:Cursor; // создаем экземпляр класса курсор

private function init():void
{
    
  cursor = new Cursor(); // инициируем курсор
  stage.addChild(cursor); // добавляем курсор в сцену   
  Mouse.hide(); // прячем стандартный курсор

                 stage.addEventListener(MouseEvent.MOUSE_MOVE, dragCursor); // заставляем курсор двигаться
  stage.addEventListener(MouseEvent.MOUSE_OUT, hideCursor);  //  если курсор выходит за пределы экрана игры - прячем
  stage.addEventListener(MouseEvent.MOUSE_OVER, showCursor);  // если курсор возвращается на экран - показываем
}

Думаю тут все ясно. Функции для обработчиков событий предельно просты:

Code

private function dragCursor(event:MouseEvent):void
{
  cursor.x = this.mouseX;
  cursor.y = this.mouseY;
}
    
private function hideCursor(event:MouseEvent):void
{
  cursor.alpha = .0;
}
    
private function showCursor(event:MouseEvent):void
{
  cursor.alpha = .75;
}

Теперь поговорим о врагах в нашей игре. Враги буду появляться в рандомно выбраном месте игрового экрана каждые 1000 мсек. Для этого мы воспользуемся таймером:

Code

private var enemyMaker:Timer; // таймер для вызова функции создания врага
private var enemyCount:int; // числовая переменная равняющася количеству врагов появящихся на экране

private function init():void
{
     
  [b]enemyCount = 10;
     
  enemyMaker = new Timer(1000, enemyCount); // инициируем таймер с количеством повторений равынм количеству врагов
  enemyMaker.addEventListener(TimerEvent.TIMER, createEnemy); // каждую секунду вызываем функцию createEnemy
  enemyMaker.start(); //  стартуем счетчик [/b]  
     
  cursor = new Cursor();
  stage.addChild(cursor);
     
  Mouse.hide();
     
  stage.addEventListener(MouseEvent.MOUSE_MOVE, dragCursor);
  stage.addEventListener(MouseEvent.MOUSE_OUT, hideCursor);
  stage.addEventListener(MouseEvent.MOUSE_OVER, showCursor);
     
}

Теперь сама функция создания врагов:

Code

private function createEnemy(event:TimerEvent):void
{
  var enemy:Sprite; // так как класс Enemy расширяет класс Sprite то мы можем для создания экземпляра врага использовать родительсткй класс
  enemy = new Enemy(); // а при инициации мы конкретно указываем экземпляром какого класса будет являться объект и соответсвенно какие свойства и методы ему будут доступны
   
                 enemy.x = Math.random() * stage.stageWidth; // задаем х врага рандомной значение по ширине сцены, ты же операции предстоит и для оси ординат
   
                 //// далее для х и у вводятся ограничения на местоположение, во избежание половинчатости врага
    
  if (enemy.x <= 50) {   
   enemy.x = 51;  
  }
  else if (enemy.x >= 450) {
   enemy.x = 449;
  }
     
  enemy.y = Math.random() * stage.stageHeight;
     
  if (enemy.y <= 50) {
   enemy.y = 51;  
  }
  else if (enemy.y >= 450) {
   enemy.y = 449;
  }
     
  stage.addChild(enemy); /// ну и наконец после того как все параметры врага заданы - добавляем его на сцену игры
     
}

Полный код Main.mxml

Code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="500" height="500" layout="absolute" applicationComplete="init()">
  <mx:Script>
   <![CDATA[
   import flash.display.DisplayObject;
         import flash.display.Sprite;
   import flash.events.MouseEvent;
   import flash.events.TimerEvent;
   import flash.utils.Timer;
    
   private var cursor:Cursor;
    
   private var enemyMaker:Timer;
   private var enemyCount:int;
    
     
   private function init():void
   {
     
    enemyCount = 10;
     
    enemyMaker = new Timer(1000, enemyCount);
    enemyMaker.addEventListener(TimerEvent.TIMER, createEnemy);
    enemyMaker.start();
     
    cursor = new Cursor();
    stage.addChild(cursor);
     
    Mouse.hide();
     
    stage.addEventListener(MouseEvent.MOUSE_MOVE, dragCursor);
    stage.addEventListener(MouseEvent.MOUSE_OUT, hideCursor);
    stage.addEventListener(MouseEvent.MOUSE_OVER, showCursor);
     
   }
    
   private function dragCursor(event:MouseEvent):void
   {
    cursor.x = this.mouseX;
    cursor.y = this.mouseY;
   }
    
   private function hideCursor(event:MouseEvent):void
   {
    cursor.alpha = .0;
   }
    
   private function showCursor(event:MouseEvent):void
   {
    cursor.alpha = .75;
   }
    
   private function createEnemy(event:TimerEvent):void
   {
    var enemy:Sprite;
    enemy = new Enemy();
    enemy.x = Math.random() * stage.stageWidth;
     
    if (enemy.x <= 50) {
     enemy.x = 51;  
    }
    else if (enemy.x >= 450) {
     enemy.x = 449;
    }
     
    enemy.y = Math.random() * stage.stageHeight;
     
    if (enemy.y <= 50) {
     enemy.y = 51;  
    }
    else if (enemy.y >= 450) {
     enemy.y = 449;
    }
     
    stage.addChild(enemy);
     
   }
    
   ]]>
  </mx:Script>
   
</mx:Application>

Полный код Cursor.as

Code

package   
{
  import flash.display.Sprite;
   
  public class Cursor extends Sprite
  {
    
   public function Cursor()  
   {
    this.graphics.lineStyle(1);
    this.graphics.beginFill(0xFF0000);
    this.graphics.drawCircle(0, 0, 10);
    this.graphics.endFill();
   }
    
  }

}

Полный код Enemy.as

Code

package   
{
  import flash.display.Sprite;
  import flash.events.MouseEvent;
   
  public class Enemy extends Sprite
  {
    
   public function Enemy()  
   {
    this.graphics.lineStyle(1);
    this.graphics.beginFill(0x0000FF);
    this.graphics.drawCircle(0, 0, 50);
    this.graphics.beginFill(0x00FF00);
    this.graphics.drawCircle(0, 0, 30);
    this.graphics.beginFill(0xFFC000);
    this.graphics.drawCircle(0, 0, 15);
    this.graphics.endFill();
     
    this.addEventListener(MouseEvent.CLICK, killEnemy);
    this.addEventListener(MouseEvent.MOUSE_MOVE, overEnemy);
    this.addEventListener(MouseEvent.MOUSE_OUT, outEnemy);
   }
    
   protected function killEnemy(e:MouseEvent):void
   {
    this.parent.removeChild(this);
   }
    
   protected function overEnemy(e:MouseEvent):void
   {
    this.alpha = .4;
   }
    
   protected function outEnemy(e:MouseEvent):void
   {
    this.alpha = 1;
   }
  }

}

Компилим, играем.

B1z ©

B1zDelKinДата: Понедельник, 11 Января 2010, 10:41 | Сообщение # 26 | Тема: Урок по созданию браузерной игры №10
частый гость
Сейчас нет на сайте
Добавим немного красоты.

Code

<?xml version="1.0" encoding="utf-8"?>   
<mx:Application layout="absolute" width="800" height="450" backgroundImage="img/bg01.jpg" xmlns:mx="http://www.adobe.com/2006/mxml">   
         <mx:Script><![CDATA[   
      import mx.managers.PopUpManager;
      import mx.effects.*;   
            
      public function mstrUp():void {   
            
      }   
           
      public function npcUp():void {   
       /*var popupQuest:quest = quest(PopUpManager.createPopUp(this, quest, false));   
       popupQuest.x = 210;   
       popupQuest.y = 100;   
       popupQuest.title = "Виктория";*/   
      }   
            
      ]]></mx:Script>
      <mx:Glow id="glowImage" duration="250"   
      alphaFrom="1" alphaTo=".3"
      blurXFrom="0.0" blurXTo="50"
      blurYFrom="0.0" blurYTo="50"
      color="0x00FF00"/>
     
      <mx:Glow id="unglowImage" duration="250"   
      alphaFrom=".3" alphaTo="1.0"
      blurXFrom="50.0" blurXTo="0.0"
      blurYFrom="50.0" blurYTo="0.0"
      color="0x00FF00"/>   

         <mx:Image id="mstr" click="mstrUp()" source="img/monster.png" x="388" y="236" width="150" height="200" mouseDownEffect="{glowImage}" mouseUpEffect="{unglowImage}" rollOverEffect="{glowImage}" rollOutEffect="{unglowImage}"/>   
         <mx:Image id="npc" click="npcUp()" source="img/npc.png" x="63" y="172" width="150" height="200" mouseDownEffect="{glowImage}" mouseUpEffect="{unglowImage}" rollOverEffect="{glowImage}" rollOutEffect="{unglowImage}"/>   
</mx:Application>


Сообщение отредактировал B1zDelKin - Понедельник, 11 Января 2010, 10:42
B1zDelKinДата: Воскресенье, 10 Января 2010, 16:27 | Сообщение # 27 | Тема: Урок по созданию браузерной игры № 11
частый гость
Сейчас нет на сайте
Аналогично колега (с)
B1zDelKinДата: Среда, 06 Января 2010, 17:07 | Сообщение # 28 | Тема: Урок по созданию браузерной игры № 11
частый гость
Сейчас нет на сайте
Проверил, в FD Application.application работает. FlexGlobals более новая и чуть более функциональная фича, но в данном случае это не играет никакой роли.

Добавлено (06.01.2010, 17:07)
---------------------------------------------
Пожалуй добавлю конкретный пример с некоторыми косметическими изменениями, иллюстрирующий использование.

Код аналога GameWindow :

Code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600" height="400">
     <mx:Script>
   <![CDATA[
   import mx.core.IFlexDisplayObject;  
   import mx.managers.PopUpManager;
    
   private var popup:IFlexDisplayObject; // создаем переменную для всплывающего окна
    
   //// функция вызова окна, принимающая аргумент, указывающий на компаненту окна (н-р, profil, inventar)
    
   public function callPOPUP(win:Class): void  
   {
    PopUpManager.removePopUp(popup); // если окно было вызвано - убираем (во избежание открытия множества одинаковых)
    popup = PopUpManager.createPopUp(this,win,false);  // вызываем новое
    PopUpManager.centerPopUp(popup);  // центрируем окно
   }
     
   ]]>
  </mx:Script>
     <mx:SWFLoader x="200" y="100" width="200" height="200" source="GameField.swf" />
</mx:Application>

Тут я счел удобным создать одну переменную для хранения всплывающих окон. Во-первых, это позволяет использовать одну переменную для всех окон в игре (экономия кода). Во-вторых, не позволяет замусорить игровое просторанство (также вопрос безопасности: возникновение различных глюков связанных с манипуляциями в нескольких окнах). Но, если требуется, то всегда можно создать несколько переменных по типу (н-р, npc, traders, char_info и тд) или для каждого окна отдельно.

Код игрового поля, аналога GameField :

Code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application width="200" height="200" xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:Script><![CDATA[
   public function gotoPOPUP(win:Class): void  
   {
    Application.application.callPOPUP(win); // вызываем функцию из GameWindow
   }
   ]]></mx:Script>
     <mx:Button label="Профиль" click="gotoPOPUP(popupEx)" x="52" y="34" width="100" height="22"/>
     <mx:Button label="Инвентарь" click="gotoPOPUP(popupEx)" x="52" y="69" width="100" height="22"/>
     <mx:Button label="Квесты" click="gotoPOPUP(popupEx)" x="51" y="109" width="100" height="22"/>
</mx:Application>

click="gotoPOPUP(popupEx)" агрументом данной функции является имя компоненты-окна, которое мы собираемся вызвать. В данном случая это должны быть profil, inventar, quests.

B1zDelKinДата: Воскресенье, 03 Января 2010, 13:34 | Сообщение # 29 | Тема: Урок по созданию браузерной игры № 11
частый гость
Сейчас нет на сайте
Действительно. Но способ обратиться к методам GameWindow явно не один.
Флекса не знаю, рытье в референсах дало только этот способ... может parent, parentApplication или parentDocument

Добавлено (03.01.2010, 13:34)
---------------------------------------------
FlexGlobals.topLevelApplication.gotoNPC();

на:

Application.application.gotoNPC();

B1zDelKinДата: Пятница, 18 Декабря 2009, 14:03 | Сообщение # 30 | Тема: Урок по созданию браузерной игры № 11
частый гость
Сейчас нет на сайте
Тем не менее, как то трудно верится что это именно "невозможно" (хотя гугль пытается уверить, что никто до нас не пытался вызывать окошки из разных флешек smile ).

Решил протестить сей момент на Flex sdk 4... и о чудо! Окошки всплывают согласно здравому смыслу.
Думается, что Адоб, усердно ратующие за использование мульти-свф для большей интерактивности и разделения обновляемого контента, вряд ли забыло о всплывающих окнах. Выход должен быть... хотя возможно это "using flex 4" smile

Добавлено (18.12.2009, 14:03)
---------------------------------------------
Помещаем все функции вызова в GameWindow.mxml (н-р функция gotoNPC() )
На их место помещаем функцию следующего вида:
public function callNPC():void
{
FlexGlobals.topLevelApplication.gotoNPC();
}
и добовим в импорты import mx.core.FlexGlobals;

Теперь все окошки будут всплывать из одной флешки и у ним можно будет применять все методы.

Сообщение отредактировал B1zDelKin - Среда, 16 Декабря 2009, 14:09
B1zDelKinДата: Вторник, 15 Декабря 2009, 21:11 | Сообщение # 31 | Тема: Урок по созданию браузерной игры № 11
частый гость
Сейчас нет на сайте
У меня возникла проблема с открытием всплывающих окон. В браузере они иногда либо вовсе не грузятся (помогает только F5), либо грузится только какая-то одна из флешек (квест из игрового поля или н-р профиль из меню).

Не было ли у Вас таких проблем, и мб подскажете в чем может быть загвоздка?

С уважением

Форум игроделов » Записи участника » B1zDelKin [31]
  • Страница 2 из 2
  • «
  • 1
  • 2
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг