1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マイクラでゲームを作ろう③実際にゲームを作ろう

1
Posted at

初めに

このアカウントでは、主に マインクラフト統合版(BE)のアドオン開発について取り上げていきます。
私自身まだアドオン開発は初心者なので、初心者の成長記録(メモ) として読んでいただけると幸いです。
この記事では、実際に簡易的なゲームを作成してみます。
使用ソフト:VScode
過去の記事
1回目(マイクラでゲームを作ろう①セットアップ編)
2回目(マイクラでゲームを作ろう②基本理解編)

手順1.ゲームの設計

まずゲーム開発において、どんなゲームを作るか、それを作るためにどんなものが必要かなど、あらかじめ決めておくのが大切です。勿論、大雑把に決めてからとりあえず開発してみて後から細部を詰めるという方法もありますが、無計画すぎると開発中に色々矛盾が生じることがあります。今回は、簡易的なゲームを開発するので、大雑把に決めるだけ決めてとりあえず開発を始めたいと思います。
そろそろ本題に入りますが、とりあえず今回は、練習になるマルチプレイゲーム(2人)を作りたいと思ってます。筆者は、スマホやPC等で2人プレイの環境がありますが、ない方はこの記事の内容を自分なりに1人用のゲームに変換しながら読むことをおススメします。最初は、何となく王道の鬼ごっこが楽かなと思ったのでそれを作りましょう。ルールは以下の通りです。
・最初に、鬼をランダムで決める
・鬼が特定のアイテム(棒)を持って逃げを殴れば交代
・時間制限(30秒)が終わったところで鬼だった方の負け

手順2.実際にプログラミング

さっき決めたルールを1つずつコードにしていきましょう。

手順2-1.鬼をランダムに決める

トリガーは、チャットにしましょう。チャットはchatSendイベントで取得できます。

// import文
import { world } from "@minecraft/server";

world.afterEvents.chatSend.subscribe(ev => {
  if (ev.message == "!start") {
    // これで!startを検知できます。
  }
})

これで、チャットを検知出ますが、恐らく
マイクラでゲームを作ろう①セットアップ編を参照してこれを実行しようとすると、エラーが出ます。原因は簡単で、何故かchatSendはずっとbeta版の機能として置かれているからです。そのため、manifest.jsonをこのように書き換える必要があります。また、ワールド設定の実験的機能からbetaAPIを有効化しましょう。

{
  "format_version": 2,
  "header": {
    "name": "---名前---",
    "description": "---説明---",
    "uuid": "---uuid1---",
    "version": [0, 1, 0],
    "min_engine_version": [1, 21, 70]
  },
  "modules": [
    {
      "type": "script",
      "language": "javascript",
      "uuid": "---uuid2---",
      "entry": "scripts/main.js",
      "version": [0, 1, 0]
    }
  ],
  "capabilities": ["script_eval"],
  "dependencies": [
    {
      "module_name": "@minecraft/server",
      "version": "2.7.0-beta"
    }
  ]
}

※2.7.0-betaは記入日(2026/05/04)時点での最新バージョンです。新しいバージョンが出てる場合はそちらに合わせないといけないのでご注意ください。

beta版に移行できたということで、ランダムに鬼を決めましょう。

// import文
import { world } from "@minecraft/server";

world.afterEvents.chatSend.subscribe(ev => {
  if (ev.message == "!start") {
    // worldの全playerを配列で取得
    let players = world.getAllPlayers();
    // 乱数を生成
    let random = Math.floor(Math.random() * players.length);
    // 乱数から1人プレイヤーを参照する
    let player = players[random];
    // 選ばれたプレイヤーにメッセージを送る
    player.sendMessage("選ばれました");
  }
})

これを実行してみると、自分だけのワールドの場合は、常に自分に。他人を入れてみると、!startを打つたびにランダム1人にチャットが送信されるようになります。これでルールの1つ目最初に、鬼をランダムで決めるはできました。

手順2-2 鬼が特定のアイテム(棒)を持って逃げを殴れば交代

今回は楽にtagで管理します。

// import文
import { world, EquipmentSlot } from "@minecraft/server";

