2012-11-05 2 views
1

Я новичок в XNA как неделю назад, но я немного поработал с C#. Я загрузил стартовый комплект для платформы Platformer 4.0. Я прошел через учебники, и теперь я пытаюсь заставить свою программу прокручивать фон по горизонтали, когда мой персонаж движется вправо (например, Super Mario Bros).XNA Game Studio 4.0 Платформа для прокрутки

У меня он работает несколько, но мой персонаж в конце концов уходит с экрана, и мои объекты остаются в кадре. Трудно нарисовать идеальную картинку в тексте, поэтому я записал видео о том, что происходит, и поставлю его here.

Я не уверен, где выровняется выравнивание. Я включаю в себя мои Player.cs и Layer2.cs.

Простите меня за музыку фона; Я только что добавил 1-й .wma-файл, который мог найти в Интернете.

Player.cs 
#region File Description 
//----------------------------------------------------------------------------- 
// Player.cs 
// 
// Microsoft XNA Community Game Platform 
// Copyright (C) Microsoft Corporation. All rights reserved. 
//----------------------------------------------------------------------------- 
#endregion 

using System; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using Microsoft.Xna.Framework.Input.Touch; 

namespace Platformer 
{ 
/// <summary> 
/// Our fearless adventurer! 
/// </summary> 
class Player 
{ 
    // Animations 
    private Animation idleAnimation; 
    private Animation idleAnimationBack; 
    private Animation runAnimation; 
    private Animation jumpAnimation; 
    private Animation celebrateAnimation; 
    private Animation dieAnimation; 
    private SpriteEffects flip = SpriteEffects.None; 
    private AnimationPlayer sprite; 

    // Sounds 
    private SoundEffect killedSound; 
    private SoundEffect jumpSound; 
    private SoundEffect fallSound; 

    public Level Level 
    { 
     get { return level; } 
    } 
    Level level; 

    public bool IsAlive 
    { 
     get { return isAlive; } 
    } 
    bool isAlive; 

    // Physics state 
    public Vector2 Position 
    { 
     get { return position; } 
     set { position = value; } 
    } 
    Vector2 position; 

    private float previousBottom; 

    public Vector2 Velocity 
    { 
     get { return velocity; } 
     set { velocity = value; } 
    } 
    Vector2 velocity; 

    // Constants for controling horizontal movement 
    private const float MoveAcceleration = 13000.0f; 
    private const float MaxMoveSpeed = 1750.0f; 
    private const float GroundDragFactor = 0.48f; 
    private const float AirDragFactor = 0.58f; 

    // Constants for controlling vertical movement 
    private const float MaxJumpTime = 0.30f; 
    private const float JumpLaunchVelocity = -3500.0f; 
    private const float GravityAcceleration = 3400.0f; 
    private const float MaxFallSpeed = 550.0f; 
    private const float JumpControlPower = 0.14f; 

    // Input configuration 
    private const float MoveStickScale = 1.0f; 
    private const float AccelerometerScale = 1.5f; 
    private const Buttons JumpButton = Buttons.A; 
    private const Buttons BackwardButton = Buttons.LeftStick; 

    /// <summary> 
    /// Gets whether or not the player's feet are on the ground. 
    /// </summary> 
    public bool IsOnGround 
    { 
     get { return isOnGround; } 
    } 
    bool isOnGround; 

    /// <summary> 
    /// Current user movement input. 
    /// </summary> 
    private float movement; 

    // Jumping state 
    private bool isJumping; 
    private bool wasJumping; 
    private float jumpTime; 
    private bool isBackwards; 

    private Rectangle localBounds; 
    /// <summary> 
    /// Gets a rectangle which bounds this player in world space. 
    /// </summary> 
    public Rectangle BoundingRectangle 
    { 
     get 
     { 
      int left = (int)Math.Round(Position.X - sprite.Origin.X) + localBounds.X; 
      int top = (int)Math.Round(Position.Y - sprite.Origin.Y) + localBounds.Y; 

      return new Rectangle(left, top, localBounds.Width, localBounds.Height); 
     } 
    } 

    /// <summary> 
    /// Constructors a new player. 
    /// </summary> 
    public Player(Level level, Vector2 position) 
    { 
     this.level = level; 

     LoadContent(); 

     Reset(position); 
    } 

