2014-07-25 5 views
2

Я работаю над своей игрой, используя XNA. Я нашел серию обучающих программ от Oyyou от YouTube и дошел до учебника по столкновению. Я успешно обработал гравитацию, движение и анимацию. Но у меня проблема с столкновением. Искровая точка моего персонажа поднимается в воздух. enter image description hereXNA не прыгает с платформы

Первое значение - мой bool hasJumped. А вторая - у-скорость. Он ускоряется на 0,25. Характер медленно падает медленно. Все четыре платформы сделаны одинаково. Все четыре находятся в списке, и я ничего не делаю для работы с ними.

enter image description here

Когда я приземлился на низшем (землю) Я получаю параметры мне нужно. hasJumped ложна и velocity.Y является 0.

enter image description here

Но когда я на одном из трех нешлифованных платформ результатов не как я хочу их. Скорость равна 0.25, хотя я делаю это 0. И hasJumped не становится истинным, потому что моя скорость является ненулевой переменной. К несчастью, я не могу отправлять изображения, поэтому я не могу их показать. Но я выложу свой код: это класс maingame, где я добавляю игроков и платформы.

protected override void LoadContent() 
    { 
     // Create a new SpriteBatch, which can be used to draw textures. 
     spriteBatch = new SpriteBatch(GraphicsDevice); 

     player = new Animation(Content.Load<Texture2D>("player"), Content.Load<Texture2D>("rect"), new Vector2(300 + 28, graphics.PreferredBackBufferHeight - 500), 47, 44, graphics.PreferredBackBufferHeight, graphics.PreferredBackBufferWidth); 
     platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(300,graphics.PreferredBackBufferHeight-100), 80,50)); 
     platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(500, graphics.PreferredBackBufferHeight - 50), 80, 50)); 
     platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(700, graphics.PreferredBackBufferHeight - 60),80,50)); 
     platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(0, graphics.PreferredBackBufferHeight - 10), graphics.PreferredBackBufferWidth, 10)); 
     // TODO: use this.Content to load your game content here 
    } 

Это мой Animation класс:

class Animation 
{ 
    Texture2D texture; 
    Texture2D rectText; 
    public Rectangle rectangle; 
    public Rectangle collisionRect; 

    public Vector2 position; 
    Vector2 origin; 
    public Vector2 velocity; 

    int currentFrame; 
    int frameHeight; 
    int frameWidth; 
    int screenHeight; 
    int screenWidth; 

    float timer; 
    float interval = 60; 

    bool movingRight; 
    public bool hasJumped; 

    public Animation(Texture2D newTexture, Texture2D newRectText, Vector2 newPosition, int newHeight, int newWidth, int screenH, int screenW) 
    { 
     rectText = newRectText; 
     texture = newTexture; 
     position = newPosition; 
     frameHeight = newHeight; 
     frameWidth = newWidth; 
     screenHeight = screenH; 
     screenWidth = screenW; 
     hasJumped = true; 
    } 

    public void Update(GameTime gameTime) 
    { 
     rectangle = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight); 
     collisionRect = new Rectangle((int)position.X-frameWidth/2, (int)position.Y - frameHeight/2, frameWidth, frameHeight); 
     origin = new Vector2(rectangle.Width/2, rectangle.Height/2); 
     position = position + velocity; 


     if (Keyboard.GetState().IsKeyDown(Keys.Right)) 
     { 
      AnimateRight(gameTime); 
      velocity.X = 5; 
      movingRight = true; 
     } 
     else if (Keyboard.GetState().IsKeyDown(Keys.Left)) 
     { 
      AnimateLeft(gameTime); 
      velocity.X = -5; 
      movingRight = false; 
     } 
     else 
     { 
      velocity.X = 0f; 
      if (movingRight) 
       currentFrame = 0; 
      else currentFrame = 4; 
     } 


     if(Keyboard.GetState().IsKeyDown(Keys.Space) && !hasJumped) 
     { 
      position.Y -= 5f; 
      velocity.Y = -10; 
      hasJumped = true; 
     } 

     if(hasJumped) 
     { 
      velocity.Y += 0.25f; 
     } 


     if(position.X<0+frameWidth/2) 
     { 
      position.X = 0 + frameWidth/2; 
     } 
     else if (position.X>screenWidth-frameWidth/2) 
     { 
      position.X = screenWidth - frameWidth/2; 
     } 
    } 

    public void AnimateRight(GameTime gameTime) 
    { 
     timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds/2; 
     if(timer>interval) 
     { 
      currentFrame++; 
      timer = 0; 
      if (currentFrame > 3) 
      { 
       currentFrame = 0; 
      } 
     } 
    } 

    public void AnimateLeft(GameTime gameTime) 
    { 
     timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds/2; 
     if (timer > interval) 
     { 
      currentFrame++; 
      timer = 0; 
      if (currentFrame > 7 || currentFrame < 4) 
      { 
       currentFrame = 4; 
      } 
     } 
    } 

    public void Draw(SpriteBatch spriteBatch) 
    { 
     spriteBatch.Draw(texture,position,rectangle,Color.White, 0f, origin, 1.0f, SpriteEffects.None, 0); 
     // spriteBatch.Draw(rectText,collisionRect,Color.White); 
    } 
}} 

Класс платформы довольно прост:

class Platform 
{ 
    Texture2D texture; 
    Vector2 position; 
    public Rectangle rectangle; 



    public Platform(Texture2D newTexture, Vector2 newPosition, int platformWidth, int platformHeight) 
    { 
     texture = newTexture; 
     position = newPosition; 

     rectangle = new Rectangle((int)position.X, (int)position.Y, platformWidth, platformHeight); 
    } 

