諦めたらそこで試合終了ですよ

Splathon Advent Calendar 2024 の3日目の記事になります。


スプラトゥーンにおける最後の大逆転について

なんと未だにスプラトゥーンをやっているのでスプラトゥーンの話をします。

試合時間は残りわずか、相手はノックアウト間近なのにこちらはあまりカウントが進んでないという絶望的状況から最後の最後に奇跡の大逆転!みたいなことってありますよね。
したら脳汁ブシャー、されたら大発狂。
明確な戦力差を感じている試合でもそれなりに発生する気がしています。
あれがなんで起こるのかっていうのをまとめてみたいと思います。

  • ラストの攻撃であるということ
  • 逆転が発生しやすい編成・ステージ
  • 豊富な資源
  • 過度なラインの後退
  • 四天王方式
  • 歯茎

の6本でお送りします。

ラストの攻撃であるということ

ラストの攻撃であるということまずそれ自体が要因の一つだと考えます。
リードしている側は勝利目前、しかしその目前に迫った勝利がプレッシャーとなりプレイヤーの行動を妨げます。
この心理状態では「もしここで失敗したらどうしよう」という考えが過度に意識され、通常なら簡単な行動が困難になることがあります。
スプラトゥーンはチームゲームのため「失敗すれば責任が自分に集中する」という恐怖も存在するでしょう。
逆に負けている側は「最後のチャンスに何としてでも追いつこう」という強いモチベーションを持っています。
このギャップがラストの攻撃の成功率を高めています。

逆転が発生しやすい編成・ステージ

そもそも編成やステージが影響しているパターンは多いんでないでしょうか。
例えば長射程が多くて一度突破されてしまうと手前が処理できないとか、防衛向きのスペシャルが少ないとか。
ステージでは一定ラインを超えると防衛が不向きとか、リスキルに弱いなどがあると思います。
マヒマヒリゾートスパやユノハナ大渓谷なんかはどのルールでもワンチャンある最後までわからないステージという印象が強いです。

豊富な資源

ゲームデザインの話ですが、不利な状況というのは盤面の塗りが取られていることが多く、裏を返すとスペシャルを貯めるチャンスでもあります。
反対に防衛側の塗り資源は少なくワイプアウトなどしてしまうとスペシャルの枚数に差が生まれます。
防衛目線では敵のスペシャルが貯まる前提で動けるとよさそうです。

過度なラインの後退

生存を意識するあまりラインを下げすぎることが悪手になる場合があります。
カウントは余裕あるからカンモンは明け渡して最後で止めるか、などと考えていると不意にボムを踏んでチーン😇なんてことあるんじゃないでしょうか。
結局試行回数ゲーなので、たとえ防衛超有利な状況でも無闇にチャンスを与えすぎるのはよくないです。
やはり攻撃は最大の防御ということで刺せるところでは刺しつつ相手を詰め切って勝ちたいですね。

四天王方式

バトルもののゲームや漫画などで敵の軍団に四天王みたいな存在が出てくると思います。
最初から複数もしくは全員で戦えばいいのに彼らはなぜか1人ずつ順番に戦いそして散っていきます。
これを元にして生まれた言葉が四天王方式です。
人数差・戦力差がある状況で戦うこと自体がよくないので防衛や打開が必要な場面では脳死特攻はせずに味方との足並みを揃えましょう。
よくあるのがリードされるのを無理矢理止めようと焦って突っ込み更に不利になるパターンです。
ノックアウトされない限りは次のチャンスが来ると信じて敢えてリードを許す(ギブする)なんて考え方も大事です。
あと沼ジャンはダメ、ゼッタイ。

歯茎

正直これが一番多いかもしれない。
「白い歯を見せるな」(優位な状況でも最後まで笑うな)という言い回しが進化して歯茎まで見せている状態を指します。
いわゆる超舐めプです。
勝ちが確定してから笑ってください。
前半楽勝ムードがあればあるほど発生し、そして沼が深くなります。
特に自分が活躍している訳でもないのになんか味方使いし気持ちよくなりたいから裏取りしちゃお〜みたいなやつは死あるのみ🧔‍♂️👎🪦

まとめ

以上、大逆転が起こるメカニズムを自分なりに考えてみました。

