Closed3

WinUI3 の Canvas を使ってマイクラのプレイヤーの移動軌跡をリアルタイム描画する

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

MinecraftConnection はさておき、GUIで描画するためのコード。
まずはXAMLから。

MainWindow.xaml
<Window
    x:Class="GuiApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:GuiApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="GuiApp">

    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>

    <Grid>
        <Canvas x:Name="MotionCanvas" Background="White"/>
    </Grid>
</Window>
たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

コードビハインド

MainWindow.cs
public sealed partial class MainWindow : Window
{
    private List<Position> playerMotions = new List<Position>();
    public MainWindow()
    {
        InitializeComponent();

        CompositionTarget.Rendering += OnRender;
        StartMotionUpdate();
    }

    private async void StartMotionUpdate()
    {
        var command = new MinecraftCommand("127.0.0.1", 25575, "your-pass");
        while (true)
        {
            var data = await command.DataGetEntityAsync("player-name");
            var info = data.Position;

            DispatcherQueue.TryEnqueue(() =>
            {
                if (playerMotions.Count > 200)
                {
                    playerMotions.RemoveAt(0);
                }
                playerMotions.Add(info);
            });
            System.Diagnostics.Debug.WriteLine($"X:{info.X} Y:{info.Y} Z:{info.Z}");
            await Task.Delay(5);
        }
    }

    private void OnRender(object? sender, object e)
    {
        MotionCanvas.Children.Clear();

        double canvasWidth = MotionCanvas.ActualWidth;
        double canvasHeight = MotionCanvas.ActualHeight;
        double scale = 20;

        foreach (var motion in playerMotions)
        {
            var ellipse = new Ellipse
            {
                Width = 5,
                Height = 5,
                Fill = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 0, 0))
            };

            // Canvas 中心を (0,0) として座標をマッピング
            double x = canvasWidth / 2 + motion.X * scale;
            double y = canvasHeight / 2 - motion.Z * scale; // Z を Y に投影

            Canvas.SetLeft(ellipse, x);
            Canvas.SetTop(ellipse, y);
            MotionCanvas.Children.Add(ellipse);
        }
    }
}
  • CompositionTarget.Rendering は毎フレーム呼び出されるイベントハンドラ
  • StartMotionUpdate() は非同期にして常時実行(座標取ってくるより早そう、Waitしてもよかったかな?)
  • マイクラのY座標は高さになるので、Canvas用に、マイクラのZ座標をCanvasのY座標へ反映
double y = canvasHeight / 2 - motion.Z * scale;
  • マイクラでの座標をそのままCanvasに描画するとめっちゃ小さかったので、20倍にスケーリング(ここは経験則から)

Windows.UI.Color ってカラープリセットないので、RGBAで指定するのがちょい面倒だったり。

このスクラップは4日前にクローズされました