Создать игру, создание игр, конструктора игр, игровые движки, разработка игр, сделать игру
Приветствую Вас Гость · Вход · Регистрация  ·  Новые сообщения · Участники · Правила · Поиск · RSS
Страница 1 из 11
Форум разработчиков игр » Полезные статьи, Примеры и Исходники » Остальные » Создание арканоида шаг за шагом в xna!
Создание арканоида шаг за шагом в xna!
MrIncrof Дата: Четверг, 25.11.2010, 08:37 | Сообщение # 1
( Приченить добро! )
Просмотр профиля: MrIncrof

Сообщений: [1553]
В этом небольшом уроке я покажу вам, как просто создавать игры на XNA Game Studio, итак приступим (Исходники можно скачать тут). Итак, что же такое Microsoft XNA?

Microsoft XNA это набор инструментов и библиотека для разработки мультиплатформенных 2D и 3D игр в управляемой среде Microsoft Managed Runtime Environment. Поддерживаются платформы Windows, Microsoft Xbox 360 и Microsoft Zune. Теоретически писать можно на любом .Net языке, в любой IDE, но оффициально поддерживаются только C# и XNA Game Studio Express и все версии Visual Studio 2005 и выше. XNA также дает возможность портировать игры на поддерживаемые платформы с минимальными изменениями.

Создание проекта

Создадим новый проект – 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 необходимого для дальнейшей анимации.

Рисуем фон игрового поля

Загрузим изображение для фона игрового поля:

Code

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 ...>
}

Отрисовка фона
Code

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 инкапсулирующий любой из наших игровых обьектов:

Code

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;
      }
    }
}

Отрисовка и анимация ракетки

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

Code

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 ...>
}

Отрисовка ракетки на экране
Code

protected override void Draw(GameTime gameTime)
{
    <... skip ...>
     
    spriteBatch.Draw(_paddle.Sprite, _paddle.Position, Color.White);
      
    <... skip ...>
}

На данном этапе, если скомпилировать приложение, получим что-то вроде этого:

Неплхо было бы заставить реагировать ракетку на нажатие клавиш, для этого добавим в метод Update следующий код
Code

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 представляющий кирпичи которые собственно и будем разбивать

Code

private int _brickPaneWidth = 10; // Сколько кипричей рисовать в ширину
private int _brickPaneHeight = 5; // Сколько кипричей рисовать в высоту
private Texture2D _brickSprite; // Спрайт кирпича
private GameObject[,] _bricks; // Массив кирпичей

Добавим следующий код в метод LoadContent()
Code

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 ...>
}

Отрисовка массива кирпичей, отисовка производится если кирпич “жив”, т.е. не разбит мячем
Code

protected override void Draw(GameTime gameTime)
{
    <... skip ...>
     
    // Рисуем кирпичи
    foreach (var brick in _bricks)
     if (brick.IsAlive)
       spriteBatch.Draw(brick.Sprite, brick.Position, Color.White);
     
    <... skip ...>
}

На данном этапе игровое поле выглядит следующим образом

Отрисовка мячика

Создаем обьект мячика

Code

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(). Данный метод нам понадобится в дальнейшем для обработки столкновений мячика с кирпичами и ракеткой
Code

private void UpdateBall()
{
    _ball.Position += _ball.Velocity;
}
     
protected override void Update(GameTime gameTime)
{
    <... skip ...>
     
    // Двигаем мячик
    UpdateBall();
      
    <... skip ...>
}

Для отрисовки мячика добавим следующий код в метод Draw()
Code

protected override void Draw(GameTime gameTime)
{
    <... skip ...>
      
    // Рисуем мячик
    spriteBatch.Draw(_ball.Sprite, _ball.Position, Color.White);
      
    <... skip ...>
}

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

Обработка столкновений

Создадим новый метод определяющий место столкновения обьектов и меняющий направление полета мяча.

Code

// Определение стороны столкновения и отражение направления полета мячика
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()
Code

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, и, надо сказать, она отлично справляется с рутиной, освобождая время разработчика для фокусировки внимания на логике игры.

Надеюсь помогло biggrin

Источник: http://habrahabr.ru/

Сообщение отредактировал: yKpon4uK - Четверг, 25.11.2010, 09:24
ДядяВолк Дата: Четверг, 25.11.2010, 09:13 | Сообщение # 2


Сообщений: [1451]
yKpon4uK, источник укажи!
MrIncrof Дата: Четверг, 25.11.2010, 09:30 | Сообщение # 3
( Приченить добро! )
Просмотр профиля: MrIncrof

Сообщений: [1553]
указал
Hagrael Дата: Четверг, 25.11.2010, 11:07 | Сообщение # 4
Просмотр профиля: Hagrael

Сообщений: [1476]
Источник я не уважаю.

George & Daniel:
Война сухофруктов
SanAV Дата: Четверг, 25.11.2010, 16:32 | Сообщение # 5
Просмотр профиля: SanAV

Сообщений: [627]
Сначала обрадовался, но после сообщения Назарбека понял, что есть это копипаст. Статья неплохая, может быть пригодится когда-нибудь.

AffenCode — Разработка игр
Скорп Дата: Четверг, 25.11.2010, 16:57 | Сообщение # 6
( Космический мутант )
Просмотр профиля: Скорп

Сообщений: [936]
Quote (SanAV)
Сначала обрадовался, но после сообщения Назарбека понял, что есть это копипаст.

Аналогично. Жаль, что не свое. Но все равно заслуживает внимания.


Рандомный текст.
MrIncrof Дата: Четверг, 25.11.2010, 18:15 | Сообщение # 7
( Приченить добро! )
Просмотр профиля: MrIncrof

Сообщений: [1553]
в следующий раз своё сделаю, подскажите, про что сделать?
Скорп Дата: Четверг, 25.11.2010, 22:53 | Сообщение # 8
( Космический мутант )
Просмотр профиля: Скорп

Сообщений: [936]
Про 3D-стратегии на PascalABC.

Рандомный текст.
ктоотоо Дата: Суббота, 19.02.2011, 14:44 | Сообщение # 9
Просмотр профиля: ктоотоо

Сообщений: [3]
Quote (yKpon4uK)
На данный момент скомпилированная игра выглядит вот так

а у меня вот так
No suitable graphis card found.
Could not find a Direct3D device that supports the XNA Framework HiDef profile.
Verify that a suitable graphics device is installed.
Make sure the desktor in not locked, and that no other application is running in full screen mode.
Avoid running under Remote Desktor or as a Windows service.
Check the display properties to make sure hardware acceleration is set to Full
Hagrael Дата: Суббота, 19.02.2011, 17:56 | Сообщение # 10
Просмотр профиля: Hagrael

Сообщений: [1476]
ктоотоо, вроде что-то с DirectX.

George & Daniel:
Война сухофруктов
ктоотоо Дата: Суббота, 19.02.2011, 18:41 | Сообщение # 11
Просмотр профиля: ктоотоо

Сообщений: [3]
Hagrael, скорее с видео картой
Форум разработчиков игр » Полезные статьи, Примеры и Исходники » Остальные » Создание арканоида шаг за шагом в xna!
Страница 1 из 11
Поиск:

При полном или частичном копировании материалов сайта ссылка на Make-Games.ru обязательна. Make-Games.ru © 2008 - 2016 Хостинг от uWeb
Топ Разработка игр Рейтинг@Mail.ru