ズタボロに負けていたとしても試合は最後までわかりません。
大抵の大逆転はこれらの事象が複合的に絡んで発生すると思います。
大逆転を実現するための勝ち筋を意識して積極的なプレイを心がけましょう。
よく防衛側で逆転負けするという方はアンチパターンとして意識してみてください。

最後に一言。
安西先生、スプラがしたいです。

チャッ♪チャッ♪チャージャー♪

Splathon Advent Calendar 2020 の3日目の記事になります。
昨日は TONY0922 さんの 英語コーチングサービスを受けて約50万溶かした話 でした。

恒例のゼルダBotWのany%RTAの最新状況ですが、2020年12月3日現在の世界記録は26分42.4秒だそうです。
去年から1分以上も縮まっていて時の流れを感じます。
意味がよくわからない人は過去記事をご参照ください。

チャージャー楽しいですよっていう記事

皆さんチャージャー使ってますか?
僕は最近チャージャーにハマっていてガチマッチでもメインで使っています。
今回はその魅力を皆さんにお伝えできればなと思い記事を執筆するに至った所存です。

ウデマエはエリアなら2400を超えるぐらいにはなってきました(先月)。
ただ計測後ダダ下がりしたので現在のXパワーについては聞かないでください。
フレンド申請も送ってこないでください。

続きを読む

カジュアルゲーマーを目指して

f:id:saihoooooooo:20191107203609j:plain

Splathon Advent Calendar 2019 の3日目の記事になります。

去年はゼルダBotWのRTAに関する記事を書きましたが今回は普通にスプラトゥーンのTIPSな記事を書きたいと思います。
ちなみに前回当時に約31分だったRTA世界記録は27分53.500秒!!と30分を大きく上回る更新となっているので興味のある方は是非御覧ください。

カジュアルについて

さて、本題ですがタイトルにあるカジュアルゲーマーは読んで字の如く「カジュアルなゲーム」をプレイする人の意味で使っています。
では「カジュアルなゲーム」とは一体何なのか。
これはスプラトゥーン有名プレイヤーのゆっきー氏がとある配信でバブルランチャーの即割でキルされて試合に敗けた際に「カジュアルなゲームになったなぁ」と(自身の持ちブキであるロングブラスターが通用しづらいことも含め)その環境を揶揄したのが発端となり、スプラ界隈でバズった言葉です。

ここからバブル即割そのものを「カジュアル」と呼ぶことも多くなり、ボディビルダーの大会のごとく「ナイスカジュアル!」と味方からの掛け声を貰うことが増えました。
厳密にはおちばシューターによるトーピード即割なのでしょうが、今回は私がここ最近気に入っているボトルガイザーフォイルによるスプラッシュボムでの即割を解説したいと思います。

続きを読む

TypeScriptでアプリのバージョンを取ってくる

例えばAngularでアプリを作っていて、package.json

{
  "name": "super-sharp-spa",
  "version": "0.0.1",
  ...
}

などと書いている場合。

resolveJsonModuleを使えば型定義もなしにjsonの内容をそのままオブジェクトとして取得できる。

www.typescriptlang.org

具体的には下記のように使う。

{
  ...
  "compilerOptions": {
    ...
    "resolveJsonModule": true,
    "esModuleInterop": true
  }
}
import packagejson from '/path/to/package.json';

console.log(packagejson.version); // 0.0.1

便利。

Ionic v3自作プラグインの基礎

Ionic Advent Calendar 2018 の17日目の記事になります。

Ionic界隈ではv4だのCapacitorだので盛り上がっていますが、最近書く機会があったので備忘録程度にv3にて自作プラグイン(Cordova)を追加する方法を書きたいと思います。

プロジェクトの作成

はじめにプロジェクトを作成します。

$ ionic start myApp tabs
$ cd myApp

Cordovaプラグインの作成

次に plugman を使ってCordovaプラグインの雛形を作ります。
入っていない場合はインストールしてください。

$ npm install -g plugman

自作プラグインの作業場所として適当に plugins_src ディレクトリを作ります。
ディレクトリに入り plugman create コマンドを使ってプラグインを作成します。

