React Nativeでシンプルなゲームエンジンを作る

React Nativeでシンプルなゲームエンジンを作る

導入

今日はReact Nativeを使ってゲームを作る方法を学びます。 React Native を使用しているため、ゲームはクロスプラットフォームとなり、Android、iOS、Web で同じゲームをプレイできます。ただし、今日はモバイル デバイスのみに焦点を当てます。それでは始めましょう。

始める

ゲームを作成するには、プレイ中にゲームを更新するループが必要です。このループはゲームをスムーズに実行するように最適化されており、そのために React Native ゲーム エンジンを使用します。

まず、次のコマンドを使用して新しい React Native アプリを作成しましょう。

npx react-native init ReactNativeGame

プロジェクトが作成されたら、ゲーム エンジンを追加できるように依存関係を追加する必要があります。

npm i -S リアクトネイティブゲームエンジン

このコマンドは、React Native ゲーム エンジンをプロジェクトに追加します。

それで、どんなゲームを作るのでしょうか?簡単にするために、食べ物の残りを食べて体長が伸びるヘビのゲームを作ってみましょう。

React Nativeゲームエンジンの簡単な紹介

React Native Game Engine は軽量のゲームエンジンです。オブジェクトの配列をエンティティとして追加し、それらを操作できるようにするコンポーネントが含まれています。ゲーム ロジックを記述するには、System Props の配列を使用します。これにより、エンティティ (ゲーム オブジェクト) を操作したり、タッチを検出したり、シンプルで機能的なゲームを作成するのに役立つその他の多くの優れた詳細を実行できます。

React Nativeでスネークゲームを作ってみよう

ゲームを作成するには、ゲーム オブジェクトを追加するキャンバスまたはコンテナーが必要です。キャンバスを作成するには、次のようにスタイル付きのビュー コンポーネントを追加するだけです。

// アプリ.js     
<表示スタイル={styles.canvas}>
</表示>

このようにスタイルを追加できます。

const スタイル = StyleSheet.create({
  キャンバス:
    フレックス: 1,
    背景色: "#000000",
    alignItems: "center",
    justifyContent: "中央",
  }
});

キャンバスでは、GameEngine コンポーネントと React Native Game Engine のいくつかのスタイルを使用します。

「react-native-game-engine」から GameEngine をインポートします。
React をインポートし、{useRef} を "react" から取得します。
「./Constants」から定数をインポートします。


デフォルト関数App()をエクスポートする{
  const BoardSize = Constants.GRID_SIZE * Constants.CELL_SIZE;
  const エンジン = useRef(null);
  戻る (
    <表示スタイル={styles.canvas}>
      <ゲームエンジン
              ref={エンジン}
              スタイル={{
                幅: ボードサイズ、
                高さ: ボードサイズ、
                フレックス: null、
                背景色: "白",
              }}
            />
    </表示>
);

また、後で使用するためにゲーム エンジンに参照を追加するために、useRef() React フックも使用します。

また、定数値を保存するために、プロジェクトのルートに Constants.js ファイルも作成しました。

// 定数.js
「react-native」から{Dimensions}をインポートします。
エクスポートデフォルト{
  MAX_WIDTH: Dimensions.get("screen").width、
  MAX_HEIGHT: Dimensions.get("screen").height、
  グリッドサイズ: 15,
  セルサイズ: 20
};

ヘビが移動する 15 x 15 のグリッドを作成していることに気付くでしょう。

この時点で、ゲーム エンジンはヘビとその餌を表示するように設定されています。 GameEngine にエンティティと小道具を追加する必要がありますが、その前に、デバイス上でレンダリングするヘビと食べ物のコンポーネントを作成する必要があります。

ゲームエンティティの作成

まずはヘビを作りましょう。ヘビは頭と胴体(または尾)の 2 つの部分に分かれています。ここでヘビの頭を作り、このチュートリアルの後半でヘビの尻尾を追加します。

ヘビの頭を作るには、components フォルダに Head コンポーネントを作成します。

ご覧のとおり、 Head 、 Food 、 Tail の 3 つのコンポーネントがあります。このチュートリアルでは、これらの各ファイルの内容を 1 つずつ見ていきます。

Head コンポーネントでは、いくつかのスタイルを持つビューを作成します。

「react」からReactをインポートします。
「react-native」から View をインポートします。
デフォルト関数Head({位置,サイズ})をエクスポートします。
  戻る (
    <表示
      スタイル={{
        幅: サイズ、
        高さ: サイズ、
        背景色: "赤",
        位置: "絶対"、
        左: 位置[0] * サイズ、
        上: 位置[1] * サイズ、
      }}
    </表示>
  );
}

