スプーキーズのちょっとTech。

SPOOKIES社内のより技工的な、専門的なブログページです。

擬似3Dダンジョンの作ってみよう!

擬似3Dダンジョンとは


擬似3Dダンジョンと聞いてなんぞやと思う人もいるでしょう。

ずばり、2D上で3Dっぽく見せるダンジョンということになります。

擬似3Dダンジョンを使った作品で有名な物を二つご紹介

  • ウィザードリィ
    • 言わずと知れた名作RPG
    • 1981年にAppleⅡ用に世間へ羽ばたく
    • 魔物の画像を表示したコマンド式戦闘システムを確立、多くのゲームに影響を与えた
  • 世界中の迷宮
    • ウィザードリィを意識して作られた現代版ウィザードリィ
    • 音楽が良い

未プレイの方にはおすすめのゲームです!

自己紹介


さて、本題に入る前に少しだけ自己紹介。

情報系大学の3年生のロックです。

名前の由来は溢れ出るロックンロール精神でしょうか。

気がついたらロックと呼ばれていました(不思議ですね)

そんな私ですが、普段は大学サークルでゲームを作っていたりします。

大学1,2年の間はしっかりと作品を完成させることが出来ずに積もり積もっていくガラクタ生産工場長でした。

しかし、最近少しずつ作品を完成させることが出来るようになってきました。

ガラクタからコードをひっぱてきたりすることもあるので、続けて来たからこそ今があると実感する今日この頃です。

前置き


今回の開発環境は以下の通りです。

  • Visual Studio 2015
  • C/C++
  • DXlib

Windowsでの開発となります。

主な実装機能


では、本題に入りましょう。

擬似3Dダンジョンを作るにあたって、今回実装する機能を紹介しておきます。

  1. ミニマップの表示
    • マップと現在位置とゴールの3種類を表示します
  2. 自由に歩ける
    • キーボードの矢印キーで自由に動けるようにします
  3. 視界の表示
    • 擬似3Dの描画をするための準備
  4. 擬似3Dの描画
    • 肝心要。主題
  5. ゴールを作る
    • 一応のゴール

目標としては擬似3Dの描画が出来れば達成とします。

それでは、一つずつ見ていきましょう。

処理の流れ


1. ミニマップの表示

ミニマップとは言っていますが、がっつりマップですね。

今回は擬似3Dとして最終的に描画してしまうので、全体マップというものが見れないことになってしまいます。

そこでこのミニマップを実装します。

< 実装方法 >

二次元配列を用意して、数字で埋めましょう。

  0:なし 1:壁 2:ゴール 3:初期位置

マップの大きさは12*12ぐらいにしておきましょうか。

最後に、数字に合わせて描画すれば完成(今回は色で表現)

  0:灰色 1:白 2:赤

初期位置に関しては描画しなくて良いでしょう。

代わりにプレイヤーの位置は表示することにします。

  プレイヤー:青

2. 自由に歩ける

プレイヤーも動けた方が良いですよね。

< 実装方法 >

Dxlib にキーボード入力を取得出来る関数があるので、それを用いればばっちりです。

  ↑:前へ進む ←→:旋回 ↓:後ろを向く

今回はマス目移動。

プレイヤーは位置と向きを持つことになります。

3. 視界の表示

突然出てきた視界という単語。

今回は3マス分の視界にしましょう。

左奥 中央奥 右奥
左中 中央中 右中
左前  私  右前

3*3のマスを調べて、壁があるのかないのかを判定出来れば良いです。

「私(プレイヤー)」の場所は調べなくても良いので、8マス調べることになります。

これが上下左右の4方向あることも踏まえて実装を考えます。

< 実装方法 >

プレイヤーの位置とプレイヤーの向きを基準にして、マス目を調べる

調べた結果は視界用の3*3の二次元配列に格納(プレイヤーの位置には 0 とか入れておきましょ)

視界用配列から、視界を取得して扱います。

せっかくなので、ミニマップと同様の手順で、視界も表示しておくことにします。

4. 擬似3Dの描画

ようやく来ました。

と言っても、ここまで順番にやってきたら、処理としてはすることがありません。

視界用配列を値を元にして、ぺたぺた画面に画像なり図形なりを貼り付けていく作業になります。

画像を用意するのは大変なので、図形を用います。

< 実装方法 >

Dxlib に四角形を描画する関数があるので、それを用いる。

左奥、中央奥、右奥、左中、中央中、右中、左前、右前、の8つそれぞれに四角形を描画する。

