为WP7 SilverLight游戏创建流畅的游戏帧计时器

时间:2013-02-23 19:09:35

标签: c# silverlight windows-phone-7 timer game-engine

所以我一直在测试一些用于在silverlight中创建垂直滚动游戏的新算法。我提出了一个非常简单的解决方案。但是,当您在手机上运行时,帧速率会出现大量不一致的情况。我不知道这是否是由于算法不佳,同时吸引了很多东西(目前只有png背景和股票播放器图像)或其他东西。

基本上我想要的是一个游戏循环计时器,它执行一种方法,我可以执行所有更新方法,并且无论你在游戏的哪个部分,都具有一致的外观和感觉。这是后端代码。

   public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        int counter = 0;
        DispatcherTimer playerTimer;

        string _START   = "START";
        string _FALLING = "FALLING";
        string _LEFT    = "LEFT";
        string _RIGHT   = "RIGHT";
        string _CENTER  = "CENTER";

        string playerState = "";
        int playerMoveTimeout = 20;
        public MainPage()
        {
            InitializeComponent();
            playerState = _START;

            playerTimer = new DispatcherTimer();
            playerTimer.Interval = TimeSpan.FromSeconds(.00999);
            playerTimer.Tick += playerTimer_Tick;
            playerTimer.Start();
        }

        void playerTimer_Tick(object sender, EventArgs e)
        {
            updatePlayer();

            if (counter > 0)
            {
                counter = updateBG(counter);
            }
        }
        public void updatePlayer()
        {
            if (Canvas.GetLeft(Player) + Player.Width >= 480)
            {
                playerState = _LEFT;

            }
            else if (Canvas.GetLeft(Player) <= 0)
            {
                playerState = _RIGHT;
            }
            if(playerMoveTimeout <= 0)
            {
                playerState = _FALLING;
            }
            if (playerState.Equals(_START))
            { }
            else if (playerState.Equals(_FALLING))
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) + 30);
            }
            else if (playerState.Equals(_LEFT))
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) - 60);
                Canvas.SetLeft(Player, Canvas.GetLeft(Player) - 20);
                playerMoveTimeout--;
            }
            else if (playerState.Equals(_RIGHT))
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) - 60);
                Canvas.SetLeft(Player, Canvas.GetLeft(Player) + 20);
                playerMoveTimeout--;
            }
            else //CENTER
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) - 60);
                playerMoveTimeout--;
            }
        }

        public int updateBG(int time)
        {
            if (Canvas.GetTop(background) > 800)
                Canvas.SetTop(background, -2400);
            int x = time;
            Canvas.SetTop(background, Canvas.GetTop(background) + 60);
            x -= 40;
            return x;
        }


        private void Player_Tap(object sender, GestureEventArgs e)
        {

            Point point = e.GetPosition(Player);
            double Y = point.Y;
            double X = point.X;
            if (X < 80)
            {
                counter = 400;
                playerMoveTimeout = 20;
                playerState = _RIGHT;

            }
            else if (X > 120)
            {
                counter = 400;
                playerMoveTimeout = 20;
                playerState = _LEFT;

            }
            else
            {
                counter = 400;
                playerMoveTimeout = 20;
                playerState = _CENTER;

            }
        }
    }

1 个答案:

答案 0 :(得分:0)

所以答案更多的是一个工作而不是一个新的计时器。我的具体问题的答案不是算法。对于我制造的家用游戏引擎来说,这实际上是最平滑和最小的。问题是我试图移动一个480X2400的背景图像,这让它陷入困境。所以我最终做的是在主要画布中嵌套一个新画布并将其命名为背景。然后我要在后台移动的所有元素都放在那里

喜欢这个

<Canvas Name="background">
    <Image Name="cloud" Source="cloud.png" Width="247" Height="158"/>
    <Image x:Name="cloud_Copy" Source="/cloud.png" Width="247" Height="158" Canvas.Left="192" Canvas.Top="268"/>
    <Image x:Name="cloud_Copy1" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-11" Canvas.Top="592"/>
    <Image x:Name="cloud_Copy2" Source="/cloud.png" Width="247" Height="158" Canvas.Left="192" Canvas.Top="-474"/>
    <Image x:Name="cloud_Copy3" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-900"/>
    <Image x:Name="cloud_Copy4" Source="/cloud.png" Width="247" Height="158" Canvas.Left="192" Canvas.Top="-1566"/>
    <Image x:Name="cloud_Copy5" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-78" Canvas.Top="-2280"/>
    <Image x:Name="cloud_Copy6" Source="/cloud.png" Width="247" Height="158" Canvas.Left="192" Canvas.Top="-2766"/>
    <Image x:Name="cloud_Copy7" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-102" Canvas.Top="-3390"/>
    <Image x:Name="cloud_Copy8" Source="/cloud.png" Width="247" Height="158" Canvas.Left="90" Canvas.Top="-3122"/>
    <Image x:Name="cloud_Copy9" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-113" Canvas.Top="-2798"/>
    <Image x:Name="cloud_Copy10" Source="/cloud.png" Width="247" Height="158" Canvas.Left="90" Canvas.Top="-3864"/>
    <Image x:Name="cloud_Copy11" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-4290" Canvas.Left="-102"/>
    <Image x:Name="cloud_Copy12" Source="/cloud.png" Width="247" Height="158" Canvas.Left="90" Canvas.Top="-4956"/>
    <Image x:Name="cloud_Copy13" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-180" Canvas.Top="-5670"/>
    <Image x:Name="cloud_Copy14" Source="/cloud.png" Width="247" Height="158" Canvas.Left="90" Canvas.Top="-6156"/>
    <Image x:Name="cloud_Copy15" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-192" Canvas.Top="-7278"/>
    <Image x:Name="cloud_Copy16" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-7010"/>
    <Image x:Name="cloud_Copy17" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-203" Canvas.Top="-6686"/>
    <Image x:Name="cloud_Copy18" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-7752"/>
    <Image x:Name="cloud_Copy19" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-8178" Canvas.Left="-192"/>
    <Image x:Name="cloud_Copy20" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-8844"/>
    <Image x:Name="cloud_Copy21" Source="/cloud.png" Width="247" Height="158" Canvas.Left="-270" Canvas.Top="-9558"/>
    <Image x:Name="cloud_Copy22" Source="/cloud.png" Width="247" Height="158" Canvas.Top="-10044"/>