頭のサイズと位置を設定するためにいくつかのプロパティを渡します。

ヘッドを簡単に移動するために、position: "absolute" プロパティを使用します。

これは正方形をレンダリングします。これ以上複雑なものは使用しません。正方形または長方形でヘビの体を表し、円形で食べ物を表します。

それでは、GameEngine にヘビの頭を追加しましょう。

エンティティを追加するには、GameEngine のエンティティ プロパティにオブジェクトを渡す必要があります。

//アプリ.js
「./components/Head」からHeadをインポートします。


 <ゲームエンジン
        ref={エンジン}
        スタイル={{
          幅: ボードサイズ、
          高さ: ボードサイズ、
          フレックス: null、
          背景色: "白",
        }}
        エンティティ={{
          頭: {
            位置: [0, 0],
            サイズ: Constants.CELL_SIZE、
            更新頻度: 10,
            次の移動: 10,
            xスピード: 0,
            y速度: 0,
            レンダラー: <Head />,
          }
        }} 
/>

キーがヘッドであるオブジェクトを、entities プロパティに渡しました。これらは定義されるプロパティです。

  • position 、ヘビの頭を配置するために使用される座標のセットです。
  • size 、ヘビの頭のサイズを設定する値です。
  • xspeedyspeed 、ヘビの動きと方向を決定する値で、1、0、または -1 になります。 xspeed が 1 または -1 に設定されている場合、yspeed は 0 にする必要があることに注意してください。その逆も同様です。
  • 最後に、 rendererコンポーネントのレンダリングを担当します。
  • updateFrequencynextMoveについては後で説明します。

Head コンポーネントを追加したら、他のコンポーネントを追加しましょう。

//commponets/Food/index.js
「react」からReactをインポートします。
「react-native」から View をインポートします。
エクスポートデフォルト関数 Food({ 位置, サイズ }) {
  戻る (
    <表示
      スタイル={{
        幅: サイズ、
        高さ: サイズ、
        背景色: "緑",
        位置: "絶対"、
        左: 位置[0] * サイズ、
        上: 位置[1] * サイズ、
        境界半径: 50
      }}
    </表示>
  );
}

Food コンポーネントは Head コンポーネントに似ていますが、背景色と境界線の半径を変更して円にしています。

次に、Tail コンポーネントを作成します。これは難しいかもしれません。

// コンポーネント/テール/index.js

「react」からReactをインポートします。
「react-native」から View をインポートします。
「../../Constants」から定数をインポートします。
デフォルト関数Tail({ 要素、位置、サイズ })をエクスポートします。
  const tailList = elements.map((el, idx) => (
    <表示
      キー={idx}
      スタイル={{
        幅: サイズ、
        高さ: サイズ、
        位置: "絶対"、
        左: el[0] * サイズ、
        上: el[1] * サイズ、
        背景色: "赤",
      }}
    />
  ));
  戻る (
    <表示
      スタイル={{
        幅: Constants.GRID_SIZE * サイズ、
        高さ: Constants.GRID_SIZE * サイズ、
      }}
    >
      {末尾リスト}
    </表示>
  );
}

ヘビが餌を食べると、ヘビの体に要素が追加され、ヘビが成長します。これらの要素は Tail コンポーネントに渡され、成長する必要があることを示します。

すべての要素をループしてヘビの体全体を作成し、それをアタッチしてレンダリングします。

必要なコンポーネントをすべて作成したら、これら 2 つのコンポーネントを GameEngine として作成します。

// アプリ.js

