[C#] Minecraftのスーパー乞食バージョンを作成します(WPF 3Dでジオメトリを選択して移動します)

要約

この記事は、WPF3Dシリーズの最後のブログです。
ソースアドレス:[C#]WPF3Dジオメトリの選択と移動

ジオメトリを操作する

Minecraftは1週間に3人のプログラマーによって開発されたと言われており、乞食バージョンのMinecraftを開発するのに1人のプログラマーが半日かかったと言われています。推論にはまったく問題はありません。

そして、ご存知のとおり、Minecraftは無数のピクセルブロックのコレクションであり、ピクセルブロックは立方体です。新しいキューブの作成に関しては、誰もがこれに非常に精通しています。新しいキューブを作成できるだけでなく、必要な数のキューブを作成することもできます。

新しいキューブ

ただし、現在、手動で作成することはできないため、次にショートカットCtrl+を追加Nして、キューブをすばやく作成します。Ctrl+を押すNと、効果は

ここに画像の説明を挿入

これは、キューブの行をすでに生成できる人にとっては間違いなく簡単です。最初にコンストラクターでショートカットをバインドします。

public MainWindow()
{
    
    
    InitializeComponent();
    KeyDown += MainWindow_KeyDown;
}

MainWindow_KeyDownとして定義

private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
    
    

    if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.N))
    {
    
    
        MeshGeometry3D mesh = MakeCubeMesh(0, 0, 0, 1);
        Color color = Color.FromArgb(255, 0, 255, 0);
        DiffuseMaterial material = new DiffuseMaterial(new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(mesh, material);
        group3d.Children.Add(model);
    }
}

その中にMakeCubeMeshは、このシリーズの最初のブログで早くも書かれているカスタム関数や、光の効果などの他の関数があります。唯一の違いは、今回はそもそも複数のキューブを生成しないため、DefineModel関数は必要ないということです。

立方体の位置を設定します

現在、新しい立方体が作成されていますが、立方体の位置を特定できません。次に、新しく作成された立方体の位置を設定するために、新しいダイアログボックスを作成する必要があります。

プロジェクトを右クリックし、新しいウィンドウを作成して名前を付けParaDialogますxaml

<Window x:Class="MyWord.ParaDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="输入参数" Height="180" Width="300">
    <DockPanel LastChildFill="True">
        <StackPanel DockPanel.Dock="Bottom"
            Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="设置" Click="okButton_Click" Margin="5" Width="60" Height="25"/>
            <Button Content="取消" IsCancel="True" Margin="5" Width="60" Height="25"/>
        </StackPanel>
        <UniformGrid Columns="1" Margin="5" x:Name="ufgLabel"/>
        <UniformGrid Columns="1" Margin="5" x:Name="ufgTextBox"/>

    </DockPanel>
</Window>

そのcsコアコードは

public partial class ParaDialog : Window
{
    
    
    static readonly string[] labels = new string[4] {
    
     "x坐标", "y坐标", "z坐标", "边长" };
    List<TextBox> paraBoxes = new List<TextBox>();
    public double[] para;
    public ParaDialog(double[] para)
    {
    
    
        this.para = para;
        InitializeComponent();
        string tmp;
        for (int i = 0; i < 4; i++)
        {
    
    
            //向UniformGrid中欧给填充文字块
            ufgLabel.Children.Add(new TextBlock() {
    
     Text = labels[i] });
            paraBoxes.Add(new TextBox());
            ufgTextBox.Children.Add(paraBoxes[i]);
        }
    }

    private void okButton_Click(object sender, RoutedEventArgs e)
    {
    
    
        for (int i = 0; i < 4; i++)
            para[i] = double.Parse(paraBoxes[i].Text);
        DialogResult = true;
    }
}

最後に、Ctrl+Nの応答コードを変更します

//...前面不用改
if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.N))
{
    
    
  double[] para = new double[4];
  ParaDialog pDialog = new ParaDialog(para);
  pDialog.ShowDialog();
  if (pDialog.DialogResult != true)
      return;
  MeshGeometry3D mesh = MakeCubeMesh(para[0],para[1],para[2],para[3]);
  //...后面不用改
}

