مقصد

جب صفحے کی تازہ کاری :
صفحہ تخلیق تاریخ :

اس تجاویز پر نوٹ

یہ نمونہ مندرجہ ذیل سائٹس پر شائع ہونے والے پروگراموں پر مبنی ہے۔ میں کوڈ کو تھوڑا سا تبدیل کرتا ہوں تاکہ جاپانی زبان میں اسے سمجھنا اور سمجھانا آسان ہو۔ بنیادی طور پر، ہم اصل کوڈ کا استعمال کرتے ہیں جیسا کہ ہے، لہذا اگر آپ واقعی اسے اپنے گیم پروگرام میں اپناتے ہیں تو اسے بروقت درست کریں اور اسے استعمال کریں۔

حوالہ سائٹ

اس کے علاوہ، یہ مفروضے پر وضاحت کی گئی ہے کہ آپ کو مونو گیم اور ایکس این اے کے بارے میں کچھ بنیادی علم ہے۔ رڈلی کے لئے مونو گیم ٹپس اور ایکس این اے ٹپس دیکھیں۔

خاص طور پر، چونکہ ریاضی، سمتیہ، مثلثی افعال، میٹرکس وغیرہ ضروری ہیں، لہذا براہ کرم جانیں کہ وہ کسی حد تک کیا ہیں۔

ماحول

پلیٹ فارم
  • ونڈوز 10
  • کوڈ کو دیگر مونو گیم فعال پلیٹ فارمز پر استعمال کیا جا سکتا ہے
بصری سٹوڈیو
  • ویژیول سٹوڈیو 2019
.نیٹ کور
  • 3.1
مونو گیم
  • 3.8

نمونوں کے بارے میں

روشنی اس سمت میں روشنی کو ٹریک کرنے کے لئے گھومتی ہے جس سمت ہدف ہے۔

اگر آپ بلی کو ماؤس یا چابی سے حرکت کرتے ہیں،

روشنی بلی کی پیروی کرتی ہے۔

کام کرنے کا طریقہ

کی ہے
بورڈ گیم پیڈ (ایکس ان پٹ) ماؤس ٹچ کرنے کے لئے کیا
بلی تحریک ↑↓←→
  • بائیں چھڑی
  • ڈی پیڈ
بائیں بٹن کہیں بھی چھوئیں
کھیل کا اختتام ایس سی واپس - -

کیا تیار کرنا ہے

وہ تصاویر جو ہدف اور روشنیوں کو ٹریک کرنے کے لئے منتقل کرتے ہیں۔

پروگرام

تمام کوڈ کے لیے پروگرام ڈاؤن لوڈ کریں۔

مستقل

/// <summary>猫が動くスピード。これはフレームあたりのピクセル数です。</summary>
const float CatSpeed = 10.0f;

/// <summary>スポットライトが回転する速度。これはフレームあたりのラジアンで表されます。</summary>
const float SpotlightTurnSpeed = 0.025f;

بلی کی نقل و حرکت اور روشنی ٹریکنگ فوری نہیں ہیں، لیکن فریم کے لحاظ سے فریم کو حرکت دیں اور گھمائیں۔

ویسے، چونکہ کھیل کا وقت اس نمونے میں استعمال نہیں کیا جاتا ہے، اصل وقت آپریشن اور رفتار پلیٹ فارم پر منحصر مختلف ہو سکتا ہے. اپنے بنائے ہوئے اصل کھیل میں کھیل کا وقت استعمال کرنے کی کوشش کریں۔

کھیت

readonly GraphicsDeviceManager _graphics;

/// <summary>画像を表示するための SpriteBatch です。</summary>
SpriteBatch _spriteBatch;

/// <summary>スポットライトのテクスチャー(画像)です。</summary>
Texture2D _spotlightTexture;

/// <summary>スポットライトの位置です。</summary>
Vector2 _spotlightPosition = new Vector2();

/// <summary>スポットライトの中心位置です、ここを中心に回転します。</summary>
Vector2 _spotlightOrigin = new Vector2();

/// <summary>スポットライトが現在向いている角度。単位はラジアンです。値 0 は右を指します。</summary>
float _spotlightAngle = 0.0f;


/// <summary>猫のテクスチャー(画像)です。</summary>
Texture2D _catTexture;

/// <summary>猫の位置です。</summary>
Vector2 _catPosition = new Vector2();

/// <summary>猫の中心位置です。</summary>
Vector2 _catOrigin = new Vector2();