「./components/Food」からFoodをインポートします。
Tailを「./components/Tail」からインポートします。


// アプリ.js
定数ランダム位置 = (最小値, 最大値) => {
    Math.floor(Math.random() * (max - min + 1) + min) を返します。
  };


// アプリ.js

<ゲームエンジン
        ref={エンジン}
        スタイル={{
          幅: ボードサイズ、
          高さ: ボードサイズ、
          フレックス: null、
          背景色: "白",
        }}
        エンティティ={{
          頭: {
            位置: [0, 0],
            サイズ: Constants.CELL_SIZE、
            更新頻度: 10,
            次の移動: 10,
            xスピード: 0,
            y速度: 0,
            レンダラー: <Head />,
          },
          食べ物:
            位置: [
              ランダム位置(0, Constants.GRID_SIZE - 1),
              ランダム位置(0, Constants.GRID_SIZE - 1),
            ]、
            サイズ: Constants.CELL_SIZE、
            レンダラー: <Food />,
          },
          しっぽ: {
            サイズ: Constants.CELL_SIZE、
            要素: [],
            レンダラー: <Tail />,
          },
        }}

      />

食べ物の位置のランダム性を保証するために、最小および最大のパラメータを持つ randomPositions 関数を作成しました。

tail では、初期状態で空の配列を追加したので、ヘビが餌を食べると、各尾の長さが elements: スペースに格納されます。

この時点で、ゲーム コンポーネントの作成は正常に完了しました。ここで、ゲーム ループにゲーム ロジックを追加します。

ゲームロジック

ゲーム ループを作成するために、GameEngine コンポーネントには、関数の配列を受け入れる systems というプロパティがあります。

すべてを構造化しておくために、systems というフォルダーを作成し、GameLoop.js というファイルを挿入します。

このファイルでは、特定のパラメータを受け取る関数をエクスポートしています。

// ゲームループ.js

エクスポートデフォルト関数(エンティティ、{イベント、ディスパッチ}){
  ...

  エンティティを返します。
}

最初の引数は、GameEngine コンポーネントに渡したすべてのエンティティを含む、entities です。これにより、それらを操作できます。もう 1 つの引数は、イベントとディスパッチというプロパティを持つオブジェクトです。

蛇の頭を動かす

ヘビの頭を正しい方向に動かすコードを書いてみましょう。

GameLoop.js 関数では、この関数がフレームごとに呼び出されるため、頭の位置を更新します。

// ゲームループ.js
エクスポートデフォルト関数(エンティティ、{イベント、ディスパッチ}){
  エンティティのヘッドを定数で表します。
  head.position[0] += head.xspeed;
  head.position[1] += head.yspeed;
}

エンティティ パラメータを使用して頭にアクセスし、各フレームでヘビの頭の位置を更新する必要があります。

今ゲームをプレイすると、xspeed と yspeed を 0 に設定しているため何も起こりません。 xspeed または yspeed を 1 に設定すると、ヘビの頭が非常に速く動きます。

ヘビの速度を落とすには、nextMove と updateFrequency の値を次のように操作します。

エンティティのヘッドを定数で表します。

head.nextMove -= 1;
head.nextMove === 0 の場合 {
  head.nextMove = head.updateFrequency;

  head.position[0] += head.xspeed;
  head.position[1] += head.yspeed;
}

各フレームごとに 1 を減算して nextMove の値を 0 に更新します。値が 0 の場合、if 条件は true に設定され、nextMove 値は初期値に更新され、ヘビの頭が移動します。

今では、ヘビは以前よりもゆっくりと動いているはずです。

「ゲームオーバー!」状態

この時点では、「ゲームオーバー!」条件はまだ追加されていません。最初の「ゲームオーバー!」条件は、ヘビが壁にぶつかるとゲームの実行が停止し、ゲームが終了したことを示すメッセージがユーザーに表示されることです。

この条件を追加するには、このコードを使用します。

