カテゴリー「フットボールのプレイ図ソフト」の27件の記事

2020年4月18日 (土)

またまたバグ発見 <span style="font-family:Impact;font-style:italic;font-weight:normal">LongDriver</span>

表題の通り、フットボールのプレイブック・ソフト LongDriver にバグが見つかりました。もちろん、スマートフォン限定のバグです。 LongDriver を単独で使用する時は良いのですが、 <iframe> 等で埋め込んだものは茶色のバーをタップしても、それが機能しません。例えば下記がそうです。

画像上下の選手ダミーマークをタップしたら、その選手が緑色になり、フィールドに薄暗いマスクが掛かります。その後、左右の茶色バーをタップすると、本来なら選手とフィールドの色が元に戻るのですが、上記画像は、そうなりません(←スマートフォンの場合)。下側の茶色バーに関しても機能しません。

なお、茶色バー上を指でなぞるとフィールドが上下左右にスライドする機能は働いています。ただし、動きがぎこちないですが。

今のところ、茶色バーをタップするような操作をしたい場合は、そのプレイブック・コードをコピーして、単独で表示させるしかテが有りません。プレイブック・コードは、画像右上の [Total][Gen. Full Code] で表示されるので、それをコピーします。コピーしたコードをアドレスバーに貼り付けると LongDriver が表示されます。

それにしても、スマートフォンのくそ仕様にはウンザリです。直った(治った)つもりが再発する・・・まるでCウィルス(注意)です。

(注意):Cウィルスの「C]はコロナとは違うっチャ。

追記:ブログの閲覧をスマートフォンで PC モードにすると、モバイル・モードとは違った結果になります。 PC モードでは、茶色バーのタップは機能します。その代り、茶色バーや仮想マウスパッド(フィールドの薄暗いマスク)上を指でなぞるドラッグは、画像自体がスライドしてドラッグになりません。ますます、混乱した状況になっています。

2020年3月22日 (日)

<span class="sl_ft" style="font-weight:normal">LongDriver</span> のデバッグ結果

フットボールのプレイブックソフト LongDriver がスマートフォンで操作出来なかったことに関して、デバッグは 90% 程度出来て、必要な操作は可能な状態になりました。しかし、これ以上の改善の見通しは立っていません。解決方法は、既に以前の記事で示したように、要素を再表示することす。ただし、要素は複数有るので、その点は変更しています。

下記の表は LongDriver 内の各要素に対する操作の可否を表したものです。第1行は要素を表しています。第2行以下は操作を表し、黒は正常、赤は異常を表しています。ただし、異常と言っても、同じ操作を再度実施すれば、それを実行することが出来ます。今回のバグは1つの操作だけで単純に可否が決まっているのではなく、複数の操作の連なりで可否が決まります。表には2つの操作の結果を記しています。第1の操作は 「click→」 など 「→」 の付いている欄、第2の操作は同一行の他の欄になっています。例えば、 dummy の click の後、 pad の drag は可能とか、 hbar の click の後、 vbar の scroll は不発(ただし、2発目は成功する)など。

操作の可否
dummypadhbarvbar
click→-clickclick
dragscrollscroll
clickclick→clickclick
-scrollscroll
click-click→click
-dragscroll
click--click→
--scroll
clickdrag→clickclick
-scrollscroll
clickclickscroll→click
-dragscroll
clickclickclickscroll→
-dragscroll

表にはデバッグしきれなかった赤い欄が4カ所残っています。これらに共通しているのは、画像の下側と左右に有る茶色のバー (hbar, vbar)の操作の連なりが「click ⇔ scroll」になっていることです。それ以上の解明は出来ていません。とは言え、例えば、 「click」 が不発だったとしても、再度 「click」 すれば、実行出来るという程度にはなっています。

それにしても、スマートフォンは変態過ぎます。それから、 Chrome のデバッガーにスマートフォン・モードが有ったのは、大いに助かりました。

2020年3月21日 (土)

非表示⇒表示の実行は同一関数内では無意味・・・たぶん

先に書いた LongDriver のデバッグ記事 touchEvent の奇妙な振る舞い⇒迂回策 で、対症療法として仮想マウスパッドを表示し直すという考えを書きました。その際、非表示のコードと表示のコードを

    // code-A
    ground.pad.setAttribute("display", "none")    // (1)
    ground.pad.setAttribute("display", "inline")  // (2)

のように続けて書いたら期待した効果は得られず、

        // code-B
        ground.pad.setAttribute("display", "none");
        setTimeout(function(){
            ground.pad.setAttribute("display", "inline");
        }, 10);