    /// <summary> 
    /// Loads the player sprite sheet and sounds. 
    /// </summary> 
    public void LoadContent() 
    { 
     // Load animated textures. 
     idleAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewIdle"), 0.1f, true); 
     idleAnimationBack = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewIdleBack"), 0.1f, true); 
     runAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewRun5"), 0.1f, true); 
     jumpAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewJump2"), 0.1f, false); 
     celebrateAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewJump"), 0.1f, false); 
     dieAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewDie"), 0.1f, false); 

     // Calculate bounds within texture size.    
     int width = (int)(idleAnimation.FrameWidth * 0.4); 
     int left = (idleAnimation.FrameWidth - width)/2; 
     int height = (int)(idleAnimation.FrameWidth * 0.9); 
     int top = idleAnimation.FrameHeight - height; 
     localBounds = new Rectangle(left, top, width, height); 

     // Load sounds.    
     killedSound = Level.Content.Load<SoundEffect>("Sounds/PlayerKilled"); 
     jumpSound = Level.Content.Load<SoundEffect>("Sounds/PlayerJump"); 
     fallSound = Level.Content.Load<SoundEffect>("Sounds/PlayerFall"); 
    } 

    /// <summary> 
    /// Resets the player to life. 
    /// </summary> 
    /// <param name="position">The position to come to life at.</param> 
    public void Reset(Vector2 position) 
    { 
     Position = position; 
     Velocity = Vector2.Zero; 
     isAlive = true; 
     sprite.PlayAnimation(idleAnimation); 
    } 

    /// <summary> 
    /// Handles input, performs physics, and animates the player sprite. 
    /// </summary> 
    /// <remarks> 
    /// We pass in all of the input states so that our game is only polling the hardware 
    /// once per frame. We also pass the game's orientation because when using the accelerometer, 
    /// we need to reverse our motion when the orientation is in the LandscapeRight orientation. 
    /// </remarks> 
    public void Update(
     GameTime gameTime, 
     KeyboardState keyboardState, 
     GamePadState gamePadState, 
     TouchCollection touchState, 
     AccelerometerState accelState, 
     DisplayOrientation orientation) 
    { 
     GetInput(keyboardState, gamePadState, touchState, accelState, orientation); 

     ApplyPhysics(gameTime); 

     if (IsAlive && IsOnGround) 
     { 
      if (Math.Abs(Velocity.X) - 0.02f > 0) 
      { 
       sprite.PlayAnimation(runAnimation); 
      } 
      else 
      { 
       sprite.PlayAnimation(idleAnimation); 
      } 
     } 

     // Clear input. 
     movement = 0.0f; 
     isJumping = false; 
    } 

    /// <summary> 
    /// Gets player horizontal movement and jump commands from input. 
    /// </summary> 
    private void GetInput(
     KeyboardState keyboardState, 
     GamePadState gamePadState, 
     TouchCollection touchState, 
     AccelerometerState accelState, 
     DisplayOrientation orientation) 
    { 
     // Get analog horizontal movement. 
     movement = gamePadState.ThumbSticks.Left.X * MoveStickScale; 

     // Ignore small movements to prevent running in place. 
     if (Math.Abs(movement) < 0.5f) 
      movement = 0.0f; 

     // Move the player with accelerometer 
     if (Math.Abs(accelState.Acceleration.Y) > 0.10f) 
     { 
      // set our movement speed 
      movement = MathHelper.Clamp(-accelState.Acceleration.Y * AccelerometerScale, -1f, 1f); 

      // if we're in the LandscapeLeft orientation, we must reverse our movement 
      if (orientation == DisplayOrientation.LandscapeRight) 
       movement = -movement; 
     } 

     // If any digital horizontal movement input is found, override the analog movement. 
     if (gamePadState.IsButtonDown(Buttons.DPadLeft) || 
      keyboardState.IsKeyDown(Keys.Left) || 
      keyboardState.IsKeyDown(Keys.A)) 
     { 
      movement = -1.0f; 
     } 
     else if (gamePadState.IsButtonDown(Buttons.DPadRight) || 
       keyboardState.IsKeyDown(Keys.Right) || 
       keyboardState.IsKeyDown(Keys.D)) 
     { 
      movement = 1.0f; 
     } 

     // Check if the player wants to jump. 
     isJumping = 
      gamePadState.IsButtonDown(JumpButton) || 
      keyboardState.IsKeyDown(Keys.Space) || 
      keyboardState.IsKeyDown(Keys.W) || 
      touchState.AnyTouch(); 

     // Check if the player is pushing up. 
     isBackwards = 
     gamePadState.IsButtonDown(Buttons.DPadUp) || 
     gamePadState.ThumbSticks.Left.Y > 0 || 
     keyboardState.IsKeyDown(Keys.Up); 





    } 