ここに画像の説明を挿入

選択したキューブ

ジオメトリを操作する場合は、ジオメトリを選択してから、マウスアクションをバインドして選択した操作を完了し、xaml最初にコードを変更してViewport3Dborder

<Border Name="mainBorder" Background="White" MouseDown="mainBorder_MouseDown">
    <Viewport3D x:Name="v3dMain">
    </Viewport3D>
</Border>

次に、新しいmainBorder_MouseDown関数を作成します

private void mainBorder_MouseDown(object sender, MouseButtonEventArgs e)
{
    
    
    if (e.LeftButton == MouseButtonState.Released) return;

    Color color = Color.FromArgb(255, 0, 255, 0);
    var material = new DiffuseMaterial(new SolidColorBrush(color));

    //获取鼠标在对象中的位置
    Point mousePos = e.GetPosition(v3dMain);

    // 执行点击操作
    HitTestResult result = VisualTreeHelper.HitTest(v3dMain, mousePos);

    //此即鼠标点击到曲面上的结果
    var meshResult = result as RayMeshGeometry3DHitTestResult;
    GeometryModel3D model = null;
    if ((meshResult != null) && (meshResult.ModelHit is GeometryModel3D))
        model = meshResult.ModelHit as GeometryModel3D;

    //如果刚才选了别的模型,则使之恢复绿色
    if (SelectedModel != null)
        SelectedModel.Material = material;
    //选择新的模型
    SelectedModel = model;
    if (model != null) 
        model.Material = new DiffuseMaterial(Brushes.Fuchsia);
}

その効果は

ここに画像の説明を挿入

ジオメトリを移動する

選択できるので、何かを動かすのは絶対に簡単です。

以前のマウス操作カメラを振り返ると、基本的なプロセスは、マウスをクリックした後、別の関数がバインドされ、マウスを離すとバインドが解除されるというものです。

WPF 3DTranform、ジオメトリの移動に使用できるメンバーが用意されているため、新しいジオメトリを作成するときは、必ず線を追加してください。

//MainWindow_KeyDown函数
model.Transform = new TranslateTransform3D(0, 0, 0);

次に、古い場所を保持するグローバル変数を追加します

private Point3D oldPoint;

次に、変更mainBorder_MouseDownします。実際、最後に追加するだけです。

mainBorder.CaptureMouse();
mainBorder.MouseMove += MainBorder_MouseMove;
mainBorder.MouseUp += MainBorder_MouseUp;

次は、マウスを動かしてバウンスしたときのアクションです。バウンスは非常に単純で、マウスアクションのバインドを解除するだけです。マウスを動かしたときは、ジオメトリの変更パラメータを変更する必要があります。

private void MainBorder_MouseUp(object sender, MouseButtonEventArgs e)
{
    
    
    mainBorder.ReleaseMouseCapture();
    mainBorder.MouseMove -= MainBorder_MouseMove;
    mainBorder.MouseUp -= MainBorder_MouseUp;
}

private void MainBorder_MouseMove(object sender, MouseEventArgs e)
{
    
    
    Point newPoint = e.GetPosition(mainBorder);
    var res = VisualTreeHelper.HitTest(v3dMain, newPoint);
    if (res == null) return;
    var newResult = res as RayMeshGeometry3DHitTestResult;

    var deltaPt = newResult.PointHit - oldPoint;
    var trans = SelectedModel.Transform as TranslateTransform3D;
    trans.OffsetX += deltaPt.X;
    trans.OffsetY += deltaPt.Y;
    trans.OffsetZ += deltaPt.Z;
    oldPoint = newResult.PointHit;
}

効果は

ここに画像の説明を挿入
さて、Minecraftのスーパー乞食バージョンは準備ができています→_→それは米国または香港にリストされていますか?

おすすめ

転載: blog.csdn.net/m0_37816922/article/details/124443939