head.nextMove === 0 の場合 {
  head.nextMove = head.updateFrequency;
  もし (
        ヘッド位置[0] + ヘッドx速度 < 0 ||
        head.position[0] + head.xspeed >= Constants.GRID_SIZE ||
        ヘッド位置[1] + ヘッドy速度 < 0 ||
        head.position[1] + head.yspeed >= Constants.GRID_SIZE
      ){
        ディスパッチ("ゲームオーバー");
      } それ以外 {
        head.position[0] += head.xspeed;
        head.position[1] += head.yspeed;
    }

2 番目の if 条件は、ヘビの頭が壁に触れるかどうかをチェックします。この条件が true の場合、ディスパッチ関数を使用して「ゲームオーバー」イベントを送信します。

else を通じて、ヘビの頭の位置を更新しています。

次に、「ゲームオーバー!」機能を追加しましょう。

「ゲームオーバー」イベントがディスパッチされるたびに、ゲームが停止し、「ゲームオーバーです!」というアラートが表示されます。これを実装してみましょう。

「ゲームオーバー」イベントをリッスンするには、onEvent プロパティを GameEngine コンポーネントに渡す必要があります。ゲームを停止するには、running プロパティを追加して useState に渡す必要があります。

GameEngine は次のようになります。

// アプリ.js
「react」から React、{useRef、useState } をインポートします。
「./systems/GameLoop」からGameLoopをインポートします。

....
....

const [isGameRunning、setIsGameRunning] = useState(true);

....
....

 <ゲームエンジン
        ref={エンジン}
        スタイル={{
          幅: ボードサイズ、
          高さ: ボードサイズ、
          フレックス: null、
          背景色: "白",
        }}
        エンティティ={{
          頭: {
            位置: [0, 0],
            サイズ: Constants.CELL_SIZE、
            更新頻度: 10,
            次の移動: 10,
            xスピード: 0,
            y速度: 0,
            レンダラー: <Head />,
          },
          食べ物:
            位置: [
              ランダム位置(0, Constants.GRID_SIZE - 1),
              ランダム位置(0, Constants.GRID_SIZE - 1),
            ]、
            サイズ: Constants.CELL_SIZE、
            レンダラー: <Food />,
          },
          しっぽ: {
            サイズ: Constants.CELL_SIZE、
            要素: [],
            レンダラー: <Tail />,
          },
        }}
        システム={[ゲームループ]}
        実行中={isGameRunning}
        onEvent={(e) => {
          スイッチ(e){
            「ゲームオーバー」の場合:
              alert("ゲームオーバー!");
              ゲームが実行されているかどうかを false に設定します。
              戻る;
          }
        }}
      />

GameEngine では、 systems プロパティを追加し、running プロパティと isGameRunning 状態とともに配列を GameLoop 関数に渡しました。最後に、イベント引数を持つ関数を受け入れる onEvent プロパティを追加して、イベントをリッスンできるようにしました。

この場合、switch ステートメントで「ゲームオーバー」イベントをリッスンし、そのイベントを受信すると「ゲームオーバー!」アラートを表示し、isGameRunning 状態を false に設定してゲームを停止します。

食べ物

「ゲームオーバー!」ロジックは書きました。次は、ヘビに餌を食べさせるためのロジックを書きましょう。

ヘビが餌を食べると、餌の位置がランダムに変化します。

GameLoop.js を開き、次のコードを記述します。

// ゲームループ.js

定数ランダム位置 = (最小値, 最大値) => {
  Math.floor(Math.random() * (max - min + 1) + min) を返します。
};

