4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PMMPでチームデスマッチプラグインをサクッと作る

Last updated at Posted at 2020-08-24

まえがき

ライブラリを使ってサーッとチームデスマッチつくります
作成するプラグインは、他のプラグインに一切干渉しないようにしています

完成品 はここに

作成するプラグインの内容

/createでゲームを作成し、/joinで参加
1キルごとにスコアが増えていき、設定した上限に達するか制限時間を超えたら、試合終了というもの
BossBarでタイマーを、Scoreboardで試合の状況を表示します

ライブラリのインストール

使用するライブラリはteam_game_system

team_game_systemの依存関係で
form_builder
slot_menu_system も導入します。

スコアボードのAPIで scoreboard_system を使用します
ボスバーのAPIで bossbar_system を使用します

コマンドプロンプトでpluginsフォルダに移動して

git clone https://github.com/MineDeepRock/team_game_system
git clone https://github.com/MineDeepRock/form_builder
git clone https://github.com/MineDeepRock/slot_menu_system
git clone https://github.com/MineDeepRock/scoreboard_system
git clone https://github.com/MineDeepRock/bossbar_system

これでOK

プロジェクトの作成

TeamDeathMatchというフォルダを作成します。

plugin.yml
name: TeamDeathMatch
main: TeamDeathMatch\Main
version: 1.0.0
api: 3.0.0

depend:
  - TeamGameSystem
  - FormBuilder
  - SlotMenuSystem

Composerでの補完

Composerで補完したい人だけ見てください

composer.json
{
  "name": "あなたの名前/TeamDeathMatch",
  "authors": [
    {
      "name": "あなたの名前"
    }
  ],
  "autoload": {
    "psr-4": {
      "": [
        "src/"
      ]
    }
  },
  "repositories": [
    {
      "type": "git",
      "name": "mine_deep_rock/form_builder",
      "url": "https://github.com/MineDeepRock/form_builder"
    },
    {
      "type": "git",
      "name": "mine_deep_rock/slot_menu_system",
      "url": "https://github.com/MineDeepRock/slot_menu_system"
    },
    {
      "type": "git",
      "name": "mine_deep_rock/scoreboard_system",
      "url": "https://github.com/MineDeepRock/scoreboard_system"
    },
    {
      "type": "git",
      "name": "mine_deep_rock/bossbar_system",
      "url": "https://github.com/MineDeepRock/bossbar_system"
    },
    {
      "type": "git",
      "name": "mine_deep_rock/team_game_system",
      "url": "https://github.com/MineDeepRock/team_game_system"
    }
  ],
  "require": {
    "pocketmine/pocketmine-mp": "3.14.2",
    "mine_deep_rock/form_builder": "dev-master",
    "mine_deep_rock/slot_menu_system": "dev-master",
    "mine_deep_rock/team_game_system": "dev-master",
    "mine_deep_rock/scoreboard_system": "dev-master",
    "mine_deep_rock/bossbar_system": "dev-master"
  }
}

コードを書く

Mainクラスの作成

src\tdm\Main.php
<?php

namespace tdm;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener
{
    public function onEnable() {
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }
}

Formからゲームを作成する

ゲームを作成するフォームを作ります

下準備としてsrc/tdm/GameTypeList.phpを作成します

src\tdm\GameTypeList.php
<?php


namespace tdm;


use team_game_system\model\GameType;

class GameTypeList
{
    static function TeamDeathMatch(): GameType {
        return new GameType("TeamDeathMatch");
    }
}

src\tdm\CreateTeamDeathMatchFormを作成します

src\tdm\CreateTeamDeathMatchForm.php
<?php


namespace tdm;


use form_builder\models\custom_form_elements\Input;
use form_builder\models\custom_form_elements\Label;
use form_builder\models\CustomForm;
use pocketmine\Player;
use pocketmine\scheduler\ClosureTask;
use pocketmine\scheduler\TaskScheduler;
use pocketmine\utils\TextFormat;
use team_game_system\model\Game;
use team_game_system\model\Score;
use team_game_system\model\Team;
use team_game_system\TeamGameSystem;

class CreateTeamDeathMatchForm extends CustomForm
{

    private $scheduler;

    private $timeLimit;
    private $maxPlayersCount;
    private $maxScore;
    private $maxPlayersDifference;

