Adobe Flash 11 Stage3D (Molehill) game programming (Chapter 6 - 10) / Программирование игр в Adobe Flash 11 Stage3D (Molehill) (Глава 6 - 10): Мир, наполненный действием

← →
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

Время спроектировать мир и заполнить его смертельными врагами!
Предпоследний шаг в нашем приключении - создать специфические игровые классы, которые конкретизируют мир и позволят создание простых уровней. Мы также должны быть способны создавать сущности, которые движутся и реагируют на игрока и знают когда они сталкиваются.

Orion45 09.05.14 в 08:05

0

Для того, чтобы сделать законченную, безупречную и играбельную 3D игру, нам нужно больше, чем просто функциональность рендеринга. Мы будем программировать путём создания сложного игрового мира, рисуя уровне в редакторе изображений вместо того, чтобы вручную помещать их в исходный код.

Orion45 09.05.14 в 08:09

0

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

Orion45 10.05.14 в 14:25

0

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

Orion45 10.05.14 в 14:32

0

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

Orion45 11.05.14 в 09:01

0

Расширение класса сущностей для "действиющих лиц".
Наш класс Stage3dEntity - класс общего назначения для рендеринга мешей, который хорош для любого вида игровой сущности. Он простой и быстрый и содержит всю полезную вспомогательную функциональность, чтобы позволить нам перемещать объекты, манипулировать поворотами и т.д.

Orion45 11.05.14 в 09:07

0

Основать более продвинутый класс на этом классе - умная идея, потому что это сохраняет один оригинальный класс, чтобы он не стал слишком запутанным и избавляет от необходимости "раздутого" класса, который содержит все классы, делающие всё. Мы сделаем специализированный класс, который расширяет Stage3dEntity, который имеет специфичную игровую функциональность, прекрасно подходящую для таких вещей как пули и космические корабли.
Время для действий - создаём игровой класс действующего лица
Создайте новый файл под именем GameActor.as в вашей папке исходного кода и начните с расширения класса Stage3dEntity некоторыми новыми фантастическими свойствами следующим образом:

Orion45 13.05.14 в 18:07

0