エクスポートデフォルト関数(エンティティ、{イベント、ディスパッチ}){
  エンティティのヘッドを定数で表します。
  エンティティをエンティティリストに追加します。

  ....
  ....
  ....
  もし (
        ヘッド位置[0] + ヘッドx速度 < 0 ||
        head.position[0] + head.xspeed >= Constants.GRID_SIZE ||
        ヘッド位置[1] + ヘッドy速度 < 0 ||
        head.position[1] + head.yspeed >= Constants.GRID_SIZE
      ){
        ディスパッチ("ゲームオーバー");
      } それ以外 {

     head.position[0] += head.xspeed;
     head.position[1] += head.yspeed;

     もし (
          頭の位置[0] == 食べ物の位置[0] &&
          頭の位置[1] == 食べ物の位置[1]
        ){

          食べ物の位置 = [
            ランダム位置(0, Constants.GRID_SIZE - 1),
            ランダム位置(0, Constants.GRID_SIZE - 1),
          ];
        }
  }

ヘビの頭と餌の位置が同じかどうか (ヘビが餌を「食べた」ことを示す) を確認するための if を追加しました。次に、上記の App.js で行ったのと同じように、randomPositions 関数を使用して食べ物の位置を更新します。エンティティ パラメータを介して食品にアクセスすることに注意してください。

蛇を制御する

次に、ヘビのコントロールを追加しましょう。ボタンを使用してヘビの移動先を制御します。

これを行うには、キャンバスの下の画面にボタンを追加する必要があります。

// アプリ.js

「react」から React、{useRef、useState } をインポートします。
「react-native」から { StyleSheet、Text、View } をインポートします。
「react-native-game-engine」から GameEngine をインポートします。
「react-native-gesture-handler」から TouchableOpacity をインポートします。
「./components/Food」からFoodをインポートします。
「./components/Head」からHeadをインポートします。
Tailを「./components/Tail」からインポートします。
「./Constants」から定数をインポートします。
「./systems/GameLoop」からGameLoopをインポートします。
デフォルト関数App()をエクスポートする{
  const BoardSize = Constants.GRID_SIZE * Constants.CELL_SIZE;
  const エンジン = useRef(null);
  const [isGameRunning、setIsGameRunning] = useState(true);
  定数ランダム位置 = (最小値, 最大値) => {
    Math.floor(Math.random() * (max - min + 1) + min) を返します。
  };
  const リセットゲーム = () => {
    エンジン.current.swap({
      頭: {
        位置: [0, 0],
        サイズ: Constants.CELL_SIZE、
        更新頻度: 10,
        次の移動: 10,
        xスピード: 0,
        y速度: 0,
        レンダラー: <Head />,
      },
      食べ物:
        位置: [
          ランダム位置(0, Constants.GRID_SIZE - 1),
          ランダム位置(0, Constants.GRID_SIZE - 1),
        ]、
        サイズ: Constants.CELL_SIZE、
        更新頻度: 10,
        次の移動: 10,
        xスピード: 0,
        y速度: 0,
        レンダラー: <Food />,
      },
      しっぽ: {
        サイズ: Constants.CELL_SIZE、
        要素: [],
        レンダラー: <Tail />,
      },
    });
    ゲームの実行状態を true に設定します。
  };
  戻る (
    <表示スタイル={styles.canvas}>
      <ゲームエンジン
        ref={エンジン}
        スタイル={{
          幅: ボードサイズ、
          高さ: ボードサイズ、
          フレックス: null、
          背景色: "白",
        }}
        エンティティ={{
          頭: {
            位置: [0, 0],
            サイズ: Constants.CELL_SIZE、
            更新頻度: 10,
            次の移動: 10,
            xスピード: 0,
            y速度: 0,
            レンダラー: <Head />,
          },
          食べ物:
            位置: [
              ランダム位置(0, Constants.GRID_SIZE - 1),
              ランダム位置(0, Constants.GRID_SIZE - 1),
            ]、
            サイズ: Constants.CELL_SIZE、
            レンダラー: <Food />,
          },
          しっぽ: {
            サイズ: Constants.CELL_SIZE、
            要素: [],
            レンダラー: <Tail />,
          },
        }}
        システム={[ゲームループ]}
        実行中={isGameRunning}
        onEvent={(e) => {
          スイッチ(e){
            「ゲームオーバー」の場合:
              alert("ゲームオーバー!");
              ゲームが実行されているかどうかを false に設定します。
              戻る;
          }
        }}
      />
      <表示スタイル={styles.controlContainer}>
        <ビュースタイル={styles.controllerRow}>
          <TouchableOpacity onPress={() => engine.current.dispatch("上に移動")}>
            <表示スタイル={styles.controlBtn} />
          </タッチ可能な不透明度>
        </表示>
        <ビュースタイル={styles.controllerRow}>
          <タッチ可能な不透明度
            onPress={() => engine.current.dispatch("左に移動")}
          >
            <表示スタイル={styles.controlBtn} />
          </タッチ可能な不透明度>
          <View style={[styles.controlBtn, { backgroundColor: null }]} />
          <タッチ可能な不透明度
            onPress={() => engine.current.dispatch("move-right")}
          >
            <表示スタイル={styles.controlBtn} />
          </タッチ可能な不透明度>
        </表示>
        <ビュースタイル={styles.controllerRow}>
          <タッチ可能な不透明度
            onPress={() => engine.current.dispatch("下へ移動")}
          >
            <表示スタイル={styles.controlBtn} />
          </タッチ可能な不透明度>
        </表示>
      </表示>
      ゲームの実行中
        <TouchableOpacity onPress={resetGame}>
          <テキスト
            スタイル={{
              色: "白",
              マージン上: 15,
              フォントサイズ: 22,
              パディング: 10,
              背景色: "グレー",
              境界半径: 10
            }}
          >
            新しいゲームを始める
          </テキスト>
        </タッチ可能な不透明度>
      )}
    </表示>
  );
}
const スタイル = StyleSheet.create({
  キャンバス:
    フレックス: 1,
    背景色: "#000000",
    alignItems: "center",
    justifyContent: "中央",
  },
  コントロールコンテナ: {
    マージン上: 10,
  },
  コントローラー行: {
    flexDirection: "行",
    justifyContent: "中央",
    alignItems: "center",
  },
  コントロールボタン: {
    背景色: "黄色",
    幅: 100,
    高さ: 100,
  },
});

