用于Sliverlight的StunEngine引擎

重用XNA代码一文中我们已经创建了可以在Silverlight平台上运行的仿制XNA Game类,因此直接将XNA平台下的StunEngine的代码复制过来即可。至于StunEngine的代码分析可参见本网站的“XNA编程”栏目中的的“游戏引擎StunEngine”,所以本文只介绍如何基于StunEngine实现乒乓游戏,代码主要参考自§2.3让我们编写Pong,但根据StunEngine引擎的特点进行了修改。

游戏屏幕

本游戏共有2个屏幕,第一个为主菜单屏幕,对应文件为MainMenuScreen.cs,第二个为游戏屏幕,对应文件为GameplayScreen.cs,主菜单屏幕如下图所示:

主菜单屏幕

主菜单屏幕

主菜单屏幕包含星空背景和XNA Pong的游戏标题,它们是Renderable2DsceneNode,两个菜单选项是按钮,它们是UIButton。由于主菜单和游戏屏幕公用星空背景图像,所以事实上有第三个Scene类BackgroundScreen.cs,它负责绘制星空背景,BackgroundScreen.cs的代码如下:

namespace Silverlight3dApp.GameScreens
{
    /// <summary>
    /// 背景屏幕在其他屏幕之后
    /// 无论在它之上的其他屏幕是否处于过渡都会绘制背景图像
    /// </summary>
    class BackgroundScreen : Scene2D
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public BackgroundScreen(Engine engine):base(engine ,"Background")
        {
            Texture2D background = engine.Content.Load<Texture2D>("Textures/SpaceBackground");
            Renderable2DSceneNode bg = new Renderable2DSceneNode(this, background);
            bg.Size = new Vector2(800, 600);
            AddNode(bg);
        }

        /// <summary>
        /// 更新背景屏幕。不同于其他屏幕,当这个屏幕被其他屏幕覆盖时也无需淡出
        /// 它总是被覆盖!这个重载方法将coveredByOtherScreen参数强制设为false使关闭基类的淡出
        /// </summary>
        public override void UpdateScene(GameTime gameTime, bool otherScreenHasFocus,bool coveredByOtherScreen)
        {
            base.UpdateScene(gameTime, otherScreenHasFocus, false );            
        }        
    }
}

由于菜单按钮还要实现当鼠标移动其上时变成桔黄色,发出声音,移出时变回白色,当点击按钮时发出另一个声音,这些功能引擎中的UIButton类并没有提供,因此需要从UIButton类继承实现新功能的按钮类,我命名为Button.cs,代码如下:

namespace Silverlight3dApp
{
    public class Button:UIButton
    {
        SoundEffectInstance highlight;
        SoundEffectInstance click;
        
        public Button(Scene setScene, UIManager setUIManager, Texture2D setTexture,SoundEffectInstance highlight,SoundEffectInstance click):base(setScene,setUIManager,setTexture)
        {
            this.highlight =highlight ;
            this.click = click;
        }
        
        protected override void OnMouseEnter(EventArgs e)
        {
            Color = new Color(255, 165, 0, 255);
            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            Color = Color.White;
            highlight.Play();
            base.OnMouseLeave(e);
        }

        protected override void OnMouseLeftButtonClick(EventArgs e)
        {
            click.Play();
            base.OnMouseLeftButtonClick(e);
        }
    }
}

做好了准备工作后,就可以实现主菜单了,代码如下:

namespace Silverlight3dApp.GameScreens
{
    /// <summary>
    /// 游戏主菜单
    /// </summary>
    class MainMenuScreen : Scene2D
    {
        Button btnGamePlaySingle, btnGamePlayMultiple;
        
        readonly SoundEffect Highlight;
        readonly SoundEffectInstance HighlightInstance;
        readonly SoundEffect Click;
        readonly SoundEffectInstance ClickInstance;

        static readonly Rectangle
            XnaPongLogoRect = new Rectangle(0, 0, 512, 110),
            MenuSingleplayerRect = new Rectangle(0, 110, 512, 38),
            MenuMultiplayerRect = new Rectangle(0, 148, 512, 38);

