Понятие компонента в 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) или курсор мыши.
Компьютерная анимация.
Слова «анимация» и «мультипликация» означают одно и то же. На «западный манер» будем использовать первый вариант. Слово 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-ом (справа).
Специальные эффекты.
Спецэффект, специальный эффект (англ. specialeffect, сокр. SPFX, SFX или FX) — технологический приём в кинематографе, на телевидении и в компьютерных играх, применяемый для визуализации сцен, которые не могут быть сняты обычным способом или не существуют в действительности (например, для визуализации сцен сражения космических кораблей в далёком будущем).
Спецэффекты также часто применяются, когда естественная съёмка сцены слишком затратна по сравнению со спецэффектом (например, съёмка масштабного взрыва). Спецэффекты применяются и для улучшения или модификации уже предварительно отснятого материала (например, для наложения погодной карты как фон для телеведущего, рассказывающего о прогнозе погоды).
Спецэффекты условно разделяют на две группы — визуальные и механические эффекты. К визуальным относятся оптические эффекты (комбинированные съёмки), а также компьютерная графика. Механические (физические) спецэффекты — это обработка материалов перед съемкой. Сюда относится моделирование, пиротехника и технические приспособления, специальный грим. Существуют также звуковые спецэффекты.
Методы исполнения спецэффектов также применяются при исполнении монтажных переходов между монтажными кадрами, например, распространённый метод вытеснения изображения.
ПРАКТИЧЕСКАЯ ЧАСТЬ
В разработанной игре используется компьютерная 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<Texture2D>(textureFolder + @"/downMove");
this.UpWalk = cont.Load<Texture2D>(textureFolder + @"/upMove");
this.LeftWalk = cont.Load<Texture2D>(textureFolder + @"/leftMove");
this.RightWalk = cont.Load<Texture2D>(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. http://edugalaxy.intel.ru/?automodule=blog&blogid=25&showentry=4235
2. http://kaltan.ucoz.com/load/grafika/skachat_toon_boom_animation_ish_1_2_na_russkom/10-1-0-1029
3. www.klyaksa.net
4. www.it-n.ru
5. www.allbest.ru
6. www.alleng.ru
7. www.orakul.spb.ru
8. www.markbook.chat.ru
9. ru.wikipedia.org/wiki/Компьютерная_графика
10. Бубнов А.Е. Компьютерный дизайн. Основы, Мн: Знание, 2008 г.
11. Кричалов А.А. Компьютерный дизайн. Учебное пособие, Мн.: СТУ МГМУ, 2008 г.
12. Стоянов П.Г. Работа с цветом и графикой, Мн.: БГУИР, 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<Bullet> listBullet = new List<Bullet>(); // Пульки
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<Texture2D>(textureFolder + @"/downMove");
this.UpWalk = cont.Load<Texture2D>(textureFolder + @"/upMove");
this.LeftWalk = cont.Load<Texture2D>(textureFolder + @"/leftMove");
this.RightWalk = cont.Load<Texture2D>(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<Bullet> listBullet)
{
// Рисуем пулю
Bullet newBullet = new Bullet(content.Load<Texture2D>(@"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<Bullet> listBullet, Decor dekor, List<Actor> 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
{
/// <summary>
/// This is the main type for your game
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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());
}
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
hp = Content.Load<Texture2D>(@"Textures/hp");
hp1 = Content.Load<Texture2D>(@"Textures/hp1");
// Границы игрового поля
_viewPortRectangle = new Rectangle(0, 0,
graphics.GraphicsDevice.Viewport.Width,
graphics.GraphicsDevice.Viewport.Height);
menu.LoadContent(Content);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
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;
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
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
}
}
}