You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让UWP FPS计数器悬浮显示在Xbox主机游戏之上?

Xbox主机FPS计数器悬浮显示方案咨询

我正在为Xbox主机开发一款FPS计数器,已完成基础UWP应用开发:

  • 采用简单计数和平滑平均两种技术计算FPS
  • 可在开发模式下的Xbox Series S及本地设备运行,结果显示在屏幕左上角

应用在Xbox Series S开发模式下的运行状态:
应用在Xbox Series S上运行截图

应用在本地设备上的运行状态:
应用在本地设备上运行截图

核心问题

我无法在官方文档中找到相关说明,以实现将该计数器悬浮在游戏上方,让玩家在游戏过程中实时查看左上角的FPS数据,达到类似Steam的效果。

已知背景

  • 部分资料显示此功能无法实现,原因是Xbox运行游戏时会暂停UWP应用,将硬件资源全部分配给游戏
  • 但Discord已登陆Xbox,可在玩家语音时弹出悬浮通知;Spotify也能在游戏期间后台播放音乐,说明存在UWP应用在游戏运行时保持活跃并显示内容的例外场景

请问是否存在已知的实现方案?


简化版测试代码

MainPage.xaml

<Page x:Class="FPSCounter.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:FPSCounter"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d"
      Background="Transparent">

    <Grid>
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
            <TextBlock x:Name="basicFPSTextBlock" FontSize="24"/>
            <TextBlock x:Name="smoothedFPSTextBlock" FontSize="24"/>
        </StackPanel>
    </Grid>
</Page>

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    private readonly BasicCounterService counterService;
    private readonly SmoothedAverageMeasurementService fpsCounter;

    public MainPage()
    {
        InitializeComponent();
        SetWindowPositionAndSize();
        counterService = new BasicCounterService();
        fpsCounter = new SmoothedAverageMeasurementService(0, 0.9);
        StartFPSCounter();

    }

    private void SetWindowPositionAndSize()
    {
        ApplicationView.GetForCurrentView();

        double desiredWidth = 50;
        double desiredHeight = 50;

        ApplicationView.GetForCurrentView().SetPreferredMinSize(new Size(desiredWidth, desiredHeight));
        ApplicationView.GetForCurrentView().TryResizeView(new Size(desiredWidth, desiredHeight));
    }

    private async void StartFPSCounter()
    {
        while (true)
        {
            int basicFPS = await counterService.CalculateFPS();
            double smoothedFPS = await fpsCounter.CalculateSmoothedAverage();
            UpdateFPSUI(basicFPS, smoothedFPS);
        }
    }

    private async void UpdateFPSUI(int basicFPS, double smoothedFPS)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            basicFPSTextBlock.Text = $"Basic FPS: {basicFPS}";
            smoothedFPSTextBlock.Text = $"Smoothed FPS: {Math.Round(smoothedFPS)}";

            if (ApplicationView.GetForCurrentView().ViewMode == ApplicationViewMode.CompactOverlay)
            {

            }
            else
            {

            }
        });
    }
}

BasicCounterService.cs

internal class BasicCounterService
{
    private readonly Stopwatch stopwatch;
    private int frameCount;

    public BasicCounterService()
    {
        stopwatch = new Stopwatch();
        frameCount = 0;
    }

    public async Task<int> CalculateFPS()
    {
        stopwatch.Start();

        while (stopwatch.Elapsed.TotalSeconds < 1)
        {
            await Task.Delay(16);
            frameCount++;
        }

        stopwatch.Stop();
        int fps = frameCount;

        frameCount = 0;
        stopwatch.Reset();

        return fps;
    }
}

SmoothedAverageMeasurementService.cs

internal class SmoothedAverageMeasurementService
{
    private readonly double smoothing;
    private double measurement;
    private readonly Stopwatch stopwatch;
    private int frameCount;

    public SmoothedAverageMeasurementService(double initialMeasurement, double smoothingFactor)
    {
        measurement = initialMeasurement;
        smoothing = smoothingFactor;
        stopwatch = new Stopwatch();
        frameCount = 0;
    }

    public async Task<double> CalculateSmoothedAverage()
    {
        stopwatch.Start();

        while (stopwatch.Elapsed.TotalSeconds < 1)
        {
            await Task.Delay(16);
            frameCount++;
        }

        stopwatch.Stop();
        double currentMeasurement = frameCount;

        measurement = (measurement * smoothing) + (currentMeasurement * (1.0 - smoothing));

        frameCount = 0;
        stopwatch.Reset();

        return Math.Round(measurement);
    }
}

内容的提问来源于stack exchange,提问作者Vinicius Donatto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 00:06:59