        /// <summary>
        /// 构造函数添加菜单内容
        /// </summary>
        public MainMenuScreen(Engine engine): base(engine,"Main Menu")
        {
            Texture2D pongMenu = engine.Content.Load<Texture2D>("Textures/PongMenu");           

            // XNA Pong标题
            Renderable2DSceneNode XnaPongLogo = new Renderable2DSceneNode(this, pongMenu);
            XnaPongLogo.Size = new Vector2(512,110);
            XnaPongLogo.Position = new Vector2(400 - XnaPongLogoRect.Width / 2, 150);
            XnaPongLogo.RectSourceOrigin = XnaPongLogoRect;
            AddNode(XnaPongLogo);

            // 加载按钮的声音
            Highlight = engine.Content.Load<SoundEffect>("Sound\\Highlight");
            HighlightInstance = Highlight.CreateInstance();
            Click = engine.Content.Load<SoundEffect>("Sound\\Click");
            ClickInstance = Click.CreateInstance();      

            // Singleplayer按钮
            btnGamePlaySingle = new Button(this, this.UiManager, pongMenu, HighlightInstance,ClickInstance );
            btnGamePlaySingle.Size = new Vector2(512, 38);
            btnGamePlaySingle.RectSourceOrigin = btnGamePlaySingle.RectSourceHighlight = btnGamePlaySingle.RectSourceClicked = MenuSingleplayerRect;
            btnGamePlaySingle.Position = new Vector2(400 - MenuSingleplayerRect.Width / 2, 300);
            btnGamePlaySingle.Text = null;
            btnGamePlaySingle.MouseLeftButtonClick += new EventHandler(btnGamePlay_MouseLeftButtonClick);
            AddNode(btnGamePlaySingle);

            // Multipleplayer按钮
            btnGamePlayMultiple = new Button(this,this.UiManager , pongMenu, HighlightInstance,ClickInstance);
            btnGamePlayMultiple.Size = new Vector2(512, 38);
            btnGamePlayMultiple.RectSourceOrigin = btnGamePlayMultiple.RectSourceHighlight =btnGamePlayMultiple.RectSourceClicked=MenuMultiplayerRect;
            btnGamePlayMultiple.Position = new Vector2(400 - MenuMultiplayerRect.Width / 2, 350);
            btnGamePlayMultiple.Text = null;
            btnGamePlayMultiple.MouseLeftButtonClick += new EventHandler(btnGamePlay_MouseLeftButtonClick);
            AddNode(btnGamePlayMultiple);                  
        }

        void btnGamePlay_MouseLeftButtonClick(object sender, EventArgs e)
        {
            GameplayScreen gameplayScreen;
            if (sender == btnGamePlayMultiple)
                gameplayScreen = new GameplayScreen(engine, true);
            else
                gameplayScreen = new GameplayScreen(engine, false);
            engine.SceneManager.AddScene(gameplayScreen );
        }
    }
}

下面是游戏屏幕,如下图所示:

游戏屏幕

游戏屏幕

其中包含左上、右上角的生命值信息,红、蓝两色球拍和小球,它们都是Renderable2DsceneNode,游戏屏幕类GameplayScreen.cs的代码如下:

namespace Silverlight3dApp
{
    /// <summary>
    /// 实际进行游戏的屏幕
    /// </summary>
    class GameplayScreen:Scene2D
    {
        #region 成员变量和构造函数

        /// <summary>
        /// 图像对应的源矩阵
        /// </summary>
        static readonly Rectangle

            GameLivesRect = new Rectangle(0, 222, 100, 34),
            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>
        /// CPU控制的挡板的速度。如果球移动的速度比这个速度大,则CPU控制的球拍就无法跟上小球,最终你会获胜
        /// </summary>
        const float ComputerPaddleSpeed = 220.0f;

        /// <summary>
        /// 小球的速度大小,即1秒能移动多少像素
        /// </summary>
        const float ballSpeed = 180.0f;

        /// <summary>
        /// 随机数生成器
        /// </summary>
        Random random = new Random();
        
        /// <summary>
        /// 左边和右边玩家的生命值。如果一方的生命值为0,则另一方获胜
        /// </summary>        
        int leftPlayerLives = 3,rightPlayerLives = 3;
        
