Компьютерная анимация
Существует множество различных форматов файлов для обозначения, по сути, одних и тех же вещей. Картинки могут иметь расширение jpg или bmp, png или gif. Музыка может храниться в форматах mp3, wav, ogg, а видео в avi, mkv или mp4. И это лишь капля в море возможных форматов. Из всего этого получается, что для обработки каждого из форматов надо знать конкретно его внутреннюю структуру, принцип… Читать ещё >
Компьютерная анимация (реферат, курсовая, диплом, контрольная)
Ни для кого не секрет, что видео игры прочно заняли свою позицию в современной индустрии развлечений. Существуют попытки выделить компьютерные игры как отдельную область искусства, наряду с театром, кино и т. п. Разработка игр может оказаться не только увлекательным, но и прибыльным делом, примеров этому предостаточно в истории. Первые примитивные компьютерные и видео игры были разработаны в 1950;х и 1960;х годах. Они работали на таких платформах, как осциллографы, университетские мейнфреймы и компьютеры EDSAC. Самой первой компьютерной игрой стал симулятор ракеты, созданный в 1942 году Томасом Голдсмитом Младшим (англ. Thomas T. Goldsmith Jr.) и Истл Рей Менном (англ. Estle Ray Mann). Позже, в 1952 году, появилась программа «OXO», имитирующая игру «крестики-нолики», созданная А. С. Дугласом как часть его докторской диссертации в Кембриджском Университете. Игра работала на большом университетском компьютере, известном как EDSAC (Electronic Delay Storage Automatic Calculator). В настоящее время, разработка игры — это многомиллионный процесс, в котором задействована целая команда разработчиков, сложные современные технологии и даже маркетинговые ходы.
1. ТЕОРЕТИЧЕСКАЯ ЧАСТЬ
1.1 Особенности 2D графики в компьютерных играх
Система координат.
Двумерная система координат, предназначенная для представления графики в компьютерных играх, перевернута по отношению к обычной декартовой системе координат. Т. е. начало этой системы координат находится в левом верхнем углу экрана. Такая практика, кстати, была введена еще на этапе становления первых «устройств вывода» типа монитор. Положительная ось Х проходит по верхней кромке экрана слева направо, а положительная ось Y — сверху вниз по левой боковой стороне экрана.
Отрицательная часть обеих осей координат лежит за областью экрана монитора. Игровая графика, которая не попадает в область экрана, отсекается и не участвует в построении сцены.
Ключевым понятием в двухмерной графике является спрайт.
Спрайт — это простое двухмерное изображение, нарисованное в любом графическом редакторе и сохраненное в одном из графических форматов. Отображая на экране монитора спрайт необходимо понимать следующее условие. Любой спрайт — это изображение, которое заключено в прямоугольник, даже если в исходном изображении у Вас нарисован круг. Рисуя спрайт на экране, его начальной точкой отчета всегда будет оставаться верхний левый угол этого самого прямоугольника. Поэтому если Вы определяете, допустим, столкновения между спрайтами, то Вам необходимо знать ширину и высоту изображения, чтобы прибавить эти значения к начальной точке координат спрайта (левый верхний угол). Соответственно середина спрайта будет находиться в половине ширины и высоты графического изображения.
Важным моментом является порядок, в котором вы отображаете на экран что-либо, будь то спрайты, текст или что-нибудь еще. Если более профессионально и технически — то это порядок вызова методов отрисовки для разных игровых объектов.
Вектора — это структура данных, которая хранит в себе несколько вещественных чисел, логически связанных между собой. В компьютерной графике повсеместно используются три типа векторов — это Vector2, Vector3 и Vector4. Доступ к отдельным компонентам получается через {x, y}, {x, y, z}, {x, y, z, w} соответственно для каждого из векторов. Vector2, например, дает возможность задавать две координаты по осям X и Y для положения в пространстве в 2д играх, а Vector4 позволяет описать любой цвет в формате RGBA (к примеру, красный цвет описывается, как {255, 0, 0, 255}).
1.2 Конвейер контента в проектах на XNA
Контент — целый конвейер по обработке содержимого для игры.
Существует множество различных форматов файлов для обозначения, по сути, одних и тех же вещей. Картинки могут иметь расширение jpg или bmp, png или gif. Музыка может храниться в форматах mp3, wav, ogg, а видео в avi, mkv или mp4. И это лишь капля в море возможных форматов. Из всего этого получается, что для обработки каждого из форматов надо знать конкретно его внутреннюю структуру, принцип записи данных в файле. Соответственно и обработка каждого формата должна производиться индивидуально. Однако XNA исправляет ситуацию введением такого понятия, как конвейер содержимого (Content Pipeline). Суть этого механизма заключается в том, что при использовании XNA вы не работаете напрямую с файлами ресурсов (mp3, wav, jpg и т. д.), а работаете с некоторым абстрактными понятиями, типа «текстура», «модель», «музыка». Визуально схему работы с контентом в XNA можно изобразить следующим образом Рис. 1 — Схема работы с контентом в XNA
1.3 Контент-импортер и контент-процессор
Первым этапом при добавлении содержимого в нашу игру идет контент-импортер. Это специально написанная библиотека, которая «исследует» входной файл и по описанным правилам его обрабатывает — задает структуру, характерную для необходимого в будущем типа (модель, звук). Так же в контент-импортере, путем использования атрибутов, задается имя контент-процессора, который должен будет использоваться для загрузки и обработки уже скомпилированного бинарного (двоичного) файла формата xnb во время работы игры, и расширения исходных файлов, которые будут обрабатываться данным импортером. Выходным файлом мы получим скомпилированный xnb, готовый для использования на следующем этапе — загрузке контента в игре. Тут в дело вступает характерный контент-процессор, имя которого записано прямо внутри самого xnb файла. Файл полностью самодостаточен и, даже будучи бинарным, может быть открыт на любом компьютере с XNA Framework’ом, в отличие от обычных файлов, за распознавание расширений которых отвечает операционная система. Т. е. контент-процессор отвечает за корректное считывание информации из файла контента и приведение его к внутреннему типубудь то Model, Texture2D, Effect или как-то другой.
1.4 Понятие компонента в XNA и его использование
Особенностью XNA Framework, которую нельзя не упомянуть, являются «игровые компоненты»:
§ Microsoft.Xna.Framework.Game Component
§ Microsoft.Xna.Framework.Drawable Game Component.
Смысл компонентов состоит в том, чтобы автоматизировать и стандартизировать вызов обновления (Update), отрисовки (Draw), загрузки контента (Load Content) и инициализации логики (Initia lization) для игровых объектов. Т. е. «облегчить» основной класс игры, внеся логику по работе с каждым объектом внутрь самого объекта и при этом сохранить структуру методов, предлагаемых нам шаблоном XNA. В итоге, просто добавив класс, наследник компонента, в коллекцию компонентов игры один раз, мы можем уже не думать о нем.
Первый компонент призван работать с невидимыми, но постоянно обновляемыми объектами, типа сила и направление ветра или логики искусственного интеллекта (ИИ) компьютерных оппонентов, а второй — для объектов, которые еще должны и выводится на экран, к примеру, счетчик FPS (Frame Per Second) или курсор мыши.
1.5 Компьютерная анимация
Слова «анимация» и «мультипликация» означают одно и то же. На «западный манер» будем использовать первый вариант. Слово animation с английского языка можно перевести как оживление или воодушевление. Когда мы видим обычное рисованное изображение, которое, вдруг начинает двигаться и изменяться, то может действительно показаться, что произошло что-то невероятное, и картинка ожила. Но научное мировоззрение не позволяет нам поверить в это; поэтому обратимся к другому, логичному объяснению.
Если множество похожих изображений (рис. 2) быстро сменять друг за другом, то при определенной скорости смены человек будет воспринимать происходящее как плавное движение (или изменение) объекта на рисунке.
Рис. 2. Ряд изображений, при быстрой смене которых может возникнуть эффект анимации Оптимальная скорость смены для человека равна 24 изображения (или кадра) в секунду. На самом деле в одном кадре может присутствовать несколько изображений (слоев). Кроме того, может быть всего одно изображение, которое в каждом последующем интервале времени (кадре) будет смещаться на небольшую величину (такую простейшую анимацию можно наблюдать, когда создаются спецэффекты в компьютерной презентации).
Из вышесказанного можно заключить, что создание анимации весьма трудоемкое занятие. Ведь зачастую каждый кадр требуется прорисовывать заново. Естественно, что с появлением современных компьютеров, начали появляться и программы, облегчающие и автоматизирующие труд аниматора. Кроме того, анимация, созданная с помощью компьютеров нашла свое применение не только в создании мультфильмов. Она широко используется в Интернет, презентациях, электронных обучающих курсах и т. д. Обычно служит для целей облегчения восприятия информации, т.к. большинство людей основную долю информации воспринимает с помощью зрения. Однако перебор анимации, ее низкое качество могут ухудшить восприятие, отвлекать и раздражать человека.
Компьютерная анимация создается с помощью специальных программ. Их достаточно много. Условно можно выделить два или три вида ПО для создания анимации:
1. Программы, позволяющие создавать анимацию из готовых изображений (различные gif-аниматоры, например, Microsoft GIF Animator).
2. Программные среды, позволяющие создавать 2D анимацию (например, Adobe Flash CS4, Synfig).
3. Программные среды, позволяющие создавать 3D анимацию (например, Autodesk 3ds Max, Blender).
Существенное облегчение труда аниматора гарантируют лишь среды из пунктов 2. и 3, т.к. в случае gif-аниматоров используется уже готовое множество изображений. В профессиональных же средах компьютерной анимации художнику не обязательно прорисовывать каждый кадр или аниматору его фиксировать, программа сама «вычислит» переход изображения из одного положения в другое. Это называется твинингом (tweening) — процесс генерации промежуточных кадров между двумя рисунками, создающий впечатление, что первый рисунок постепенно превращается во второй. Рассмотрим, как это делается.
Представим временную шкалу (киноленту) как дорожку, состоящую из отдельных кадров. Допустим, что в кадре № 1 объект должен находиться слева, а в кадре № 100 — справа. Эти два кадра отмечаются как ключевые для данного объекта. В них он располагается в начале и конце движения (рис. 3). Все остальные кадры — промежуточные — не требуют фиксации объекта — изображение в них создаст компьютерная программа. Она сама вычислит, где и в какой момент должен находиться объект. Понятно, что если мы ходим сделать передвижение объекта по кривой, то и ключевых кадров придется сделать больше (или использовать специальные средства, предоставляемые программой, для создания траектории).
Рис. 3. Положение объекта в 1-ом кадре киноленты (слева) и в 100-ом (справа).
1.6 Специальные эффекты
Спецэффект, специальный эффект (англ. specialeffect, сокр. SPFX, SFX или FX) — технологический приём в кинематографе, на телевидении и в компьютерных играх, применяемый для визуализации сцен, которые не могут быть сняты обычным способом или не существуют в действительности (например, для визуализации сцен сражения космических кораблей в далёком будущем).
Спецэффекты также часто применяются, когда естественная съёмка сцены слишком затратна по сравнению со спецэффектом (например, съёмка масштабного взрыва). Спецэффекты применяются и для улучшения или модификации уже предварительно отснятого материала (например, для наложения погодной карты как фон для телеведущего, рассказывающего о прогнозе погоды).
Спецэффекты условно разделяют на две группы — визуальные и механические эффекты. К визуальным относятся оптические эффекты (комбинированные съёмки), а также компьютерная графика. Механические (физические) спецэффекты — это обработка материалов перед съемкой. Сюда относится моделирование, пиротехника и технические приспособления, специальный грим. Существуют также звуковые спецэффекты.
Методы исполнения спецэффектов также применяются при исполнении монтажных переходов между монтажными кадрами, например, распространённый метод вытеснения изображения.
графика компьютерный анимация контент
2. ПРАКТИЧЕСКАЯ ЧАСТЬ
В разработанной игре используется компьютерная 2D анимация. Она предназначена для анимации движения персонажей в 4 направлениях, для реализации этого используется 4 графических файла формата .png, содержащих по 4 кадра, для каждого персонажа. Примеры файлов представлены на рисунках 4 и 5.
Рис. 4 Анимация движения вниз для главного героя Рис. 5 Анимация движения влево для противника Для создания анимации сначала необходимо создать самого персонажа. За все действия, связанные с персонажем отвечает класс Actor. Полный листинг этого класса представлен в Приложении А.
За создание персонажа отвечает конструктор класса. В нем находятся переменные, отвечающие за текстуры, ширину и высоту, направление, количество жизней и скорость персонажей.
public Actor (string textureFolder, ContentManager cont, int countFrames, int hp, int speed, Physics gamePhysics)
{
this.content = cont;
this.DownWalk = cont. Load (textureFolder + @" /downMove");
this.UpWalk = cont. Load (textureFolder + @" /upMove");
this.LeftWalk = cont. Load (textureFolder + @" /leftMove");
this.RightWalk = cont. Load (textureFolder + @" /rightMove");
this.countFrames = countFrames;
Width = DownWalk. Width / countFrames; // Ширина
Height = DownWalk. Height; // Высота
Position = Vector2. Zero;
Move = Vector2. Zero;
sourceRect = new Rectangle (0, 0, Width, Height);
this.hp = hp;
this.Speed = speed;
this.gamePhysics = gamePhysics;
// Ни с чем не пересекается
StopMove = Vector4. Zero;
}
За анимацию персонажей отвечает методы heroAnimation (отвечает за перемещение кадров), MoveUp, MoveDown, MoveLeft, MoveRight — отвечают за движение персонажа в 4 направлениях и DrawMotion (отвечает за анимацию персонажа).
public void heroAnimation (float elapsedTime) // Перемещение прямоугольника фрейма
{
elapsed += elapsedTime; // Смотрим на секундомер
if (elapsed >= delay) // Если прошло время
{
if (frame == countFrames — 1)
frame = 0;
else
frame++; // Меняем фрейм
elapsed = 0; // Сбрасываем секундомер
}
sourceRect.X = frame * Width; // Перемещаем прямоугольник фрейма
}
public void MoveUp ()
{
Move.Y = -1; // Движение вверх
View.X = 0; // Меняем вид
View.Y = -1;
if (StopMove.Z == 0)
{
StopMove.Y = 0;
Position.Y -= Speed; // Меняем позицию
}
}
public void MoveDown ()
{
Move.Y = 1; // Движение вниз
View.X = 0; // Меняем вид
View.Y = 1;
if (StopMove.Y == 0)
{
StopMove.Z = 0;
Position.Y += Speed; // Меняем позицию
}
}
public void MoveLeft ()
{
Move.X = -1; // Движение влево
View.X = -1; // Меняем вид
View.Y = 0;
if (StopMove.W == 0)
{
StopMove.X = 0;
Position.X -= Speed; // Меняем позицию
}
}
public void MoveRight ()
{
Move.X = 1; // Движение вверх
View.X = 1; // Меняем вид
View.Y = 0;
if (StopMove.X == 0)
{
StopMove.W = 0;
Position.X += Speed; // Меняем позицию
}
}
public void DrawMotion (SpriteBatch spriteBatch)
{
float layer = 0.8f + (Position.Y + Height) / 5400;
float scale = 1;
Rectangle zeroRec = new Rectangle (0, 0, Width, Height);
if (Move.Y < 0) // Идет вверх
spriteBatch.Draw (UpWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.Y == 0 && View. Y < 0) // Смотрит вверх
spriteBatch.Draw (UpWalk, Position, zeroRec, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.Y > 0) // Идет вниз
spriteBatch.Draw (DownWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if ((Move.Y == 0 && View. Y > 0) || (View.X == 0 && View. Y == 0)) // Смотрит вниз
spriteBatch.Draw (DownWalk, Position, zeroRec, Color. White, 0f, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X > 0) // Если движется вправо
spriteBatch.Draw (RightWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X == 0 && View. X > 0) // Смотрит вправо
spriteBatch.Draw (RightWalk, Position, zeroRec, Color. White, 0f, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X < 0) // Если движется влево
spriteBatch.Draw (LeftWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X == 0 && View. X < 0) // Смотрит влево
spriteBatch.Draw (LeftWalk, Position, zeroRec, Color. White, 0f, Vector2. Zero, scale, SpriteEffects. None, layer);
foreach (Bullet b in listBullet) // Рисуем пули
{ b. DrawBullet (spriteBatch); }
}
Для создания игрового окна используется класс Game1. Листинг класса представлен в Приложении Б. На рисунке 6 представлено игровое окно.
Рис. 6 Запущенная игра
ЗАКЛЮЧЕНИЕ
Анимация в играх очень важный элемент без которого не обходится ни одна игра. Она отвечает за передвижение персонажей, взаимодействие их с окружающим миром. Также компьютерная анимация (последовательный показ слайд-шоу из заранее подготовленных графических файлов, а также компьютерная имитация движения с помощью изменения и перерисовки формы объектов или показа последовательных изображений с фазами движения, подготовленных заранее или порождаемых во время анимации) может применяться в мультимедийных приложениях (например, энциклопедиях), а также для «оживления» отдельных элементов оформления, например, веб-страниц и рекламы (анимированные баннеры). На веб-страницах анимация может формироваться средствами стилей (CSS) и скриптов (JavaScript) или модулями, созданными с помощью технологии Flash или её аналогов (флеш-анимация).
1. Бубнов А. Е. Компьютерный дизайн. Основы, Мн: Знание, 2008 г.
2. Кричалов А. А. Компьютерный дизайн. Учебное пособие, Мн.: СТУ МГМУ, 2008 г.
3. Стоянов П. Г. Работа с цветом и графикой, Мн.: БГУИР, 2008 г.
ПРИЛОЖЕНИЕ A
Класс Actor
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game1
{
class Actor
{
public Texture2D DownWalk { get; set; }
public Texture2D RightWalk { get; set; }
public Texture2D LeftWalk { get; set; }
public Texture2D UpWalk { get; set; }
public int intersect;
public Vector2 Position; // Положение в пространстве
public List listBullet = new List (); // Пульки
public int countFrames; //Количество кадров анимации
public int Width; // Ширина
public int Height; // Высота
public Vector2 Move; // Вектор направление
public Vector2 View; // Вектор взгляда
public int Speed; //скорость
public Vector4 StopMove; //Остановление направления
public Rectangle sourceRect; //Прямоугольник одного фрейма
public float elapsed;
public float delay = 200f;
public int frame = 0; //номер фрейма
public int hp;
ContentManager content;
Physics gamePhysics;
public Rectangle zBounds // Z — Границы обьекта
{
get { return new Rectangle ((int)Position.X, (int)Position.Y, Width, Height); }
}
public Rectangle shadow // Границы шага обьекта
{ get { return new Rectangle ((int)Position.X, (int)Position.Y + Height / 2, Width, Height / 2); } }
public Point pointN
{ get { return new Point (shadow.Center.X, shadow. Top); } }
public Point pointS
{ get { return new Point (shadow.Center.X, shadow. Bottom); } }
public Point pointW
{ get { return new Point (shadow.Left, shadow.Center.Y); } }
public Point pointE
{ get { return new Point (shadow.Right, shadow.Center.Y); } }
public Point pointNE
{ get { return new Point (shadow.Right, shadow. Top); } }
public Point pointNW
{ get { return new Point (shadow.Left, shadow. Top); } }
public Point pointSE
{ get { return new Point (shadow.Right, shadow. Bottom); } }
public Point pointSW
{ get { return new Point (shadow.Left, shadow. Bottom); } }
public Actor (string textureFolder, ContentManager cont, int countFrames, int hp, int speed, Physics gamePhysics)
{
this.content = cont;
this.DownWalk = cont. Load (textureFolder + @" /downMove");
this.UpWalk = cont. Load (textureFolder + @" /upMove");
this.LeftWalk = cont. Load (textureFolder + @" /leftMove");
this.RightWalk = cont. Load (textureFolder + @" /rightMove");
this.countFrames = countFrames;
Width = DownWalk. Width / countFrames; // Ширина
Height = DownWalk. Height; // Высота
Position = Vector2. Zero;
Move = Vector2. Zero;
sourceRect = new Rectangle (0, 0, Width, Height);
this.hp = hp;
this.Speed = speed;
this.gamePhysics = gamePhysics;
// Ни с чем не пересекается
StopMove = Vector4. Zero;
}
public void heroAnimation (float elapsedTime) // Перемещение прямоугольника фрейма
{
elapsed += elapsedTime; // Смотрим на секундомер
if (elapsed >= delay) // Если прошло время
{
if (frame == countFrames — 1)
frame = 0;
else
frame++; // Меняем фрейм
elapsed = 0; // Сбрасываем секундомер
}
sourceRect.X = frame * Width; // Перемещаем прямоугольник фрейма
}
public void MoveUp ()
{
Move.Y = -1; // Движение вверх
View.X = 0; // Меняем вид
View.Y = -1;
if (StopMove.Z == 0)
{
StopMove.Y = 0;
Position.Y -= Speed; // Меняем позицию
}
}
public void MoveDown ()
{
Move.Y = 1; // Движение вниз
View.X = 0; // Меняем вид
View.Y = 1;
if (StopMove.Y == 0)
{
StopMove.Z = 0;
Position.Y += Speed; // Меняем позицию
}
}
public void MoveLeft ()
{
Move.X = -1; // Движение влево
View.X = -1; // Меняем вид
View.Y = 0;
if (StopMove.W == 0)
{
StopMove.X = 0;
Position.X -= Speed; // Меняем позицию
}
}
public void MoveRight ()
{
Move.X = 1; // Движение вверх
View.X = 1; // Меняем вид
View.Y = 0;
if (StopMove.X == 0)
{
StopMove.W = 0;
Position.X += Speed; // Меняем позицию
}
}
public void DrawMotion (SpriteBatch spriteBatch)
{
float layer = 0.8f + (Position.Y + Height) / 5400;
float scale = 1;
Rectangle zeroRec = new Rectangle (0, 0, Width, Height);
if (Move.Y < 0) // Идет вверх
spriteBatch.Draw (UpWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.Y == 0 && View. Y < 0) // Смотрит вверх
spriteBatch.Draw (UpWalk, Position, zeroRec, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.Y > 0) // Идет вниз
spriteBatch.Draw (DownWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if ((Move.Y == 0 && View. Y > 0) || (View.X == 0 && View. Y == 0)) // Смотрит вниз
spriteBatch.Draw (DownWalk, Position, zeroRec, Color. White, 0f, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X > 0) // Если движется вправо
spriteBatch.Draw (RightWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X == 0 && View. X > 0) // Смотрит вправо
spriteBatch.Draw (RightWalk, Position, zeroRec, Color. White, 0f, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X < 0) // Если движется влево
spriteBatch.Draw (LeftWalk, Position, sourceRect, Color. White, 0, Vector2. Zero, scale, SpriteEffects. None, layer);
else if (Move.X == 0 && View. X < 0) // Смотрит влево
spriteBatch.Draw (LeftWalk, Position, zeroRec, Color. White, 0f, Vector2. Zero, scale, SpriteEffects. None, layer);
foreach (Bullet b in listBullet) // Рисуем пули
{ b. DrawBullet (spriteBatch); }
}
public void Shoot (List listBullet)
{
// Рисуем пулю
Bullet newBullet = new Bullet (content.Load (@" Textures/fireball"), this); // Устанавливаем текстуруH
// Задаем координаты
if (View.X == 0 && View. Y == 0)
newBullet.Velocity = new Vector2(0, 7);
else
newBullet.Velocity = View * 7f;
if (View.X > 0)
{
newBullet.Position.X = Position. X + Width;
newBullet.Position.Y = Position. Y + Height / 2;
}
else if (View.X < 0)
{
newBullet.Position.X = Position. X;
newBullet.Position.Y = Position. Y + Height / 2;
}
else if (View.Y > 0 || View. X == View. Y)
{
newBullet.Position.X = Position. X + Width / 2; ;
newBullet.Position.Y = Position. Y + Height;
}
else if (View.Y < 0)
{
newBullet.Position.X = Position. X + Width / 2;
newBullet.Position.Y = Position. Y;
}
// Добавляем пульку
listBullet.Add (newBullet);
}
void moveBullet (List listBullet, Decor dekor, List listActor)
{
foreach (Bullet b in listBullet) // Для каждой пульки
{
b.Position += b. Velocity; // Направление и скорость пули
if (Vector2.Distance (b.Position, Position) > 400)
b.isAlive = false;
if (gamePhysics.contactBulletDekor (b, dekor))
b.isAlive = false;
gamePhysics.contactBulletActor (b, listActor);
}
for (int i = 0; i < listBullet. Count; i++)
{
if (!listBullet[i]. isAlive && listBullet[i]. isVisible)
{
listBullet.RemoveAt (i);
i—;
}
}
}
public void hunt (Actor a)
{
}
}
}
ПРИЛОЖЕНИЕ Б
Класс Game1
using System;
using System.Collections.Generic;
using System. IO;
using System. Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Game1
{
/// This is the main type for your game
public class Game1: Microsoft.Xna.Framework.Game
{
private Menu menu;
private Physics physics;
private ContentManager contentManager;
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
private Rectangle _viewPortRectangle; // Границы игрового поля
private Physics gamePhysics = new Physics ();
private Actor Hero; // Герой
private Field[] level = new Field[5];
private int currentLevel = 1;
private KeyboardState pastKey; //Отпускаемая кнопка
private GameState gameState = GameState. Menu;
public int[,] Layer;
private Texture2D hp;
private Texture2D hp1;
public Game1()
{
graphics = new GraphicsDeviceManager (this);
Content.RootDirectory = «Content» ;
graphics.PreferredBackBufferWidth = 1080; // ширина экрана
graphics.PreferredBackBufferHeight = 640; // высота экрана
//graphics.IsFullScreen = true;
}
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base. Initialize will enumerate through any components
/// and initialize them as well.
protected override void Initialize ()
{
menu = new Menu ();
MenuItem newGame = new MenuItem («Start Game»);
MenuItem resumeGame = new MenuItem («Resume Game»);
MenuItem exitGame = new MenuItem («Exit»);
resumeGame.Active = false;
newGame.Click += new EventHandler (newGame_Click);
resumeGame.Click += new EventHandler (resumeGame_Click);
exitGame.Click += new EventHandler (exitGame_Click);
menu.Items.Add (newGame);
menu.Items.Add (resumeGame);
menu.Items.Add (exitGame);
base.Initialize ();
}
private void exitGame_Click (object sender, EventArgs e)
{
this.Exit ();
}
private void resumeGame_Click (object sender, EventArgs e)
{
gameState = GameState. Game;
}
private void newGame_Click (object sender, EventArgs e)
{
menu.Items[1]. Active = true;
gameState = GameState. Game;
Hero = new Actor («Hero», Content, 4, 2, 3, gamePhysics);
for (int i = 1; i < 5; i++)
{
level[i] = new Field (gamePhysics, Hero);
level[i]. LoadField (Content, «level» + i. ToString ());
}
}
/// LoadContent will be called once per game and is the place to load
/// all of your content.
protected override void LoadContent ()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch (GraphicsDevice);
hp = Content. Load (@" Textures/hp");
hp1 = Content. Load (@" Textures/hp1″);
// Границы игрового поля
_viewPortRectangle = new Rectangle (0, 0,
graphics.GraphicsDevice.Viewport.Width,
graphics.GraphicsDevice.Viewport.Height);
menu.LoadContent (Content);
}
/// UnloadContent will be called once per game and is the place to unload
/// all content.
protected override void UnloadContent ()
{
}
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// Provides a snapshot of timing values.
protected override void Update (GameTime gameTime)
{
if (gameState == GameState. Game)
UpdateGameLogic (gameTime);
else menu. Update ();
base.Update (gameTime);
}
private void UpdateGameLogic (GameTime gameTime)
{
if (level[currentLevel]. fieldEmpty () == true)
{
Hero.Position.X = MathHelper. Clamp (Hero.Position.X, -Hero.Width,
_viewPortRectangle.Width + Hero. Width);
Hero.Position.Y = MathHelper. Clamp (Hero.Position.Y, -Hero.Height,
_viewPortRectangle.Height + Hero. Height);
if (currentLevel == 1)
{
currentLevel = 1;
}
/*1—>2
000*/
if (Hero.Position.X > 1080 && currentLevel == 1)
{
currentLevel = 3;
Hero.Position.X = 0;
}
/*1—>2
000*/
if (Hero.Position.X < -Hero.Width + 10 && currentLevel == 3)
{
currentLevel = 1;
Hero.Position.X = 1080 — Hero. Width;
}
/*1—>2
020*/
if (Hero.Position.Y > 640 && currentLevel == 1)
{
currentLevel = 4;
Hero.Position.Y = 0;
}
/*1—>2
010*/
if (Hero.Position.Y < -Hero.Height + 10 && currentLevel == 4)
{
currentLevel = 1;
Hero.Position.Y = 640 — Hero. Height;
}
/*1—>2
012*/
if (Hero.Position.X > 1080 && currentLevel == 4)
{
currentLevel = 2;
Hero.Position.X = 0;
}
/*1—>2
021*/
if (Hero.Position.X < -Hero.Width + 10 && currentLevel == 2)
{
currentLevel = 4;
Hero.Position.X = 1080 — Hero. Width;
}
/*1—>2
002*/
if (Hero.Position.Y > 640 && currentLevel == 3)
{
currentLevel = 2;
Hero.Position.Y = 0;
}
/*1—>2
001*/
if (Hero.Position.Y < -Hero.Height + 10 && currentLevel == 2)
{
currentLevel = 3;
Hero.Position.Y = 640 — Hero. Height;
}
}
else
{
Hero.Position.X = MathHelper. Clamp (Hero.Position.X, 0, _viewPortRectangle.Width — Hero. Width);
Hero.Position.Y = MathHelper. Clamp (Hero.Position.Y, 0, _viewPortRectangle.Height — Hero. Height);
}
level[currentLevel]. UpdateField (gameTime); //Обновеляем комнату
control (); //Смотрим движение по клавишам
if (Hero.hp == 0)
gameState = GameState. Menu;
}
/// This is called when the game should draw itself.
/// Provides a snapshot of timing values.
protected override void Draw (GameTime gameTime)
{
GraphicsDevice.Clear (Color.Black);
if (gameState == GameState. Game)
DrawGame ();
else menu. Draw (spriteBatch);
base.Draw (gameTime);
}
private void DrawGame ()
{
spriteBatch.Begin (SpriteSortMode.FrontToBack, BlendState. AlphaBlend);
level[currentLevel]. DrawField (spriteBatch); //Рисуем комнату
if (Hero.hp == 2)
spriteBatch.Draw (hp, new Vector2(50, 50), null, Color. White, 0, Vector2. Zero, 1, SpriteEffects. None, 1);
else if (Hero.hp == 1)
spriteBatch.Draw (hp1, new Vector2(50, 50), null, Color. White, 0, Vector2. Zero, 1, SpriteEffects. None, 1);
spriteBatch.End ();
}
public void control ()
{
if (Keyboard.GetState ().IsKeyDown (Keys.Escape))
gameState = GameState. Menu;
if (Keyboard.GetState ().IsKeyUp (Keys.W) || Keyboard. GetState ().IsKeyUp (Keys.S))
Hero.Move.Y = 0;
if (Keyboard.GetState ().IsKeyUp (Keys.D) || Keyboard. GetState ().IsKeyUp (Keys.A))
Hero.Move.X = 0;
if (Keyboard.GetState ().IsKeyDown (Keys.D)) //Вправо
{
Hero.MoveRight ();
}
if (Keyboard.GetState ().IsKeyDown (Keys.A)) //Влево
{
Hero.MoveLeft ();
}
if (Keyboard.GetState ().IsKeyDown (Keys.W)) //Вверх
{
Hero.MoveUp ();
}
if (Keyboard.GetState ().IsKeyDown (Keys.S)) //Вниз
{
Hero.MoveDown ();
}
if (Keyboard.GetState ().IsKeyDown (Keys.E) && pastKey. IsKeyUp (Keys.E)) //W — стрелять
Hero.Shoot (Hero.listBullet);
if (Keyboard.GetState ().IsKeyDown (Keys.Q) && pastKey. IsKeyUp (Keys.Q))
{
Hero.hp—;
hp = null;
}
if (Keyboard.GetState ().IsKeyDown (Keys.Space) && pastKey. IsKeyUp (Keys.Space))
{
level[currentLevel]. AddEnemy ();
}
pastKey = Keyboard. GetState ();
}
private enum GameState
{
Game,
Menu
}
}
}
.ur