Спонсор: Microsoft
Опубликован: 10.04.2009 | Уровень: специалист | Доступ: платный
Самостоятельная работа 4:

Взаимодействие объектов

Аннотация: Обработка взаимодействия объектов – это очень важная часть создания игры. В этой лабораторной работе мы рассмотрим обработку столкновений объектов.

Примеры к лабораторной работе

Задачи работы:

  • Изучить теоретические основы обработки столкновений объектов в двумерном пространстве
  • Изучить алгоритмы обработки столкновений объектов в двумерном пространстве
  • Рассмотреть алгоритм проверки принадлежности точки фигуре в двумерном пространстве
  • Создать простую игру – игровой объект автоматически перемещается по экрану, отскакивая от его границ. Игрок должен с помощью мыши попасть по объекту. Каждое попадание должно привести к выводу информации о количестве попаданий в заголовок игрового окна.
  • Создать простую игру "Стрельба по мишени" с реализацией алгоритма проверки принадлежности точки окружности

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

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

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

Непересекающиеся прямоугольники

Рис. 8.1. Непересекающиеся прямоугольники

На рис. 8.2. вы можете видеть пересекающиеся прямоугольники.

Пересекающиеся прямоугольники

Рис. 8.2. Пересекающиеся прямоугольники

Алгоритмически условие пересечения прямоугольников можно записать в виде такого условия (листинг 8.1.)

Если (А.X+A.Ширина > B.X И 
	A.X < B.X+B.Ширина И
	A.Y+A.Высота>В.Высота И
	A.Y<B.Y+B.Высота)
Тогда
	Есть столкновение
Иначе
	Нет столкновения
Листинг 8.1. Проверка пересечения прямоугольников

Создадим пример, иллюстрирующий этот алгоритм. Возьмем за основу проект P3_6. Назовем новый проект P4_1. Напомним, что в проекте P3_6 мы рассматривали централизованное управление объектами из основного игрового объекта. Продолжим этот пример, доработав основной игровой объект таким образом, чтобы при перемещении объектов проводилась проверка на их столкновение.

В листинге 8.2. приведен код объекта Game1, где мы и реализовали такую проверку. Так как объекты перемещаются путем модификации их позиции на игровом экране, реализуем проверку на столкновение при попытке перемещения объекта. Если объекты сталкиваются – мы таким образом модифицируем их координаты, чтобы они не перекрывались.

using System;
using System.Collections.Generic;
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.Net;
using Microsoft.Xna.Framework.Storage;

namespace P4_1
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        spriteComp gameObject1, gameObject2;
        Texture2D texture;
        Rectangle scrBounds;
        float sprSpeed;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Services.AddService(typeof(SpriteBatch), spriteBatch);
            texture = Content.Load<Texture2D>("BallandBats");
            scrBounds = new Rectangle(0, 0,
                this.Window.ClientBounds.Width,
                this.Window.ClientBounds.Height);
            sprSpeed = 5;
            CreateNewObject();
            // TODO: use this.Content to load your game content here
        }

        protected void CreateNewObject()
        {
            gameObject1 = new spriteComp(this, ref texture,
                new Rectangle(18, 9, 17, 88),
                new Vector2(100, 150));
            Components.Add(gameObject1);
            gameObject2 = new spriteComp(this, ref texture,
                new Rectangle(17, 106, 17, 88),
                new Vector2(200, 150));
            Components.Add(gameObject2);
        }

        void Test(spriteComp spr, Rectangle scr)
        {
            if (spr.sprPosition.X < scr.Left)
            {
                spr.sprPosition.X = scr.Left;
            }
            if (spr.sprPosition.X > scr.Width - spr.sprRectangle.Width)
            {
                spr.sprPosition.X = scr.Width - spr.sprRectangle.Width;
            }
            if (spr.sprPosition.Y < scr.Top)
            {
                spr.sprPosition.Y = scr.Top;
            }
            if (spr.sprPosition.Y > scr.Height - spr.sprRectangle.Height)
            {
                spr.sprPosition.Y = scr.Height - spr.sprRectangle.Height;
            }
        }
        void MoveUp(spriteComp spr, float speed)
        {
            spr.sprPosition.Y -= speed ;
        }
        void MoveDown(spriteComp spr,float speed)
        {
            spr.sprPosition.Y += speed;
        }
        void MoveLeft(spriteComp spr, float speed)
        {
            spr.sprPosition.X -= speed ;
        }
        void MoveRight(spriteComp spr, float speed)
        {
            spr.sprPosition.X += speed ;
        }
        bool  IsCollide(spriteComp sp1, spriteComp sp2)
        {
            if (sp1.sprPosition.X < sp2.sprPosition.X + sp2.sprRectangle.Width &&
                sp1.sprPosition.X + sp1.sprRectangle.Width > sp2.sprPosition.X &&
                sp1.sprPosition.Y < sp2.sprPosition.Y + sp2.sprRectangle.Height &&
                sp1.sprPosition.Y + sp1.sprRectangle.Height > sp2.sprPosition.Y)
            {
                return true;
            }
            else return false;

        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            // TODO: Add your update logic here
            KeyboardState kbState = Keyboard.GetState();
            if (kbState.IsKeyDown(Keys.Up))
            {
                MoveUp(gameObject1, sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveDown(gameObject1, (sprSpeed / 10));
                }
            }
            if (kbState.IsKeyDown(Keys.Down))
            {
                MoveDown(gameObject1, sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveUp(gameObject1, (sprSpeed / 10));
                }
            }
            if (kbState.IsKeyDown(Keys.Left))
            {
                MoveLeft(gameObject1, sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveRight(gameObject1, (sprSpeed / 10));
                }
            }
            if (kbState.IsKeyDown(Keys.Right))
            {
                MoveRight(gameObject1,sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveLeft(gameObject1, (sprSpeed / 10));
                }
            }
            Test(gameObject1, scrBounds);
            if (kbState.IsKeyDown(Keys.W))
            {
                MoveUp(gameObject2,sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveDown(gameObject2, (sprSpeed / 10));
                }
            }
            if (kbState.IsKeyDown(Keys.S))
            {
                MoveDown(gameObject2,sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveUp(gameObject2, (sprSpeed / 10));
                }
            }
            if (kbState.IsKeyDown(Keys.A))
            {
                MoveLeft(gameObject2,sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveRight(gameObject2, (sprSpeed / 10));
                }
            }
            if (kbState.IsKeyDown(Keys.D))
            {
                MoveRight(gameObject2,sprSpeed );
                while (IsCollide(gameObject1, gameObject2))
                {
                    MoveLeft(gameObject2, (sprSpeed / 10));
                }
            }
            Test(gameObject2, scrBounds);
            
            base.Update(gameTime);
        }

        /// <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)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            spriteBatch.Begin();
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}
Листинг 8.2. Код объекта Game1, реализующий проверку столкновений объектов
Alina Lasskaja
Alina Lasskaja

Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить.....

Дмитрий Кацман
Дмитрий Кацман
Израиль
Андрей Веденин
Андрей Веденин
Россия, Белгород