// игровой класс действующего лица версия 1.1
// сущность которая может перемещаться, стрелять, создавать частицы
// запускать звуки и обнаруживать столкновения
//
package
{
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.display3D.Context3D;
import flash.display3D.Program3D;
import flash.display3D.textures.Texture;
import flash.media.Sound;
public class GameActor extends Stage3dEntity
{
// связанные с игрой состояния
public var name:String = ''; // уникальный
public var classname:String = ''; // не уникальный

Orion45 13.05.14 в 18:10

0

public var owner:GameActor; // так вы не можете стрелять сами
public var touching:GameActor; // последнее столкновение обнаружено
public var active:Boolean = true; // анимировать?
public var visible:Boolean = true; //рендерить?
public var health:Number = 1; //когда ноль, умер
public var damage:Number = 250; // связана с другими
public var points:Number = 25; // зарабатываем очки, если разрушено
public var collides:Boolean = false; // проверять столкновения?
public var collidemode:uint = 0; // 0=sphere, 1=aabb
public var radius:Number = 1; // используется для столкновения сфер
public var aabbMin:Vector3D = new Vector3D(1, 1, 1, 1);
public var aabbMax:Vector3D = new Vector3D(1, 1, 1, 1);

Orion45 13.05.14 в 18:13

0

Что же произошло?
В предыдущем коде мы определили несколько удобных свойств класса. Некоторые - ссылки на другие GameActors, такие как владелец свойства которое может быть использовано, например, что очки заработанные при разрушении чего-либо, относятся к тому, кто стреляет конкретной пулей. Свойство здоровья используется всякий раз, когда пуля попадает в нас - чем выше это число, тем больше раз действующее лицо должно будет стрелять, прежде чем это взорвётся.

Orion45 14.05.14 в 16:41

0

Время для действий - расширяем свойства действующего лица
Давайте добавим ещё несколько свойств, чтобы действительно конкретизировать наш игровой класс, следующим образом:
//функции колбэков
public var runConstantly:Function;
public var runConstantlyDelay:uint = 1000;
public var runWhenNoHealth:Function;
public var runWhenMaxAge:Function;
public var runWhenCreated:Function;
// переменные, связанные со временем
public var age:uint = 0;
public var ageMax:uint = 0;
public var stepCounter:uint = 0;
// переменные анимации в единицах в СЕКУНДУ (1000ms)
public var posVelocity:Vector3D;
public var rotVelocity:Vector3D;
public var scaleVelocity:Vector3D;
public var tintVelocity:Vector3D;
// автоматически стреляет пулями когда враг поблизости
public var bullets:GameActorpool;
public var shootName:String = '';
public var shootDelay:uint = 4000;

Orion45 14.05.14 в 16:46

0

public var shootNext:uint = 0;
public var shootRandomDelay:Number = 2000;
public var shootDist:Number = 100;
public var shootAt:GameActor = null;
public var shootVelocity:Number = 50;
public var shootSound:Sound;
// частицы создания
public var particles:GameParticlesystem;
public var spawnConstantly:String = '';
public var spawnConstantlyDelay:uint = 0;
public var spawnConstantlyNext:uint = 0;
public var spawnWhenNoHealth:String = '';
public var spawnWhenMaxAge:String = '';
public var spawnWhenCreated:String = '';
// звуковые эффекты
public var soundConstantlyDelay:uint = 1000;
public var soundConstantlyNext:uint = 0;
public var soundConstantly:Sound;
public var soundWhenNoHealth:Sound;
public var soundWhenMaxAge:Sound;
public var soundWhenCreated:Sound;

Orion45 14.05.14 в 16:47

0

Что же произошло?
Эти переменные очень удобны и приносят глубину и геймплей в вашу игру. Например, вы могли бы установить звук, чтобы он играл каждый раз, когда вы разрушаете космический корабль или определяете частицу, которую вы хотите, чтобы сущность производила каждые несколько миллисекунд, такую как клубы дыма, выходящие из повреждённого корабля.

Orion45 14.05.14 в 16:52

0

Время для действий - программируем конструктор класса GameActor
Давайте продолжим и установим новый класс и всю функциональность, обещанную этими новыми свойствами.
public function GameActor(mydata:Class = null,
mycontext:Context3D = null,
myshader:Program3D = null,
mytexture:Texture = null,
modelscale:Number = 1,
flipAxis:Boolean = true,
flipTexture: Boolean = true)
{
super(mydata, mycontext, myshader, mytexture,
modelscale, flipAxis, flipTexture);
}

Orion45 14.05.14 в 16:55

0

Что же произошло?
Конструктор класса в предыдущем коде просто запускает оригинальную версию конструктора, который определён в нашем старом классе Stage3dEntity. Это сделано вызовом "super", который ссылается на конструктор класса, который мы расширили (Stage3dEntity). Как всегда обратите внимание, что параметры flipAxis и flipTexture, которые инструктируют OBJfile парсер перевёрнуты ли или нет данные в вашей модели, что обычно случается только в старых экспортёрах, таких как тот, что используется в 3D Studio Max 9. Более новые версии как правило не нуждаются в том, чтобы это было установлено на TRUE, так что если вы имеете проблемы с вашей моделью, которая выглядит "вывернутой наизнанку", попробуйте различные значения для них и ваша проблема исчезнет.

Orion45 15.05.14 в 12:32

0

Время для действий - создание функции пошаговой анимации
Теперь мы можем создать пошаговую функцию, которая запускается каждый кадр в нашем цикле рендеринга следующим образом:
public function step(ms:uint):void
{
if (!active) return;
age += ms;
stepCounter++;
if (health <= 0)
{
//trace(name + " out of health.");
if (particles && spawnWhenNoHealth)
{
trace(name + " exploding into " + spawnWhenNoHealth);
var spawnxform:Matrix3D = new Matrix3D();
spawnxform.position = position.clone();
//particles.spawn(spawnWhenNoHealth,transform);
particles.spawn(spawnWhenNoHealth,spawnxform,5555,0,10);
}
if (soundWhenNoHealth)
soundWhenNoHealth.play();
if (runWhenNoHealth != null)
runWhenNoHealth();
die();
return;
}
if ((ageMax != 0) && (age >= ageMax))
{
//trace(name + " old age.");

Orion45 15.05.14 в 13:57

0

if (particles && spawnWhenMaxAge)
particles.spawn(spawnWhenMaxAge, transform);
if (soundWhenMaxAge)
soundWhenMaxAge.play();
if (runWhenMaxAge != null)
runWhenMaxAge();
die();
return;
}

Orion45 15.05.14 в 13:57

0

Что же произошло?
Предыдущий код просто обновляет возраст действующего лица и выполняет всё, что требуется для этого, если был установлен максимальный возраст. Легко убедиться, что пули, например, не летят вперёд вечно, если они ни с чем ни сталкиваются. Если действующее лицо умирает (кончается здоровье), тогда мы, по желанию, генерируем систему частиц и запускаем функцию обратного вызова, если это было установлено. Эта функция обратного вызова может быть использована, чтобы запустить звук, начислить игроку очки или оповестить об окончании уровня.

Orion45 17.05.14 в 07:13

0

Время для действий - анимируем действующие лица
Далее, мы обращаемся к основной анимации, которая может быть установлена, когда мы создаём новое действующее лицо. Это может включать постоянное движение, так что она летит вперёд, или вы могли бы установить астероид, чтобы он медленно вращался каждый кадр или пузырь увеличивался в размерах с течением времени. Добавить следующий код в вашу функцию step():

Orion45 17.05.14 в 07:37

0

if (posVelocity)
{
x += posVelocity.x * (ms / 1000);
y += posVelocity.y * (ms / 1000);
z += posVelocity.z * (ms / 1000);
}
if (rotVelocity)
{
rotationDegreesX += rotVelocity.x * (ms / 1000);
rotationDegreesY += rotVelocity.y * (ms / 1000);
rotationDegreesZ += rotVelocity.z * (ms / 1000);
}
if (scaleVelocity)
{
scaleX += scaleVelocity.x * (ms / 1000);
scaleY += scaleVelocity.y * (ms / 1000);
scaleZ += scaleVelocity.z * (ms / 1000);
}

Orion45 17.05.14 в 07:37

0

Реализация искусственного интеллекта (ИИ)
Все игры имеют что-то из искусственного интеллекта. Вам могут понадобиться враги, которые будут следовать за игроком, избегать препятствий или даже составлять сложные стратегии. ИИ является предметом достаточно глубоким, чтобы гарантировать целую серию книг и огромные ресурсы, доступные онлайн, чтобы вести вас дальше по пути проектирования автономных действующих лиц в вашей игре.

Orion45 17.05.14 в 13:07

0

Для наших целей мы определим чрезвычайно простое поведение для врагов в игре. Нам нужно дать нашей игровой сущности механизм, чтобы отслеживать прошедшее время, так что наши действия могут быть разделены соответствующим образом. Простое "восприятие" в форме географической осведомлённости для наших плохих парней позволит им решать, когда хорошее время, чтобы стрелять в игрока.

Orion45 19.05.14 в 17:17

0

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

Orion45 19.05.14 в 17:24

0

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

Orion45 20.05.14 в 14:35

0

// может генерироваться новую частица
if (visible && particles && spawnConstantlyDelay > 0)
{
if (spawnConstantly != '')
{
if (age >= spawnConstantlyNext)
{
//trace("actor spawn " + spawnConstantly);
spawnConstantlyNext =
age + spawnConstantlyDelay;
particles.spawn(spawnConstantly, transform);
}
}
}
// может вызываться звук
if (visible && soundConstantlyDelay > 0)

Orion45 20.05.14 в 14:36

0

{
if (soundConstantly)
{
if (age >= soundConstantlyNext)
{
soundConstantlyNext =
age + soundConstantlyDelay;
soundConstantly.play();
}
}
}

Orion45 20.05.14 в 14:36

0

Время для действий - стреляем в врагов
"выстрел" ИИ - то же самое, что и выше, но с небольшой дополнительной сложностью: действующие лица будут стрелять только во врагов, которые находятся в пределах определённой ограниченной дистанции, если враг был обнаружен.
Продолжим, добавив в функцию step() следующее:

Orion45 20.05.14 в 14:42

0

// может быть "выстрел" (порождается игроком)
if (visible && bullets && (shootName != ''))
{
var shouldShoot:Boolean = false;
if (age >= shootNext)
{
shootNext = age + shootDelay +
(Math.random() * shootRandomDelay);
if (shootDist < 0)
shouldShoot = true;
else if (shootAt &&
(shootDist > 0) &&
(Vector3D.distance(
position, shootAt.position) <= shootDist))
{
shouldShoot = true;
}
if (shouldShoot)
{
var b:GameActor =
bullets.spawn(shootName, transform);
// запоминаем кому эта пуля принадлежит
b.owner = this;

Orion45 20.05.14 в 14:44

0

// целимся на врага?
if (shootAt)
{
b.transform.pointAt(
shootAt.transform.position);
b.rotationDegreesY -= 90;
b.posVelocity =
b.transform.position.subtract(
shootAt.transform.position);
b.posVelocity.normalize();
b.posVelocity.negate();
b.posVelocity.scaleBy(shootVelocity);
}
// иначе мы просто стреляем куда угодно
// направление было дано во время генерации
// когда игра установила posVelocity
if (shootSound)
shootSound.play();
}
}
}
} // конец функции step

Orion45 20.05.14 в 14:48

0

Что же произошло?
Это всё, что нужно для нашей фантастической новой пошаговой функции GameActor. Как вы можете видеть, она добавляет изобилие разнообразию геймплея в ваш мешок трюков. Мы просто реализовали анимацию действующего лица, приурочили ко времени события, такие как проигрывание звуков или излучение эффекта частиц и поведение ИИ для стрельбы в врагов когда они поблизости.

Orion45 21.05.14 в 17:29

0

Это функция могла бы быть очень легко расширена, чтобы реагировать различно, в зависимости от того, какой вид объекта поблизости. Например, вообразите игру с трусливым врагом, который отступает, если сталкиваются со слишком сильным оппонентом, всегда двигается к ближайшему бонусу, меняя направление случайным образом каждые несколько секунд, или того, кто бросает бомбы замедленного действия (или "следы") через установленные интервалы.

Orion45 22.05.14 в 17:42

0

Время для действий - клонируем действующее лицо.
Следующая функция очень проста, но удобна: функция клонирования. Мы хотим быть способны клонировать исходное определение типа действующего лица (так что мы можем инструктировать игровой движок какой "злой гоблин" есть и затем легко порождать множество копий) прямо как мы это делали для частиц.

Orion45 22.05.14 в 17:47

0

Мы не хотим копировать каждое отдельное свойство, так как мы не хотим повторять в цикле каждую отдельную переменную, определённую в нашем классе. Нам также нужно клонировать Matrix3Ds, вместо того, чтобы делиться ссылками между клонами, так что перемещение одного действующего лица не заставит нечаянно другое двигаться также. Поэтому нам нужно вручную скопировать данные как нужно.

Orion45 22.05.14 в 17:53

0

public function cloneactor():GameActor
{
var myclone:GameActor = new GameActor();
updateTransformFromValues();
myclone.transform = this.transform.clone();
myclone.updateValuesFromTransform();
myclone.mesh = this.mesh;
myclone.texture = this.texture;
myclone.shader = this.shader;
myclone.vertexBuffer = this.vertexBuffer;
myclone.indexBuffer = this.indexBuffer;
myclone.context = this.context;
myclone.polycount = this.polycount;
myclone.blendSrc = this.blendSrc;
myclone.blendDst = this.blendDst;
myclone.cullingMode = this.cullingMode;
myclone.depthTestMode = this.depthTestMode;
myclone.depthTest = this.depthTest;
myclone.depthDraw = this.depthDraw;
// связанные с игрой состояния
myclone.name = this.name;
myclone.classname = this.classname;
myclone.owner = this.owner;

Orion45 22.05.14 в 17:53

0

myclone.active = this.active;
myclone.visible = this.visible;
myclone.health = this.health;
myclone.damage = this.damage;
myclone.points = this.points;
myclone.collides = this.collides;
myclone.collidemode = this.collidemode;
myclone.radius = this.radius;
myclone.aabbMin = this.aabbMin.clone();
myclone.aabbMax = this.aabbMax.clone();

Orion45 22.05.14 в 17:53

0

// функция обратного вызова
myclone.runConstantly = this.runConstantly;
myclone.runConstantlyDelay = this.runConstantlyDelay;
myclone.runWhenNoHealth = this.runWhenNoHealth;
myclone.runWhenMaxAge = this.runWhenMaxAge;
myclone.runWhenCreated = this.runWhenCreated;
// связанные с временем переменные
myclone.age = this.age;
myclone.ageMax = this.ageMax;
myclone.stepCounter = this.stepCounter;
// связанные с анимацией переменные - в мс.
myclone.posVelocity = this.posVelocity;
myclone.rotVelocity = this.rotVelocity;
myclone.scaleVelocity = this.scaleVelocity;
myclone.tintVelocity = this.tintVelocity;
// пули
myclone.bullets = this.bullets;
myclone.shootName = this.shootName;
myclone.shootDelay = this.shootDelay;
myclone.shootNext = this.shootNext;
myclone.shootRandomDelay = this.shootRandomDelay;
myclone.shootDist = this.shootDist;

Orion45 22.05.14 в 17:55

0

myclone.shootAt = this.shootAt;
myclone.shootVelocity = this.shootVelocity;
myclone.shootSound = this.shootSound;
// порождаемые частицы
myclone.particles = this.particles;
myclone.spawnConstantly = this.spawnConstantly;
myclone.spawnConstantlyDelay = this.spawnConstantlyDelay;
myclone.spawnConstantlyNext = this.spawnConstantlyNext;
myclone.spawnWhenNoHealth = this.spawnWhenNoHealth;
myclone.spawnWhenMaxAge = this.spawnWhenMaxAge;
myclone.spawnWhenCreated = this.spawnWhenCreated;
// звуковые эффекты
myclone.soundConstantlyDelay = this.soundConstantlyDelay;
myclone.soundConstantlyNext = this.soundConstantlyNext;
myclone.soundConstantly = this.soundConstantly;
myclone.soundWhenNoHealth = this.soundWhenNoHealth;
myclone.soundWhenMaxAge = this.soundWhenMaxAge;
myclone.soundWhenCreated = this.soundWhenCreated;
myclone.active = true;

Orion45 22.05.14 в 17:55

0

myclone.visible = true;
return myclone;
}

Orion45 22.05.14 в 17:56

0

Время для действий - управляем смертью действующего лица.
Функция смерти чрезвычайно проста и вызывается когда действующее лицо потратило всё здоровье или умирает "от старости". Так как мы будет в конечном счёте создавать "бассейн" действующих лиц, которые могут быть повторно использован во время игры, всё, что нам нужно сделать тут это "выключить" действующее лицо, так что в будущем игра сможет повторно использовать его. Этим способом, так как игрок разрушает вражеские корабли, например, будущие враги могут приходить из повторно используемого бассейна без дальнейшей инициализации или потребления памяти.
{
//trace(name + " dies!");
active = false;
visible = false;
}

Orion45 24.05.14 в 02:57

0

Время для действий - пересоздаём действующее лицо
Функция перерождения очень похожа на ту, что ту запрограммировали для нашего класса частиц. Она сбрасывает несколько ключевых свойств и заставляет до этого "мёртвые" или неактивные частицы возвращаться к жизни готовыми к повторному использованию. Как упоминалось ранее, это то, как бассейн действующих лиц сможет повторно использовать "мёртвое" действующее лицо, возвращая его обратно к "жизни":
public function respawn(pos:Matrix3D = null):void

Orion45 24.05.14 в 06:56

0

{
age = 0;
stepCounter = 0;
active = true;
visible = true;
// не стреляем сразу
shootNext = Math.random() * shootRandomDelay;
if (pos)
{
transform = pos.clone();
}
if (soundWhenCreated)
soundWhenCreated.play();
if (runWhenCreated != null)
runWhenCreated();
if (particles && spawnWhenCreated)
particles.spawn(spawnWhenCreated, transform);
//trace("Respawned " + name + " at " + posString());

Orion45 24.05.14 в 06:57

0

Обнаружение столкновений
Последняя функциональность, которую нам нужно реализовать в нашем классе действующего лица это то, что добавит итеративность в вашу игру как никто другой: столкновения! Способность обнаруживать коснулось ли действующее лицо другого это ключ к способности симулировать, например, пули. Обнаружение столкновений - тема достаточно широкая, чтобы оправдать свою собственную книгу, так что сейчас мы запрограммируем простейший алгоритм обнаружения столкновений.

Orion45 24.05.14 в 09:49

0

Для продвинутого обнаружения столкновений и ответной реакции (отскакивание, трение, столкновение со сложными формами) вы бы больше помогло использование настоящих физических движков, которые находятся за рамками этой книги и оставлены как упражнение для читателя.
Время для действий - обнаружение столкновений.
Сейчас мы создадим наши базовые, простейшие алгоритмы обнаружения столкновений.

Orion45 24.05.14 в 09:57

0

//использованный для обнаружения столкновений коллбэк выполненный в бассейне GameActor
public function colliding(checkme:GameActor):GameActor
{
if (collidemode == 0)
{
if (isCollidingSphere(checkme))
return checkme;
else
return null;
}
else
{
if (isCollidingAabb(checkme))
return checkme;
else
return null;
}
}

Orion45 24.05.14 в 09:59

0

Время для действий - обнаруживаем столкновений двух сфер.
Наша простая игра не должна делать ничего больше, кроме как обнаруживать как близко одно действующее лицо к другому основываясь на позиции трансформации и их радиусе. Это называется обнаружением столкновений двух сфер. Это быстро, просто для понимания и прекрасно подходит для примера shoot-em-up игры, которую мы создаём.

Orion45 24.05.14 в 10:05

0

//простое столкновение двух сфер
public function isCollidingSphere(checkme:GameActor):Boolean
{
// никогда не сталкивается с собой
if (this == checkme) return false;
// только проверяет, если эти сферы сталкиваемые
if (!collides || !checkme.collides) return false;
// don't check your own bullets
if (checkme.owner == this) return false;
// не проверять, если нет радиуса
if (radius == 0 || checkme.radius == 0) return false;
var dist:Number =
Vector3D.distance(position, checkme.position);
if (dist <= (radius+checkme.radius))
{
// trace("Collision detected at distance="+dist);
touching = checkme; // remember who hit us
return true;
}
// по умолчанию: слишком далеко
// trace("No collision. Dist = "+dist);
return false;
}

Orion45 24.05.14 в 10:08

0

Как вы можете видеть, предыдущая функция просто проверяет, чтобы убедиться если действующее лицо установлено беспокоиться о проверке столкновений и, если это так, измерение делается и возвращается результат.
Время для действий - обнаруживаем столкновения с границами коробки.
Для завершённости, хотя наш пример игры не будет использовать это, мы должны реализовать также столкновения для коробкообразной формы. Быстрейший и простейший способ сделать это называется aabb, который основан на выровненных по осям ограничивающих коробках. Термин "выровненный по осям" значит прямоугольник, определённый по минимальной и максимальной координатам никогда не поворачивающихся: это держится на "сетке" и используется, чтобы быстро определить, если один бокс коснулся другого.

Orion45 24.05.14 в 13:53

0

//выровненное по осям ограничительного бокса определение столкновений
//не используется в примере игры, но здесь для удобства
private function aabbCollision(
min1:Vector3D, max1:Vector3D,
min2:Vector3D, max2:Vector3D ):Boolean
{
if ( min1.x > max2.x ||
min1.y > max2.y ||
min1.z > max2.z ||
max1.x < min2.x ||
max1.y < min2.y ||
max1.z < min2.z )
{
return false;
}
return true;
}
public function isCollidingAabb(checkme:GameActor):Boolean
{
// никогда не сталкивается с собой
if (this == checkme) return false;
// только проверяет, могут ли эти формы сталкиваться
if (!collides || !checkme.collides) return false;
// не проверяйте ваши собственные пули
if (checkme.owner == this) return false;
// не проверять если нет данных aabb
if (aabbMin == null ||

Orion45 24.05.14 в 13:57

0

aabbMax == null ||
checkme.aabbMin == null ||
checkme.aabbMax == null)
return false;
if (aabbCollision(
position + aabbMin,
position + aabbMax,
checkme.position + checkme.aabbMin,
checkme.position + checkme.aabbMax))
{
touching = checkme; // remember who hit us
return true;
}
// trace("No collision.");
return false;
}
} // конец пакета
} // конец класса

Orion45 24.05.14 в 13:57

0

Это всё, что нужно для нашего богатого характеристиками, смутно умного, в вышей степени повторно используемого класса GameActor. Добавив всю эту функциональность в наш класс, который является производным от класса Stage3dEntity, мы сохранили отдельно код рендеринга и трансформации матрицы от высокоуровневой определённой для геймплея логики.

Orion45 24.05.14 в 14:04

0
Минутку...

Следующая страница →