のように、間にディレイを入れると良いと書きました。実は、ディレイを入れるだけならば下記コードもアリですが、これでは LongDriver の不具合は解消されません。

        // code-C
        ground.pad.setAttribute("display", "none");
        setTimeout(function(){return;}, 10);    // (3)
        ground.pad.setAttribute("display", "inline");

このことより、不具合解消に必要なのはディレイではない他の何かだと思われます。裏付けの無い推測ですが、表示に関わるコードは、それが置かれている関数を抜け出る時にまとめて反映されるのではないかと思います。その時、不要な処理は省略されるのではないでしょうか。すなわち、 code-A で (1) は省略されて仮想マウスパッドは非表示化されずに、ただ表示されたままのため、表示し直す効果が得られなかったのではないでしょうか。実際、 code-C を実行した時、仮想マウスパッドが一瞬でも非表示化されることはありませんでした。 (3) の 101000 すなわち 1000ms に増やしても非表示化は確認されませんでした。 code-B では、それが置かれている関数を抜けた後で setTimeout() で指定されている関数を実行するので、非表示と表示が確実に実施されるのだと思います。

そういう訳で、仮想マウスパッドの表示し直しは code-B で行いました。

2020年3月16日 (月)

touchEvent の奇妙な振る舞い⇒迂回策

フットボールのプレイブック・ソフト LongDriver がスマートフォンで正常に動作していないことは既に書いていますが、いくつか有る不具合のうち1つは改善出来ました。その不具合と対策は以下の通りです。

スマートフォンでの LongDriver

まず、選手を移動する手順(期待される動作)は次の通りです。この手順は、正常に動作した場合のもので、実際は 4. で異常が発生します。

    選手移動手順
  1. 画像の上下に配置している選手のダミーマークをタップ
  2. フィールドに薄い灰色のシート(←仮想マウスパッド)が表示される
  3. そのパッドに指をタッチして動かすとフィールドの選手が移動する
  4. 上記 3. を繰り返す
  5. 画像の左右に有る茶色バーをタップ
  6. 仮想マウスパッドが消える

手順の 3. 4. で発生するイベント touchstart, touchmove, touchend に応じてイベントハンドラー startDrag(), drag(), endDrag() が実行されます。3つのハンドラーとも evt.preventDefault() を実行しています。 startDrag() でイベント touchmove に対するハンドラー drag() が登録され、 endDrag()drag() が解除されます。

function startDrag(evt){
	evt.preventDefault();
	・・・
	pad.addEventListener(touchmove, drag, {passive: false});
}

function drag(evt){
	evt.preventDefault();
	・・・
}

function endDrag(evt){
	evt.preventDefault();
	・・・
	ground.pad.removeEventListener(touchmove, drag, {passive: false});
	・・・
}

上記の選手移動手順を実行していて不思議なのは、 3. を最初に実行する時は問題が発生しないのに、 4. で 3. を繰り返そうとしても drag() が実行されず、選手の移動が出来ないことです。その時、 startDrag()evt.preventDefault()

  • Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.

というエラーが発生します。これは、「スクロールか何かの最中なので evt.preventDefault() 出来ない」ということです・・・スクロール?? そんなことしていないのに? なお、 endDrag()evt.preventDefault() ではこのエラーは発生していません。

選手移動の手順を一通り終了して再度実施すると、同じく 3. は実行出来て 4. でエラーが発生します。これも不思議です。選手移動モードを一旦抜ける(手順の 5. 6.)と、エラーメッセージに有る 「scrolling is in progress」 がキャンセルされるということなのでしょうか? 手順の 6. は hidePad() というハンドラーで実現されています。また、再実行の入り口では手順の 1. 2. で pickup() というハンドラーが実行されます。しかし、これらのハンドラー内で「scrolling is in progress」 のキャンセルに関わりそうな箇所は有りません。何故、手順の再実行が可能なのか不明です。

とにかく、手順を最初から実施すれば、 3. は実行できるので、試しに、デバッガーのコンソールから

ground.pad.setAttribute("display", "none")

ground.pad.setAttribute("display", "inline")

を続けて実行してみました。これらは仮想マウスパッドを非表示および表示するコードです。これを実行すると、直後の1回だけ選手移動(つまり 3.)が出来ました。カラクリは判りませんが、とにかく、仮想マウスパッドを表示しなおせばエラーは発生しないわけです。そこで、そのコードを endDrag() に追加しました(1)。ただし、非表示と表示のコードをただ並べただけではダメで、幾ばくかのディレイが必要です(注意)。数百ミリ秒から試してみて、 10 ミリ秒でもOKなことは確認済みです(最小値かどうかは未確認)。