コントロールに加えて、前のゲームが終了したときに新しいゲームを開始するためのボタンも追加しました。このボタンはゲームが実行されていないときにのみ表示されます。ボタンがクリックされると、ゲーム エンジンの swap 関数を使用してゲームをリセットし、エンティティの元のオブジェクトを渡し、ゲームの実行状態を更新します。

さて、コントロールについて話しましょう。押すとゲーム ループで処理されるイベントをディスパッチするタッチ可能なオブジェクトを追加しました。

// ゲームループ.js
....
....
 エクスポートデフォルト関数(エンティティ、{イベント、ディスパッチ}){
    エンティティのヘッドを定数で表します。
    エンティティをエンティティリストに追加します。

  if (イベント.長さ) {
    イベント.forEach((e) => {
      スイッチ(e){
        「上へ移動」の場合:
          head.yspeed === 1 の場合、戻り値:
          ヘッドのy速度 = -1;
          ヘッドのxスピード = 0;
          戻る;
        ケース「右へ移動」:
          head.xspeed === -1 の場合、戻り値は次のようになります。
          ヘッドの速度 = 1;
          ヘッドのy速度 = 0;
          戻る;
        「下へ移動」の場合:
          head.yspeed === -1 の場合、戻り値は次のようになります。
          ヘッドのy速度 = 1;
          ヘッドのxスピード = 0;
          戻る;
        ケース「左に移動」:
          head.xspeed === 1 の場合、戻り値は次のようになります。
          ヘッドスピード = -1;
          ヘッドのy速度 = 0;
          戻る;
      }
    });
  }

....
....
});

上記のコードでは、イベントを認識してスネークの方向を更新するための switch ステートメントを追加しました。

まだ聞いてますか?すごい!あとは尻尾だけ。

テール機能

ヘビが餌を食べると、尻尾がまた生えてくることを願います。また、ヘビが自分の尻尾や体を噛んだときに、「ゲームオーバー!」イベントを発生させたいと考えています。

末尾のロジックを追加しましょう。

// ゲームループ.js

エンティティの末尾に tail を追加します。

....
....

