Στοχεύοντας

Σελίδα ενημέρωση :
Ημερομηνία δημιουργίας σελίδας :

Σημειώσεις σχετικά με αυτές τις συμβουλές

Αυτό το δείγμα βασίζεται στα προγράμματα που δημοσιεύονται στις ακόλουθες τοποθεσίες. Αλλάζω λίγο τον κώδικα για να διευκολύνω την κατανόηση και την εξήγησή του στα ιαπωνικά. Βασικά, χρησιμοποιούμε τον αρχικό κώδικα ως έχει, οπότε αν πραγματικά τον υιοθετήσετε στο πρόγραμμα παιχνιδιού σας, διορθώστε τον εγκαίρως και χρησιμοποιήστε τον.

Τοποθεσία αναφοράς

Επιπλέον, εξηγείται με την υπόθεση ότι έχετε κάποιες βασικές γνώσεις σχετικά με το MonoGame και το XNA. Δείτε συμβουλές monogame και συμβουλές XNA για το ruddly.

Συγκεκριμένα, καθώς τα μαθηματικά, οι φορείς, οι τριγωνομετρικές λειτουργίες, οι μήτρες κ.λπ.

περιβάλλον

πλατφόρμα
  • Παράθυρα 10
  • Ο κώδικας μπορεί να χρησιμοποιηθεί σε άλλες πλατφόρμες με δυνατότητα MonoGame
Οπτικό Στούντιο
  • Οπτικό Στούντιο 2019
.NET πυρήνας
  • 3.1
Μονογαμιό
  • 3.8

Σχετικά με τα δείγματα

Το φως περιστρέφεται για να ανιχνεύσει το φως προς την κατεύθυνση που είναι ο στόχος.

Αν μετακινήσετε τη γάτα με ποντίκι ή κλειδί,

Το φως ακολουθεί τη γάτα.

Πώς να λειτουργήσετε

πληκτρολόγιο
Τι πρέπει να κάνετε gamepad (XInput) άγγιγμα του ποντικιού
Κίνηση γάτας ↑↓←→
  • Αριστερό ραβδί
  • DPad
Αριστερό κουμπί Αγγίξτε οπουδήποτε
Τέλος παιχνιδιού Εσκτ Πλάτη - -

Τι να προετοιμάσετε

Εικόνες που μετακινούν το στόχο και τα φώτα για παρακολούθηση.

πρόγραμμα

Κατεβάστε το πρόγραμμα για όλο τον κώδικα.

σταθερός

/// <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;
}

Καθορίζει την αρχική θέση κάθε εικόνας. Σημειώστε ότι γράφετε Viewport κώδικα μετά τη base.Initialize() χρήση του .

Μέθοδος LoadContent

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);
}

Η μέθοδος HandleInput χειρίζεται τις λειτουργίες του παίκτη, οι οποίες θα συζητηθούν αργότερα. Η θέση της γάτας καθορίζεται από την είσοδο. Χρησιμοποιούμε επίσηςViewport για να αποτρέψουμε την εμφάνιση της γάτας στην οθόνη.

TurnToFace Η μέθοδος περιστρέφεται τα φώτα της δημοσιότητας. Η θέση του προβολέα και η θέση της γάτας, η τρέχουσα γωνία του φωτός και η μέγιστη ταχύτητα περιστροφής καθορίζονται τώρα για να καθορίσουν τον προσανατολισμό του φωτός στο πλαίσιο. Θα μιλήσουμε για το τι θα κάνουμε αργότερα.

Παρεμπιπτόντως, δεν το χρησιμοποιώ σε αυτές τις Συμβουλές, αλλά πρέπει να χρησιμοποιήσετε τη μεταβλητή gameTime για να ταιριάζει με την ταχύτητα του παιχνιδιού.

Μέθοδος HandleInput

/// <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;
}

Η διαδικασία εισόδου του παίκτη. Αυτό που κάνουμε εδώ είναι η μετακίνηση της γάτας και το τέλος της λειτουργίας του παιχνιδιού .