(注意):訂正有り(非表示⇒表示の実行は同一関数内では無意味・・・たぶん

function endDrag(evt){
	・・・
	if (ground.isTouchPnl){			// (1) 6行追加
		ground.pad.setAttribute("display", "none");
		setTimeout(function(){
			ground.pad.setAttribute("display", "inline");
		}, 10);
	}
}

取り敢えず、これで選手の移動は出来るようになりました。しかし、未だ解決出来ていない不具合は有ります。デバッグはもう少しかかりそうです。

追記:LongDriver にアクセスしただけではキャッシュが残っていて、デバッグの効果が反映されないかも知れません。 LongDriver のキャッシュをクリアーしてからアクセスする必要が有ります。

2020年2月28日 (金)

スマートフォンでの <span class="sl_ft" style="font-weight:normal">LongDriver</span> の不具合

昨年7月にフットボールのプレイブックソフト LongDriver がスマートフォンでは使えないことが分かり、その時、一応使えるようにしたのですが、先日、久しぶりに使ってみたら、再び使えなくなっていました。(それとも、昨年のデバッグが間違いだったのでしょうか?)

不具合の症状は次のようなものです。

  1. 選手のドラッグおよびフィールドのスクロールに不具合有り
    • 初めの1回は操作出来るが、それ以降は反応無し
    • その反応無しの時 touchstarttouchend のイベントリスナーは呼び出されるが touchmove のイベントリスナーは呼ばれない
  2. イベントリスナーで evt.preventDefault() を実行しようとすると下記のエラーが発生する
    • Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted. (cancelable=false である touchstart イベントをキャンセルすることが無視された)

別のソフトでビリヤードの配置図ソフト FlatTable でも上記 (2) のエラーは発生していますが (1) の不具合は有りません。1つの DOM 要素に対して LongDrivertouchstartclick のイベントリスナーを登録しているのに対して FlatTable では click は登録していないことが両者の違いになっていると思われます。そこで、 LongDriver でも click のイベントは使わずに touchstarttouchend でエミュレートしてみようと思っています。

上記 (2) については FlatTable でもエラーが発生するので evt.preventDefault() をコメントアウトしたところ、エラーの発生が抑制されました。また、コメントアウトしたことによって何か新たな不具合が生じた様子も見られませんでした。 evt.preventDefault() の実行は意味が無かったということでしょうか?(←画面がスクロールすることが分かった)

2019年7月28日 (日)

LongDriver がスマートフォンでは使えなかった?

フットボールのプレイブックソフト LongDriver がスマートフォンでは使えなかったようですが、不具合の一部を修正しました。

今頃気付いた

そもそも私はスマートフォンを持っていませんでした。それで、携帯端末での動作確認・デバッグはタブレットを使用していたのですが、まさかタブレットとスマートフォンは動作が共通ではないと思っていませんでした(あるいは、私の持っているタブレットは少し古いので、その後仕様が変更されたのかも知れません)。

ところが、今まで使って来た所謂ガラケーは今年の11月いっぱいで、ほとんど使い物にならないほど機能が限定されるとの連絡が有り、止むを得ずスマートフォンに切り替えることになりました。そのスマートフォンで LongDriver を使ってみてビックリ。まともに動きません。今頃気付きました。

preventDfault() が効かない

最近のスマートフォンはデフォルトでは preventDfault() が効かないようです。効かせるためには、イベントリスナーの追加時にパラメータで指定する必要が有るそうです(参照: addEventListener の第3引数が拡張されてるという話スクロール禁止が overflow:hidden や preventDefault(); でできないときの対処法)。下記コードの赤色部分です。

    eventtarget.addEventListener(event, listener, {passive: false});

LongDriver では、今までイベント処理の指定は

    eventtarget.onevent = listener;

という方式でやっていたので、これらを置き換える必要が有るのですが、話しは単純ではありません。 addEventListener() するだけではなく、それまでリスナーだったものを removeEventListener() する必要が有ります。そのリスナーが何だったかを調べてコードを修正して行きました。

画像を拡大するとドラッグ時にページがスライドする

画像を拡大していない時は問題無いのですが、拡大した状態で選手マークをドラッグするとページがスライドするという問題が有ることも分かりました。これは、イベント touchstart, touchend のリスナー内では preventDfault() を実行していないことが原因と思われます。しかし、これを実行するとイベント click を捕捉出来なくなるので、現時点では preventDfault() は実行していません。イベント click はプレイルート作成のトリガである水平バーのクリックやメニュー等のクリックに使用しており、 preventDfault() を実行するとクリックに反応しなくなります。イベント click は使わずに touchstarttouchend でエミュレートすれば良いのかなと思っていますが、未だ修正していません。

2017年2月26日 (日)

プレイルートに曲線を導入

LongDriver のプレイルートで曲線を使用できるようにしました。曲線は2次のベジェ曲線(放物線)です。プレイルートのノードにフォーカスが当たっている時にメニュー [Each][Curve/Straight] をクリックするとフォーカスの当たっていたノードがベジェ曲線の制御点になるような曲線が描画されます。下記サンプルで4番の選手の2つ目のノードが制御点になっています(画像下側の選手マーク4番を繰り返しクリックするとノードが順次表示されます)。制御点のノードにフォーカスを当てて再度 [Each][Curve/Straight] をクリックすると通常の直線に戻ります。

曲線化とプレイ図のエンコードはすんなり出来たのですが、デコードで暴走させてしまいました。デコードの関数内に曲線用のルーチンを追加したところ、プレイ図コードのスキャン位置が合わなくなり、それが原因で暴走しました。ルーチンを追加したくらいで暴走するようなプログラムを書いていてはダメですね。

ところで、ブレイクポイントを設定してデバッグしていた時に気付いたのですが、「var foo;」のような変数宣言にはブレイクポイントを設定できないのですね。これは、最初に構文解析したら、その後の実行では変数宣言はスキャンしないということでしょうか? 今まで、このような変数宣言はループの外に記述していたのですが、実行中にスキャンしないのなら、ループの内側に記述しても効率は落ちないことになります。

    var foo;		// ループの内側↓に入れても効率は落ちない?
    for (・・・){
        var bar;
        ・・・
    }

ちなみに、最近の JavaScript では var よりも let の方が良いとか言われていますが、馴染みが薄いので、今回は let は使っていません。

なお、LongDriver を読み込む時、ブラウザによってはキャッシュのせいで古い LongDriver を実行することがあるようです。 Chrome では、再読み込みをしてもキャッシュが効いていてダメでした。新しい LongDriver を実行するには、 Chrome の再読み込みマークを右クリックして「ハード再読み込み」を実行する必要がありました。

2016年11月26日 (土)

インターネットで見つけたプレイ図ソフト

アメリカンフットボールのプレイ図(プレイブック)ソフトを検索してみたところ、図のようなソフトを見つけました。アドレスは
http://footballtactics.net/playbook.html
です。

Pbsoft_alt

私のようなデザインのセンスの無い者の作った LongDriver よりも綺麗な絵になっています。

このソフトを扱っているメインページは
http://footballtactics.net/
で、サッカー用ソフトは完成しているようですが、アメリカンフットボール用は途中で止まっているのか、完成には至っていないようです。このサイトに掲載されている 「documentation」 はサッカー用なので注意が必要です。

さて、 LongDriver を、この footballtactics と比較すると次のような違いが有りました。 LongDriver とは次のようなソフトです。

当ブログのプレイブックソフト LongDriver の公開を参照してください。

まず、footballtactics はデータや画像をローカルファイルに保存できるのに対して LongDriver は出来ません。方法が分からないので、画像の取得は PrtScr キーを使うという姑息な手段を使っています。

次に、 footballtactics はフィールドの向きを変えられるのに、 LongDriver は出来ません。当初、 LongDriver も変えられるようにする積りでいたのですが、気が向いたらやるということにして、未だ実装していません。

3つ目は、 footballtactics はプレイルートに曲線が使えるのに対して、 LongDriver は出来ません。これも当初は予定していたのですが LongDriver では未実装です。モチベーションが上がったら実装するかも知れません(追記2:モチベーションが上がったので曲線も表示できるようにしました)。

4つ目の違いは初期状態に関してです。 footballtactics の初期状態は選手が居ませんが、 LongDriver はデフォルトで基本的な(と思われる)フォーメーションに配置されます。それは、ゼロの状態から22人を配置するのは骨が折れるので、前もって配置しておいた方が良いだろうと考えたからです。

5つ目は、 footballtactics は単一のプレイ図しか扱えないのに対して、 LongDriver は複数のプレイ図を扱えます。これはビリヤードの配置図ソフト FlatTable からの流れとして当然の仕様です。因みに、複数のプレイ図を扱えることが LongDriver という名前の由来です。

6つ目の違いはデータの共有方法についてです。 footballtactics ではこのサイトがサーバーとなってデータを保管し、それをダウンロードすることでデータの共有を行っています。この方法だと、ブログではただの画像を表示するに止まるため、ブログのみで footballtactics のデータを再利用(共有)することは出来ません。そのため footballtactics ではサーバーを使ってデータ共有をサポートしているのだと思われます。それに対して LongDriver では、ブログに貼り付けたデータを利用できるようになっています。

そして最後に footballtactics は Flash で出来ているのに対して LongDriver は SVG+JavaScript で出来ている点が違います。 Flash はいつまで大丈夫なのでしょうか?

追記1:
6番目の項目のデータの共有は footballtactics のサッカー版では可能ですが、アメリカンフットボール版は未実装ではないかと思われます。

2016年11月21日 (月)

SVG の変換行列(CTM)

LongDriver の動作確認をしていて、選手マークをドラッグする時、マークの移動量とマウスの移動量が異なることに気付きました。試しに下に表示している LongDriver でマークをドラッグして下さい。マウスに比べてマークの移動量の小さいことが分かります(注1)

(注1):その後、この記事の方法でマウスとマークの移動を一致させました。

LongDriver では、マークの移動量 deltX, deltY は、次の式で決定しています。

    deltX = (evt.clientX - pad.prevX);	// 右辺はマウスの移動量
    deltY = (evt.clientY - pad.prevY);
    ・・・
    var x = Number(target.getAttribute("x")) + deltX;
    var y = Number(target.getAttribute("y")) + deltY;
    target.setAttribute("x", x);	// target は選手マークを指す
    target.setAttribute("y", y);

このように、マウスの移動量をそのままマークの移動量としているのに、何故両者は一致しないのでしょうか?この原因は LongDriver が縮小表示され、その座標系とブラウザの座標系のスケールが異なることにあります。マウスの位置を表す evt.clientX や、それから得られる deltX 等はブラウザの座標系での値です。しかし target.setAttribute("x", x) を実行する時は LongDriver の座標系に基づいた点が選ばれるのです。そして LongDriver の座標系は縮小されているためマウスの移動量とマークの移動量が異なるのです。

SVG では、表示の大きさが変更された場合、その情報が変換行列 CTM に保存されます。 CTM は3×3行列で、新・旧座標を次の関係で繋ぎます。 \[ \begin{pmatrix} x_\mathrm{prev} & y_\mathrm{prev} & 1 \end{pmatrix} = \begin{pmatrix} x_\mathrm{curr} & y_\mathrm{curr} & 1 \end{pmatrix} \begin{pmatrix} a & b & 0 \\ c & d & 0 \\ e & f & 1 \end{pmatrix} \tag{1} \]

この式で左辺は旧座標系での値、右辺が新座標系での値だということに気を付けて下さい。今の場合、旧座標系とは LongDriver の初期座標系(すなわち、縮小前の座標系)のことです。この初期座標系はブラウザの座標系に一致しています。画面に表示されるのは初期座標系に換算されたものです。

上に表示している LongDriver を例に取ると CTM は \[ \rm{CTM} = \begin{pmatrix} 0.602 & 0 & 0 \\ 0 & 0.602 & 0 \\ 0 & 7.229 & 1 \end{pmatrix} \] になっています。ここで、マウスの移動量を新座標系の LongDriver に代入すると約 0.602 倍され初期座標系での移動量に換算して表示されます。逆の言い方をすると、マウスとマークの移動を一致させるには、マウスの移動量を 0.602 で割った値を選手マークの移動量とすると良いことになります。

余談ながら、式 (1) でベクトルが横になっていて、さらに変換行列を右から掛けているのが気持ち悪い。

2016年11月 5日 (土)

選手のマークの番号を変更可能にした

LongDriver は一段落させた積りだったのですが、気になることが出て来て、それを改良しました。プレイ図を使っているブログを検索して見て回っていたら、実際のプレイを図示したものが有り、それには実際の選手の番号が記入されていました。LongDriver は、選手のマークの番号は固定されているので、そのような時に違和感が生じます。そこで、選手のマークの番号を変更できるようにしました。

番号の変更は次のようにやります。まず、変更したい選手を選択してからメニューの EachRenumber をクリックするとメッセージボックスが出ます。そこで、そのメッセージボックスに2ケタもしくは1ケタの文字列を入力します。すると、選択した選手のマークに付いている番号が新しいものに変わります。数字に限らずアルファベットも可能です。ちなみに、漢字を入力した場合の動作は保証しません。

サンプルを示します。今までの記事に載せたサンプルと番号が違うのが分かります。