Wrox Programmer Forums

Need to download code?

View our list of code downloads.

| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: Professional XNA Game Programming: For Xbox 360 and Windows ISBN: 978-0-470-12677-6
This is the forum to discuss the Wrox book Professional XNA Game Programming: For Xbox 360 and Windows by Benjamin Nitschke; ISBN: 9780470126776
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional XNA Game Programming: For Xbox 360 and Windows ISBN: 978-0-470-12677-6 section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
 
 
Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old January 14th, 2008, 10:39 AM
Registered User
 
Join Date: Jan 2008
Location: Urbana, Illinois, USA.
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default Ball movement problems

This will probably end up being a rather silly issue. Been working my way through the pong example in chapter 2. I've just finished the bit on page 47, where the ball should move but no collision deetection has been added. However, the ball only moves very jerkily in the center of the screen. Just sort of pops around inside of about a half-inch by half-inch area. Here's the math bit in my update method that should move the ball:

ballPosition += ballSpeedVector *
                moveFactorPerSecond * BallSpeedMultiplicator;

That's a straight copy from the book and none of the erratta seems to touch on this. Has anyone else had any problmes? I've also reviewed the example code for download. The base movement line is the same as above. I know there are also a bunch of collision detection checks in the example too, but I'm just not to that point and wondering if the behaviour I'm seeing is expected or not. Seems as though I should see more fluid movement, just not collision, at this point.
Thanks in advance for any help. I can also post the whole code file if need be. Just didn't wanna overrun everyone with code.

  #2 (permalink)  
Old January 15th, 2008, 02:50 PM
Registered User
 
Join Date: Jan 2008
Location: Urbana, Illinois, USA.
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I thought since no one had replied just yet I would go ahead and post the code in it's entirety. I'm hoping it just comes down to a silly mistake on my part. Not getting any compile errors, just a couple of values set but not used warnings, but I know why those are there (because not reached that part of the book yet).