    public function __construct(TaskScheduler $scheduler) {
        $this->scheduler = $scheduler;

        $this->maxScore = new Input("勝利判定スコア", "", "20");
        $this->maxPlayersCount = new Input("人数制限", "", "");
        $this->maxPlayersDifference = new Input("人数差制限", "", "1");
        $this->timeLimit = new Input("制限時間(秒)", "", "300");

        parent::__construct("", [
            new Label("無い場合は空白でお願いします"),
            $this->maxScore,
            $this->maxPlayersCount,
            $this->maxPlayersDifference,
            $this->timeLimit,
        ]);
    }

    function onSubmit(Player $player): void {
        $maxScore = $this->maxScore->getResult();
        $maxScore = $maxScore === "" ? null : new Score(intval($maxScore));

        $maxPlayersCount = $this->maxPlayersCount->getResult();
        $maxPlayersCount = $maxPlayersCount === "" ? null : intval($maxPlayersCount);

        $maxPlayersDifference = $this->maxPlayersDifference->getResult();
        $maxPlayersDifference = $maxPlayersDifference === "" ? null : intval($maxPlayersDifference);

        $timeLimit = $this->timeLimit->getResult();
        $timeLimit = $timeLimit === "" ? null : intval($timeLimit);

        //チーム
        $teams = [
            Team::asNew("Red", TextFormat::RED),
            Team::asNew("Blue", TextFormat::BLUE),
        ];

        //マップを選択(あとからMinecraft内でマップを登録します)
        $map = TeamGameSystem::selectMap("city", $teams);
        //ゲームを作成
        $game = Game::asNew(GameTypeList::TeamDeathMatch(), $map, $teams);
        $game->setMaxScore($maxScore);
        $game->setMaxPlayersCount($maxPlayersCount);
        $game->setMaxPlayersDifference($maxPlayersDifference);
        $game->setTimeLimit($timeLimit);

        //ゲームを登録
        TeamGameSystem::registerGame($game);

        //試合がひらかれてから20秒後にスタートされるように
        $gameId = $game->getId();
        $this->scheduler->scheduleDelayedTask(new ClosureTask(function (int $tick) use ($gameId): void {
            TeamGameSystem::startGame($this->scheduler, $gameId);
        }), 20 * 5);
    }

    function onClickCloseButton(Player $player): void { }
}

Formからゲームに参加する

src/tdm/TeamDeathMatchListForm.php
<?php


namespace tdm;


use form_builder\models\simple_form_elements\SimpleFormButton;
use form_builder\models\SimpleForm;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use team_game_system\TeamGameSystem;

class TeamDeathMatchListForm extends SimpleForm
{

    public function __construct() {
        $buttons = [];

        foreach (TeamGameSystem::findGamesByType(GameTypeList::TeamDeathMatch()) as $game) {
            $gameId = $game->getId();
            $map = $game->getMap();

            $maxScore = $game->getMaxScore() === null ? "無し" : $game->getMaxScore()->getValue();

            $timeLimit = $game->getTimeLimit() === null ? "無し" : $game->getTimeLimit() . "秒";

            $participantsCount = count(TeamGameSystem::getGamePlayersData($gameId));
            $participants = $game->getMaxPlayersCount() === null ? $participantsCount : "{$participantsCount}/{$game->getMaxPlayersCount()}";

            $buttons[] = new SimpleFormButton(
                "ゲームモード:" . TextFormat::BOLD . strval($game->getType()) . TextFormat::RESET .
                ",マップ:" . TextFormat::BOLD . $map->getName() . TextFormat::RESET .
                "\n勝利判定:" . TextFormat::BOLD . $maxScore . TextFormat::RESET .
                ",時間制限:" . TextFormat::BOLD . $timeLimit . TextFormat::RESET .
                ",参加人数:" . TextFormat::BOLD . $participants . TextFormat::RESET,
                null,
                function (Player $player) use ($gameId) {
                    TeamGameSystem::joinGame($player, $gameId);
                }
            );
        }

        parent::__construct("チームデスマッチ一覧", "", $buttons);
    }

    function onClickCloseButton(Player $player): void { }
}

コマンドからフォームを呼び出す

plugin.ymlに以下を付け足します

plugin.yml
commands:
  create:
    usage: "/create"
    description: ""
  join:
    usage: "/join"
    description: ""

src/tdm/Main.phpを編集します

src/tdm/Main.php
<?php

namespace tdm;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\event\Listener;
use pocketmine\Player;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener
{
    public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
        if ($sender instanceof Player) {
            switch ($label) {
                case "create":
                    $sender->sendForm(new CreateTeamDeathMatchForm($this->getScheduler()));
                    return true;
                case "join":
                    $sender->sendForm(new TeamDeathMatchListForm());
                    return true;
            }
        }

        return false;
    }
}