$ mkdir plugins_src
$ plugman create --name Hoge --plugin_id cordova-plugin-hoge --plugin_version 0.0.0 --path plugins_src

その後 plugman platform add コマンドにてプラットフォームを追加します。
今回はAndroidプラグインを作りますが、iOSの場合は適宜書き換えてください。

$ cd plugins_src/Hoge
$ plugman platform add --platform_name android

結果、下記のような構成が出来ます。

  • plugin.xml プラグインの設定
  • src/android/Hoge.java 実際のAndroidのコードを記述する
  • www/Hoge.js Webviewとのインターフェース
plugins_src/Hoge/
├── plugin.xml
├── src
│   └── android
│       └── Hoge.java
└── www
    └── Hoge.js

中身はこんな感じです。coolMethod、なんてクールな名前なんだ。
やってることは渡ってきた文字列をそのまま返しているだけですね。

<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova-plugin-hoge" version="0.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <name>Hoge</name>
    <js-module name="Hoge" src="www/Hoge.js">
        <clobbers target="cordova.plugins.Hoge" />
    </js-module>
    <platform name="android">
        <config-file parent="/*" target="res/xml/config.xml">
            <feature name="Hoge">
                <param name="android-package" value="cordova-plugin-hoge.Hoge" />
            </feature>
        </config-file>
        <config-file parent="/*" target="AndroidManifest.xml">
        </config-file>
        <source-file src="src/android/Hoge.java" target-dir="src/cordova-plugin-hoge/Hoge" />
    </platform>
</plugin>
var exec = require('cordova/exec');

exports.coolMethod = function (arg0, success, error) {
    exec(success, error, 'Hoge', 'coolMethod', [arg0]);
};
package cordova-plugin-hoge;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * This class echoes a string called from JavaScript.
 */
public class Hoge extends CordovaPlugin {

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("coolMethod")) {
            String message = args.getString(0);
            this.coolMethod(message, callbackContext);
            return true;
        }
        return false;
    }

    private void coolMethod(String message, CallbackContext callbackContext) {
        if (message != null && message.length() > 0) {
            callbackContext.success(message);
        } else {
            callbackContext.error("Expected one non-empty string argument.");
        }
    }
}

今回はこれをちょっと編集してメソッドの実行時に一瞬バイブするよう書き換えたいと思います。
ついでにパッケージ名を変更。

     <platform name="android">
         <config-file parent="/*" target="res/xml/config.xml">
             <feature name="Hoge">
-                <param name="android-package" value="cordova-plugin-hoge.Hoge" />
+                <param name="android-package" value="com.example.hoge.Hoge" />
             </feature>
         </config-file>
         <config-file parent="/*" target="AndroidManifest.xml">
+            <uses-permission android:name="android.permission.VIBRATE" />
         </config-file>
         <source-file src="src/android/Hoge.java" target-dir="src/cordova-plugin-hoge/Hoge" />
     </platform>
-package cordova-plugin-hoge;
+package com.example.hoge;

 import org.apache.cordova.CordovaPlugin;
 import org.apache.cordova.CallbackContext;
@@ -7,6 +7,9 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;

+import android.content.Context;
+import android.os.Vibrator;
+
 /**
  * This class echoes a string called from JavaScript.
  */