بنیادی طور پر، آپ کے پاس صرف سپرائیٹ دکھانے کے لئے معلومات ہیں۔ اہم بات یہ ہے _spotlightAngle کہ ہدف کی طرف اشارہ کرنے کے لئے خود بخود حساب لگانا ہے۔

تعمیرکار

public AimingGame()
{
  graphics = new GraphicsDeviceManager(this);
  ontent.RootDirectory = "Content";
  sMouseVisible = true;

  graphics.PreferredBackBufferWidth = 320;
  graphics.PreferredBackBufferHeight = 480;

  // フルスクリーンにしたい場合はコメントを外してください。
  //graphics.IsFullScreen = true;
}

موبائل کے لئے کم قراردادوں کے علاوہ ذہن میں رکھنے کے لئے کچھ نہیں ہے۔

طریقہ ابتدا کریں

protected override void Initialize()
{
  base.Initialize();

  // base.Initialize が完了すると、GraphicsDevice が作成され、ビューポートの大きさがわかります。
  // スポットライトを画面の中央に配置する必要があるため、ビューポートを使用してそれがどこにあるかを計算します。
  Viewport vp = _graphics.GraphicsDevice.Viewport;
  _spotlightPosition.X = vp.X + vp.Width / 2;
  _spotlightPosition.Y = vp.Y + vp.Height / 2;

  // もう一度ビューポートサイズを使用して、今度は猫を画面に配置します。位置は x=1/4 y=1/2 です。
  _catPosition.X = vp.X + vp.Width / 4;
  _catPosition.Y = vp.Y + vp.Height / 2;
}

ہر تصویر کی ابتدائی پوزیشن کا تعین کرتا ہے۔ نوٹ کریں کہ آپ استعمال کرنے کے بعد کوڈ base.Initialize() لکھ رہے ہیںViewport۔

مشمول اتلاف کا طریقہ

protected override void LoadContent()
{
  // テクスチャをロードし、スプライトバッチを作成します。
  _spotlightTexture = Content.Load<Texture2D>("spotlight");
  _catTexture = Content.Load<Texture2D>("cat");
  _spriteBatch = new SpriteBatch(_graphics.GraphicsDevice);

  // テクスチャをロードしたので、それらを使用して、描画時に使用するいくつかの値を計算できます。
  // スポットライトを描くときは、光源の周りを回転する必要があります。
  // 今回用意した画像は左中央が光源なのでその位置を中心位置として設定します。
  _spotlightOrigin.X = 0;
  _spotlightOrigin.Y = _spotlightTexture.Height / 2;

  // 猫の中心位置を決定します。とりあえず画像の真ん中とします。
  _catOrigin.X = _catTexture.Width / 2;
  _catOrigin.Y = _catTexture.Height / 2;
}

SpriteBatch میں بناوٹ بنا رہا ہوں اور لوڈ کر رہا ہوں۔

اس کے علاوہ بلی کی تصویر کی مرکز پوزیشن اور اسپاٹ لائٹ کی مرکز پوزیشن (گردش محور) یہاں سیٹ کی گئی ہے۔ کیونکہ مرکز کی پوزیشن تصویر کے لحاظ سے تبدیل ہو تی ہے یہ انفرادی طور پر سیٹ کیا گیا ہے.

طریقہ تازہ کاری کریں

protected override void Update(GameTime gameTime)
{
  HandleInput();

  // 猫が画面外に出ないように制御します。
  Viewport vp = _graphics.GraphicsDevice.Viewport;
  _catPosition.X = MathHelper.Clamp(_catPosition.X, vp.X, vp.X + vp.Width);
  _catPosition.Y = MathHelper.Clamp(_catPosition.Y, vp.Y, vp.Y + vp.Height);

  // TurnToFace 関数を使用して、_spotlightAngle を更新して猫の方を向くようにします。
  _spotlightAngle = TurnToFace(_spotlightPosition, _catPosition, _spotlightAngle, SpotlightTurnSpeed);

  base.Update(gameTime);
}

ہینڈل ان پٹ طریقہ کھلاڑی کے آپریشنز کو سنبھالتا ہے، جس پر بعد میں تبادلہ خیال کیا جائے گا۔ بلی کی پوزیشن کا تعین ان پٹ سے ہوتا ہے۔ ہم بلی کو اسکرین پر ظاہر ہونے سے روکنے کے لئے بھیViewport استعمال کرتے ہیں۔