Code:
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 pong
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class PongGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public PongGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        public static void StartGame()
        {
            using (PongGame game = new PongGame())
            {
                game.Run();
            }//using
        }//StartGame()
        static TestPongGame testGame;
        static void StartTest(TestDelegate testLoop)
        {
            using (testGame = new TestPongGame(testLoop))
            {
                testGame.Run();
            } //using
        } //StartTest(testLoop)
        // Global Vars
        Texture2D backgroundTexture, menuTexture, gameTexture;
        int width = 0;
        int height = 0;
        int leftPlayerLives = 0;
        int rightPlayerLives = 0;
        ///<summary>
        /// Current Paddle Postions, 0 means top, 1 means bottom
        ///</summary>
        float leftPaddlePosition = 0.5f,
            rightPaddlePostion = 0.5f;
        ///<summary>
        ///Current ball psotion, again from 0 to 1, 0 is left and top,
        /// 1 is bottom and right
        ///</summary>
        Vector2 ballPosition = new Vector2(0.5f, 0.5f);
        ///<summary>
        ///Ball speed vector, randomized for every new ball.
        /// Will be set to Zero if we are in menu or game is over.
        ///</summary>
        Vector2 ballSpeedVector = new Vector2(0, 0);
        ///<summary>
        /// Ball speed multiplicator, this is how much scree space the ball
        /// will travel each second.
        ///</summary>
        const float BallSpeedMultiplicator = 0.5f;
        ///<summary>
        /// Computer paddle speed. If the ball moves faster up or down than
        /// this, the computer paddle can't keep up and finally we will win.
        ///</summary>
        const float ComputerPaddleSpeed = 0.5f;
        ///<summary>
        /// Game Modes
        ///</summary>
        enum GameMode
        {
            Menu,
            Game,
            GameOver,
        }
        ///<summary>
        /// Are we in multiplayer game? If this is false, the computer
        /// controls the left paddle.
        ///</summary>
        bool multiplayer = false;
        ///<summary>
        /// Game mode we are currently in
        ///</summary>
        GameMode gameMode = GameMode.Menu;
        ///<summary>
        /// Currently Selected Menu Item
        ///</summary>
        int currentMenuItem = 0;
        //Rectangles
        static readonly Rectangle
            XnaPongLogoRect = new Rectangle(0, 0, 512, 110),
            MenuSingleplayerRect = new Rectangle(0,110,512,38),
            MenuMultiplayerRect = new Rectangle(0,148,512,38),
            MenuExitRect = new Rectangle(0,185,512,38),
            GameLivesRect = new Rectangle(0,222,155,35),
            GameRedWonRect = new Rectangle(151,222,155,34),
            GameBlueWonRect = new Rectangle(338,222,165,34),
            GameRedPaddleRect = new Rectangle(23,0,22,92),
            GameBluePaddleRect = new Rectangle(0,0,22,92),
            GameBallRect = new Rectangle(1,94,33,33),
            GameSmallBallRect = new Rectangle(37,108,19,19);
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            // Remember resolution
            width = graphics.GraphicsDevice.Viewport.Width;
            height = graphics.GraphicsDevice.Viewport.Height;
            //Set Lives
            leftPlayerLives = 3;
            rightPlayerLives = 3;
            //load graphics
            backgroundTexture = Content.Load<Texture2D>("SpaceBackground");
            menuTexture = Content.Load<Texture2D>("PongMenu");
            gameTexture = Content.Load<Texture2D>("PongGame");
            base.Initialize();
        }
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        public void RenderSprite(Texture2D texture, int x, int y, Rectangle sourceRect, Color color)
        {
            sprites.Add(new SpriteToRender(texture, new Rectangle(x, y, sourceRect.Width, sourceRect.Height), sourceRect, color));
        }
        public void RenderSprite(Texture2D texture, Rectangle rect, Rectangle? sourceRect, Color color)
        {
            sprites.Add(new SpriteToRender(texture, rect, sourceRect, color));
        }//RenderSprite(texture, rect, sourceRect, color)
        public void RenderSprite(Texture2D texture, int x, int y, Rectangle sourceRect)
        {
            sprites.Add(new SpriteToRender(texture, new Rectangle(x,y,sourceRect.Width,sourceRect.Height),sourceRect,Color.LightGray));
        }//RenderSprite(texture, rect, sourceRect)
        public static void TestGameSprites()
        {
            StartTest(
                delegate
                {
                    //Show Lives
                    testGame.ShowLives();
                    //Ball in Center
                    testGame.RenderBall();
                    //Render both paddles
                    testGame.RenderPaddles();
                    //Start ball
                    testGame.StartNewBall();
                }
            );
        }//TestGameSprites()
        /// <summary>
        /// Start new ball at the beginning of each game and when a ball is lost.
        /// </summary>
        public void StartNewBall()
        {
            ballPosition = new Vector2(0.5f, 0.5f);
            Random rnd = new Random((int)DateTime.Now.Ticks);
            int direction = rnd.Next(4);
            ballSpeedVector =
                direction == 0 ? new Vector2(1, 0.8f) :
                direction == 1 ? new Vector2(1, -0.8f) :
                direction == 2 ? new Vector2(-1, 0.8f) :
                new Vector2(-1, -0.8f);
        }//StartNewBall();
        public void ShowLives()
        {
            //Left Player Lives
            RenderSprite(menuTexture, 2, 2, GameLivesRect);
            for (int num = 0; num < leftPlayerLives; num++)
            {
                RenderSprite(gameTexture, 2 + GameLivesRect.Width +
                    GameSmallBallRect.Width * num - 2, 9, GameSmallBallRect);
            }
            //Right Player Lives
            int rightX = 1024 - GameLivesRect.Width - GameSmallBallRect.Width * 3 - 4;
            RenderSprite(menuTexture, rightX, 2, GameLivesRect);
            for (int num = 0; num < rightPlayerLives; num++)
            {
                RenderSprite(gameTexture, rightX + GameLivesRect.Width +
                    GameSmallBallRect.Width * num - 2, 9, GameSmallBallRect);
            }
        }//ShowLives()
        public void RenderBall()
        {
            RenderSprite(gameTexture,
                (int)((0.05f + 0.9f * ballPosition.X) * 1024) -
                GameBallRect.Width / 2,
                (int)((0.02f + 0.96f * ballPosition.Y) * 768) -
                GameBallRect.Height / 2,
                GameBallRect);
        }//RenderBall()
        public void RenderPaddles()
        {
            RenderSprite(gameTexture,
                (int)(0.05f * 1024) - GameRedPaddleRect.Width / 2,
                (int)((0.06f + 0.88f * leftPaddlePosition) * 768) -
                GameRedPaddleRect.Height / 2,
                GameRedPaddleRect);
            RenderSprite(gameTexture,
                (int)(0.95f * 1024) - GameBluePaddleRect.Width / 2,
                (int)((0.06f + 0.88f * rightPaddlePostion) * 768) -
                GameBluePaddleRect.Height / 2,
                GameBluePaddleRect);
        }//RenderPaddles()

        public static void TestMenuSprites()
        {
            StartTest(
                delegate
                {
                    testGame.RenderSprite(testGame.menuTexture,
                        512 - XnaPongLogoRect.Width / 2, 150,
                        XnaPongLogoRect);
                    testGame.RenderSprite(testGame.menuTexture,
                        512 - MenuSingleplayerRect.Width / 2, 300,
                        MenuSingleplayerRect);
                    testGame.RenderSprite(testGame.menuTexture,
                        512 - MenuMultiplayerRect.Width / 2, 350,
                        MenuMultiplayerRect,Color.Orange);
                    testGame.RenderSprite(testGame.menuTexture,
                        512 - MenuExitRect.Width / 2, 400,
                        MenuExitRect);
                });
        }//test menu sprites
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            //Get current keyboard states
            KeyboardState keyboard = Keyboard.GetState();
            //move half way across the screen each second
            float moveFactorPerSecond = 0.5f *
                (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            //ESCAPE to quit
            if (keyboard.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }
            //MOve up if key is pressed
            if (keyboard.IsKeyDown(Keys.Up))
            {
                rightPaddlePostion -= moveFactorPerSecond;
            }
            //Move down if key is pressed
            if (keyboard.IsKeyDown(Keys.Down))
            {
                rightPaddlePostion += moveFactorPerSecond;
            }
            //Enable Multiplayer keyboard inputs
            if (multiplayer)
            {
                if (keyboard.IsKeyDown(Keys.W))
                {
                    leftPaddlePosition -= moveFactorPerSecond;
                }
                if (keyboard.IsKeyDown(Keys.S))
                {
                    leftPaddlePosition += moveFactorPerSecond;
                }
            }//if
            else
            {
                //Just let the computer follow the ball position
                float computerChange = ComputerPaddleSpeed * moveFactorPerSecond;
                if (leftPaddlePosition > ballPosition.Y + computerChange)
                    leftPaddlePosition -= computerChange;
                if (leftPaddlePosition < ballPosition.Y - computerChange)
                    leftPaddlePosition += computerChange;
            }//else
            //Make sure the paddles stay on screen
            if (leftPaddlePosition < 0)
                leftPaddlePosition = 0;
            if (leftPaddlePosition > 1)
                leftPaddlePosition = 1;
            if (rightPaddlePostion < 0)
                rightPaddlePostion = 0;
            if (rightPaddlePostion > 1)
                rightPaddlePostion = 1;
            //update ball position
            ballPosition += ballSpeedVector *
                moveFactorPerSecond * BallSpeedMultiplicator;
            //end paddle area
            base.Update(gameTime);
        }
        public void DrawSprites()
        {
            //Don't render if there are no sprites this frame
            if (sprites.Count == 0)
            {
                return;
            }
            //Start Rendering Sprites
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.BackToFront, SaveStateMode.None);
            //Render all sprites
            foreach (SpriteToRender sprite in sprites)
            {
                spriteBatch.Draw(sprite.texture,
                    //Rescale to fit resolution
                    new Rectangle(
                    sprite.rect.X * width / 1024,
                    sprite.rect.Y * height / 768,
                    sprite.rect.Width * width / 1024,
                    sprite.rect.Height * height / 768),
                    sprite.sourceRect, sprite.color);
                //We are done, draw everything on screen with help of the end method.
            }
            spriteBatch.End();
            //kill list of remembered sprites
            sprites.Clear();
        }//DrawSprites()
        /// <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
            //DrawSprites
            spriteBatch.Begin();
            spriteBatch.Draw(backgroundTexture, new Rectangle(0, 0, width, height), Color.LightGray);
            spriteBatch.End();
            DrawSprites();
            base.Draw(gameTime);
        }
        List<SpriteToRender> sprites = new List<SpriteToRender>();
    }
    delegate void TestDelegate();
    class TestPongGame : PongGame
    {
        TestDelegate testLoop;
        public TestPongGame(TestDelegate setTestLoop)
        {
            testLoop = setTestLoop;
        }//TestPongGame(setTestLoop)

        protected override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            testLoop();
        }
    }//class TestPongGame

    class SpriteToRender
    {
        public Texture2D texture;
        public Rectangle rect;
        public Rectangle? sourceRect;
        public Color color;

        public SpriteToRender(Texture2D setTexture, Rectangle setRect,
            Rectangle? setSourceRect, Color setColor)
        {
            texture = setTexture;
            rect = setRect;
            sourceRect = setSourceRect;
            color = setColor;
        }//SpriteToRender(setTexture, setRect, setColor)
    } //class SpriteToRender
}
  #3 (permalink)  
