見出し画像

Overwatch 2用Python風言語OverPyでミニゲームを作ってみる

この記事はjig.jp Advent Calendar 2023の12月5日(火)の記事です。


はじめに

Overwatch 2というのはブリザード・エンターテインメントが開発を行っているチーム対戦型の無料アクション・シューターゲームです。今回はゲーム内にあるワークショップ機能を使ってミニゲームを作っていこうと思います。作成したコードはGitHubでこちらのリポジトリに置いておきます。

ワークショップとは

ゲーム内のエディタでルールを記述していき、自分の好きなようにカスタムゲームのゲームモードを作成できる機能です。

ゲーム内エディタ

今回はゲーム内のエディタを使わずに、Pythonライクに書ける独自言語でVS Codeのプラグインを入れるだけで開発が始められるOverPyというものがあったので、そちらを使っていきたいと思います。
詳しいコードの書き方はOverPyのwikiを参照して下さい。

簡単なミニゲームを作る

今回は、「敵を倒し続けないとHPが減っていき、HPが無くなるまでに倒せた敵の数を競う」的なミニゲームを作っていこうと思います。

ゲーム内設定

まず、ゲーム内でカスタムゲームを作成し、設定画面を開きマップやゲームモードなどを選択します。

カスタムゲーム設定画面

具体的には、

  • マップ

  • ゲームモード

  • チームの人数上限

  • 使えるキャラを制限

  • 使えるアビリティを制限

  • キャラのHPとダメージを調整

などなどを設定しました。OverPyにはコンパイル・デコンパイル機能が備わっているので、ゲーム内で編集した設定をデコンパイルしてOverPyコードにすることが出来ます。
自分の環境ではゲーム内言語が英語でないとデコンパイル出来なかったので要注意です。
デコンパイルされたコードはクリップボードに保存されるのでmain.opyを作成し、そちらにペーストして下さい。以下はデコンパイルされたコードです。

settings {
    "lobby": {
        "team1Slots": 1,
        "team2Slots": 11
    },
    "gamemodes": {
        "skirmish": {
            "enabledMaps": [
                "workshopChamber"
            ]
        },
        "general": {
            "enableHeroSwitching": false,
            "gamemodeStartTrigger": "immediately",
            "heroLimit": "off",
            "enableKillCam": false,
            "enableRandomHeroes": true,
            "respawnTime%": 0,
            "tankPassiveHealthBonus": "alwaysEnabled"
        }
    },
    "heroes": {
        "team1": {
            "mccree": {
                "enableAbility1": false,
                "enableAbility2": false,
                "enableInfiniteAmmo": true,
                "enableSecondaryFire": false,
                "enableUlt": false
            }
        },
        "team2": {
            "mccree": {
                "enableAbility1": false,
                "health%": 10,
                "enableAbility2": false,
                "enablePrimaryFire": false,
                "enableHeadshotsOnly": true,
                "enableSecondaryFire": false,
                "enableUlt": false
            }
        },
        "allTeams": {
            "enabledHeroes": [
                "mccree"
            ]
        }
    }
}

ルール作成

自分のHPが減り続ける機能を追加します。

rule "生きている間はHPが減り続ける":
    while true:
        damage(getLivingPlayers(Team.1), null, 1)
        wait(0.1)

左下のHPバーがジリジリと減っていっていることが分かります。

次にランダムな位置に敵botを追加する機能、botを倒した時にbotがランダムな位置に再出現し自分のHPが回復する機能を追加します。

rule "マッチ開始時にBOT追加":
    createDummy(Hero.MCCREE, Team.2, 1, vect(random.randint(-15, 15), 0, random.randint(-15, 15)), vect(0, 0, 0))
    createDummy(Hero.MCCREE, Team.2, 2, vect(random.randint(-15, 15), 0, random.randint(-15, 15)), vect(0, 0, 0))
    createDummy(Hero.MCCREE, Team.2, 3, vect(random.randint(-15, 15), 0, random.randint(-15, 15)), vect(0, 0, 0))
    createDummy(Hero.MCCREE, Team.2, 4, vect(random.randint(-15, 15), 0, random.randint(-15, 15)), vect(0, 0, 0))
    createDummy(Hero.MCCREE, Team.2, 5, vect(random.randint(-15, 15), 0, random.randint(-15, 15)), vect(0, 0, 0))