....

    それ以外 {
      tail.elements = [[head.position[0], head.position[1]], ...tail.elements];
      tail.elements.pop();

      head.position[0] += head.xspeed;
      head.position[1] += head.yspeed;

      tail.elements.forEach((el, idx) => {
        もし (
          ヘッドの位置[0] === el[0] &&
          ヘッドの位置[1] === el[1] 
        )
          ディスパッチ("ゲームオーバー");
      });
      もし (
        頭の位置[0] == 食べ物の位置[0] &&
        頭の位置[1] == 食べ物の位置[1]
      ){
        末尾の要素 = [
          [ヘッドの位置[0]、ヘッドの位置[1]]、
          ...末尾の要素、
        ];

        食べ物の位置 = [
          ランダム位置(0, Constants.GRID_SIZE - 1),
          ランダム位置(0, Constants.GRID_SIZE - 1),
        ];
      }
    }

尾がヘビの頭に追従するようにするには、尾の要素を更新する必要があります。これを実行するには、要素配列の先頭にヘッドの位置を追加し、末尾の要素配列の最後の要素を削除します。

この後、ヘビが自分の体を噛んだ場合に「ゲームオーバー」イベントを送信するように条件を記述します。

最後に、ヘビが餌を食べるたびに、ヘビの尻尾の要素をヘビの頭の現在の位置に追加して、ヘビの尻尾の長さを増やします。

以下は GameLoop.js の完全なコードです。

// ゲームループ.js

「../Constants」から定数をインポートします。
定数ランダム位置 = (最小値, 最大値) => {
  Math.floor(Math.random() * (max - min + 1) + min) を返します。
};
  エクスポートデフォルト関数(エンティティ、{イベント、ディスパッチ}){
    エンティティのヘッドを定数で表します。
    エンティティをエンティティリストに追加します。
    エンティティの末尾に tail を追加します。
  if (イベント.長さ) {
    イベント.forEach((e) => {
      スイッチ(e){
        「上へ移動」の場合:
          head.yspeed === 1 の場合、戻り値:
          ヘッドのy速度 = -1;
          ヘッドのxスピード = 0;
          戻る;
        ケース「右へ移動」:
          head.xspeed === -1 の場合、戻り値は次のようになります。
          ヘッドの速度 = 1;
          ヘッドのy速度 = 0;
          // ToastAndroid.show("右に移動", ToastAndroid.SHORT);
          戻る;
        「下へ移動」の場合:
          head.yspeed === -1 の場合、戻り値は次のようになります。
          // ToastAndroid.show("下に移動", ToastAndroid.SHORT);
          ヘッドのy速度 = 1;
          ヘッドのxスピード = 0;
          戻る;
        ケース「左に移動」:
          head.xspeed === 1 の場合、戻り値は次のようになります。
          ヘッドスピード = -1;
          ヘッドのy速度 = 0;
          // ToastAndroid.show("左に移動", ToastAndroid.SHORT);
          戻る;
      }
    });
  }
  head.nextMove -= 1;
  head.nextMove === 0 の場合 {
    head.nextMove = head.updateFrequency;
    もし (
      ヘッド位置[0] + ヘッドx速度 < 0 ||
      head.position[0] + head.xspeed >= Constants.GRID_SIZE ||
      ヘッド位置[1] + ヘッドy速度 < 0 ||
      head.position[1] + head.yspeed >= Constants.GRID_SIZE
    ){
      ディスパッチ("ゲームオーバー");
    } それ以外 {
      tail.elements = [[head.position[0], head.position[1]], ...tail.elements];
      tail.elements.pop();
      head.position[0] += head.xspeed;
      head.position[1] += head.yspeed;
      tail.elements.forEach((el, idx) => {
        コンソールログ({el, idx});
        もし (
          ヘッドの位置[0] === el[0] &&
          ヘッドの位置[1] === el[1] 
        )
          ディスパッチ("ゲームオーバー");
      });
      もし (
        頭の位置[0] == 食べ物の位置[0] &&
        頭の位置[1] == 食べ物の位置[1]
      ){
        末尾の要素 = [
          [ヘッドの位置[0]、ヘッドの位置[1]]、
          ...末尾の要素、
        ];

        食べ物の位置 = [
          ランダム位置(0, Constants.GRID_SIZE - 1),
          ランダム位置(0, Constants.GRID_SIZE - 1),
        ];
      }
    }
  }
  エンティティを返します。
}

