まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

カスタマイズネタでテトリスを扱うことがあるのですが、その時のベースに使っているのがこちらです:
https://github.com/dionyziz/canvas-tetris

Dionysis Zindros さんが HTML5 Canvas で作ったテトリスです。Canvas 、JavaScript 、そして CSS でテトリスが再現されていて、MIT ライセンスで公開されています。実際に遊ぶ時にもブラウザで index.html ファイルを開くだけ(index.html ファイルは HTTP サーバー上にアップロードされている必要はなく、ローカルファイルとして開くだけでも可)で遊べます。

一応、遊び方にも触れておきます。index.html ファイルをブラウザで開くと以下のような画面になります。この「Play」ボタンをクリックするとテトリスがスタートします:
2019061703


操作はキーボードを使います。矢印の左右でテトリミノ(ピース)を左右に移動、上矢印で回転、下矢印で強制的に下に移動します:
2019061704



といった背景もあって実際に遊ぶのはもちろん、改良する場合においても技術的&ライセンス的なハードルが低く、デモやハンズオンも含めたセミナーのネタとして重宝しています。


そんなわけで、今日のブログエントリはこのテトリスを Obniz で操作する、というカスタマイズの紹介です。


Obniz (オブナイズ)をご存じない人のために簡単に紹介しておきます。Obniz は 2017 年に Kickstarter でクラウドファンディングが開始された IoT ボードです。Arduino や Raspberry Pi(Zero) と比較しても小型で、単体ではダイヤル式のスイッチと簡単な文字が表示できるディスプレイを入出力装置として持っています。これ以外に標準で無線 LAN および Bluetooth につながることができ(そのための設定をダイヤル式スイッチで指定します)、そして 12 個の GPIO によって各種センサーやモーターを接続することができます。MicroUSB からの給電により、(単体では)最大 1.8A の電流で稼働します。

そして最大の特徴といえるのが JavaScript による API の提供です。HTML や Node.js から利用可能な JavaScript でこれらの入出力装置の状態を監視したり、値を入力/設定/出力することができます。Obniz の JavaScript そのものの紹介が本ブログエントリの目的ではないので、詳しくは公式ドキュメントを参照してください。ググればネット上にサンプルを含めた使い方がたくさん見つかりますが、要するに「ウェブ(ページ)との連携が容易なボード」なのです:
https://obniz.io/doc/root





この Obniz ボードとの連携として、ボードのダイヤルスイッチでテトリミノを動かせるように改良しました。そのコードがこちらです:
https://github.com/dotnsf/canvas-tetris


こちらのコードをダウンロード(または git clone)して、Obniz を WiFi に接続後にブラウザで index.html ファイルを開いてください。すると最初に以下のような画面になって Obniz ID の指定を促されるので所有する Obniz の ID を指定します:
2019061702


そして "Play" ボタンをクリックでゲームスタートです。ここでは Obniz のダイヤルスイッチを使って、以下のように操作することができます:
ダイヤルスイッチ操作
左に回す左移動
右に回す右移動
押し込む回転


実際に遊んでいる様子がこちらです(下手すぎるのは撮影しながらだから、です・・・):



この仕組みのすごい所は「ゲーム画面とコントローラー(Obniz)が離れていても実現できる」点です。↑の動画では Obniz のある場所でゲーム画面を開いていますが、たとえばゲーム画面は地球の裏側で見られていたり、コンサート会場の大型スクリーンなどに表示されていてもいいわけです。そんな仕組みを簡単に実現できてしまっている、という点が素晴らしいと感じてます。

ちなみにカスタマイズの肝となっている箇所のコードはこちらです。js/controller.js ファイル内に以下のコードを追加して、Obniz スイッチの変更イベントを obniz.switch.onchange でハンドリングし、その内容に応じて対応するキーが押されたようにイベントを発生させています:
  :
//. obniz
var obniz = new Obniz("XXXX-XXXX"); //. <-- Edit with your own Obniz ID
obniz.onconnect = async function(){
  obniz.display.clear();
  obniz.display.print( "Obniz TETRIS" );

  obniz.switch.onchange = function( state ){
    obniz.display.clear();
    obniz.display.print( state );

    switch( state ){
    case 'left':
      keyPress( 'left' );
      render();
      break;
    case 'right':
      keyPress( 'right' );
      render();
      break;
    case 'push':
      keyPress( 'rotate' );
      render();
      break;
    default:
    }
  }
}

この Obniz の JavaScript SDK は本当に強力で、簡単にこういうことが実現できちゃいます。LED やセンサーを繋いだり、モーターを繋いだりしなくても、手軽にこんな使い方が実現できちゃうという、このポテンシャルの高さが魅力で気に入ってます。



むかーし、むかし、ダイアルアップ接続という仕組みがありました。。
hqdefault


