WPF 3Dプログラミング

第7回「キャラ同士の当たり判定」の巻

WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング

先生「次はVC#で、2体のキャラを表示して当たり判定を取ります。
まずは『Identity』で、『Identity』フォルダの『Tag.idt』を開いてください。ツリービューに『Swordsman』と『Witch』と『Grass』の3つのキャラアイテムがありますね。
前回も言ったように、3Dデータは1つのxamlファイルに全て収めなくてはいけません」
WPF 3Dプログラミング



先生
WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング

ツカサ「『Identity』から『Tag.xaml』に書き出しました」 WPF 3Dプログラミング



天使
WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング

先生「VC#で、第4回を参考に、新たなプロジェクトを作ります。
プロジェクト名は『WpfApplication3』にしましょう」
WPF 3Dプログラミング



先生
タクヤ
WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング
WPF 3Dプログラミング タクヤ「第4回のように、テキストエディタで『Tag.xaml』を開いて全て選択コピーし、『Window1.xaml』の『Grid』タグの間に貼り付けて、『デバッグ>実行』メニューで剣士キャラと魔女キャラと地面が現れました。
前回のを応用して、魔女キャラも凹凸地形にあうようコーディングしました」

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
//3Dが使えるようにする
using System.Windows.Media.Media3D;//追加
//タイマーが使えるようにする
using System.Windows.Threading;//追加

namespace WpfApplication3
{
    /// ‹summary›
    /// Window1.xaml の相互作用ロジック
    /// ‹summary›
    public partial class Window1 : Window
    {
        //タイマー
        private DispatcherTimer intervalTimer = new DispatcherTimer();
        //剣士キャラの位置
        Vector3D pos = new Vector3D(1000, 0, 1000);
        //剣士キャラの向き
        float angle = 0;
        //魔女キャラの位置
        Vector3D pos2 = new Vector3D(0, 0, 0);
        //魔女キャラの向き
        float angle2 = 200;

        public Window1()
        {
            InitializeComponent();

            //30ミリ秒ごとに、『Update3DEvent』関数を呼び出す
            intervalTimer.Interval = TimeSpan.FromMilliseconds(30);
            intervalTimer.Tick += new EventHandler(Update3DEvent);
            intervalTimer.Start();
        }

        //30ミリ秒ごとに呼ばれる関数
        void Update3DEvent(object sender, EventArgs e)
        {
            //カメラ位置
            Camera_Tag.Position =
				new Point3D(pos.X + 3000, pos.Y + 1000, pos.Z + 3000);
            //カメラの向き
            Camera_Tag.LookDirection = new Vector3D(-3, -0.9, -3);

            SwordsmanMove();
            WitchMove();
        }

        //剣士キャラの操作はこちらに移転
        private void SwordsmanMove()
        {
            if (Keyboard.IsKeyDown(Key.Right))
            {
                //キャラの角度を減算
                angle -= 10;
                //0度を下回ったら360度加算
                if (angle < 0)
                {
                    angle += 360;
                }
            }
            if (Keyboard.IsKeyDown(Key.Left))
            {
                //キャラの角度を加算
                angle += 10;
                //1回転したら360度減算
                if (angle >= 360)
                {
                    angle -= 360;
                }
            }
            //ディグリーからラジアンへ変換
            float radian = toRadian(angle);
            if (Keyboard.IsKeyDown(Key.Up))
            {
                //向いた方向へXとZ座標を加算
                pos.X += (float)(Math.Sin(radian) * 10);
                pos.Z += (float)(Math.Cos(radian) * 10);
            }
            if (Keyboard.IsKeyDown(Key.Down))
            {
                //向いた方向へXとZ座標を減算
                pos.X -= (float)(Math.Sin(radian) * 10);
                pos.Z -= (float)(Math.Cos(radian) * 10);
            }
            //3D行列
            Matrix3D m = new Matrix3D();
            //回転
            Quaternion q = new Quaternion(new Vector3D(0, 1, 0), angle);
            //回転を3D行列にセット
            m.Rotate(q);
            //3D行列に平行移動した位置posをセット
            m.OffsetX = pos.X;
            m.OffsetY = pos.Y;
            m.OffsetZ = pos.Z;
            //3D行列を3D変形行列にセット
            MatrixTransform3D trans = new MatrixTransform3D(m);
            //剣士キャラに移動した変形行列をセット
            Character_Tag_Swordsman.Transform = trans;
            //地面と当たり判定
            //pointはキャラの位置
            Point3D point = new Point3D(pos.X, pos.Y, pos.Z);
            //剣士のレイの向き
            Vector3D dir = new Vector3D(0, -1, 0);
            //剣士キャラの位置からのレイのセット
            RayHitTestParameters rayparams = new RayHitTestParameters(point, dir);
            //レイが地面Character_Grass_Grassにヒットしたら
			//ResultsOfHit関数を呼び出すようにセット
            VisualTreeHelper.HitTest(
                Character_Tag_Grass, null,
					new HitTestResultCallback(ResultsOfHit), rayparams);
        }