world.afterEvents.chatSend.subscribe(ev => {
  if (ev.message == "!start") {
    // worldの全playerを配列で取得
    let players = world.getAllPlayers();
    // 乱数を生成
    let random = Math.floor(Math.random() * players.length);
    // 乱数から1人プレイヤーを参照する
    let player = players[random];
    // 選ばれたプレイヤーにメッセージを送る
    player.sendMessage("選ばれました");
    player.addTag("oni");
  }
})

world.afterEvents.entityHitEntity.subscribe(ev => {
  // 攻撃したプレイヤーを取得
  const player = ev.damagingEntity;
  const victim = ev.hitEntity;
  // 攻撃したプレイヤーがoniタグを持っていたら...
  if (player.typeId == "minecraft:player" && victim.typeId == "minecraft:player" && player.hasTag("oni") ) {
    // playerのメインハンドのアイテムを取得(説明が難しいので割愛)
    const equippable = player.getComponent("minecraft:equippable");
    const item = equippable.getEquipment(EquipmentSlot.Mainhand);
    if (!item) return;
    // itemのtypeIDが棒なら...
    if (item.typeId == "minecraft:stick") {
      // tagを操作して、メッセージを送る
      player.removeTag("oni");
      victim.addTag("oni");
      victim.sendMessage("鬼になりました");
    } 
  }
})

このコードでは、鬼かどうかの状態をtagで管理し、棒を持って殴るたびにtagごと入れ替えています。これで、2つ目のルール鬼が特定のアイテム(棒)を持って逃げを殴れば交代ができました。

2-3.時間制限(30秒)を追加

大まかな手順としては、!startをされたタイミングからsystem.runTimeoutを用いて30秒遅延を入れて処理を行い、タグを用いた勝ち負けを判定します。

// import文
import { world, EquipmentSlot, system } from "@minecraft/server";

world.afterEvents.chatSend.subscribe(ev => {
  if (ev.message == "!start") {
    // worldの全playerを配列で取得
    let players = world.getAllPlayers();
    // 乱数を生成
    let random = Math.floor(Math.random() * players.length);
    // 乱数から1人プレイヤーを参照する
    let player = players[random];
    // 選ばれたプレイヤーにメッセージを送る
    player.sendMessage("選ばれました");
    player.addTag("oni");
    system.runTimeout(() => {
      // 30秒後に実行される。
      // forで全てのplayerに対してそれぞれ処理をする
      for (let p of players) {
        // oniタグを持ってたら負けのメッセージを表示
        if (p.hasTag("oni")) p.sendMessage("30秒が経過しました。あなたは負けです。");
        // oniタグを持っていなかったら勝ちのメッセージを表示
        else p.sendMessage("30秒が経過しました。あなたは勝ちです。");
      }
    }, 600); // 600tick = 30秒
  }
})

world.afterEvents.entityHitEntity.subscribe(ev => {
  // 攻撃したプレイヤーを取得
  const player = ev.damagingEntity;
  const victim = ev.hitEntity;
  // 攻撃したプレイヤーがoniタグを持っていたら...
  if (player.typeId == "minecraft:player" && victim.typeId == "minecraft:player" && player.hasTag("oni") ) {
    // playerのメインハンドのアイテムを取得(説明が難しいので割愛)
    const equippable = player.getComponent("minecraft:equippable");
    const item = equippable.getEquipment(EquipmentSlot.Mainhand);
    if (!item) return;
    // itemのtypeIDが棒なら...
    if (item.typeId == "minecraft:stick") {
      // tagを操作して、メッセージを送る
      player.removeTag("oni");
      victim.addTag("oni");
      victim.sendMessage("鬼になりました");
    } 
  }
})

これで一応設計していたゲームは完成です。1つのゲームを作成する流れが理解できたでしょうか。

最後に

実際にゲームを作成する場合は、この後にデバックや機能追加等の作業がありますが、今回は割愛させていたただきました。しかし、実際にこのゲームをやってみればわかると思いますが、リセット機能等足りない機能がたくさんあります。やる気のある方は是非このゲームを完成まで作り上げてみてください!
初心者の成長記録として、これからも記事を投稿していく予定なので、よければ引き続きお付き合いください!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?