    public void Draw(SpriteBatch spriteBatch) 
    { 
     spriteBatch.Draw(texture, rectangle, Color.White); 

    } 
} 

и метод столкновения:

public static bool isOnTopOf(this Rectangle r1, Rectangle r2) 
    { 
     return (r1.Bottom >= r2.Top - 10 && 
      r1.Bottom <= r2.Top + 10 && 
      r1.Right >= r2.Left + 10 && 
      r1.Left <= r2.Right - 10); 
    } 

Проблема должна находится здесь:

foreach (Platform a in platformList) 
     { 
      if (player.collisionRect.isOnTopOf(a.rectangle) && player.velocity.Y>=0) 
      { 
       player.hasJumped = false; 
       player.velocity.Y = 0f; 

       if(player.collisionRect.Bottom > a.rectangle.Top || player.collisionRect.Bottom - a.rectangle.Top <=10) 
       { 
        player.position.Y = a.rectangle.Y - 48/2; 
        player.hasJumped = false; 

       } 
      } 

      else 
      { 
       player.hasJumped = true; 
      } 
     } 

Но если я исключу последнее, это не упадет с платформы.

Благодарим вас за вопрос. Я добавил изображения.

+0

Где именно вы устанавливаете haspedded to false? – SKleanthous

+0

@SKleanthous извините, обновите вопрос сейчас – Vendetta8247

+0

@ Vendetta8247 Похоже, когда вы прыгаете, вы устанавливаете ** скорость.Y = -10 **. Однако в коде, где вы проверяете, находится ли игрок поверх поля, вы также проверяете, есть ли ** speed.Y> = 0 **. Может ли это быть вашей проблемой? –

ответ

1

Проблема заключается в том, что, когда пользователь находится на вершине платформы, которая не является самой низкой, во время другой проверки, если пользователь находится на платформе, вы явно устанавливаете hasJumped в true.

Что вы должны сделать в своем предпродаже, где вы проверяете свои платформы, чтобы заказать их, УВЕЛИЧИВАЯ Y-координату (очень сильно в зависимости от настроек вашей камеры) и перерыв после того, как вы установили hasJumped в false. Таким образом, вы избежите ваш вопрос:

foreach (Platform a in platformList.OrderByY()) 
{ 
    if (player.collisionRect.isOnTopOf(a.rectangle) && player.velocity.Y>=0) 
    { 
     player.hasJumped = false; 
     player.velocity.Y = 0f; 

     if(player.collisionRect.Bottom > a.rectangle.Top || player.collisionRect.Bottom - a.rectangle.Top <=10) 
     { 
      player.position.Y = a.rectangle.Y - 48/2; 
      player.hasJumped = false; 
     } 

     break; 
    } 
    else 
    { 
     player.hasJumped = true; 
    } 
} 

К сожалению, это часто бывает с развитием 3D, что мы должны сделать некоторые хаки, чтобы получить приложение, чтобы правильно оказать. Это особенно важно при рендеринге сложного элемента с продвинутыми прозрачными пленками. Однако в вашем случае я бы посоветовал представить себе, как вы работаете с столкновениями.

Разработка игр - непростая задача. Внешне ограничения, с которыми вы работаете, обеспечивают минимальную архитектуру. Все в игре XNA вращается вокруг цикла обновления, и способность контролировать, какой элемент обновляется, настолько легка и заманчива, что люди склонны использовать это.Однако, как правило, это гораздо лучший подход, чтобы попытаться экстраполировать функциональные возможности таким образом, чтобы ваши модели действовали определенным образом. Одним из способов достижения этой цели является разделение цикла обновления вашей игры в следующих фазах:

  1. Input Phase: Получение данных от пользователя и обрабатывать их как события (это может быть простой метод вызывает на элементах в метод, отличный от Update или более сложный, но лучший метод, например, использование Rx)
  2. Фаза перемещения: Разработка некоторых физических характеристик в ваших моделях (ускорение, скорость, вес и т. д.) и позволяющая им выполнять работу по позиционированию, вращаясь самостоятельно во время фазы движения. Это единственное, что они должны делать в Update.
  3. Стадия столкновений: Испытание на столкновение, а затем огонь на объектах для обработки столкновений.
  4. Этап очистки: Устранение любых проблем, например, перемещение внутри стены во время фазы обнаружения столкновения. или поэтапное удаление частиц и т. д. Это становится важным, когда у вас есть требования опираться на точные пиксели, чтобы избежать размытия и т. д.

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

Мое предложение использовать Rx может показаться странным для игры XNA, но поверьте мне, это отличный способ работать с событиями. Наконец, я хотел бы упомянуть MonoGame, отличную основу для разработки игр для Windows, Mac, Linux, Android, iPhone, Windows Phone, WinRT (и даже больше), если вы еще этого не знаете.

+0

Благодарим вас за ответ. Я изменил порядок добавления платформ. Теперь он работает только с вершиной. И земли нет. Просто кажется, что вместо foreach он просто проверяет последнее добавленное. Но я хотел бы знать, есть ли лучший способ переделать столкновение. Я не полный новичок, но это было, как я думал, столкновение работает. Я был бы очень признателен, если бы вы могли рассказать мне об этом. – Vendetta8247

+0

@ Vendetta8247 Я обновил свой ответ, чтобы решить вашу текущую проблему и предоставить некоторую информацию о том, как лучше двигаться отсюда. – SKleanthous

+0

Большое спасибо за действительно хороший ответ. Оказывается, перерыва было достаточно, чтобы решить мою проблему. Но я буду держать ваши советы в голове и надеюсь, что это поможет мне в будущем. Теперь я буду работать над своим AI, камерой и так далее. – Vendetta8247

Смежные вопросы