        //要绘制的图像、文字
        Renderable2DSceneNode redPaddle, bluePaddle, ball, livesRed, livesBlue,blueWon,redWon; 
        Renderable2DSceneNode [] redBallLives=new Renderable2DSceneNode  [3];
        Renderable2DSceneNode [] blueBallLives = new Renderable2DSceneNode [3];

        /// <summary>
        /// 当前的小球位置
        /// </summary>
        Vector2 ballPosition = new Vector2(367.0f, 267.0f);
        
        /// <summary>
        /// 小球的速度方向矢量,每个新小球都是随机的
        /// 如果游戏结束则设为0
        /// </summary>
        Vector2 ballSpeedVector = Vector2.Zero; 

        /// <summary>
        /// 是否多人游戏,如果不是则CPU控制左方蓝色球拍
        /// </summary>
        bool multiplayer = false;

        /// <summary>
        /// 游戏是否结束
        /// </summary>
        bool isGameOver = false;

        readonly SoundEffect PongBallHit;
        readonly SoundEffectInstance PongBallHitInstance;
        readonly SoundEffect PongBallLost;
        readonly SoundEffectInstance PongBallLostInstance;

        /// <summary>
        /// 构造函数
        /// </summary>
        public GameplayScreen(Engine  engine,bool setMultiplayer):base(engine,"Gameplay")
        {
            PongBallHit = engine.Content.Load<SoundEffect>("Sound\\PongBallHit");
            PongBallHitInstance = PongBallHit.CreateInstance();
            PongBallLost = engine.Content.Load<SoundEffect>("Sound\\PongBallLost");
            PongBallLostInstance = PongBallLost.CreateInstance();
            
            Texture2D background = engine.Content.Load<Texture2D>("Textures/SpaceBackground");
            Texture2D pongMenu = engine.Content.Load<Texture2D>("Textures/PongMenu");
            Texture2D pongGame = engine.Content.Load<Texture2D>("Textures/PongGame");
            
            // 背景
            Renderable2DSceneNode bg = new Renderable2DSceneNode(this, background);
            bg.Size = new Vector2(800, 600);
            //AddNode(bg);    

            //左边的生命值
            livesRed = new Renderable2DSceneNode( this, pongMenu);
            livesRed.Position = new Vector2(10, 10);
            livesRed.Size = new Vector2(GameLivesRect.Width, GameLivesRect.Height);
            livesRed.RectSourceOrigin = GameLivesRect;
            livesRed.Color = new Color(255,0,0,255);
            AddNode(livesRed);

            for (int num = 0; num < leftPlayerLives; num++)
            {
                redBallLives[num] = new Renderable2DSceneNode(this, pongGame);
                redBallLives[num].Position = new Vector2(GameLivesRect.Width + GameSmallBallRect.Width * num, 18);
                redBallLives[num].Size = new Vector2(GameSmallBallRect.Width, GameSmallBallRect.Height);
                redBallLives[num].RectSourceOrigin = GameSmallBallRect;
                AddNode(redBallLives[num]);
            }

            //右边的生命值
            livesBlue = new Renderable2DSceneNode (this, pongMenu);
            livesBlue.Position = new Vector2(600, 10);
            livesBlue.Size = new Vector2(GameLivesRect.Width, GameLivesRect.Height);
            livesBlue.RectSourceOrigin = GameLivesRect;
            livesBlue.Color = new Color(0,0,255,255);
            AddNode(livesBlue);

            for (int num = 0; num < rightPlayerLives; num++)
            {
                blueBallLives[num] = new Renderable2DSceneNode (this, pongGame);
                blueBallLives[num].Position = new Vector2(600 + GameLivesRect.Width + GameSmallBallRect.Width * num, 18);
                blueBallLives[num].Size = new Vector2(GameSmallBallRect.Width, GameSmallBallRect.Height);
                blueBallLives[num].RectSourceOrigin = GameSmallBallRect;
                AddNode(blueBallLives[num]);
            }

            //显示“蓝方获胜”的文字
            blueWon = new Renderable2DSceneNode(this,pongMenu);
            blueWon.RectSourceOrigin = GameBlueWonRect;
            blueWon.Size = new Vector2(GameBlueWonRect.Width ,GameBlueWonRect .Height );
            blueWon.Position = new Vector2(400.0f - blueWon.Size.X / 2, 200.0f);
            blueWon.Color = new Color(0, 0, 255, 255);
            blueWon.Visible = false;
            AddNode(blueWon);

            //显示“红方获胜”的文字
            redWon = new Renderable2DSceneNode(this,pongMenu);
            redWon.RectSourceOrigin = GameRedWonRect;
            redWon.Size = new Vector2(GameRedWonRect.Width, GameRedWonRect.Height);
            redWon.Position = new Vector2(400.0f - redWon.Size.X / 2, 200.0f);
            redWon.Color = new Color(255, 0, 0, 255);
            redWon.Visible = false;
            AddNode(redWon);
            
            //小球
            ball = new Renderable2DSceneNode (this, pongGame);
            ball.Position = new Vector2(367.0f, 267.0f);
            ball.Size = new Vector2 (GameBallRect .Width,GameBallRect .Height ) ;
            ball.RectSourceOrigin = GameBallRect;
            AddNode(ball);

            multiplayer = setMultiplayer;
            //左边红色球拍
            redPaddle = new Renderable2DSceneNode (this, pongGame);
            redPaddle.Position = new Vector2(10, 254);
            redPaddle.Size = new Vector2(GameRedPaddleRect.Width, GameRedPaddleRect.Height);
            redPaddle.RectSourceOrigin=GameRedPaddleRect;
            if (multiplayer)
            {
                PaddleController redPaddleController = new PaddleController(Key.W,Key.S,10.0f);
                redPaddle.AttachController(redPaddleController);
            }
            AddNode(redPaddle);

            //右边蓝色球拍
            bluePaddle = new Renderable2DSceneNode (this,pongGame);
            bluePaddle.Position = new Vector2(768, 254);
            bluePaddle.Size = new Vector2(GameBluePaddleRect.Width, GameBluePaddleRect.Height);
            bluePaddle.RectSourceOrigin = GameBluePaddleRect;            
            AddNode(bluePaddle);
            PaddleController bluePaddleController = new PaddleController(Key.Up ,Key.Down,768.0f);
            bluePaddle.AttachController(bluePaddleController);
        }