rule "botが死んだときの処理":
    @Event playerDied
    @Condition eventPlayer.isDummy() == true
    
    eventPlayer.teleport(vect(random.randint(-15, 15), 0, random.randint(-15, 15)))
    eventPlayer.resurrect()
    eventPlayer.setHealth(22.5)
    heal(getLivingPlayers(Team.1), null, 10)

スコア記録機能も追加しました。

#Player variables

playervar score 0
playervar maxScore 1

rule "キルをとった時の処理":
    @Event playerDealtFinalBlow
    @Condition eventPlayer.isDummy() == false
    
    eventPlayer.score += 1
    if eventPlayer.score > eventPlayer.maxScore:
        eventPlayer.maxScore = eventPlayer.score


rule "プレイヤーが死んだときの処理":
    @Event playerDied
    @Condition eventPlayer.isDummy() == false
    
    eventPlayer.score = 0


rule "HUD":
    @Event eachPlayer
    
    hudText(eventPlayer, "", "スコア:{0}".format(eventPlayer.maxScore), null, HudPosition.RIGHT, 0, Color.WHITE, Color.WHITE, Color.WHITE, HudReeval.VISIBILITY_AND_STRING, SpecVisibility.DEFAULT)

敵botが倒された時にHPが回復し、表示が小さいですが右上のスコアが増えていることが分かります。

ミニゲームっぽくなってきました。
ですがこのままではHPの減りが遅いため簡単すぎます、少し難しくしてみましょう。

まずsettingsのteam2の部分を書き換えてヘッドショットでしか倒せないようにします。

        "team2": {
            "mccree": {
                "enableAbility1": false,
                "health%": 10,
                "enableAbility2": false,
                "enablePrimaryFire": false,
                "enableHeadshotsOnly": true,
                "enableSecondaryFire": false,
                "enableUlt": false
            }
        },

次に受けるダメージ量を8倍にして回復量を5倍にしてみました。

rule "生きている間はHPが減り続ける":
    while true:
        damage(getLivingPlayers(Team.1), null, 8)
        wait(0.1)
rule "botが死んだときの処理":
    @Event playerDied
    @Condition eventPlayer.isDummy() == true
    
    eventPlayer.teleport(vect(random.randint(-15, 15), 0, random.randint(-15, 15)))
    eventPlayer.resurrect()
    eventPlayer.setHealth(22.5)
    heal(getLivingPlayers(Team.1), null, 50)

こちら完成形です。

HPの減りが早くなり、回復量が上がったことでかなりシビアなゲーム性になったと思います。

作成したゲームはコードが発行でき、簡単に配布できます。

コード入力画面

今回作成したゲームは「45S7W」で遊べるので良ければ遊んでみてください。
自分のテストプレイでの最高スコアは35でした。

まとめ

コード発行機能のおかげで自作ゲームの配布が簡単、本体のゲーム自体も無料なので遊びやすい環境が整っていると思います。

実際に記述したコードは丁度50行でかなり短いですが、ゲーム内の設定やリソースを使う事が出来るため短いコードでそれなりに遊べるミニゲームを作ることが出来ました。

キャラクター・マップ・設定・関数などOverwatch 2・OverPy固有のものが多いのでちゃんと調べる必要があったり、独自言語なので補完が弱かったりもするのですが、デコンパイル機能が備わっているので既存のワークショップから機能と記法を参考にして実装していくことが出来たり、OverPyの他にも独自のスクリプトや、TypeScriptで書けるライブラリもあったりするのでそちらを試してみるのも面白いと思います。

この記事が気に入ったらサポートをしてみませんか?