Minecraft xna framework redistributable что это
Несколько дней назад, бороздя просторы великого и могучего Интернета, наткнулся на Microsoft XNA Studio. Не то чтобы услышал об этом фреймворке в первый раз, но все предыдущие разы как-то проходил мимо, времени разбираться не было совершенно.
В этот раз что-то меня дернуло покопаться поглубже. Справедливо рассудив что для знакомства с библиотекой лучшего метода чем реализовать что нибудь на нем нет, а также имея в распоряжении свободный вечер, решил написать что нибудь простенькое, например любимый мною с детства Arkanoid (Brick Out), не корысти ради, а ознакомления для.
Это моя первая статья на хабре, убедительно прошу ногами не пинать
Смысл данной статьи показать как легко можно начать создавать свои игры при помощи XNA и, собственно, дать стимул для дальнейшего изучения этой платформы. Посему, на полноценную игру не претендует, графика — никакая, как и художник из меня. Да и физика могла бы быть пореалистичнее, но это уже выходит за рамки данной статьи, уверен что интересующиеся разработкой игр найдут немало достойных (и не очень) материалов в сети.
Исходники можно скачать тут
Итак, что же такое Microsoft XNA?
Последняя версия на момент написания статьти – Microsoft XNA Game Studio 3.1 (73.2 MB)
Создание проекта
Создадим новый проект – XNA Game Studio 3.1 – Windows Game (3.1)
Мастер создаст скелет игры:
Самый большой интерес для нас представляет файл Game1.cs, в котором определен класс Game1, наследованный от Microsoft.Xna.Framework.Game, где мы и будем разрабатывать нашу игру.
В классе Game1 переопределены следующие методы Game:
void Initialize() – Вызывается единожды, для инициализации ресурсов до начала игры
void LoadContent() – Вызывается единожды, используется для загрузки контента (спрайты и т.д.)
void UnloadContent() – Вызывается единожды, используется для выгрузки контента
void Update(GameTime gameTime) – В этом методе реализуется собственно логика игры, обработка коллизий, обработка событий клавиатуры или джойстика, проигрывание аудио и т.д.
void Draw(GameTime gameTime) – Вызывается для прорисовки игрового поля.
На данный момент скомпилированная игра выглядит вот так
Добавление контента
Добавим игровые ресурсы, в данном случае картинки фона кирпича, ракетки и мячика – Content (Right Click) -> Add -> Existing Item…
Обратите внимание на свойство Asset Name, его мы используем для создания обьекта Texture2D необходимого для дальнейшей анимации.
Рисуем фон игрового поля
Загрузим изображение для фона игрового поля:
- private Rectangle _viewPortRectangle; // Границы игрового поля
- private Texture2D _background; // Фон игрового поля
- protected override void LoadContent()
- <. skip . >
- // Границы игрового поля
- _viewPortRectangle = new Rectangle(0, 0,
- graphics.GraphicsDevice.Viewport.Width,
- graphics.GraphicsDevice.Viewport.Height);
- _background = Content.Load<Texture2D>( @"background" );
- <. skip . >
- >
- protected override void Draw(GameTime gameTime)
- GraphicsDevice.Clear(Color.CornflowerBlue);
- spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
- // Рисуем фон
- spriteBatch.Draw(_background, _viewPortRectangle, Color.White);
- spriteBatch.End();
- base .Draw(gameTime);
- >
Метод SpriteBatch.Begin подготавливает графическое устройство к отрисовке спрайтов, SpriteBatch.End завершает процесс отрисовки и возвращает устройство к начальному состоянию. Все методы SpriteBatch.Draw должны быть заключены в SpriteBatch.Begin — SpriteBatch.End.
Создание игрового обьекта
Создадим класс GameObject инкапсулирующий любой из наших игровых обьектов:
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework. Graphics ;
- namespace Arkanoid
- public class GameObject
- public Texture2D Sprite < get ; set ; >// Спрайт
- public Vector2 Position; // Положение
- public Vector2 Velocity; // Скорость
- public int Width < get < return Sprite.Width; >> // Ширина
- public int Height < get < return Sprite.Height; >> // Высота
- public bool IsAlive < get ; set ; >// Жив ли обьект
- public Rectangle Bounds // Границы обьекта
- get
- return new Rectangle(( int )Position.X, ( int )Position.Y, Width, Height);
- >
- >
- // Разворачивание движения по горизонтальной оси
- public void ReflectHorizontal()
- Velocity.Y = -Velocity.Y;
- >
- // Разворачивание движения по вертикальной оси
- public void ReflectVertical()
- Velocity.X = -Velocity.X;
- >
- public GameObject(Texture2D sprite)
- Sprite = sprite;
- IsAlive = true ;
- Position = Vector2.Zero;
- Velocity = Vector2.Zero;
- >
- >
- >
Отрисовка и анимация ракетки
Сначала создадим обьект представляющий ракетку и расположим его в середине игрового поля чуть повыше от его нижнего края
- private GameObject _paddle; // Ракетка
- protected override void LoadContent()
- <. skip . >
- // Создание ракетки, начальное положение в середине игрового поля, повыше нижнего края
- _paddle = new GameObject(Content.Load<Texture2D>( @"paddle" ));
- _paddle.Position = new Vector2((_viewPortRectangle.Width - _paddle.Width) / 2,
- _viewPortRectangle.Height - _paddle.Height - 20);
- <. skip . >
- >
Отрисовка ракетки на экране
- protected override void Draw(GameTime gameTime)
- <. skip . >
- spriteBatch.Draw(_paddle.Sprite, _paddle.Position, Color.White);
- <. skip . >
- >
На данном этапе, если скомпилировать приложение, получим что-то вроде этого:
Неплхо было бы заставить реагировать ракетку на нажатие клавиш, для этого добавим в метод Update следующий код
- protected override void Update(GameTime gameTime)
- <. skip . >
- KeyboardState keyboardState = Keyboard.GetState();
- // Двигаем ракетку вправо
- if (keyboardState.IsKeyDown(Keys.Right))
- _paddle.Position.X += 6f;
- // Двигаем ракетку влево
- if (keyboardState.IsKeyDown(Keys.Left))
- _paddle.Position.X -= 6f;
- // Ограничиваем движение ракетки игровым полем
- _paddle.Position.X = MathHelper.Clamp(_paddle.Position.X, 0, _viewPortRectangle.Width - _paddle.Width);
- <. skip . >
- >
Отрисовка кирпичей
Создадим массив GameObject представляющий кирпичи которые собственно и будем разбивать
- private int _brickPaneWidth = 10; // Сколько кипричей рисовать в ширину
- private int _brickPaneHeight = 5; // Сколько кипричей рисовать в высоту
- private Texture2D _brickSprite; // Спрайт кирпича
- private GameObject[,] _bricks; // Массив кирпичей
Добавим следующий код в метод LoadContent()
- protected override void LoadContent()
- <. skip . >
- // Создание массива кирпичей
- _brickSprite = Content.Load<Texture2D>( @"brick" );
- _bricks = new GameObject[_brickPaneWidth,_brickPaneHeight];
- for ( int i = 0; i < _brickPaneWidth; i++)
- for ( int j = 0; j < _brickPaneHeight; j++)
- _bricks[i, j] = new GameObject(_brickSprite)
- Position = new Vector2(i * 55 + 120, j * 25 + 100)
- >;
- >
- >
- <. skip . >
- >
Отрисовка массива кирпичей, отисовка производится если кирпич “жив”, т.е. не разбит мячем
- protected override void Draw(GameTime gameTime)
- <. skip . >
- // Рисуем кирпичи
- foreach ( var brick in _bricks)
- if (brick.IsAlive)
- spriteBatch.Draw(brick.Sprite, brick.Position, Color.White);
- <. skip . >
- >
На данном этапе игровое поле выглядит следующим образом
Отрисовка мячика
Создаем обьект мячика
- private GameObject _ball; // Мячик
- protected override void LoadContent()
- <. skip . >
- // Создание мячика, начальное положение в середине на ракетке,
- // начальное направление - вправо, вверх
- _ball = new GameObject(Content.Load<Texture2D>( @"ball" ));
- _ball.Position = new Vector2((_viewPortRectangle.Width - _ball.Width) / 2,
- _viewPortRectangle.Height - _paddle.Height - _ball.Height - 20);
- _ball.Velocity = new Vector2(3,-3);
- <. skip . >
- >
Для анимации мячика добавим новый метод UpdateBall(), и его вызов в в метод Update(). Данный метод нам понадобится в дальнейшем для обработки столкновений мячика с кирпичами и ракеткой
- private void UpdateBall()
- _ball.Position += _ball.Velocity;
- >
- protected override void Update(GameTime gameTime)
- <. skip . >
- // Двигаем мячик
- UpdateBall();
- <. skip . >
- >
Для отрисовки мячика добавим следующий код в метод Draw()
- protected override void Draw(GameTime gameTime)
- <. skip . >
- // Рисуем мячик
- spriteBatch.Draw(_ball.Sprite, _ball.Position, Color.White);
- <. skip . >
- >
На данный момент, мы имеем почти полностью готовое игровое поле, но без обработки столкновений мячик сразу же вылетает за пределы игрового поля. Добавим обработку столкновений мячика с игровым полем, кирпичами и ракеткой
Обработка столкновений
Создадим новый метод определяющий место столкновения обьектов и меняющий направление полета мяча.
- // Определение стороны столкновения и отражение направления полета мячика
- public void Collide(GameObject gameObject, Rectangle rect2)
- // Обьект столкнулся сверху или снизу, отражаем направление полета по горизонтали
- if (rect2.Left <= gameObject.Bounds.Center.X && gameObject.Bounds.Center.X <= rect2.Right)
- gameObject.ReflectHorizontal();
- // Обьект столкнулся слева или справа, отражаем направление полета по вертикали
- else if (rect2.Top <= gameObject.Bounds.Center.Y && gameObject.Bounds.Center.Y <= rect2.Bottom)
- gameObject.ReflectVertical();
- >
Добавим следующий код в метод UpdateBall()
- private void UpdateBall()
- // Будущее положение мяча, нужно для предотвращения "залипания" мяча на поверхности обьекта
- Rectangle nextRect = new Rectangle(( int )(_ball.Position.X + _ball.Velocity.X),
- ( int )(_ball.Position.Y + _ball.Velocity.Y),
- _ball.Width, _ball.Height);
- // Столкновение с верхним краем игрового поля
- if (nextRect.Y <= 0)
- _ball.ReflectHorizontal();
- // При сталкивании мяча с нижним краем игрового поля, мячик "умирает"
- if (nextRect.Y >= _viewPortRectangle.Height - nextRect.Height)
- _ball.IsAlive = false ;
- >
- // Столкновение мячика с левым или правым краем игрового поля
- if ((nextRect.X >= _viewPortRectangle.Width - nextRect.Width) || nextRect.X <= 0)
- _ball.ReflectVertical();
- >
- // Столкновение мячика с ракеткой
- if (nextRect.Intersects(_paddle.Bounds))
- Collide(_ball, _paddle.Bounds);
- // Столкновение мячика с кирпичами
- foreach ( var brick in _bricks)
- if (nextRect.Intersects(brick.Bounds) && brick.IsAlive)
- brick.IsAlive = false ;
- Collide(_ball, brick.Bounds);
- >
- >
- _ball.Position += _ball.Velocity;
- >
Итак, что получилось
Конечно физика в игре, мягко говоря, никакая, мячик иногда залипает при столкновении с движущейся ракеткой. Но, повторюсь, смысл данной статьи знакомство со средой Microsoft XNA Game Studio, и, надо сказать, она отлично справляется с рутиной, освобождая время разработчика для фокусировки внимания на логике игры.
Исходники можно скачать тут
PS. Большое спасибо ivv за приглашение.
PPS. Спасибо за карму, перенес в XNA
Microsoft XNA Framework Redistributable – Набор необходимых библиотек и классов для разработки и запуски игр в операционной системе Windows, на текущий момент не используется в современных играх, но достаточно актуален и помогает решить некоторые проблемы, связанные с нормальной работой компьютерных игр.
Если в целом, то XNA Framework необходим по большей части для разработчиков, и позволяет запускать игры и приложения вне зависимо от версии операционной системы, будь то windows XP, Vista или Windows 10, являясь между ними некой стабильной средой прослойкой.
XNA Framework предоставляет поддержку создания и двухмерных, и трёхмерных игр и позволяет использовать возможности контроллеров Xbox 360. Игры фреймворка XNA, предназначенные для платформы Xbox на данный момент могут быть проданы только членам клуба Microsoft XNA Creator’s Club. Десктопные приложения могут распространяться бесплатно под текущим лицензированием Microsoft.
Знакомство с XNA и написание первой музыкальной игры
Краткое описание на википедии
Что для этого нам будет нужно?
Что предполагается разобрать и сделать на этом уроке?
- Подключить сборки XNA Framework
- Создать пустое приложение с закрашиванием фона
- Научиться подгружать контент
- Научиться работать со звуком
- Научиться работать с графикой
Какую игру мы будем реализовывать?
Механика игры проста до безумия. Смысл будет построен на музыке, в случае с этой игрой, будет использована композиция Исаака Шепарда — Leaves in the Wind. Нужно будет ловить мышкой «ноты», скорость и кол-во которых будут зависимы от текущей позиции в музыки, грубо говоря игровой «визуализатор». Для разнообразия существуют 5 тип нот: обычные, красные (враги), пурпурные (мощь), мигающие (превращает все в желтые), желтые (увеличивает скорость набора очков и размеры).
Собираем вещи пустой проект
Создается пустой проект, который при компиляции только чистит «экран» приложения, давайте более подробно рассмотрим структуру нового проекта.
Проект music_catch — «логика» нашего приложения.
Game1.cs — главный класс приложения, унаследован он от Microsoft.Xna.Framework.Game
Program.cs — «точка входа» в приложение, он нам не интересен.
Проект music_catchContent — «контент» нашего приложения, туда мы будем складывать ресурсы.
Более подробно взглянем на Game1.cs
В нем можно выделить основные функции, такие как:
Game1() — конструктор класса.
Initialize() — инициализация приложения.
LoadContent() — загрузка контента.
UnloadContent() — выгрузка контента.
Update(GameTime gameTime) — обновление логики приложения (например физики, etc)
Draw(GameTime gameTime) — отрисовка игры. ВНИМАНИЕ, любые операции с рисованием нужно проводить тут и только тут.
Пустой проект собран, идем дальше, добавляем ресурсы в приложение, все нужные ресурсы «кидаем» в папку music_catch\music_catchContent. В нашем случае — пять PNG файлов и одно музыкальное сопровождение. Добавляем это все в проект:
Там же создаем шрифт, в теле SpriteFont1.spritefont указываем имя и размер:
Создаем переменные для будущего контента:
И грузим его в LoadContent():
Кстати, подгружается контент следующим образом: вызывается Content.Load<>(«asset»);
В треугольных скобках указывается процессор контента, в нашем случае это Texture2D, Song, SpriteFont. Можно использовать свои процессоры, об этом я расскажу как-нибудь потом.
Контент подгружен, идем в конструктор Game1() и пишем:
Пишем «игровую логику»
Теперь нам нужно создать контроллер системы частиц и сами частицы (ноты), которые мы будем виртуозно ловить мышкой.
Создаем два класса: Catcher (сами частицы) и CatcherHolder (система частиц).
Листинг Catcher с комментариями:
Листинг CatcherHolder с комментариями:
Объясню, что за загадочный аккумулятор и зачем он нужен. Поговорим о «музыкальном» спектре.
Музыкальный сигнал – пища для аудиосистемы. Точнее – не так. Динамики музыку не слушают, ее восстанавливает наш мозг, получая сложный сигнал, содержащий множество частотных составляющих.
Дак вот, идея такая, слушать «частоты» каждый Update и записывать их в какой-нибудь, например, VisualizationData. Проще говоря, в массив из 128 элементов, которые изменяются от 0f до 1f.
Как этим можно воспользоваться?
Каждый Update: значения в массиве меняются в соответствии с музыкой, нам нужно проверить все 128 элементов, если значение элемента больше чем 0.6f, вызываем Beat-функцию и передаем ей Wave (индекс элемента массива, в котором произошло событие). Все бы хорошо, можно в Beat создавать частичку-ноту. Но представим, что у нас выполняется три Update'а подряд, в котором в одном и том же индексе — значение > 0.6f, как итог будет 100500 частичек за секунду. Чтобы таких вещей не происходило, можно использовать аккумулятор. Смысл его прост: при Beat'е у ячейки массива-аккумулятора соотвествующего индексу Wave отнимается константа BEAT_COST. Каждый Update ко всем элементам аккумулятора прибавляется ACCUMULATE_SPEED. Перед тем, как вызвать Beat проверяется выполняется ли условие — значение аккумулятора > ACCOMULATOR_REACTION, если да, то вызываем Beat. Это решает проблему.
Кстати, BEAT_REACTION — значение, после которых нужно проверять, стоит ли вызывать Beat.
Дальше приведу полный листинг GameLogic (Game1). Много кода, но постараюсь расписать в комментариях.
Скриншот:
Что с Microsoft XNA Framework?
Что с ним случилось? Microsoft перестала прддерживать? Какие есть аналоги? Хочу написать 2D игру.
- Вопрос задан более трёх лет назад
- 2851 просмотр
MonoGame is an Open Source implementation of the Microsoft XNA 4 Framework. Our goal is to allow XNA developers on Xbox 360, Windows & Windows Phone to port their games to the iOS, Android, Mac OS X, Linux and Windows 8 Metro. PlayStation Mobile, Raspberry PI, and PlayStation 4 platforms are currently in progress.
Читайте также: