XNA пересекается/сталкивается с несколькими классами?

В течение последних 12 часов я пробовал «все» различные методы, которые я могу придумать, чтобы правильно пересечь/проверить столкновение двух прямоугольников в XNA (4.0).

У меня есть три класса (просто примеры имен):

  • Game1.cs
  • Player.cs
  • Man.cs

В Game1 я загружаю контент следующим образом:

// В начале Game1:

    Player player;
    Man man;

// Загрузить содержимое:

    man = new Man(Content.Load<Texture2D>("ManImage"), new Rectangle(440, 310, 150, 98));
    player = new Player(Content.Load<Texture2D>("playerSheet"), new Vector2(40, 420), 50, 44);

Тем не менее, я хочу проверить наличие столкновения между человеком и игроком, но я не понимаю, как «присоединиться» к этим двум классам, чтобы иметь возможность выполнять if (пересекается) в Game1 (если это место для этого).

Прямоугольник игрока выглядит так:

playerRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);

Я только что стал полностью «кодовым слепым» здесь, или что? Любой, кто может помочь мне с этим, мотивация упала после 12 часов испытаний на столкновение.


person AndreasB    schedule 29.04.2012    source источник
comment
Возможно, я не понимаю вопроса, но если вы можете получить два объекта Rectangle, один для игрока и один для мужчины, не могли бы вы просто написать функцию в Game1, которая проверяет, пересекаются ли два прямоугольника? Тогда вам не нужно беспокоиться о присоединении к классам, верно? Просто создайте функцию GetRect() как для человека, так и для игрока, а затем отправьте эти два прямоугольника в функцию Intersects() в Game1.   -  person M Katz    schedule 29.04.2012


Ответы (1)


Вы можете для обоих классов добавить свойство

public Rectangle PositionRectangle { get; private set; }

затем в соответствующих конструкторах вам нужно будет инициировать это свойство

public Man(..., Rectangle rectangle)
{
    PositionRectangle = rectangle;
}

public Player(..., Vector2 position, int width, int height)
{
    PositionRectangle = new rectangle((int)position.X, (int)position.Y, width, height);
}

Вам не нужно беспокоиться о том, какой кадр вы показываете, так как он связан с исходным прямоугольником, а не с целевым прямоугольником (это то, что вам нужно для тест на столкновение).

Затем вы можете легко проверить эти столкновения

if(man.PositionRectangle.Intersects(player.PositionRectangle))
{
    //collision logic
}

Конечно, вам нужно позаботиться об обновлении этих прямоугольников каждый раз, когда вы меняете позиции (или ширину и высоту, если они изменяемы)


Небольшое редактирование (или лучшая версия)

Если вы хотите легко расположить Человека и Игрока, не беспокоясь об обновлении их прямоугольников, вы можете настроить это следующим образом:

class Man
{
    Texture2D _texture;

    public Vector2 Position { get; set; }
    public int Width { get; set; } 
    public int Height { get; set; }

    public Rectangle PositionRectangle
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
        }
    }

    public Man(Texture2D texture)
    {
        this._texture = texture;
        this.Width = texture.Width;
        this.Height = texture.Height;
    }

    ... //other man related logic!
}

class Player
{
    Texture2D _texture;
    int _frameCount;
    int _currentFrame;
    //other frame related logic...

    public Vector2 Position { get; set; }
    public int Width { get; set; } 
    public int Height { get; set; }

    public Rectangle PositionRectangle
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
        }
    }

    public Rectangle SourceRectangle
    {
        get
        {
            return new Rectangle(Width * _currentFrame, 0, Width, Height);
        }
    }

    public Player(Texture2D texture, int frameWidth, int frameCount)
    {
        this._texture = texture;
        this.Width = frameWidth;
        this.Height = texture.Height;
        this._frameCount = frameCount;
        this._currentFrame = 0;
        //etc...
    }

    ... //other player related logic! such as updating _currentFrame

    public Draw(SpriteBatch spriteBatch)
    {
         spriteBatch.Draw(_texture, PositionRectangle, SourceRectangle, Color.White);
    }
}

Здесь я дал вам пример того, как вы можете использовать методы доступа к свойствам для динамического создания соответствующих прямоугольников!

Вы используете PositionRectangle, чтобы определить, где ваш игрок (или человек) будет расположен на экране, и вы используете SourceRectangle, чтобы определить, какую часть текстуры вы собираетесь рисовать.