TurnToFace طریقہ روشنی کو گھماتا ہے۔ اسپاٹ لائٹ کی پوزیشن اور بلی کی پوزیشن، روشنی کا موجودہ زاویہ اور زیادہ سے زیادہ گردش کی رفتار اب فریم میں روشنی کے رخ کا تعین کرنے کے لئے پرعزم ہیں۔ ہم بعد میں اس بارے میں بات کریں گے جس کے بارے میں ہم ہیں۔

ویسے، میں اس تجاویز میں اس کا استعمال نہیں کر رہا ہوں, لیکن آپ کھیل کی رفتار سے میل کھانے کے لئے گیم ٹائم متغیر استعمال کرنے کی ضرورت ہے.

ہینڈل ان پٹ طریقہ

/// <summary>
/// 入力を処理します。
/// </summary>
void HandleInput()
{
  KeyboardState currentKeyboardState = Keyboard.GetState();
  GamePadState currentGamePadState = GamePad.GetState(PlayerIndex.One);
  MouseState currentMouseState = Mouse.GetState();
  TouchCollection currentTouchState = TouchPanel.GetState();

  // ゲーム終了操作を確認します。
  if (currentKeyboardState.IsKeyDown(Keys.Escape) ||
      currentGamePadState.Buttons.Back == ButtonState.Pressed)
  {
    Exit();
  }

  // ユーザーが猫を動かしたいかどうかを確認します。 catMovement というベクトルを作成します。
  // これは、すべてのユーザーの入力の合計を格納します。
  Vector2 catMovement = currentGamePadState.ThumbSticks.Left;

  // y を反転:スティックでは、下は -1 ですが、画面では、下がプラスです。
  catMovement.Y *= -1;

  if (currentKeyboardState.IsKeyDown(Keys.Left) ||
      currentGamePadState.DPad.Left == ButtonState.Pressed)
  {
    catMovement.X -= 1.0f;
  }
  if (currentKeyboardState.IsKeyDown(Keys.Right) ||
      currentGamePadState.DPad.Right == ButtonState.Pressed)
  {
    catMovement.X += 1.0f;
  }
  if (currentKeyboardState.IsKeyDown(Keys.Up) ||
      currentGamePadState.DPad.Up == ButtonState.Pressed)
  {
    catMovement.Y -= 1.0f;
  }
  if (currentKeyboardState.IsKeyDown(Keys.Down) ||
      currentGamePadState.DPad.Down == ButtonState.Pressed)
  {
    catMovement.Y += 1.0f;
  }

  // タッチポイントに向かって移動します。
  // CatSpeed からタッチポイントまでの距離内に入ると、猫の速度を落とします。
  float smoothStop = 1;

  //if (currentTouchState != null )
  {
    if (currentTouchState.Count > 0)
    {
      Vector2 touchPosition = currentTouchState[0].Position;
      if (touchPosition != _catPosition)
      {
        catMovement = touchPosition - _catPosition;
        float delta = CatSpeed - MathHelper.Clamp(catMovement.Length(), 0, CatSpeed);
        smoothStop = 1 - delta / CatSpeed;
      }
    }
  }

  Vector2 mousePosition = new Vector2(currentMouseState.X, currentMouseState.Y);
  if (currentMouseState.LeftButton == ButtonState.Pressed && mousePosition != _catPosition)
  {
    catMovement = mousePosition - _catPosition;
    float delta = CatSpeed - MathHelper.Clamp(catMovement.Length(), 0, CatSpeed);
    smoothStop = 1 - delta / CatSpeed;
  }

  // ユーザーの入力を正規化して、猫が CatSpeed より速く進むことができないようにします。
  if (catMovement != Vector2.Zero)
  {
    catMovement.Normalize();
  }

  _catPosition += catMovement * CatSpeed * smoothStop;
}

کھلاڑی کا ان پٹ عمل. ہم یہاں جو کچھ کر رہے ہیں وہ بلی کی چال اور کھیل کے آپریشن کا اختتام ہے۔

ان پٹ ڈیوائسز کو مختلف شعبوں میں سپورٹ کیا جاتا ہے: کی بورڈ، گیم پیڈ، ماؤس، ٹچ ۔