5. ゴールを作る

マップを作ったときに実はゴールが出来ています。

あとはそれを取得するだけです。

< 実装方法 >

プレイヤー位置のマップ情報を取得して、ゴールならゴールする

成果物


f:id:ishiyamacocoa:20170622235041p:plain 右上:ミニマップ   ミニマップの下:視界   左:擬似3D描画

f:id:ishiyamacocoa:20170623011253p:plain ゴールしました。

おまけ


触れていませんでしたが、通路も描画しています。

中央、中央奥にかけて、真っ暗じゃない床を描画しておくと、方向感覚が狂いにくいです(ないとわかりづらい)

これでウィザードリィも作れるぞーと思っていますが、特に作る予定はない。

知的好奇心だけで実装しちゃうお茶目なロックでした。

ありがとうございました。

以下に拙いですが、ソースコードを載せておきます。

  • Dungeon3D.cpp
  • Dungeon3D.h

の二つです。

改めて、ありがとうございました。

Dungeon3D.cpp


gist08766e3ec20e70c56dd91de28944df00

OSS Gate WorkshopをやってOSS開発者率が42.8%になった

5/10, 5/12 の2日間で社内向けOSS Gate Workshop (Closed Kyoto) を開催しました。

OSS Gateとは東京・札幌・大阪で開催されているOSS開発者を増やすための取り組みです。詳しくはこちらの公式ページを御覧ください。そのWorkshopを社内向けに開催しました。

筆者がOss Gate Workshopw@大坂(2017-02-22)へ参加した時の様子を勉強会にて発表したところ、若手メンバーを中心に興味がありそうだったので、社内向けで開催する運びとなりました。

開催後には社員メンバーのOSS開発参加者率が42.8%(3/7)となり、OSS開発参加企業として大きな1歩を踏み出しました。アルバイトや関係者を都合よく含めると60%(6/10)となって過半数を超える結果となりました。

Workshopの流れ

通常のWorkshopは5〜6時間のスケジュールで構成されていますが、就業後に実施するため2日に分けての開催となりました。

1日目ではOSS GateおよびWorkshopの説明を行ない、OSSを動かして作業ログを取り、ミニふりかえりを実施しました。 2日目にOSSへのフィードバックを実際に行い、Workshopのふりかえりを行って終了しました。

両日とも2時間半で構成しました。

1日目の様子

1日目の参加者は6名で、Skype越しに東京からも2名参加してくれました。

アイスブレイクでしっかりと声を出しましょう。

f:id:masayuki14:20170510192538j:plain

作業ログを取るためのデモの様子。

f:id:masayuki14:20170510195524j:plain

OSSを選定後、実際に動かしてみます。

f:id:masayuki14:20170510191852j:plain

f:id:masayuki14:20170510204144j:plain

最後にミニふりかえりでフィードバックポイントを探して1日目は終了です。

2日目の様子

2日目の参加者は4名で、連続参加出来たのはそのうちの2名でした。 1日目のミニふりかえりで見つかったフィードバックポイントを実際にOSSにフィードバックするのが2日目の目標です。 2日目からの参加者2人は、後追いでOSSを動かして作業ログを取っていました。

Issue作成をする役員を学生アルバイトがサポートします。普段と立場が逆転しています。

f:id:masayuki14:20170512202544j:plain

後追いの2人もIssue起票のために議論を交わします。

f:id:masayuki14:20170512202528j:plain

最終的には4名全員がIssueを起票し、2名がPullRequestを行うという結果となりました。

よかったこと

アルバイトメンバーがサポーターとして役員のフィードバック作業を手伝うという、珍しい光景がみられました。社内開催のため和やかな雰囲気で開催できました。就業後の遅い時間に開催してるので、経費でのピザが手配されるなどのサポートもありました。全体的に満足してもらえたようです。

そして、OSS開発の参加者が増えたことが何よりの成果です。

困ったこと

初日にビギナー6人に対しサポーターが2人だったので、十分にサポートができませんでした。そのためOSSの選定に時間がかかってしまったり、フィードバックしづらいOSSを選んでしまったメンバーがいました。また仕事の都合で前半のみ、後半のみなど全てに参加できない人がいたことが残念でした。

皆の成果

それぞれが選んだOSSにIssueやPullRequestの提出を行ないました。

皆の感想