結論

最初の React Native ゲームが完成したので、デバイス上で実行してプレイできます。何か新しいことを学んで、それを友達と共有していただければ幸いです。

読んでいただきありがとうございます。良い一日をお過ごしください。

React Native でシンプルなゲームを構築する方法という記事が最初に LogRocket Blog に掲載されました。

React Native を使用した簡単なゲームの構築はこれで完了です。React Native ゲームの詳細については、123WORDPRESS.COM の他の記事を参照してください。

以下もご興味があるかもしれません:
  • React Nativeはモニタリングジェスチャーの上下プル効果を実現します
  • VSCodeはReact Native環境を構築します
  • 反応ネイティブソフトキーボードがポップアップして入力ボックスをブロックする問題を解決する
  • react-native WebViewの戻り処理の詳細説明(コールバック以外の方法も解決可能)
  • React-native bridge Androidネイティブ開発の詳細説明
  • React Native Flexboxレイアウトについての簡単な説明(要約)
  • React Native react-navigation ナビゲーションの使用法の詳細
  • ReactNativeにおけるFlatListの具体的な使い方
  • ReactNative FlatList の使い方と落とし穴パッケージの概要

<<:  データベースの削除から逃走までの MySQL の徹底分析_上級編 (I) - データ整合性

>>:  Dockerfile echoは、指定されたファイル内の複数行のテキストを実装する方法を指定します。

推薦する

MySQL トリガーの使用方法と利点と欠点の紹介

目次序文1. トリガーの概要2. トリガーの作成2.1 トリガー構文の作成2.2 コード例3. トリ...

Vue のレスポンシブ原則と双方向データの詳細な分析

応答性を実現するための object.defineProperty の理解observe/watch...

Centos7.3 に mysql5.7.18 をインストールするための詳細なチュートリアル

1 Linuxディストリビューションのバージョンを確認する[root@typecodes ~]# c...

MySQL 匿名ログインでデータベースを作成できない問題の解決方法

よくある質問ユーザー ''@'localhost' によるデータベー...

HTMLリンクを書くときは、HTTPリクエストを減らすためにサブフォルダに必ずスラッシュを追加してください。

サブフォルダーの末尾にスラッシュがない場合、2 つの HTTP リクエストが生成され、効率に影響しま...

カスタムスクロールバー効果を実現するJavaScript

実際のプロジェクトでは、上下のスクロール バーと左右のスクロール バーは DIV 内にないため、右の...

WeChat アプレットのシンプルなログイン ページの実装 (ソース コード付き)

目次1. 上の写真2. ユーザーが存在しない3. コードをアップロードする1. 上の写真 2. ユー...

mysql5.7 の新しい json フィールド タイプの使用例の分析

この記事では、MySQL 5.7 で追加された json フィールド タイプの使用方法を例を使って説...

両端揃えレイアウトを実現する CSS 列のサンプルコード

1. 堂々巡りいろいろ試行錯誤した結果、均等割り付けレイアウトを実現する最も簡単な方法は CSS ...

Linux の圧縮および解凍コマンドの紹介

目次一般的な圧縮形式: gz .bz2 .xz .zip一般的に使用されるアーカイブは圧縮を必要とす...

Vueプロジェクトでコンポーネントをカプセル化する簡単な手順

目次序文Toastコンポーネントをカプセル化する方法ユースケース具体的な実装要約する序文ビジネスが発...

Tomcat 実行時の JVM エンコーディングの問題を修正

質問:最近、プロジェクトを展開すると文字化けしたデータが出てきました。確認したところ、プロジェクトは...

MySQL MGR 構築時の一般的な問題と解決策

目次01 よくある故障 1 02 よくある欠陥 2 03 よくある欠陥 3 04 よくある欠陥 4 ...

JavaScript の parseInt() の魔法についての簡単な説明

原因このブログを書いた理由は、今日Leetcodeの日課問題をやっていたからです。文字列を整数(at...

Docker Swarmの概念と使用法の詳細な説明

Docker Swarm は、Docker によって開発されたコンテナ クラスター管理サービスです。...