        #endregion

        #region 开始和停止小球

        /// <summary>
        /// 当游戏开始时或小球出界时重新设置小球
        /// </summary>
        public void StartNewBall()
        {
            ballPosition = new Vector2(367.0f, 267.0f);
            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);
        }

        /// <summary>
        /// 当游戏结束时停止小球
        /// </summary>
        public void StopBall()
        {
            ballSpeedVector = Vector2.Zero ;
        }

        #endregion        

        #region 更新

        public override void UpdateScene(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.UpdateScene(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            [...]
            }            
        }

        #endregion
    }
}

游戏逻辑

游戏逻辑位于GameplayScreen.cs类的Update方法中,代码如下,原理可参见其中的注释:

public override void UpdateScene(GameTime gameTime, bool otherScreenHasFocus,
                                               bool coveredByOtherScreen)
{
    base.UpdateScene(gameTime, otherScreenHasFocus, coveredByOtherScreen);

    if (this.IsActive)
    {
        {
            float moveFactorPerSecond = (float)gameTime.ElapsedGameTime .TotalMilliseconds / 1000.0f;

            // 当小球停止并且游戏还没有结束,则重新设置小球
            if (ballSpeedVector == Vector2.Zero && !isGameOver)
                StartNewBall();

            // 如果第二个玩家由CPU控制
            if (!multiplayer)
            {
                // 让CPU控制的左边红色球拍跟随小球的运动
                float computerChange = ComputerPaddleSpeed * moveFactorPerSecond;
                if (redPaddle.Position.Y > ball.Position.Y + computerChange)
                    redPaddle.Position -= new Vector2(0, computerChange);
                else if (redPaddle.Position.Y < ball.Position.Y - computerChange)
                    redPaddle.Position += new Vector2(0, computerChange);
            }

            //避免红色球拍移出上下边界
            if (redPaddle.Position.Y < 0)
                redPaddle.Position = new Vector2(10, 0);
            if (redPaddle.Position.Y > 508)
                redPaddle.Position = new Vector2(10, 508);

            #region 碰撞检测

            // 检测小球是否与屏幕顶部或底部碰撞
            bool hasNegativeVelocity;
            if (ballSpeedVector.Y < 0) 
                hasNegativeVelocity = true; 
            else
                hasNegativeVelocity = false;

            // 只有在小球超出上边界且向上运动时;超出下边界且向下运动时
            // 才让小球回弹,这样可以避免小球速度过快时发生在边界上快速
            // 小幅度碰撞的不合理情况的发生。
            if ((ballPosition.Y < 0&&hasNegativeVelocity) ||
                (ballPosition.Y > 567&&!hasNegativeVelocity))
            {
                //如果碰撞,则将小球速度矢量的Y分量取反
                ballSpeedVector.Y = -ballSpeedVector.Y;
                //播放声音
                PongBallHitInstance.Play();
            }

            // 创建小球、两个球拍的包围盒用于碰撞检测
            BoundingBox ballBox = new BoundingBox(new Vector3(ball.Position.X, ball.Position.Y, 0), 
                new Vector3((ball.Position.X + ball.Size.X), (ball.Position.Y + ball.Size.Y), 0));
            BoundingBox redPaddleBox = new BoundingBox(new Vector3(redPaddle.Position.X, redPaddle.Position.Y, 0), 
                new Vector3((redPaddle.Position.X + redPaddle.Size.X),  (redPaddle.Position.Y + redPaddle.Size.Y), 0));
            BoundingBox bluePaddleBox = new BoundingBox(new Vector3( bluePaddle.Position.X, bluePaddle.Position.Y, 0), 
                new Vector3((bluePaddle.Position.X + bluePaddle.Size.X), (bluePaddle.Position.Y + bluePaddle.Size.Y), 0));

            // 球是否与左边的红色球拍碰撞?
            if (ballBox.Intersects(redPaddleBox))
            {
                // Bounce of the paddle (always make positive)
                ballSpeedVector.X = Math.Abs(ballSpeedVector.X);
                // 增加球的速度
                ballSpeedVector *= 1.2f;
                // 如果碰撞在红色球拍右上角
                if (ballBox.Intersects(new BoundingBox(
                    new Vector3( (redPaddleBox.Max.X - 1.0f), (redPaddleBox.Min.Y - 1.0f), 0),
                    new Vector3((redPaddleBox.Max.X + 1.0f), (redPaddleBox.Min.Y + 1.0f), 0))))
                    // 给对方设置一个更快的小球
                    ballSpeedVector.Y = -2;
                // 如果碰撞在红色球拍右下角
                else if (ballBox.Intersects(new BoundingBox(
                    new Vector3( (redPaddleBox.Max.X - 1.0f),  (redPaddleBox.Max.Y - 1.0f), 0),
                    new Vector3( (redPaddleBox.Max.X + 1.0f), (redPaddleBox.Max.Y + 1.0f), 0))))
                    // 给对方设置一个更快的小球
                    ballSpeedVector.Y = +2;
                // 播放撞击声
                PongBallHitInstance.Play();
            }

            // 球是否与右边的蓝色球拍碰撞?
            if (ballBox.Intersects(bluePaddleBox))
            {
                // 使小球向左方运动
                ballSpeedVector.X = -Math.Abs(ballSpeedVector.X);
                // 碰撞后增加一点速度
                ballSpeedVector *= 1.2f;
                // 如果碰撞在蓝色球拍左上角
                if (ballBox.Intersects(new BoundingBox(
                    new Vector3( (bluePaddleBox.Min.X - 1.0f),  (bluePaddleBox.Min.Y - 1.0f), 0),
                    new Vector3( (bluePaddleBox.Min.X + 1.0f),  (bluePaddleBox.Min.Y + 1.0f), 0))))
                    // 给对方设置一个更快的小球
                    ballSpeedVector.Y = -2;
                // 如果碰撞在蓝色球拍左下角
                else if (ballBox.Intersects(new BoundingBox(
                    new Vector3( (bluePaddleBox.Min.X - 1.0f),  (bluePaddleBox.Max.Y - 1.0f), 0),
                    new Vector3( (bluePaddleBox.Min.X + 1.0f), (bluePaddleBox.Max.Y + 1.0f), 0))))
                    // 给对方设置一个更快的小球
                    ballSpeedVector.Y = +2;

                // 播放撞击声
                PongBallHitInstance.Play();
            }

            // 更新小球位置
            ballPosition += ballSpeed * moveFactorPerSecond * ballSpeedVector;
            ball.Position = ballPosition;

            // 球是否出左边界?
            if (ballPosition.X < 0)
            {
                // 播放声音
                PongBallLostInstance.Play();
                // 左边的生命值减1
                leftPlayerLives--;
                redBallLives[leftPlayerLives].Visible = false;
                // 重新设置一个新的小球
                StartNewBall();
            }

                //球是否出右边界?
            else if (ballPosition.X > 767.0f)
            {
                ballSpeedVector.X = -ballSpeedVector.X;
                // 播放声音
                PongBallLostInstance.Play();
                // 右边的生命值减1
                rightPlayerLives--;
                blueBallLives[rightPlayerLives].Visible = false;
                // 重新设置一个新的小球
                StartNewBall();
            }

            #endregion

            // 如果任意一方的生命值为0,则另一方获胜
            if (leftPlayerLives == 0 || rightPlayerLives == 0)
            {
                StopBall();
                isGameOver = true;
                if (leftPlayerLives == 0)
                    blueWon.Visible = true;
                else
                    redWon.Visible = true;
            }

            //如果在游戏过程中按下Escape键,则返回主菜单
            if (Input.KeyboardKeyJustPressed (Key.Escape ))
                this.ExitScreen(); ;

            //如果游戏结束,按下空格键或鼠标左键可以重新开始
            if (isGameOver)
            {
                if (Input.KeyboardKeyJustPressed(Key.Space) || Input.MouseLeftButtonJustPressed)
                {
                    leftPlayerLives = rightPlayerLives = 3;
                    for (int num = 0; num < leftPlayerLives; num++)
                    {
                        blueBallLives[num].Visible = redBallLives[num].Visible = true;
                    }
                    redWon.Visible = false;
                    blueWon.Visible = false;
                    StartNewBall();
                    isGameOver = false;
                }
            }
        }
    }            
}