    /// <summary> 
    /// Updates the player's velocity and position based on input, gravity, etc. 
    /// </summary> 
    public void ApplyPhysics(GameTime gameTime) 
    { 
     float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; 

     Vector2 previousPosition = Position; 

     // Base velocity is a combination of horizontal movement control and 
     // acceleration downward due to gravity. 
     velocity.X += movement * MoveAcceleration * elapsed; 
     velocity.Y = MathHelper.Clamp(velocity.Y + GravityAcceleration * elapsed, -MaxFallSpeed, MaxFallSpeed); 

     velocity.Y = DoJump(velocity.Y, gameTime); 

     // Apply pseudo-drag horizontally. 
     if (IsOnGround) 
      velocity.X *= GroundDragFactor; 
     else 
      velocity.X *= AirDragFactor; 

     // Prevent the player from running faster than his top speed.    
     velocity.X = MathHelper.Clamp(velocity.X, -MaxMoveSpeed, MaxMoveSpeed); 

     // Apply velocity. 
     Position += velocity * elapsed; 
     Position = new Vector2((float)Math.Round(Position.X), (float)Math.Round(Position.Y)); 

     // If the player is now colliding with the level, separate them. 
     HandleCollisions(); 

     // If the collision stopped us from moving, reset the velocity to zero. 
     if (Position.X == previousPosition.X) 
      velocity.X = 0; 

     if (Position.Y == previousPosition.Y) 
      velocity.Y = 0; 

     DoBackwards(gameTime); 
    } 

    /// <summary> 
    /// Calculates the Y velocity accounting for jumping and 
    /// animates accordingly. 
    /// </summary> 
    /// <remarks> 
    /// During the accent of a jump, the Y velocity is completely 
    /// overridden by a power curve. During the decent, gravity takes 
    /// over. The jump velocity is controlled by the jumpTime field 
    /// which measures time into the accent of the current jump. 
    /// </remarks> 
    /// <param name="velocityY"> 
    /// The player's current velocity along the Y axis. 
    /// </param> 
    /// <returns> 
    /// A new Y velocity if beginning or continuing a jump. 
    /// Otherwise, the existing Y velocity. 
    /// </returns> 
    private float DoJump(float velocityY, GameTime gameTime) 
    { 
     // If the player wants to jump 
     if (isJumping) 
     { 
      // Begin or continue a jump 
      if ((!wasJumping && IsOnGround) || jumpTime > 0.0f) 
      { 
       if (jumpTime == 0.0f) 
        jumpSound.Play(); 

       jumpTime += (float)gameTime.ElapsedGameTime.TotalSeconds; 
       sprite.PlayAnimation(jumpAnimation); 
      } 

      // If we are in the ascent of the jump 
      if (0.0f < jumpTime && jumpTime <= MaxJumpTime) 
      { 
       // Fully override the vertical velocity with a power curve that gives players more control over the top of the jump 
       velocityY = JumpLaunchVelocity * (1.0f - (float)Math.Pow(jumpTime/MaxJumpTime, JumpControlPower)); 
      } 
      else 
      { 
       // Reached the apex of the jump 
       jumpTime = 0.0f; 
      } 
     } 
     else 
     { 
      // Continues not jumping or cancels a jump in progress 
      jumpTime = 0.0f; 
     } 
     wasJumping = isJumping; 

     return velocityY; 
    } 

    private void DoBackwards(GameTime gameTime) 
    { 
     Animation idleOrig = idleAnimation; 

     // If the player pushes up 
     if (isBackwards) 
     { 
      idleAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewIdleBack"), 0.2f, true); 
     } 
     else 
     { 
      idleAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/DrewIdle"), 0.1f, true); 
     } 
    } 

    /// <summary> 
    /// Detects and resolves all collisions between the player and his neighboring 
    /// tiles. When a collision is detected, the player is pushed away along one 
    /// axis to prevent overlapping. There is some special logic for the Y axis to 
    /// handle platforms which behave differently depending on direction of movement. 
    /// </summary> 
    private void HandleCollisions() 
    { 
     // Get the player's bounding rectangle and find neighboring tiles. 
     Rectangle bounds = BoundingRectangle; 
     int leftTile = (int)Math.Floor((float)bounds.Left/Tile.Width); 
     int rightTile = (int)Math.Ceiling(((float)bounds.Right/Tile.Width)) - 1; 
     int topTile = (int)Math.Floor((float)bounds.Top/Tile.Height); 
     int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom/Tile.Height)) - 1; 

     // Reset flag to search for ground collision. 
     isOnGround = false; 