Issueを提出したりPullRequestを出してMergeされたりと、 参加者それぞれの成果が見える形で残ることで満足してもらえたようです。今後は本家のWorkshopでもサポーターとして活躍してもらえそうです。

進行をやってみて

筆者が進行役を務めての個人的な感想です。ちょうど参加したWorkshopの動画が公開されていたので進行方法についてかなり参考になりました。準備が不十分だった自覚があったので不安はありましたが、参加者には楽しんでもらい満足してもらえたので嬉しい限りです。

OSS Gate 運営の方のサポートも特に受けずに開催できたのでWorkshopとしての完成度はとても高くてすごいなと思いました。OSS Gate 運営のメンバーに参加して京都での開催を進めていきたいと思います。

今回の開催にあたっての運営面については個人のブログに書きたいと思います。

masayuki14.hatenablog.com

Seleniumというブラウザ操作を自動でやってくれるツールの紹介

どうも、一人暮らし歴10ヶ月ようやく電子レンジを買いました、いまもんです。
興奮のあまり牛乳を600Wで30秒チンして新品の電子レンジ内を牛乳まみれにしてしまいました。
次はゆで卵でリベンジしてやろうと思います。

さて、面白いツール見つけたのでご紹介します。

Seleniumとは

f:id:spoo-imamoto:20161124042020p:plain

Seleniumはクロスブラウザ、クロスプラットフォームのUIテストツールです。 ブラウザに表示される要素を操作し、取得して想定されうる状態になっているかをテストできます。

macで環境構築しよう

今回はrubyを使うのでgemでinstall かつchromeで動かしたいのでドライバをDLしておきます。

seleniumをinstallする gem install selenium-webdriver

chromedriverをDL https://sites.google.com/a/chromium.org/chromedriver/downloads

DLしてきたchromedriverを/usr/local/bin以下に配置

さあこれで準備が整いました、seleniumを動かしてみましょう。

なにができるのか

Selenium WebDriver — Selenium Documentation

(若干読みづらい)ドキュメントを見てみましょう。 主に要素を検索して中身を書き換えたりクリックさせたりという感じですね、javascriptも実行できるのでn番目の子要素を取得なども可能です!

サンプル

require "selenium-webdriver"

# chrome用のドライバを使う
driver = Selenium::WebDriver.for :chrome

sleep 5 #目視確認用に5秒待つ

# Googleにアクセス
driver.navigate.to "http://google.com"

# `q`というnameを持つ要素を取得
element = driver.find_element(:name, 'q')

# `spookies`という文字を、上記で取得したinput要素に入力
element.send_keys "spookies"

# submitを実行する(つまり検索する)
element.submit

# 表示されたページのタイトルをコンソールに出力
puts driver.title

sleep 5 #目視確認用に5秒待つ

# テストを終了する(ブラウザを終了させる)
driver.quit

参考にした記事 qiita.com

大体こんな感じです。 わかりやすくていいですね。

ちなみにspookiesと検索していますが、titleはgoogleのままなのでgoogleと出力されます。 実行したら裏でChromeが立ち上がるので切り替えて目視確認してみてください。 いい使い道探してます!アイデアあったらどんどん記事にしてください!

twilioとAWS Lambdaで自分に電話をかけてみた

こんにちは。

最近体重の増加が止まりません。秋ですねー。 逆に電話の着信が減った気がします。 前者を治す方法は皆目検討がつきませんが、後者なら解決できそうです。

そこで、 「slackでコマンド命令を与えると、自分の電話が鳴ってカラオケに誘われる。」 ってのをやってみたいと思います。

twilio

twilioとは「クラウド通信企業」であり、プログラムを使って簡単に電話がかけられるAPIを提供している会社です。 本社はアメリカにあり、日本ではKDDIウェブコミュニケーションズさんが代理店としてサービスを提供しています。

f:id:spookies-nishimura:20161123041537p:plain

お試し期間ならクレジットカード登録もいらないので、気軽に試せますね。

API利用するにあたって必要なもの

  1. twilioアカウント登録
  2. 050電話番号の取得
    • この番号からかかってくるようになります。(お試しでも取得できました)
  3. 認証用AccessTokenの確認
    • コンソールダッシュボードに表示されているのでコピっときます。

サンプルプログラムを試す

ドキュメントもしっかり整備されてます。

今回は、AWSのLambdaにプログラムを置きたかったので、Nodeで書くことにします。 https://jp.twilio.com/docs/quickstart/node/programmable-voice
↑に記載された通りに書き換えてローカルPC上で動かすだけで、電話がかかってきました。