現在ではスマートフォンが直接インターネットに接続され、スマートフォンだけでインターネットサービスを利用することができるようになりました。PC もインターネットに常時接続している職場や自宅から有線/無線 LAN を経由してインターネットに接続できる環境が整っています。

ただ(特に自宅で)このようなインターネットへの常時接続環境が整ったのは ADSL が普及しはじめた 2000 年代前半からでした。一方で、その前からインターネットは多くのユーザーによって利用されていました。特に「インターネット接続機能が標準搭載された」 Windows 95 (1995)の発表からインターネットの利用者が増えたのではないかと思っています。ではスマホや常時接続環境がまだ存在してなかったこの頃、どうやって自宅からインターネットを利用していたのでしょうか?

その答が冒頭のダイアルアップ接続でした。簡単にいうと電話線(携帯電話回線ではなく、自宅のアナログ回線)を通じてプロバイダと呼ばれる業者に電話をかけて接続し、電話回線を使ってデータを送受信する、という仕組みを使っていたのでした。今から 20 年ほど前、個人がインターネットを利用するにはほぼこの方法を使っていました。ダイアルアップ接続をするには(通信そのものは電話の音声回線を使うため)モデムと呼ばれる音声通信データとインターネット通信データとを変換する機器が必要になります。当初はモデムは PC 本体とは別に購入・接続する必要があったのですが、後にモデムは PC に内蔵されることが大半となる時期もありました。また公衆電話にもインターネット通信を行う前提で PC(モデム)との接続インターフェースを持つものが多く設置されていました:
20190620


さてノスタルジックな話はここまで。ここからが本ブログエントリの本番です。

このダイアルアップ接続は現在ではほぼ使われていないと理解していますが、仕組みとしては 2019 年の現在も残っています。モデムは(以前のシリアル接続ではなく USB 接続のものばかりですが)新品が入手できます。また以前ほど多くはありませんが、現在もダイアルアップ接続を提供するプロバイダーは存在しています。自宅に固定電話回線を持っていない人が増えているかもしれませんが、上述のモデム接続インターフェースを持つ公衆電話も(わずかですが・・)残っています。

というわけで 2019 年の今、あえてダイアルアップ接続がどこまで使えるのかを試してみました。一部ネタバレを先に言ってしまいますが、想像以上に出費があったので好奇心だけで真似するのはあまりオススメしません(笑)。以下、準備段階も含めたその記録です。


【PC】
これはほぼ「なんでも可」だと思います。条件を付けるとすれば「後述のモデムが接続できるもの」です。昔のモデムは RS-232C ポートを使ってシリアル接続するものが多かったのですが、最近のモデムは「ほぼ USB 接続」です。シリアル接続のモデムを使う場合のみ、シリアルポート付き PC を用意してください。ちなみに今回は Windows 10 Pro が導入されている GPD MicroPC を使いました(最近では珍しいシリアルポート付きラップトップ PC ですが、今回は USB 接続のモデムを使っています):


【モデム】
モデムの入手に苦労することを想像していたのですが、あっけないほどアマゾンで見つかります。「持ち運び時に邪魔にならない小さいのがいいな」程度の理由で、自分が購入したのは AGPtek の USB 2.0 FAX モデムです:




電話機とモデムとを物理的に接続する線(6極2芯ケーブル)も付属しているので、PC とこの箱ごと持っていれば公衆電話でもダイアルアップ接続できます。またドライバ用の CD が付属していましたが、PC の USB に接続した所、特別な作業もなく(標準ドライバで)正しく認識できました。ドライバ CD は使っていません。

なお通信の最高速度は 56kbps です。「ま、今もたまにマイネオの低速通信(200kbps)を使ってツイッターやってるし、この位でなんとかなるんじゃね?」と軽く考えていました。が、後にここが最大の苦難になるとは・・・


【プロバイダ】
ダイアルアップ接続をするには、ダイアルアップ接続に対応したインターネット・サービス・プロバイダ(ISP 、以下「プロバイダ」)と契約する必要があります。常時接続と異なり、接続中は通話料金が発生するので、昔は同一市内にアクセスポイント(=電話先)を持っているプロバイダを選んで契約するのが一般的でした。

2019 年6月時点でダイアルアップ接続サービスを提供しているプロバイダを検索するといくつかありました。自分はその中から @nifty を選びました。@nifty でのダイアルアップ接続やセットアップの方法はこちらに公開されています(Windows 10 が対象に含まれていないようでしたが、結論としては問題なく接続できました)。なお公衆電話から接続する場合は公衆電話専用番号が用意されているようで、こちらの番号でないと接続できないようでした。また @nifty でダイアルアップ接続する場合のアクセスポイントの電話番号や料金は全国共通のようです。契約さえしておけば、どこからでも同一料金で利用することができる、ということになると思います。