</Canvas>


<Image Name="Star"  Visibility="Collapsed" Source="star.png" Height="50" Width="50" />
<Image x:Name="Player" Source="star.png" Width="200" Height="200" Canvas.Left="117" Canvas.Top="403"/>
<Rectangle Name="TapBox" Fill="#FFF4F4F5" Height="248" Stroke="Black" Width="301" Canvas.Left="68" Canvas.Top="403" Opacity="0" Tap="Rectangle_Tap_1"/>
    <TextBlock x:Name="alt"/> 
</Canvas>

你可以在这个画布上加载大量的东西而不会降低我所看到的性能。

然后在这里更新它是我的新游戏循环

public partial class MainPage : PhoneApplicationPage
    {
        DispatcherTimer gameTimer;

        string _START           = "START";
        string _FALLING         = "FALLING";
        string _LEFT            = "LEFT";
        string _RIGHT           = "RIGHT";
        string _CENTER          = "CENTER";
        string playerState      = "";

        int counter             = 0;
        int playerMoveTimeout   = 40;
        public int altitude { get; set; }

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            buildGameArea();
            alt.Text = altitude.ToString();
            playerState = _START;
            gameTimer = new DispatcherTimer();
            gameTimer.Interval = new TimeSpan(3333);
            gameTimer.Start();
            gameTimer.Tick+=gameTimer_Tick;

        }

        void gameTimer_Tick(object sender, EventArgs e)
        {

            updatePlayer();
            updateGameElements();
        }

        public void buildGameArea()
        {
            Canvas.SetTop(cloud, -300);
        }
        public void reloadPlayer()
        {
            playerState = _START;
            playerMoveTimeout = 40;
            Canvas.SetTop(Player, 300);
            Canvas.SetLeft(Player, 200);
        }
        public void updatePlayer()
        {
            if (Canvas.GetTop(Player) > 800)
            {
                reloadPlayer();
            }


            if (Canvas.GetLeft(Player) + Player.Width >= 480)
            {
                playerState = _LEFT;

            }
            else if (Canvas.GetLeft(Player) <= 0)
            {
                playerState = _RIGHT;
            }

            if (playerMoveTimeout <= 0)
            {
                playerState = _FALLING;
            }


            if (playerState.Equals(_START))
            { }
            else if (playerState.Equals(_FALLING))
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) + 30);

            }
            else if (playerState.Equals(_LEFT))
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) - 40);
                Canvas.SetLeft(Player, Canvas.GetLeft(Player) - 20);
                playerMoveTimeout--;
            }
            else if (playerState.Equals(_RIGHT))
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) - 40);
                Canvas.SetLeft(Player, Canvas.GetLeft(Player) + 20);
                playerMoveTimeout--;

            }
            else //CENTER
            {
                Canvas.SetTop(Player, Canvas.GetTop(Player) - 40);
                playerMoveTimeout--;
            }
            TapBox.Margin = Player.Margin;
        }
        public void updateGameElements()
        {
            alt.Text = altitude.ToString();


            //This single conditional moves every single thing on the background canvas
            if (counter > 0)
            {
                Canvas.SetTop(background, Canvas.GetTop(background) + 20);
                counter -= 20;
            }
        }

        private void Rectangle_Tap_1(object sender, GestureEventArgs e)
        {
            System.Windows.Point point = e.GetPosition(Player);
            double Y = point.Y;
            double X = point.X;
            altitude += 100;
            if (X < 80)
            {
                counter = 400;
                playerMoveTimeout = 40;
                playerState = _RIGHT;

            }
            else if (X > 120)
            {
                counter = 400;
                playerMoveTimeout = 40;
                playerState = _LEFT;

            }
            else
            {
                counter = 400;
                playerMoveTimeout = 40;
                playerState = _CENTER;

            }
        }
    }

如果你要将它放在你的设备上,你会发现无论你有多少,你始终都会有始终如一的帧速率。

希望我浪费的时间能够解决这个问题,这有助于将来的某些人。

这再次适用于Silverlight游戏编程。这里没有XNA