        private void WitchMove()
        {
            //3D行列
            Matrix3D m = new Matrix3D();
            //回転
            Quaternion q = new Quaternion(new Vector3D(0, 1, 0), angle2);
            //回転を3D行列にセット
            m.Rotate(q);
            //3D行列に平行移動した位置posをセット
            m.OffsetX = pos2.X;
            m.OffsetY = pos2.Y;
            m.OffsetZ = pos2.Z;
            //3D行列を3D変形行列にセット
            MatrixTransform3D trans = new MatrixTransform3D(m);
            //魔女キャラに移動した変形行列をセット
            Character_Tag_Witch.Transform = trans;

            //魔女キャラを高い位置から地面と当たり判定
            pos2.Y = 1000;
            //pointはキャラの位置
            Point3D point = new Point3D(pos2.X, pos2.Y, pos2.Z);
            //魔女のレイの向き
            Vector3D dir = new Vector3D(0, -1, 0);
            //魔女キャラの位置からのレイのセット
            RayHitTestParameters rayparams = new RayHitTestParameters(point, dir);
            //レイが地面Character_Tag_Grassにヒットしたら
			//ResultsOfHit2関数を呼び出すようにセット
            VisualTreeHelper.HitTest(
                Character_Tag_Grass, null,
				new HitTestResultCallback(ResultsOfHit2), rayparams);
        }

        //地面と剣士キャラとの距離だけY座標を移動
        private HitTestResultBehavior ResultsOfHit(HitTestResult myresult)
        {
            RayHitTestResult rayResult = myresult as RayHitTestResult;

            if (rayResult != null)
            {
                RayMeshGeometry3DHitTestResult rayMeshResult
                    = rayResult as RayMeshGeometry3DHitTestResult;
                //剣士のレイがヒットした場合
                if (rayMeshResult != null)
                {
                    pos.Y = pos.Y + 10 - rayMeshResult.DistanceToRayOrigin;
                    return HitTestResultBehavior.Stop;//Exit
                }
            }

            return HitTestResultBehavior.Continue;
        }

        //地面と魔女キャラとの距離だけY座標を移動
        private HitTestResultBehavior ResultsOfHit2(HitTestResult myresult)
        {
            RayHitTestResult rayResult = myresult as RayHitTestResult;

            if (rayResult != null)
            {
                RayMeshGeometry3DHitTestResult rayMeshResult
                    = rayResult as RayMeshGeometry3DHitTestResult;
                //魔女のレイがヒットした場合
                if (rayMeshResult != null)
                {
                    pos2.Y = pos2.Y + 10 - rayMeshResult.DistanceToRayOrigin;
                    return HitTestResultBehavior.Stop;//Exit
                }
            }

            return HitTestResultBehavior.Continue;
        }

        //ディグリー(度)からラジアンへ変換
        private float toRadian(float degree)
        {
            return (float)((float)degree / 360 * Math.PI * 2);
        }
    }
}
            




WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング

ツカサ「もう、ゲームになりそうですね!」 WPF 3Dプログラミング



天使
WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング

先生「キャラ同士の当たり判定は、2者の位置をピタゴラスの定理で距離を測って200以内ならば当たっていると判定します。
以下の赤字のようにコーディングしてください」

        void Update3DEvent(object sender, EventArgs e)
        {
            //カメラ位置
            Camera_Tag.Position =
				new Point3D(pos.X + 3000, pos.Y + 1000, pos.Z + 3000);
            //カメラの向き
            Camera_Tag.LookDirection = new Vector3D(-3, -0.9, -3);

            SwordsmanMove();
            WitchMove();

            //ピタゴラスの定理で当たり判定
            double x = pos2.X - pos.X;
            double z = pos2.Z - pos.Z;
            if (x * x + z * z <= 200 * 200)
            {
                pos2.X += x;
                pos2.Z += z;
            }
        }
            
WPF 3Dプログラミング



先生
タクヤ
WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング
WPF 3Dプログラミング タクヤ「でもこれは単純な当たり判定で、格闘ゲームで腕や足の当たり判定には無理そう・・・」



WPF 3Dプログラミング WPF 3Dプログラミング WPF 3Dプログラミング

先生「最初のうちはこの当たり判定で十分です。
今までのプロジェクトはここまで」
WPF 3Dプログラミング



先生

前のページへ HOME 1 2 3 4 5 6 7 8 9 次のページへ