Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Взаимодействие объектов
Задачи работы:
- Изучить теоретические основы обработки столкновений объектов в двумерном пространстве
- Изучить алгоритмы обработки столкновений объектов в двумерном пространстве
- Рассмотреть алгоритм проверки принадлежности точки фигуре в двумерном пространстве
- Создать простую игру – игровой объект автоматически перемещается по экрану, отскакивая от его границ. Игрок должен с помощью мыши попасть по объекту. Каждое попадание должно привести к выводу информации о количестве попаданий в заголовок игрового окна.
- Создать простую игру "Стрельба по мишени" с реализацией алгоритма проверки принадлежности точки окружности
Обработка столкновений
Выше мы уже имели дело с простым примером обработки столкновений объектов. Были созданы правила, в соответствии с которыми игровой объект не мог пересечь границы экрана. Часто для обработки столкновений двумерных объектов обрабатывают столкновения прямоугольников, описывающих эти объекты. Для этого нужно знать координаты прямоугольника, в нашем случае координаты задаются координатой левой верхней вершины, шириной и высотой фигуры.
На рис. 8.1. вы можете видеть пример объектов, которые не сталкиваются друг с другом.
На рис. 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, реализующий проверку столкновений объектов