スコアボードの作成

src\tdm\TeamDeathMatchScoreboard.phpを作成します

src\tdm\TeamDeathMatchScoreboard.php
<?php


namespace tdm;


use pocketmine\Player;
use scoreboard_system\models\Score;
use scoreboard_system\models\Scoreboard;
use scoreboard_system\models\ScoreboardSlot;
use scoreboard_system\models\ScoreSortType;
use team_game_system\model\Game;

class TeamDeathMatchScoreboard extends Scoreboard
{
    private static function create(Game $game): Scoreboard {
        $slot = ScoreboardSlot::sideBar();
        $scores = [
            new Score($slot, "====TeamDeathMatch====", 0, 0),
            new Score($slot, "Map:" . $game->getMap()->getName(), 1, 1),
        ];

        $index = count($scores);
        foreach ($game->getTeams() as $team) {
            $scores[] = new Score($slot, $team->getTeamColorFormat() . $team->getName() . ":" . $team->getScore()->getValue(), $index, $index);
            $index++;
        }

        return parent::__create($slot, "Server Name", $scores, ScoreSortType::smallToLarge());
    }

    static function send(Player $player, Game $game) {
        $scoreboard = self::create($game);
        parent::__send($player, $scoreboard);
    }

    static function update(Player $player, Game $game) {
        $scoreboard = self::create($game);
        parent::__update($player, $scoreboard);
    }
}

ボスバーの下準備

src\tdm\BossBarTypeList.phpを作成します

src\tdm\BossBarTypeList.php
<?php


namespace tdm;


use bossbar_system\model\BossBarType;

class BossBarTypeList
{
    static function TeamDeathMatch(): BossBarType {
        return new BossBarType("TeamDeathMatch");
    }
}

ゲーム参加時にロビーにいた人に知らせる&途中参加の処理を書く

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onJoinGame(PlayerJoinedGameEvent $event) {
        $player = $event->getPlayer();
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($event->getGameId());

        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $level = Server::getInstance()->getLevelByName("lobby");
        foreach ($level->getPlayers() as $lobbyPlayer) {
            $lobbyPlayer->sendMessage($player->getName() . "がチームデスマッチに参加しました");
        }
        
        //途中参加
        if ($game->isStarted()) {
            $playerData = TeamGameSystem::getPlayerData($player);
            //スポーン地点をセット
            TeamGameSystem::setSpawnPoint($player);

            //テレポート
            $player->teleport($player->getSpawn());

            //通知
            $player->sendTitle("チームデスマッチ スタート");
            $team = TeamGameSystem::getTeam($gameId, $playerData->getTeamId());
            $player->sendMessage("あなたは" . $team->getTeamColorFormat() . $team->getName() . TextFormat::RESET . "です");

            //Scoreboardのセット
            TeamDeathMatchScoreBoard::send($player, $game);
            //ボスバーをセット
            $bossBar = new BossBar($player, BossBarTypeList::TeamDeathMatch(), "TeamDeathMatch", 0);
            $bossBar->send();

            //アイテムをセット
            $player->getInventory()->setContents([
                ItemFactory::get(ItemIds::WOODEN_SWORD, 0, 1),
                ItemFactory::get(ItemIds::APPLE, 0, 10),
            ]);
        }
    }

試合開始時の処理を書く

src/tdm/Main.phpを編集します

src/tdm/Main.php
    public function onStartedGame(StartedGameEvent $event) {
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($gameId);
        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $playersData = TeamGameSystem::getGamePlayersData($gameId);

        foreach ($playersData as $playerData) {
            $player = $this->getServer()->getPlayer($playerData->getName());

            //スポーン地点をセット
            TeamGameSystem::setSpawnPoint($player);

            //テレポート
            $player->teleport($player->getSpawn());

            //通知
            $player->sendTitle("チームデスマッチ スタート");
            $team = TeamGameSystem::getTeam($gameId, $playerData->getTeamId());
            $player->sendMessage("あなたは" . $team->getTeamColorFormat() . $team->getName() . TextFormat::RESET . "です");

            //Scoreboardのセット
            TeamDeathMatchScoreBoard::send($player, $game);
            //ボスバーをセット
            $bossBar = new BossBar($player, BossBarTypeList::TeamDeathMatch(), "TeamDeathMatch", 0);
            $bossBar->send();

            //アイテムをセット
            $player->getInventory()->setContents([
                ItemFactory::get(ItemIds::WOODEN_SWORD, 0, 1),
                ItemFactory::get(ItemIds::APPLE, 0, 10),
            ]);
        }
    }

