Windowsストア アプリ 作り方解説 XNA編 第6回 ~画面の構成~

マイクロソフトの田中達彦です。
本連載では、Windows Phone 7用のXNAで開発したShoot EvoというゲームをWindowsストア アプリとして移植したときのポイントを紹介します。
本連載では、C#とXAMLを使用して同様のアプリを作っていきます。

[Windows PhoneとWindows 8の画面の相違]
Windows Phone 7では、画面サイズが800x480に固定されています。
Windows Phone版のShoot Evoは、このサイズに合わせて作られています。

一方Windows 8の画面には、いろいろなサイズがあります。
最小スクリーンサイズは1024x768で、それ以外にも1366x768、1280x800、1920x1080など様々なサイズがあります。
これらの画面でも動くように画面を設計します。
さらに、スナップや縦長画面にまで対応させましょう。

画面の構成については、横長画面のときには左側にゲーム本体の部分、右側に情報を表示する部分を配置しました。
スナップと縦長の画面のときには、上にゲーム本体、下に情報を表示するように変えています。

画面の大きさにあわせてゲーム本体の部分を拡大/縮小し、なるべく大きくなるように表示しています。
残った部分を適当な分量で分割し、各種の情報を掲載しています。

ランドスケープ

ポートレイト

スナップ

[ゲーム本体の拡大/縮小]
ゲーム本体の拡大縮小は、Gridコントロールそのものの縮尺を変えることで実現しています。
下図は、画面の部分の構成です。
使用しているコントロール名と、その後ろにカッコでShoot Evoで使用している名前を記しています。

Shoot Evoの全体はgrid1というGridコントロールの中に構成されています。
この中に、fieldGridという名前のGridコントロールを配置しています。
fieldGridの中には3つのImageコントロールを配置し、それぞれボール、モンスター、ゴールを表示させています。

Gridコントロールは、RenderTransformという、図形を変形させるためのプロパティがあります。
その中で、ScaleX、ScaleYというプロパティを使うことで、Gridコントロールを拡大/縮小させることができるのです。

現在の画面の縦横のピクセル数は、field1のActualHeightとActualWidthによって取得できます。
この値を使用して、適切な大きさにfieldGridを拡大/縮小させています。

アプリの実行中に画面のサイズが変わったときは、SizeChangedというイベントが発生します。
このイベントが発生したときは、拡大率を再度計算しています。
画面がランドスケープからポートレイトになったときや、スナップしたときもこのイベントが発生します。

[情報表示の部分]
情報を表示しているところは、RectangleコントロールとTextBlockコントロールを使用して文字を表示させています。
これらのコントロールの位置は、画面の大きさを元に計算しています。
SizeChangedイベントが発生したときには、再計算を行っています。

[画面部分のコード]
Shoot Evoの画面を構成しているMainPage.xamlの内容は、以下のとおりです。

<Page
    x:Class="App33_xnafake.MainPage"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App33_xnafake"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" PointerPressed="Page_PointerPressed_1" PointerReleased="Page_PointerReleased_1" SizeChanged="Page_SizeChanged_1">

    <Grid x:Name="grid1" >
        <Grid.Background>
            <ImageBrush ImageSource="Assets/back2.png" Stretch="UniformToFill"/>
        </Grid.Background>
        <Grid x:Name="fieldGrid" RenderTransformOrigin="0,0" Margin="120, 140, 0, 0">
            <Grid.RenderTransform>
                <CompositeTransform x:Name="fieldScale1" ScaleX="1" ScaleY="1"/>
            </Grid.RenderTransform>
            <Rectangle x:Name="field1" Fill="Green" HorizontalAlignment="Left" Height="580" Stroke="Black" VerticalAlignment="Top" Width="400"/>
            <Image x:Name="goal1" HorizontalAlignment="Left" Height="150" Margin="0,0,0,0" VerticalAlignment="Top" Width="400" Stretch="Fill" Source="Assets/goal.png"/>
            <Image x:Name="monster1" HorizontalAlignment="Left" Height="160" Margin="123,248,0,0" VerticalAlignment="Top" Width="160" Source="Assets/monster.png" Stretch="Fill"/>
            <Image x:Name="ball1" HorizontalAlignment="Left" Height="60" Margin="338,403,0,0" VerticalAlignment="Top" Width="60" Source="Assets/ball.png" Stretch="Fill"/>
        </Grid>

        <Rectangle x:Name="info1" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="548">
            <Rectangle.Fill>
                <ImageBrush ImageSource="Assets/textback1.png" Stretch="UniformToFill"/>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle x:Name="info2" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="548">
            <Rectangle.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/textback1.png"/>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle x:Name="info3" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="548">
            <Rectangle.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/textback1.png"/>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle x:Name="info4" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="548">
            <Rectangle.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/textback1.png"/>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle x:Name="info5" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="548">
            <Rectangle.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/textback1.png"/>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle x:Name="info6" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="548">
            <Rectangle.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/textback1.png"/>
            </Rectangle.Fill>
        </Rectangle>

        <TextBlock x:Name="text1" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="548" FontFamily="Meiryo UI" FontSize="36" TextAlignment="Center"/>
        <TextBlock x:Name="text2" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="548" FontFamily="Meiryo UI" FontSize="36" TextAlignment="Center"/>
        <TextBlock x:Name="text3" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="548" FontFamily="Meiryo UI" FontSize="36" TextAlignment="Center"/>
        <TextBlock x:Name="text4" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="548" FontFamily="Meiryo UI" FontSize="36" TextAlignment="Center"/>
        <TextBlock x:Name="text5" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="548" FontFamily="Meiryo UI" FontSize="36" TextAlignment="Center"/>
        <TextBlock x:Name="text6" HorizontalAlignment="Left" Height="72" Margin="724,160,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="548" FontFamily="Meiryo UI" FontSize="36" TextAlignment="Center"/>
        <Image x:Name="logoImage1" HorizontalAlignment="Left" Height="70" Margin="120,30,0,0" VerticalAlignment="Top" Width="328" Source="Assets/logo3.png"/>

    </Grid>
</Page>

情報を表示させる部分のRectangleやTextBlockの位置が重なっていますが、これらはあとで計算して再配置しています。

[前後の記事]
第5回 : ジェスチャーのシミュレート
第7回 : スナップへの対応と不具合の回避
番外1 : Shoot Evoリリース1を公開
番外2 : Shoot Evoのソースコード / プロジェクト ファイルを公開

マイクロソフト
田中達彦