     // For each potentially colliding tile, 
     for (int y = topTile; y <= bottomTile; ++y) 
     { 
      for (int x = leftTile; x <= rightTile; ++x) 
      { 
       // If this tile is collidable, 
       TileCollision collision = Level.GetCollision(x, y); 
       if (collision != TileCollision.Passable) 
       { 
        // Determine collision depth (with direction) and magnitude. 
        Rectangle tileBounds = Level.GetBounds(x, y); 
        Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); 
        if (depth != Vector2.Zero) 
        { 
         float absDepthX = Math.Abs(depth.X); 
         float absDepthY = Math.Abs(depth.Y); 

         // Resolve the collision along the shallow axis. 
         if (absDepthY < absDepthX || collision == TileCollision.Platform) 
         { 
          // If we crossed the top of a tile, we are on the ground. 
          if (previousBottom <= tileBounds.Top) 
           isOnGround = true; 

          // Ignore platforms, unless we are on the ground. 
          if (collision == TileCollision.Impassable || IsOnGround) 
          { 
           // Resolve the collision along the Y axis. 
           Position = new Vector2(Position.X, Position.Y + depth.Y); 

           // Perform further collisions with the new bounds. 
           bounds = BoundingRectangle; 
          } 
         } 
         else if (collision == TileCollision.Impassable) // Ignore platforms. 
         { 
          // Resolve the collision along the X axis. 
          Position = new Vector2(Position.X + depth.X, Position.Y); 

          // Perform further collisions with the new bounds. 
          bounds = BoundingRectangle; 
         } 
        } 
       } 
      } 
     } 

     // Save the new bounds bottom. 
     previousBottom = bounds.Bottom; 
    } 

    /// <summary> 
    /// Called when the player has been killed. 
    /// </summary> 
    /// <param name="killedBy"> 
    /// The enemy who killed the player. This parameter is null if the player was 
    /// not killed by an enemy (fell into a hole). 
    /// </param> 
    public void OnKilled(Enemy killedBy) 
    { 
     isAlive = false; 

     if (killedBy != null) 
      killedSound.Play(); 
     else 
      fallSound.Play(); 

     sprite.PlayAnimation(dieAnimation); 
    } 

    /// <summary> 
    /// Called when this player reaches the level's exit. 
    /// </summary> 
    public void OnReachedExit() 
    { 
     sprite.PlayAnimation(celebrateAnimation); 
    } 

    /// <summary> 
    /// Draws the animated player. 
    /// </summary> 
    public void Draw(GameTime gameTime, SpriteBatch spriteBatch) 
    { 
     // Flip the sprite to face the way we are moving. 
     if (Velocity.X > 0) 
      flip = SpriteEffects.FlipHorizontally; 
     else if (Velocity.X < 0) 
      flip = SpriteEffects.None; 

     // Draw that sprite. 
     sprite.Draw(gameTime, spriteBatch, Position, flip); 
    } 
} 
} 

Layer2.cs 
#region File Description 
//----------------------------------------------------------------------------- 
// Layer2.cs 
// 
// Microsoft XNA Community Game Platform 
// Copyright (C) Microsoft Corporation. All rights reserved. 
//----------------------------------------------------------------------------- 
#endregion 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Content; 

namespace Platformer 
{ 
class Layer 
{ 
    public Texture2D[] Textures { get; private set; } 
    public float ScrollRate { get; private set; } 

    public Layer(ContentManager content, string basePath, float scrollRate) 
    { 
     // Assumes each layer only has 3 segments. 
     Textures = new Texture2D[3]; 
     for (int i = 0; i < 3; ++i) 
      Textures[i] = content.Load<Texture2D>(basePath + "_" + i); 

     ScrollRate = scrollRate; 
    } 

    public void Draw(SpriteBatch spriteBatch, float cameraPosition) 
    { 
     // Assume each segment is the same width. 
     int segmentWidth = Textures[0].Width; 

     // Calculate which segments to draw and how much to offset them. 
     float x = cameraPosition * ScrollRate; 
     int leftSegment = (int)Math.Floor(x/segmentWidth); 
     int rightSegment = leftSegment + 1; 
     x = (x/segmentWidth - leftSegment) * -segmentWidth; 

     spriteBatch.Draw(Textures[leftSegment % Textures.Length], new Vector2(x, 0.0f), Color.White); 
     spriteBatch.Draw(Textures[rightSegment % Textures.Length], new Vector2(x + segmentWidth, 0.0f), Color.White); 
    } 
} 
} 
+0

Возможно, это может быть проблема с вашей камерой. Можете ли вы это показать? –

ответ

0

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

Здесь я перечислю несколько из них, включая игру с прокруткой и 2D-игру.

Rimer's 2D tutoria является одним из лучших, что я нашел для начала работы с 2D XNA. Даже у него есть 3D-серия.

[Серия учебников по технике черепицы Ника Гравелина] (http://www.youtube.com/playlist?list=PL0A865073DA96A7DA) Замечательные видеоролики включают в себя 2D-редактор карт, анимацию, привязку границ, столкновение. Почти все, что вам нужно знать, чтобы создать замечательную 2D-игру. Боковая прокрутка, стиль RPG.

И последнее, но не менее три должны иметь книгу Learning XNA XNA Game Programming Recipes Building Game a practical guide to Independent developers

Я надеюсь, что мой ответ поможет вам с вашим обучением XNA начинания.

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