@@ -24,6 +27,7 @@ public class Hoge extends CordovaPlugin {

     private void coolMethod(String message, CallbackContext callbackContext) {
         if (message != null && message.length() > 0) {
+            ((Vibrator) cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE)).vibrate(100);
             callbackContext.success(message);
         } else {
             callbackContext.error("Expected one non-empty string argument.");

最後にプラグインのインストール時に必要となるpackage.jsonを下記のコマンドで作成します。

$ plugman createpackagejson .

CordovaプラグインのIonic Native化

これでCordovaプラグインは完成しましたがIonicで使うためにIonic Native化(Typescript化)します。
任意の場所に ionic-team/ionic-native を置きます。
今回は例として本家を直接サブモジュール化していますが実際使うならフォークしたものを使用してください。
gulp plugin:create -n [プラグイン名]で雛形を作成します。

$ cd ../..
$ git submodule add https://github.com/ionic-team/ionic-native plugins_src/ionic-native
$ cd plugins_src/ionic-native/
$ npm install
$ gulp plugin:create -n Hoge

src/@ionic-native/plugins/hoge/index.tsが出来上がるので下記の様に編集します。
import文はtslintさんが怒ってくるので。

  *
  */
 import { Injectable } from '@angular/core';
-import { Plugin, Cordova, CordovaProperty, CordovaInstance, InstanceProperty, IonicNativePlugin } from '@ionic-native/core';
+import { Cordova, CordovaInstance, CordovaProperty, InstanceProperty, IonicNativePlugin, Plugin } from '@ionic-native/core';
 import { Observable } from 'rxjs/Observable';

 /**
@@ -36,24 +36,23 @@ import { Observable } from 'rxjs/Observable';
  */
 @Plugin({
   pluginName: 'Hoge',
-  plugin: '', // npm package name, example: cordova-plugin-camera
-  pluginRef: '', // the variable reference to call the plugin, example: navigator.geolocation
+  plugin: 'cordova-plugin-hoge', // npm package name, example: cordova-plugin-camera
+  pluginRef: 'cordova.plugins.Hoge', // the variable reference to call the plugin, example: navigator.geolocation
   repo: '', // the github repository URL for the plugin
   install: '', // OPTIONAL install command, in case the plugin requires variables
   installVariables: [], // OPTIONAL the plugin requires variables
-  platforms: [] // Array of platforms supported, example: ['Android', 'iOS']
+  platforms: ['Android'] // Array of platforms supported, example: ['Android', 'iOS']
 })
 @Injectable()
 export class Hoge extends IonicNativePlugin {

   /**
    * This function does something
-   * @param arg1 {string} Some param to configure something
-   * @param arg2 {number} Another param to configure something
+   * @param message {string} Some param to configure something
    * @return {Promise<any>} Returns a promise that resolves when something happens
    */
   @Cordova()
-  functionName(arg1: string, arg2: number): Promise<any> {
+  coolMethod(message: string): Promise<any> {
     return; // We add return; here to avoid any IDE / Compiler errors
   }

ビルドします。
成果物は dist/@ionic-native/hoge に置かれます。
これで準備は整ったのでプロジェクト直下に戻ります。

$ npm run build hoge
$ cd ../..

Ionicで実装

最後に実際に使うIonic側のコードを記述します。
src/app/app.module.ts に登録した後、 src/pages/home/home.ts にメソッドを追加してボタンで呼ぶようにします。

 import { StatusBar } from '@ionic-native/status-bar';
 import { SplashScreen } from '@ionic-native/splash-screen';
+import { Hoge } from '@ionic-native/hoge';

 @NgModule({
   declarations: [
@@ -34,6 +35,7 @@ import { SplashScreen } from '@ionic-native/splash-screen';
   providers: [
     StatusBar,
     SplashScreen,
+    Hoge,
     {provide: ErrorHandler, useClass: IonicErrorHandler}
   ]
 })
 import { Component } from '@angular/core';
 import { NavController } from 'ionic-angular';
+import { Hoge } from '@ionic-native/hoge';

 @Component({
   selector: 'page-home',
@@ -7,8 +8,14 @@ import { NavController } from 'ionic-angular';
 })
 export class HomePage {

-  constructor(public navCtrl: NavController) {
+  constructor(public navCtrl: NavController, public hoge: Hoge) {

   }

+  coolMethod() {
+    this.hoge.coolMethod('aaaa').then(message => {
+      alert(message);
+    });
+  }
+
     Take a look at the <code>src/pages/</code> directory to add or change tabs,
     update any existing page or create new pages.
   </p>
+  <button ion-button (click)="coolMethod()">coolMethod</button>
 </ion-content>

プラグインをインスールして実機で確認。

$ ionic cordova plugin add plugins_src/Hoge
$ npm install plugins_src/ionic-native/dist/@ionic-native/hoge
$ ionic cordova run android --device

COOLMETHODボタンを押すたびに端末がブルブルと震えるようになりました。
やったね。

f:id:saihoooooooo:20181214164955j:plain:w300

まとめ

初歩の初歩ですが割と簡単にできたと思います。
Capacitorだともっと楽にネイティブの機能を呼び出せるっぽいので期待ですね。