Кроме того, если ширина и высота вашего мужчины и игрока не будут меняться, вам следует установить их аксессоры set на private.

Когда вам нужно изменить местоположения, вы просто устанавливаете их свойство position

man.Position = new Vector2(100, 100); //i.e.

и ваши коллизии и логика рисования будут автоматически использовать новые прямоугольники без какого-либо дополнительного вмешательства!

Надеюсь, вам понравится!

Редактировать2

Что касается исходного прямоугольника, который является общедоступным, вам это нужно только в том случае, если вы рисуете его снаружи (т.е. Game1 вызывает spriteBatch.Draw(player.Texture, player.PositionRectangle, player.SourceRectangle, Color.White);).

Если вы рисуете его, как в примере (изнутри), вы можете просто отказаться от всего public Recangle SourceRectangle{...} и просто использовать этот прямоугольник непосредственно в отрисовке:

    public Draw(SpriteBatch spriteBatch)
    {
         spriteBatch.Draw(_texture, PositionRectangle, new Rectangle(Width * _currentFrame, 0, Width, Height), Color.White);
    }
person neeKo    schedule 29.04.2012
comment
Это кажется отличной идеей, конечно! Я сейчас реализую ваши обновленные идеи, но на данный момент персонаж игрока стоит совершенно неподвижно (однако спрайтовая анимация работает, когда я использую клавиши), но он не перемещается по экрану. Я предполагаю, что это как-то связано с frameCount и currentFrame. Я также реализовал функцию Edit2, но мне придется поработать над движением персонажа. - person AndreasB; 29.04.2012
comment
Хм, это не должно иметь никакого отношения к currentFrame (это используется только для источника) - вы уверены, что обновляете player.Position? попробуйте присвоить ему какие-то значения, просто чтобы посмотреть, переместится ли туда игрок - person neeKo; 29.04.2012
comment
Ха-ха, какая глупая ошибка с моей стороны. Я случайно использовал player.Position (начальную позицию) в обновлении Game1 вместо LoadContent. Теперь работает ОТЛИЧНО! Тем не менее, я пытаюсь использовать простые проверки if, чтобы запретить уход с экрана, используя это, но playerPosition не является переменной, как он говорит. Любые идеи по этому поводу? если (playerPosition.Y ›= 480) playerPosition.Y = 480; - person AndreasB; 29.04.2012
comment
Вы должны просто установить его следующим образом: player.Position = new Vector2(player.Position.X, 480); Это потому, что player.Position имеет тип Vector2, который является типом значения (struct), а не ссылочным типом (class). - person neeKo; 29.04.2012
comment
Но тогда позиция игрока будет равна 480, верно? Я пытаюсь создать некоторые стены, куда игрок не может попасть (например, в воздух или за пределы области просмотра). И я не могу использовать if(player.Position.X >= 480) { player.Position.X = 480; }, так как Position не является переменной. Извините, если то, что вы объяснили, является ответом на этот вопрос, я могу неправильно понять. - person AndreasB; 29.04.2012
comment
Когда вы устанавливаете значения player.Position, вы всегда должны использовать другой Vector2 (либо новый, либо существующий). Из-за того, как работают свойства (как работает их set;), вы не можете напрямую назначать значения подсвойствам (в данном случае X) свойств (в данном случае Position), тип которых является типом значения (в данном случае Vector2). Вы всегда должны назначать целый тип значения. Пример: if(player.Position.X >= 480) { player.Position = new Vector2(480, player.Position.Y); } Это было бы эквивалентно простому присвоению 480 player.Position.X, потому что Y остается прежним! :) - person neeKo; 29.04.2012
comment
И снова здравствуйте! Большое спасибо, я продолжу пробовать это, когда вернусь домой к файлам проекта. Я только что заметил, что значения не будут работать с этим методом, как с четырьмя комментариями выше. Я могу остановить движение персонажа за пределы экрана влево, но не остановить его от перемещения с тротуара / тротуара, поскольку он просто телепортируется из-за значений. Надо будет только потом переделать :) - person AndreasB; 29.04.2012
comment
НВМ, работает! Мне просто пришлось немного поиграть со значениями :). Отлично, большое спасибо! Если бы не ты, я бы использовал остаток недели :) - person AndreasB; 29.04.2012