Οι συσκευές εισόδου υποστηρίζονται σε διάφορους τομείς: Πληκτρολόγιο, Gamepad, Ποντίκι, Αφή .

Βασικά, απλά κινούμαι με ένα κατευθυντικό κλειδί, το αγγίζω ή δείχνω τη γάτα στη θέση που έκανα κλικ, οπότε δεν θα μπω σε πολλές λεπτομέρειες. Ως λεπτομερές σημείο ελέγχου,

  • Το ραβδί αντιστρέφεται επειδή η ανοδική κατεύθυνση είναι θετική, ενώ η θέση της οθόνης είναι θετική προς τα κάτω.
  • Μην μετακινείτε πέρα από τα σημεία αφού η γάτα φτάσει στην επιθυμητή θέση με το ποντίκι ή την αφή
  • Μόλις καθορίσετε την κατεύθυνση του ταξιδιού, ομαλοποιήστε το για να το κάνετε ένα διάνυσμα μονάδας (μόνο κατεύθυνση) και τελικά πολλαπλασιάστε την ταχύτητα κίνησης.

Έρχεται στο.

Μέθοδος TurnToFace

/// <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);

Όπως αναφέρεται στα σχόλια, η τριγωνομετρική (αντίστροφες τριγωνομετρικές λειτουργίες) χρησιμοποιείται για τον υπολογισμό των γωνιών από τις θέσεις. Αν εξηγήσετε το περιεχόμενο των μαθηματικών, θα είναι μια συμβουλή, οπότε θα πρέπει να γνωρίζετε ότι θα πρέπει να χρησιμοποιήσετε το arctangent εδώ. Η μέθοδος που χρησιμοποιείται είναι Math.Atan2 . Math.Atan σημειώστε ότι δεν είναι.

Δείτε την παρακάτω εικόνα για την τιμή επιστροφής. Επιστρέφει μια τιμή από -π έως +π με κατεύθυνση +x ως 0. Σημειώστε ότι η κατεύθυνση +y επιστρέφει ένα θετικό αποτέλεσμα, αλλά στις συντεταγμένες παραθύρου το κάτω μέρος είναι η κατεύθυνση +y.

// これで猫を向くために必要な設定角度がわかりました。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) δεν υπερβαίνει τη μέγιστη τιμή.

Επίσης, εάν υπολογίζεται απλά με συν ή πλην, περιστρέφεται προς τα πίσω πέρα από το εύρος +π και -π, οπότε το προσαρμόζω με τη μέθοδο WrapAngle. Αυτή η μέθοδος περιγράφεται στην επόμενη ενότητα.

Τέλος, όταν καθοριστεί η γωνία στην οποία περιστρέφεται, επιστρέψτε.

Μέθοδος WrapAngle

/// <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);
}

Μόλις υπολογίσετε τη θέση και την περιστροφή, το μόνο που έχετε να κάνετε είναι να σχεδιάσετε το ξωτικό κατά μήκος αυτού του αριθμού. Προκειμένου να εκφραστεί η γάτα σαν να χτυπά το φως, πραγματοποιείται πρόσθετη σύνθεση κατά τη σχεδίαση του προβολέα.

Περίληψη

Νομίζω ότι είναι πολύ σημαντικό να γνωρίζουμε για αυτή την τεχνική, επειδή υπάρχουν σχετικά πολλές καταστάσεις στο παιχνίδι όπου αποφασίζετε σε ποιον τρόπο βρίσκεται ο αντίπαλός σας. Αυτή η μέθοδος χρησιμοποιείται συνήθως σε παιχνίδια 2D και μπορεί να υπολογιστεί χρησιμοποιώντας quaternions σε 3D παιχνίδια. Αλλά υπάρχουν πολλά πράγματα που χρησιμοποιούν υπολογισμούς 2D σε 3D, οπότε είναι ασφαλές να γνωρίζουμε.