如何在Xbox One上的UWP MonoGame中实现全屏绘制?
问题:MonoGame UWP游戏在Xbox One上无法填满1920x1080屏幕
我正在开发一款基于MonoGame框架、打包为UWP应用的游戏项目。该项目在Windows和Xbox One设备上均可正常运行,但在Xbox One上的视口尺寸仅为1728x972,而非预期的1920x1080,推测是自适应到了标题安全区域。即便所有图形都能适配标题安全区域,我仍希望使用纯色填充整个电视屏幕,请问是否可以放大视口或在视口外进行绘制?
App.xaml
<Application x:Class="FirstXboxGame.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </Application>
App.xaml.cs
using System; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace FirstXboxGame { sealed partial class App : Application { public App() { this.InitializeComponent(); this.Suspending += this.OnSuspending; } protected override void OnLaunched(LaunchActivatedEventArgs e) { // 如果窗口没有内容,创建框架并导航到第一页 if (!(Window.Current.Content is Frame rootFrame)) { rootFrame = new Frame(); rootFrame.NavigationFailed += (sender, navigationFailedEventArgs) => throw new Exception("Failed to load Page " + navigationFailedEventArgs.SourcePageType.FullName); // 将框架放入当前窗口 Window.Current.Content = rootFrame; if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: 从之前暂停的应用加载状态 } } if (!e.PrelaunchActivated) { if (rootFrame.Content == null) { rootFrame.Navigate(typeof(GamePage), e.Arguments); } Window.Current.Activate(); } } private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); //TODO: 保存应用状态并停止所有后台活动 deferral.Complete(); } } }
GamePage.xaml
<Page x:Class="FirstXboxGame.GamePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" > <SwapChainPanel x:Name="swapChainPanel"/> </Page>
GamePage.xaml.cs
using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace FirstXboxGame { public sealed partial class GamePage : Page { readonly FirstXboxGame game; public GamePage() { this.InitializeComponent(); // 创建游戏实例 var launchArguments = string.Empty; this.game = MonoGame.Framework.XamlGame<FirstXboxGame>.Create(launchArguments, Window.Current.CoreWindow, this.swapChainPanel); } } }
FirstXboxGame.cs
using Windows.Foundation; using Windows.Graphics.Display; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace FirstXboxGame { public class FirstXboxGame : Game { private GraphicsDeviceManager graphics; private SpriteBatch spriteBatch; private Size resolution; private Rectangle screenBounds; private Color matteColor; public FirstXboxGame() { this.graphics = new GraphicsDeviceManager(this); this.Content.RootDirectory = "Content"; } protected override void Initialize() { // 保存屏幕信息 var view = DisplayInformation.GetForCurrentView(); this.resolution = new Size(view.ScreenWidthInRawPixels, view.ScreenHeightInRawPixels); this.screenBounds = new Rectangle(0, 0, (int) this.resolution.Width, (int) this.resolution.Height); // 屏幕填充色 this.matteColor = Color.Red; // 切换到全屏 if (!this.graphics.IsFullScreen) { this.graphics.ToggleFullScreen(); } this.IsMouseVisible = true; // 创建SpriteBatch this.spriteBatch = new SpriteBatch(this.GraphicsDevice); base.Initialize(); } protected override void LoadContent() { // TODO: 使用this.Content加载游戏资源 } protected override void Update(GameTime gameTime) { var pressingBackButton = GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed; var pressingBButton = GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed; var pressingEscapeKey = Keyboard.GetState().IsKeyDown(Keys.Escape); if (pressingBackButton || pressingBButton || pressingEscapeKey) { this.Exit(); } base.Update(gameTime); } protected override void Draw(GameTime gameTime) { // 获取视口边界 var isFullScreen = this.graphics.IsFullScreen; var viewportBounds = this.GraphicsDevice.Viewport.Bounds; var viewportTitleSafeArea = this.GraphicsDevice.Viewport.TitleSafeArea; // 用填充色清空视口 this.GraphicsDevice.Clear(this.matteColor); // 绘制内容 this.spriteBatch.Begin(); // TODO: 绘制精灵 this.spriteBatch.End(); base.Draw(gameTime); } } }
解决方案
要让游戏填满Xbox One的1920x1080屏幕,需要突破标题安全区域限制,具体操作如下:
1. 让SwapChainPanel占满整个窗口
修改GamePage.xaml,确保SwapChainPanel填充整个Page:
<Page x:Class="FirstXboxGame.GamePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" > <SwapChainPanel x:Name="swapChainPanel" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/> </Page>
2. 强制设置后台缓冲区分辨率
在FirstXboxGame构造函数中,直接指定目标分辨率:
public FirstXboxGame() { this.graphics = new GraphicsDeviceManager(this); this.Content.RootDirectory = "Content"; // 强制设置Xbox One目标分辨率 graphics.PreferredBackBufferWidth = 1920; graphics.PreferredBackBufferHeight = 1080; graphics.ApplyChanges(); }
3. 自定义视口覆盖整个屏幕
如果仍有黑边,手动创建覆盖全屏的视口:
protected override void Initialize() { // ... 原有代码 ... // 创建覆盖整个屏幕的视口 var fullViewport = new Viewport(0, 0, 1920, 1080); GraphicsDevice.Viewport = fullViewport; base.Initialize(); }
4. 启用真实全屏模式
确保使用硬件全屏而非窗口化全屏:
protected override void Initialize() { // ... 原有代码 ... graphics.IsFullScreen = true; graphics.HardwareModeSwitch = true; // 禁用窗口化全屏,使用真实全屏 graphics.ApplyChanges(); base.Initialize(); }
原理说明
Xbox One默认将UWP应用限制在标题安全区域(1728x972是1920x1080的90%),通过强制设置后台缓冲区分辨率、自定义视口,再配合全屏SwapChainPanel布局,就能突破这个限制,让纯色填充整个电视屏幕。
内容的提问来源于stack exchange,提问作者amoss
相关产品推荐
相关产品推荐