ちなみに @nifty のアカウントを作るのは NIFTY Serve 時代も含めると3度めです。困った時の @nifty 様!



【ISDN 公衆電話】
自宅電話や公衆電話そのものを使ったことがない人がちらほら存在しているのではないかと思いつつ、、、今回は公衆電話からプロバイダへのダイアルアップ接続を行います。公衆電話そのものが以前ほど見かけなくなっている印象ですが、ダイアルアップ接続を行うには「グレー電話」とも呼ばれている、専用の公衆電話を利用する必要があります:
upload_0001_20141009
(↑左のタイプではなく、右のタイプの公衆電話を使う必要があります)


この「アナログ」という口に6極2芯の電話ケーブルを挿してPCと繋げて・・・
2019061901



このグレー電話を探すのが意外と大変でした。記憶の中に「そういえばあそこに公衆電話があった。あそこにもあった」と、公衆電話自体は存在場所をいくつか把握していたのですが、そのほとんどがグレー電話ではない、緑の公衆電話でした。数少ない公衆電話の中から更に珍しいグレー電話を探す必要があり、これが想定以上に手間取ってしまいました。

自分はJR津田沼駅北口のこの辺り↓で、2台存在する公衆電話のうちの1台がグレー電話であることを発見しました(ストリートビューはこちら):
2019061801


【テレホンカード】
公衆電話といえば「テレホンカード」です。知らない人のために書いておくと、公衆電話に必要な料金は10円単位で支払う必要があり、10円玉か100円玉を用意する必要がありました(これ以外の硬貨や紙幣は使えません)。またお釣りは出ません、つまり100円硬貨を入れて仮に20円ぶんしか通話しなくても80円のお釣りが出てくるわけではないのです。この点については現代でも変わっていません。

そんな不便な中、長時間通話をする人の多くはテレホンカードを使っていました。これはプリペイド式の公衆電話用カードです。通話で使ったぶんだけが度数として引かれます。今もコンビニなどで売られていますが、僕が購入したお店では105度数(1000円で1050円ぶん使える)のカードしか取り扱っていませんでした。本当は50度数(500円で500円ぶん使える)カードでよかったのですが、仕方なくこれを購入しました:
2019061801


【コントロールパネル】
残された準備はソフトウェア的な設定でダイアルアップ接続ができるようにするだけです。Windows 10 どころか XP あたりからダイアルアップ接続を使った記憶がないんだけど。。

今回の例では Windows 10 で @nifty にダイアルアップ接続するための設定を作成します。といっても、手順はほぼこちらで紹介されている通りです(Windows 7 用ですが、10 でもほぼ一緒):
https://support.nifty.com/support/manual/internet/dialup/setup/win7.htm


注意点として、上述しましたが @nifty の場合は公衆電話回線用の専用電話番号が用意されている、という点です。今回のようにグレーの公衆電話を使ってアクセスする場合は公衆電話用アクセスナンバー(0570-054-300)を指定する必要がある点に注意が必要です。


【いざ接続!】
事前に必要な準備は全て整いました。PC にモデムを接続し、グレー電話とケーブルで接続:
2019061902


いざダイアルアップ接続!・・・・



遅っ! 接続完了まで40秒もかかるの!?

ともあれ 10数年ぶりのダイアルアップ接続に成功しました。全然使ってなかったから知らなかったのですが、ダイアルアップ接続状態で画面右下のネットワークプロパティをこんな感じの電話アイコンが見えるようです:
2019061903


緊急事態を想定して、自宅のマンホールマップサーバーへ公衆電話から SSH でログイン! これもできました!!
2019061904

↑脳ごとノスタルジックになってしまったのか、なぜかスクリーンショットではなく PC 画面を撮影してました(笑)


【感想】
とりあえず当初の目的は達成できました。これでこのモデムを持ち歩いてさえいれば(苦笑)スマホがぶっ壊れても出先からネットを使う、ということはできそうだという安心感が得られました。