控制两个球拍是使用不同参数的PaddleController类,代码如下:

namespace Silverlight3dApp
{
    public class PaddleController : Controller
    {
        #region 构造函数和成员变量

        /// <summary>
        /// 要控制的球拍
        /// </summary>
        private Renderable2DSceneNode paddle;

        /// <summary>
        /// 球拍的移动速度
        /// </summary>
        const float paddleSpeed = 200.0f;

        // 控制球拍上下移动的键
        Key upKey;
        Key downKey;
        // 球拍的x坐标
        float positionX;

        /// <summary>
        /// 创建一个新Controller
        /// </summary>
        /// <param name="setUpKey">向上运动的按键设置</param>
        /// <param name="setDownKey">向下运动的按键设置</param>
        public PaddleController(Key setUpKey,Key setDownKey,float setX): base()
        {
            upKey = setUpKey;
            downKey = setDownKey;
            positionX =setX ;
        }

        #endregion
        
        /// <summary>
        /// 控制逻辑
        /// </summary>        
        public override void ControllerAction(GameTime gameTime)
        {
            paddle = (Renderable2DSceneNode )controlledNode;
            float moveFactorPerSecond = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            ProcessInput(moveFactorPerSecond);
        }

        private void ProcessInput(float moveFactorPerSecond)
        {
            //按upKey键向上移动
            if (Input.Keyboard .IsKeyDown (upKey))
            {
                paddle.Position -= new Vector2(0, paddleSpeed*moveFactorPerSecond);
                if (paddle.Position.Y < 0)
                    paddle.Position = new Vector2(positionX, 0);                
            }
            //按downKey键向下移动
            if (Input.Keyboard.IsKeyDown(downKey))
            {
                paddle.Position += new Vector2(0, paddleSpeed*moveFactorPerSecond);
                if(paddle .Position .Y>508)
                    paddle.Position = new Vector2(positionX, 508);                
            }
        }
    }
}

源代码PongGame4SL.zip下载。

文件下载(已下载 2139 次)

发布时间:2012/9/25 下午10:57:45  阅读次数:7863

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号