بنیادی طور پر، میں صرف ایک سمتیہ کلید کے ساتھ آگے بڑھ رہا ہوں، اسے چھو رہا ہوں، یا بلی کو اس پوزیشن کی طرف اشارہ کر رہا ہوں جس پر میں نے کلک کیا تھا، لہذا میں بہت زیادہ تفصیل میں نہیں جاؤں گا۔ ایک تفصیلی کنٹرول پوائنٹ کے طور پر،

  • چھڑی الٹ جاتی ہے کیونکہ اوپر کی سمت مثبت ہے، جبکہ سکرین کی پوزیشن نیچے کی سمت میں مثبت ہے۔
  • بلی کے ماؤس یا چھونے کے ساتھ اپنی مطلوبہ پوزیشن پر پہنچنے کے بعد پوائنٹس سے آگے نہ بڑھیں
  • ایک بار جب آپ سفر کی سمت کا تعین کر لیں تو اسے ایک اکائی سمتیہ (صرف سمت) بنانے کے لیے معمول پر لائیں اور آخر میں حرکت کی رفتار کو ضرب دیں۔

یہ آتا ہے.

بدلیں بطرف چہرہ طریقہ

/// <summary>
/// オブジェクトの位置、ターゲットの位置、現在の角度、および最大回転速度を指定して、
/// オブジェクトが直面する必要のある角度を計算します。
/// </summary>
/// <param name="position">オブジェクトの位置。ここではスポットライトの位置。</param>
/// <param name="faceThis">ターゲットの位置。ここでは猫の位置。</param>
/// <param name="currentAngle">現在の角度。</param>
/// <param name="turnSpeed">最大回転速度。</param>
/// <returns>決定された角度。</returns>
private static float TurnToFace(Vector2 position, Vector2 faceThis, float currentAngle, float turnSpeed)
{
  // :
  // :
}

تجاویز کے لئے یہ اہم عمل ہے۔ زاویہ کا تعین کرنے کا عمل تاکہ روشنی بلی کا سامنا کرے۔ پاس اسپاٹ لائٹ پوزیشن، بلی کی پوزیشن، موجودہ زاویہ، دلائل کے طور پر زیادہ سے زیادہ گردش رفتار. واپسی کی قدر آخری گردش پوزیشن ہے۔ یہ موجودہ پوزیشن سے گردش کی مقدار نہیں ہے۔

// この図を参照してください。
// 
//      C 
//     /|
//    / |
//   /  | y
//  / o |
// S----
//     x
// 
// ここで、S はスポットライトの位置、C は猫の位置、o は猫を指すためにスポットライトが向いている角度です。
// o の値を知る必要があります。
// これには三角法を使用して算出します。
// 
//      tan(theta)       = 高さ / 底辺
//      tan(o)           = y / x
// 
// この方程式の両辺のアークタンジェントを取ると
// 
//      arctan( tan(o) ) = arctan( y / x )
//      o                = arctan( y / x )
// 
// したがって、x と y を使用して、「desiredAngle」である o を見つけることができます。
// x と y は、2つのオブジェクト間の位置の違いにすぎません。
float x = faceThis.X - position.X;
float y = faceThis.Y - position.Y;

// Atan2 関数を使用します。Atanは、y / x のアークタンジェントを計算し、x と y の符号を使用して、
// 結果を入れるデカルト象限を決定するという追加の利点があります。
// https://docs.microsoft.com/dotnet/api/system.math.atan2
float desiredAngle = (float)Math.Atan2(y, x);

جیسا کہ تبصروں میں ذکر کیا گیا ہے، مثلثی (معکوس مثلثی افعال) پوزیشنوں سے زاویوں کا حساب لگانے کے لیے استعمال کیا جاتا ہے۔ اگر آپ ریاضی کے مندرجات کی وضاحت کرتے ہیں، تو یہ ایک ٹوٹکا ہوگا، لہذا آپ کو معلوم ہونا چاہئے کہ آپ کو یہاں آرکٹنجینٹ استعمال کرنا چاہئے۔ استعمال کیا جانے والا طریقہ ہے Math.Atan2 ۔ Math.Atan نوٹ کریں کہ ایسا نہیں ہے۔

واپسی کی قدر کے لیے درج ذیل اعداد و شمار دیکھیں۔ +ایکس کی سمت کے ساتھ +π کو π کی قدر واپس کرتا ہے۔ نوٹ کریں کہ +وائی سمت ایک مثبت نتیجہ واپس کرتی ہے، لیکن کھڑکی پر متناسقات پر نیچے +وائی سمت ہے۔

// これで猫を向くために必要な設定角度がわかりました。turnSpeed (回転スピード) に制約されていなければ簡単です。
// desiredAngle を返すだけです。
// 代わりに回転量を計算し、それが turnSpeed を超えないようにする必要があります。

// まず、WrapAngle を使用して、-Pi から Pi(-180度から180度)の結果を取得し、
// どれだけ回転させたいかを判断します。
// これは猫の方向に向くのに必要な回転角度です。
float difference = WrapAngle(desiredAngle - currentAngle);