書き換えたのは以下だけ

  • accountSid
  • authToken
  • to
  • from

実に簡単。

音声レスポンス命令の作成とアップロード

電話がかかってきた際に、特定の文言を喋らせたり、音楽データを流したり、通話を録音したりすることができます。 それを制御するのが、TWIMLと呼ばれるXMLです。

<Say>: 発信者にテキストを読み上げます。
<Play>: 発信者に音声ファイルを再生します。
<Record>: 通話や通話の一部を録音します。
<Gather>: 発信者がダイヤルした数字を取得します。
<Dial>: 相手の電話番号またはカンファレンスに電話をかけ、発信者を接続します。
<Sms>: 通話中に SMS メッセージを送信します。

自分で設定した音声レスポンスを使う場合はアップグレードが必要みたいです。 管理画面から、クレジットを登録して、2000円だけ入れてみました。

f:id:spookies-nishimura:20161123041637p:plain

今回は カラオケに誘われる 為に、以下の内容のxmlファイルをサーバ(amazon S3)にアップロードし、公開設定を行いました。

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="alice">let's go karaoke</Say>
</Response>

プログラム書き換え

xmlのアップロードが完了したので先程のプログラム内の url 箇所を S3にアップしたxmlの公開urlに書き換えます。

client.calls.create({
    url: 'https://xxxxxx.xxxxxx/xxxxxx.xml',

Debugger

プログラムを動かしたら電話はかかってきたのですが、 「アプリケーションエラーが発生しました」とアナウンスされました。

おやおや?と悩んでいたら、twilioの管理画面にDebugger機能があったので見てみました。

f:id:spookies-nishimura:20161123041748p:plain

f:id:spookies-nishimura:20161123041801p:plain

むむ?POSTでアクセスに行っているではないか・・。 デフォルトではこのような挙動になるようです。

プログラムを修正して、methodにGETを指定します。

client.calls.create({
    url: 'https://xxxxxx.xxxxxx/xxxxxx.xml',
    method: 'GET',
    ...

これで無事に読み上げてくれました。

AWS Lambdaにプログラムを配置

Lambdaは最近よく聞くサーバレスアーキテクチャ。 リクエスト待受するために常にサーバを立てておくのではなく、必要な時に呼び出されて実行プログラムが起動する仕組み。イベントドリブンな感じ。

今回は、

  • API gateway
  • Lambda

を組み合わせ、作成したURLが叩かれた時に先程のプログラムが動くようにしました。

Lambda関数

Lambda関数として動かす為に、先程のプログラムに handler の関数名を指定します。

exports.handler = function(event, context) {
    // プログラム
    ...
}

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-prog-model-handler.html

NodeプロジェクトとしてZip圧縮

Lambdaでは、node_modulesも含めてアップする必要があるため、zipに固めます。

$ zip -r index.zip index.js node_modules

Lambdaにアップロード

  1. Select blueprint templateのようなものですかね。今回はAPI Gatewayと連携するので「api-gateway-authorizer-nodejs」を選びました

  2. Configure triggers API Gatewayを選択

  3. Configure function

Name: callme
Runtime: Node.js 4.3
Code Entry Type: Upload a .ZIP file
    先程固めたzipをアップロード
Hander: index.hander // 先程のプログラム(index.js)をhandlerの名でexportしたので。ファイル名やhandler名が異なってるとエラーになるので注意。
Role: create new role from template
Role Name: test
残りはデフォルト

API Gateway

  1. APIを作成して、GETをLambdaで作成したcallmeファンクションと紐付け
  2. APIのデプロイで、公開(stageは新規作成) するとURLが手に入ります!!

slackのコマンドでプログラムを呼び出そう

さて、呼び出しURLが決まったので、これを直接呼び出してもいいんですが、 どうせならSlackから特定のコマンドを入力した時に、呼び出すようにしてみましょう。

slackのAppDirectoryで Slash Commands を選択。

f:id:spookies-nishimura:20161123042025p:plain

叩いてみたら 電話かかってきましたー

まとめ

少し今更感もありますが、twilioもLambdaも興味あったけど使ったことがなかったので遊んでみました。

サービスでアカウント登録後に電話がかかってきて、音声で流れてきたコードを入力して完了という流れがたまにありますが、twilio使ってるんですかね?

コールセンターや受付サービスなどたくさんの事例があるみたいです。
サーバ監視で障害発生したら電話で叩き起こすってのもよくありですが、いいですね。
遅刻メンバーを叩き起こす・・。

さて、寒くなってきましたが、皆さん風邪にはお気をつけください。
では一人カラオケへ行こうかな。いやジムですかね。
それでは、失礼します。

Three.js を用いてインタラクティブなコンテンツを作ってみよう

 こんにちは、モリタです。

最近、Web上で3Dグラフィックを描画できるjsライブラリであるThree.jsに魅了されています。

f:id:moritanian:20161014213058p:plain

three.js では、以下のようにシーンオブジェクトにライトオブジェクト、ボックスオブジェクトなどを追加することで3D空間をつくりだすことができます。

$(function(){
    // create scene
    var scene = new THREE.Scene();
    // create camera
    var width  = 600;
    var height = 400;
    var fov    = 60;
    var aspect = width / height;
    var near   = 1;
    var far    = 1000;
    var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );

    // マウスでうごかせるようにする
    var controls = new THREE.OrbitControls(camera);
    
    // set renderrer
    camera.position.set( 0, 0, 50 );
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize( width, height );
    $("body").append( renderer.domElement );
    
    // add light
    var directionalLight = new THREE.DirectionalLight( 0xffffff );
    directionalLight.position.set( 0, 0.7, 0.7 );
    scene.add( directionalLight );

    // create box
    var geometry = new THREE.CubeGeometry( size_x, size_y, size_x);
    var material = new THREE.MeshPhongMaterial( { color : Math.random() * 0xffffff } );
    var mesh = new THREE.Mesh( geometry, material );
    mesh.position.set(pos_x,pos_y,0);
    scene.add( mesh );
        
    // rendering
    controls.update(); 
    renderer.render( scene, camera );

    // オブジェクトを回転させる
    ( function renderLoop () {
    requestAnimationFrame( renderLoop );
     mesh.rotation.set(
          0,
          mesh.rotation.y + .008,
          mesh.rotation.z + .008
        );
    renderer.render( scene, camera );
  } )();
});

three.jsの公式サイト には素晴らしいデモが沢山紹介されています。 早速いくつか紹介してみましょう

Ellie Goulding – Lights

f:id:moritanian:20161014173126p:plain

イギリスのシンガーソングライター、エリー・ゴールディングの曲に合わせて、光の球が輝きます。 光はユーザのクリックに反応し、インタラクティブなミュージックライブ体験ができます。

WorldPopulation

f:id:moritanian:20161014173423p:plain

年別に世界の人口密度が視覚的にわかるデモです。地球をスクロールすることで回転することができます。 学術的なコンテンツにもこういった技術が多用されていく予感がします。

The Boat

f:id:moritanian:20161014174810p:plain

スクロールすると背景のアニメージョンとともに、イラストと文章が表示されます。インタラクティブな「動くマンガ」といった感じです。新しいwebマンガのスタイルになりそうな予感がします。

The Fallen of World War Ⅱ

f:id:moritanian:20161014180618p:plain

通常の動画の中にインタラクティブタイムというものが設けられており、この間はユーザがグラフを選択して、詳細を見ることができます。 内部でどう処理されているのか気になります!

3D図書館

自分でもインタラクティブな3Dコンテンツを作ってみよう、ということで、3D図書館を作ってみました!

f:id:moritanian:20161014185339p:plain

外部のwebAPI から今月のマンガの新刊を取得して、表示するようにしています。 本にカーソルを合わせると、本が飛び出し詳細情報が表示され、クリックするとアマゾンの商品ページに飛ぶようにしました。 たまに商品画像が取得できないものがあり、この場合、デフォルトの画像を表示するようにしたかったのですが、うまい方法が見つかっていません。 画像サイズが0かどうか調べればよさそうですが、画像を取得するのにタイムラグがあるため、画像を張り付けた平面オブジェクトを作成し、画像のロードが完了したタイミングで画像サイズを調べるコールバックを設定する、なんてまわりくどいやり方しか思いつきません。どなたかいい方法ご存じないですかね?

さらに最近のVRブームのもと、webVRなんてのも登場しています。webにVRを持ち出す必要性があるのかな、という気もしますが、箱スコなどスマホ向けのVRコンテンツに利用価値があるみたいです。URLだけでコンテンツを共有できれば手軽です。Three.js のサンプルにはwebVRに対応したサンプルもいくつかあるので、今後試したいなと考えています。

以上、Three.js の紹介でした!