Old January 18th, 2008, 05:25 AM
Wrox Author
 
Join Date: May 2007
Location: Hannover, , Germany.
Posts: 29
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via ICQ to abi.exdream.com
Default

Hi lyndonh,

Not exactly sure what the issue is, the only thing I can think of is that either the value of ballSpeedVector is way too high or the moveFactorPerSecond is not a small enough value. The reason for this could be either a very low frame rate (you should check that, how many frames does the game have? maybe use fraps (http://fraps.softonic.de/) to check it). Less than 10 or 20 frames per second would be bad, usually you have 60 or more frame regardless of using a fixed time-step (default in XNA) or not (default in most of my games).

I would first of all set the moveFactorPerSecond variable to a fixed value (like 0.01f) and see if this changes anything, maybe the calculation for this variable is not correct for your game settings. If you use a fixed time step (set Game.IsFixedTime to true) you can safely use a fixed value for moveFactorPerSecond because the method will only be called every 1/60 of a second (results to a value of 0.0166f).

If you still have a problem, please zip up your project and attach it here or email it to me (abi@exdream.com) so I can take a look.
Ben

http://abi.exdream.com
 


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
XnaPong ball movement note jedifreeman BOOK: Professional XNA Programming 2nd Edition ISBN: 978-0-470-26128-6 0 May 11th, 2008 03:01 PM
can any one tell me how i can add ball in run time humera Beginning VB 6 1 May 1st, 2008 11:15 AM
Why won't Mac's play ball Adam H-W Javascript 5 November 27th, 2006 09:59 AM
Ball class in C# devcon5 VB.NET 2002/2003 Basics 0 April 2nd, 2006 12:13 AM
validate.asp problems and logon.asp problems p2ptolu Classic ASP Databases 0 February 16th, 2005 02:34 PM



All times are GMT -4. The time now is 02:11 AM.


Powered by vBulletin®
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.