Zamerané

Stránka aktualizovaná :
Dátum vytvorenia strany :

Poznámky k týmto tipom

Táto vzorka je založená na programoch publikovaných na nasledujúcich lokalitách. Trochu mením kód, aby som ho ľahšie pochopil a vysvetlil v japončine. V podstate používame pôvodný kód tak, ako je, takže ak ho skutočne prijmete vo svojom hernom programe, opravte ho včas a použite ho.

Referenčná lokalita

Okrem toho je to vysvetlené za predpokladu, že máte niektoré základné znalosti o MonoGame a XNA. Pozrite si tipy monogame a tipy XNA pre hrubo.

Najmä preto, že matematika, vektory, trigonometrické funkcie, matrice atď. sú nevyhnutné, takže prosím vedieť, čo sú do určitej miery.

životné prostredie

nástupište
  • Windows 10
  • Kód je možné použiť na iných platformách s podporou monogame
Vizuálne štúdio
  • Visual Studio 2019
.NET Core
  • 3.1
Monogame
  • 3.8

Informácie o vzorkách

Svetlo sa otáča, aby sledovalo svetlo v smere, v akom je cieľ.

Ak pohybujete mačku myšou alebo kľúčom,

Svetlo nasleduje mačku.

Ako pracovať

Čo robiť Klávesnica Gamepad (XInput) Mouse Touch
Pohyb mačky ↑↓←→
  • Ľavá palica
  • DPad
Ľavé tlačidlo Dotknite sa kdekoľvek
Koniec hry Esc Chrbát - -

Čo pripraviť

Obrázky, ktoré posúvajú cieľ a svetlá na sledovanie.

program

Stiahnite si program pre všetky kódy.

konštanta

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

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

Pohyb mačiek a sledovanie svetla nie sú okamžité, ale pohybujú a otáčajú rám po ráme.

Mimochodom, keďže hrací čas sa v tejto vzorke nepoužíva, skutočná časová prevádzka a rýchlosť sa môžu líšiť v závislosti od platformy. Pokúste sa využiť herný čas v skutočnej hre, ktorú urobíte.

pole

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

V podstate máte len informácie na zobrazenie sprite. Dôležité je _spotlightAngle automaticky vypočítať, aby ste ukázali na cieľ.

staviteľ

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

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

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

Nie je nič, čo by ste mali mať na pamäti, okrem nižších rozlíšení pre mobilné zariadenia.

Inicializácia metódy

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

Určuje počiatočnú polohu každého obrázka. Všimnite si, že kód píšete Viewport po base.Initialize() použití .

Metóda 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 Vytváram a načítavam textúry.

Okrem toho je tu nastavená stredná poloha obrazu mačky a stredná poloha (rotačná os) reflektora. Pretože stredná poloha sa mení v závislosti od obrázka Je nastavený individuálne.

Metóda aktualizácie

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

Metóda HandleInput sa zaoberá operáciami hráča, o ktorých sa bude diskutovať neskôr. Poloha mačky je určená vstupom. Používame tiežViewport na zabránenie tomu, aby sa mačka objavila na obrazovke.

TurnToFace Metóda otáča reflektory. Poloha reflektora a poloha mačky, aktuálny uhol svetla a maximálna rýchlosť otáčania sú teraz určené na určenie orientácie svetla v ráme. Porozprávame sa o tom, o čom sme neskôr.

Mimochodom, nepoužívam ho v týchto tipoch, ale musíte použiť premennú gameTime, aby zodpovedala rýchlosti hry.

Metóda 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;
}

Vstupný proces hráča. To, čo tu robíme , je pohyb mačky a koniec operácie hry .

Vstupné zariadenia sú podporované v rôznych oblastiach: Klávesnica, Gamepad, Myš, Touch .

V podstate sa len pohybujem so smerovým kľúčom, dotýkam sa ho alebo ukazujem mačku na pozíciu, na ktorú som klikol, takže nebudem zachádzať do prílišných detailov. ako podrobný kontrolný bod,

  • Palica je obrátená, pretože smer nahor je kladný, zatiaľ čo poloha obrazovky je pozitívna v smere nadol.
  • Nepohybujte sa za body po tom, čo mačka dosiahne požadovanú polohu myšou alebo dotykom
  • Akonáhle ste určili smer jazdy, normalizujte ho tak, aby sa stal jednotkovým vektorom (iba smerom) a nakoniec znásobte rýchlosť pohybu.

Príde na to.

Metóda 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)
{
  // :
  // :
}

To je hlavný proces pre tipy. Proces určovania uhla tak, aby reflektor smeroval ku mačke. Prejdite polohu reflektora, polohu mačky, uhol prúdu, maximálnu rýchlosť otáčania ako argumenty. Vrátená hodnota je konečná poloha otáčania. Nie je to veľkosť rotácie zo súčasnej polohy.

// この図を参照してください。
// 
//      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);

Ako je uvedené v komentároch, trigonometrické (inverzné trigonometrické funkcie) sa používa na výpočet uhlov z polôh. Ak vysvetlíte obsah matematiky, bude to tip, takže by ste mali vedieť, že by ste tu mali používať arktangent. Použitá metóda je Math.Atan2 . Math.Atan Všimnite si, že nie je.

Spätnú hodnotu nájdete na nasledujúcom obrázku. Vráti hodnotu -π na +π so smerom +x ako 0. Všimnite si, že smer +y vráti kladný výsledok, ale v okne koordinuje spodnú časť je smer +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);

Akonáhle máte uhol na nasmerovanie cieľa, zvyšok je určený uhol od aktuálnej polohy do požadovaného uhla. Tu máme maximálnu rýchlosť, ktorú je možné otočiť v jednom ráme, MathHelper.Clamp(difference, -turnSpeed, turnSpeed) nepresahuje maximálnu hodnotu.

Tiež, ak sa vypočíta jednoducho podľa plus alebo mínus, otáča sa dozadu za rozsah +π a -π, takže ho upravím metódou WrapAngle. Táto metóda je popísaná v ďalšej časti.

Nakoniec, keď sa určí uhol, do ktorého sa otáča, vráťte sa.

Metóda 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;
}

Ak uhol prekročí rozsah -π do +π, môže sa otáčať v opačnom smere k smeru, ktorý by sa mal otáčať, Ak je tento rozsah prekročený, pridajte alebo odčítajte 2π, aby ste ho udržali vo vyššie uvedenom rozsahu.

Metóda kreslenia

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

Akonáhle ste vypočítali polohu a rotáciu, všetko, čo musíte urobiť, je nakresliť sprite pozdĺž tohto čísla. S cieľom vyjadriť mačku, ako keby bolo svetlo zasiahnuté, doplnková syntéza sa vykonáva pri kreslení reflektora.

Súhrn

Myslím si, že je veľmi dôležité vedieť o tejto technike, pretože v hre je relatívne veľa situácií, v ktorých sa rozhodnete, akým spôsobom je váš súper. Táto metóda sa bežne používa v 2D hrách a môže byť vypočítaná pomocou kvarternions v 3D hrách. Existuje však veľa vecí, ktoré používajú 2D výpočty v 3D, takže je to bezpečné vedieť.