// -turnSpeed と turnSpeed の間にクランプします。
// 要は1フレームの回転角度上限を超えないようにします。
difference = MathHelper.Clamp(difference, -turnSpeed, turnSpeed);

// したがって、ターゲットに最も近いのは currentAngle + difference です。
// もう一度 WrapAngle を使用して、それを返します。
return WrapAngle(currentAngle + difference);

ایک بار جب آپ کے پاس ہدف کی نشاندہی کرنے کے لئے زاویہ ہو جاتا ہے، باقی کو موجودہ پوزیشن سے مطلوبہ زاویہ تک زاویہ کا تعین کیا جاتا ہے۔ یہاں ہمارے پاس زیادہ سے زیادہ رفتار ہے جسے ایک فریم میں گھمایا جا سکتا ہے، MathHelper.Clamp(difference, -turnSpeed, turnSpeed) زیادہ سے زیادہ قدر سے تجاوز نہیں کرتا۔

اس کے علاوہ، اگر صرف جمع یا منفی حساب لگایا جائے تو یہ +π اور -π کی حد سے آگے پیچھے کی طرف گھومتا ہے، لہذا میں اسے ریپ اینگل طریقہ کے ساتھ ایڈجسٹ کرتا ہوں۔ یہ طریقہ اگلے حصے میں بیان کیا گیا ہے۔

آخر میں، جب زاویہ جس کی طرف اسے گھمایا جاتا ہے، کا تعین کیا جاتا ہے، واپس آجائیں۔

لفافہ زاویہ طریقہ

/// <summary>
/// -Pi と Pi の間のラジアンで表される角度を返します。
/// 例えば degree で -200°なら +360°して 160°とします。反対側も同様です。
/// </summary>
private static float WrapAngle(float radians)
{
  while (radians < -MathHelper.Pi)
  {
    radians += MathHelper.TwoPi;
  }
  while (radians > MathHelper.Pi)
  {
    radians -= MathHelper.TwoPi;
  }
  return radians;
}

اگر زاویہ حد اطلاق سے بڑھ کر -π سے +π تک پہنچ جائے تو یہ مخالف سمت میں اس سمت میں گھوم سکتا ہے جسے گھمانا چاہیے، اگر یہ حد اطلاق تجاوز کر گئی ہے تو اسے اوپر کی حد کے اندر رکھنے کے لیے 2π اضافہ یا تفریق کریں۔

طریقہ قرعہ اندازی کریں

protected override void Draw(GameTime gameTime)
{
  GraphicsDevice device = _graphics.GraphicsDevice;

  device.Clear(Color.Black);

  // 猫を描画します。
  _spriteBatch.Begin();
  _spriteBatch.Draw(_catTexture, _catPosition, null, Color.White, 0.0f, _catOrigin, 1.0f, SpriteEffects.None, 0.0f);
  _spriteBatch.End();

  // 加算合成でスプライトバッチを開始し、スポットライトを当てます。 加算合成は、ライトや火などの効果に非常に適しています。
  _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
  _spriteBatch.Draw(_spotlightTexture, _spotlightPosition, null, Color.White, _spotlightAngle, _spotlightOrigin, 1.0f, SpriteEffects.None, 0.0f);
  _spriteBatch.End();

  base.Draw(gameTime);
}

ایک بار جب آپ پوزیشن اور گردش کا حساب لگا چکے ہیں، تو آپ کو صرف اس نمبر کے ساتھ سپرائیٹ کھینچنا ہے۔ بلی کو اس طرح ظاہر کرنے کے لئے جیسے روشنی کو مارا جاتا ہے، روشنی کھینچتے وقت اضافوں کی تالیف کی جاتی ہے۔

خلاصہ

میرے خیال میں اس تکنیک کے بارے میں جاننا بہت ضروری ہے کیونکہ کھیل میں نسبتا بہت سے حالات ہیں جہاں آپ فیصلہ کرتے ہیں کہ آپ کا حریف کس راستے میں ہے۔ یہ طریقہ عام طور پر 2ڈی گیمز میں استعمال کیا جاتا ہے، اور تھری ڈی گیمز میں کواٹرینز کا استعمال کرتے ہوئے حساب لگایا جاسکتا ہے۔ لیکن بہت سی چیزیں ایسی ہیں جو تھری ڈی میں 2ڈی حساب استعمال کرتی ہیں، لہذا یہ جاننا محفوظ ہے۔