相手を倒したときにスコアが入るように

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onPlayerKilledPlayer(PlayerKilledPlayerEvent $event): void {
        $attacker = $event->getAttacker();
        $attackerData = TeamGameSystem::getPlayerData($attacker);

        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        $game = TeamGameSystem::getGame($attackerData->getGameId());
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        TeamGameSystem::addScore($attackerData->getGameId(), $attackerData->getTeamId(), new Score(1));
    }

スコア追加時にスコアボードを更新するように

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onAddedScore(AddedScoreEvent $event): void {
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($gameId);

        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $playersData = TeamGameSystem::getGamePlayersData($gameId);

        foreach ($playersData as $playerData) {
            $player = $this->getServer()->getPlayer($playerData->getName());
            TeamDeathMatchScoreBoard::update($player, $game);
        }
    }

リスポーン時にアイテムをセットする

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onRespawn(PlayerRespawnEvent $event) {
        $player = $event->getPlayer();
        $playerData = TeamGameSystem::getPlayerData($player);

        if ($playerData->getGameId() === null) return;
        
        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        $game = TeamGameSystem::getGame($playerData->getGameId());
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;
        
        $player->getInventory()->setContents([
            ItemFactory::get(ItemIds::WOODEN_SWORD, 0, 1),
            ItemFactory::get(ItemIds::APPLE, 0, 10),
        ]);
    }

死亡時のアイテムドロップを消す

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onPlayerDeath(PlayerDeathEvent $event) {
        $player = $event->getPlayer();
        $playerData = TeamGameSystem::getPlayerData($player);

        if ($playerData->getGameId() === null) return;

        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        $game = TeamGameSystem::getGame($playerData->getGameId());
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;
        
        $event->setDrops([]);
    }

試合時間経過時にボスバーを更新する

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onUpdatedGameTimer(UpdatedGameTimerEvent $event): void {
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($gameId);
        //チームデスマッチ以外のゲームに関するものだったら処理を行わない
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $playersData = TeamGameSystem::getGamePlayersData($gameId);
        $timeLimit = $event->getTimeLimit();
        $elapsedTime = $event->getElapsedTime();

        foreach ($playersData as $playerData) {
            $player = Server::getInstance()->getPlayer($playerData->getName());
            $bossBar = BossBar::findByType($player, BossBarTypeList::TeamDeathMatch());

            //制限時間がなかったら
            if ($timeLimit === null) {
                $bossBar->updateTitle("経過時間:" . $elapsedTime);
                continue;
            }

            $bossBar->updatePercentage($elapsedTime / $timeLimit);
            $bossBar->updateTitle($elapsedTime . "/" . $timeLimit);
        }
    }

試合終了後に参加者をロビーに送る

src\tdm\Main.phpを編集します

src\tdm\Main.php
    public function onFinishedGame(FinishedGameEvent $event): void {
        $game = $event->getGame();
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $wonTeam = $event->getWonTeam();
        if ($wonTeam === null) {
            $message = "引き分け";
        } else {
            $message = $wonTeam->getTeamColorFormat() . $wonTeam->getName() . TextFormat::RESET . "の勝利!";
        }


        $playersData = $event->getPlayersData();

        //lobbyに送り返す
        $server = Server::getInstance();
        $level = $server->getLevelByName("lobby");
        foreach ($playersData as $playerData) {
            $player = $server->getPlayer($playerData->getName());
            //スコアボードを消す
            TeamDeathMatchScoreboard::delete($player);
            //ボスバーを消す
            $bossBar = BossBar::findByType($player, BossBarTypeList::TeamDeathMatch());
            $bossBar->remove();

            $player->getInventory()->setContents([]);

            //テレポート
            $player->teleport($level->getSpawnLocation());

            //メッセージ送信
            $player->sendMessage($message);
        }
    }

以上でプラグインは完成です
次はマップの設定を行っていきます

Mapの設定

1,まず登録したいマップにテレポートします
2,/mapコマンドを打ちます
3,Createを選択
4,マップ名を入力し送信
5,スポーン地点グループを2つ追加(0と1ができる)
6,0を選択しいくつかスポーン地点を登録 1も同様に行う
7,終わり

src\tdm\CreateTeamDeathMatchForm.phpの54行目のmapnameを登録したマップ名に変更

src\tdm\CreateTeamDeathMatchForm.php
$map = TeamGameSystem::selectMap("city", $teams);

以上
お疲れさまでした
ばいばい

4
2
2

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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?