それにしても・・・一番の想定外だったのは通信の遅さでした。ツイッター程度はもう少し楽に使えると思っていたのですが、1分待っても2分待ってもトップ画面が開かずにテレホンカードのクレジットだけがどんどん減って行って・・・ 最後は諦めたという (^^;

上記の SSH ログインも実はかなり苦戦しています。top コマンドを実行したかったのですが、"top" と入力したつもりだったのに画面には "t" しか出てこず、エコーバックが追いついていないようでした。で "op" と押し足すと今度は "topop" って表示されて、BackSpace でもなかなか消えてくれなくて・・・といった感じでした。56kbps を甘く見てました。。

今回の挑戦当初の目的であった「2019 年の今、あえてダイアルアップ接続がどこまで使えるのか」の答としては
 繋がるけどほぼ使えない (^^;
ということだったと思います。


あと、モデム特有の「ピーー、が~~~」音を聞くことを期待していたのですが、公衆電話からオンフックでかけると音ってしないんですね。 (^^;



 

jQuery の animate 関数を使う機会があります。

この animate 関数を使うと HTML 要素に比較的簡単にアニメーション要素を加えることができます。サンプルとして 200 x 200 の矩形の左下から右上に <p> 要素を移動させる例を紹介します("animate1" ボタンをクリックすると移動します):

 




このアニメーションのために記述した CSS および JavaScript は以下になります:
<style>
div.sample{
  position: relative;
  border: 1px solid #ccc;
  width: 200px;
  height: 200px;
}
div.sample p.point{
  position: absolute;
  left: 0px;
  top: 180px;
  margin: 0;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  background-color: #d00;
}
</style>
<script>
function animateStraight(){
  var $point = $('#point1');

  var startAnimate1 = function(){
    $point.animate( { left: 180, top: 0 } );
  };

  startAnimate1();
}

</script>

<div  class="sample">
  <p  id="point1" class="point"> </p>
</div>
<button  onclick="animateStraight();">animate1</button>

</body>

初期状態で { left: 0, top: 180 } (矩形の左下)に設置されている id='#point1' の <p> 要素に対して animate() 関数を実行し、そのパラメータに { left: 180, top:0 } (矩形の右上)を指定しています。これだけで現在位置から目的位置までの間を(直線的に)移動するアニメーションが実現できます。

#細かく説明すると、#point1 の <p> 要素の left パラメータを 0 から 180 へ、top パラメータを 180 から 0 へ少しずつ移動させることで実現できています。

ここで紹介したのは位置に関するパラメータでしたが、位置以外でも数字で指定できる要素を使って現在の値から目的の値までアニメーション処理させるだけであれば同様に実現できます。


さて、本ブログエントリで紹介するのは曲線的な軌道でアニメーション移動処理させたい場合の方法です。例えば左下から右上まで、円軌道でアニメーション処理させたい場合にどうすればよいか、という場合の方法を紹介します。

この実現のために animate() 実行時のパラメータの中で step 関数を使います:
    $point.animate(
      { count: 1 },
      {
        step: function( current ){
             :
        }
      }
    );

上の例では値を変化させるパラメータに count を指定しています。値を(初期値の 0 から)1 へ変化させるという指定ですが、この count 自体は位置には関係ありません(つまりこの animate 関数自体では画面上のアニメーションの処理は行っておらず、単に count 変数を 0 から 1 へ変化させているだけです)。

アニメーション処理を行っているのは animate 関数実行時の2つ目のパラメータである step 関数です。この関数は count 関数の値が少しずつ変化するたびに、その値を引数(current)にして実行されるます。なのでこの step 関数の中で current の値を使って要素の移動位置となる x 座標および y 座標を計算して css で位置移動する、という方法によってアニメーション処理を実現します。

具体的にはこのようになります("animate2" ボタンをクリックすると移動します):

 





<style>
div.sample{
  position: relative;
  border: 1px solid #ccc;
  width: 200px;
  height: 200px;
}
div.sample p.point{
  position: absolute;
  left: 0px;
  top: 180px;
  margin: 0;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  background-color: #d00;
}
</style>
<script>
function getXY( t ){
  var r = 180;

  var x = r * t;
  var y = Math.sqrt( ( r * r ) - ( x * x ) );

  return { x: x, y: y };
}

function animateCurve(){
  var $point = $('#point2');

  var current = 0;
  var startAnimate2 = function(){
    $point.animate(
      { count: 1 },
      {
        step: function( current ){
           var point = getXY( current );
           $point.css( { left: point.x, top: point.y } );
        }
      }
    );
  };

  startAnimate2();
}
</script>

<div  class="sample">
  <p  class="point" id="point2"> </p>
</div>
<button  onclick="animateCurve();">animate2</button>

step 関数の中で current の値をパラメータに指定して getXY() 関数を実行しています。getXY() 関数では x2 + y2 = 1802 (中心座標 [0, 0] 、半径 180 の円)上において、[ 0, -180 ] から [ 180, 0 ] まで移動する間の [ x, y ] の軌跡を計算して返しています(※)。また、この getXY() 関数によって返された値を使って、<p> 要素の位置を変える、という処理を加えています。これによって animate() 関数で count の値を 0 から 1 まで直線的に移動させながら、<p> 要素の位置を円曲線に沿って移動させる、という処理を実現しています。

※この円における x 座標は 0 から 180 まで変化します。したがって、x = current * 180 で求めることができます。また x2 + y2 = 1802 より y = (1802 - x2 )の平方根なので、この数値を計算して求めています。これが getXY() 関数の中身です。

この方法を応用することで(曲線の軌道計算式がわかっていれば)animate() 関数で要素を曲線軌道でアニメーション移動させることができます。



このページのトップヘ