chibi929's blog

その一歩先へ。ちびです!猫の名前です!ドラゴンボール好き!純粋なサイヤ人のように生きたいと思っています!IT技術で少しでも多くの人が笑顔になってくれたらいいなと。

ブラウザで 3D モデルを作成できる Tinkercad を使ってみた

Tinkercad は AUDODESK 製の 3D モデリングツール。ブラウザでポチポチするだけで 3D モデルが作れちゃうやつです。 チュートリアルも充実していて、使いやすい印象です。

f:id:chibi929:20200317091518p:plain
Tinkercad_スターター

3D モデリングは初めてなので、まずは、スターターからやろうかなと思いつつ、ほとんど直感的に出来るのでハマったところだけ。

スターターには7種類のチュートリアルがありました。

  • Place It
  • View It
  • Move It
  • Rotate It
  • Size It
  • Group It
  • Align It

View It (1/4)

f:id:chibi929:20200317092259p:plain
Tinkercad_ViewIt_1

単純にオブジェクトを回転させ、いろいろな方向から見るだけですが、直感的に空間をグリグリ動かせてしまうので説明が言いたいことがわかっていませんでした。

  1. Just left-click and drag anywhere on the ViewCube and see how it changes the point of view.
    (左クリックしながらグリグリすれば視点が変わるよ) と読んだ。

にも関わらず、作業台のある空間を直感的に 右クリック しながらグリグリして視点を変更してしまったのだ。そのまま進めると View It (3/4) でおかしな問題にぶつかる。

f:id:chibi929:20200317093434p:plain
Tinckercad_ViewIt_3

Press and hold the right mouse button while moving your mouse to practice rotating your view of the design.
(右クリックを押したままグリグリすればビューを回転できるよ) と読んだ。

あれ?さっきやったよな?このチュートリアル何か間違っているのかな? と思い、そのまま進める。 間違っているのは自分の脳内変換だとは気づかずに。。。

後から気付いた話ですが、以下の画像の通り、メインビューの左上にある箱を 左クリック でグリグリすることが View It (1/4) の練習だったようです。

f:id:chibi929:20200317092928p:plain
Tinkercad_ViewIt_1_2

「obniz x LINE Things」ハンズオンのサポートスタッフをしてきた話

linedevelopercommunity.connpass.com

こちらで obniz の木戸さんのサポートをしてきました!

f:id:chibi929:20190731194246j:plain

講師

木戸先生

ハンズオンの内容

LINE Things 名物、無限 PUSH 通知を obniz から実行する

流れ

  1. 事前確認
    • obniz のバージョン確認・アップデート
    • LINE のバージョン確認・アップデート
  2. BOT 作成
    • Messaging API チャネル作成
    • LIFF の設定
    • LINE Things のシナリオ作成
  3. repl.io を用いて BOT サーバーを起動
  4. ペアリング

サポートした各種トラブル

  • repl.io の使い方
  • LINE Things シナリオの作り方
  • repl.io のコピーする URL を間違えていた
  • 連携デバイスが表示できない (LINE Things のバグの可能性も...と中の人が仰っていました)
    • 対処方法
      • Bluetooth の ON/OFF
      • 端末の再起動、デバイスの再起動
      • LINE 自体の再起動
      • LINE Things 画面での過去の連携デバイス全部削除
      • Bluetooth を OFF にしたまま LINE Things 画面に行って ON にする
      • など、色々なパターンで回避方法があるようです。

その他

今回は、入り口の前に立って参加者をご案内しました。
また、同じフロアの別会場で別のイベントが開催されていたため、
そちらのご案内もちらほらしました。

バイス連携が中々上手く行かず、ハマっている方々も多数いらっしゃいましたが、 なんとか突破して動いたときは感動です。

「TypeScript x Clova」ハンズオンのサポートスタッフをしてきた話

f:id:chibi929:20190729093004j:plain

linedevelopercommunity.connpass.com

こちらで講師のみそさんのサポートをしてきました。

講師

みそ先生

ハンズオンの内容

JavaScript で実装されている公式のサンプルプログラムであるサンプルダイスを CEK_SDK 版で構築し、 最終的に TypeScript へ置き換えていくという流れとなっています。
そして TypeScript はいいぞ!っていうお話をするハンズオンですw

流れ

  1. サンプルダイスの JavaScript 版で CEK 上でテストができるところまで作業する
  2. TypeScript の説明と環境構築
  3. 【手順1】でやった JavaScript 版を TypeScript 版へ置き換えていく

サポートとしてやったこと

作業に詰まってしまって、資料より遅れてしまっている方々のサポートだったり、気づいたら(変なところを消してしまって)エラーが大量発生していた方のサポートだったりをしました。
みそさんの資料がとても良く WindowsMac の両コマンドが記載されているため、コマンド関連で悩む方は少なかったように思いました。

最後に

JavaScript は実行してみないとエラーに気づかないことも多いですが、TypeScript では型定義があるとこによって事前にエラーに気づくことができます。(存在しないプロパティにアクセスしていたり等)

小さなプロジェクトでは TypeScript の恩恵は少ないですが、
大きくなってくると型定義や型推論、そして古い構文へのトランスパイルなど、
とても助かることが多くなるので、皆さんが型好きになってくれれば嬉しいなと!

「M5StickC + LINE Things + Amazon Connect 連携ハンズオン」に参加してきた

linedevelopercommunity.connpass.com

に参加してきました。
IoT よくわからないので Arduino IDE 初体験です。

講師

がおまる先生

流れ

  1. Amazon Connect で問い合わせフローを作る
  2. Lambda 関数・API Gateway を作る
  3. LINE Bot (LIFF) を作る
  4. LINE Things を設定する
  5. M5StickC にコードを書きこむ

完成システム構成図

f:id:chibi929:20190725091506p:plain

だいたいこんなイメージだろうか?

1. Amazon Connect で問い合わせフローを作る

Amazon Connect を使って、コールセンターフローを作る。
フロー自体は Node-RED のようにブロックプログラミングで作れる。

2. Lambda 関数・API Gateway を作る

API Gateway 経由で実行する Lambda 関数を作る。
Lambda では、Amazon Connect の API をキックするだけの簡単な Lambda。

Amazon Connect の電話番号や各種 ID などを環境変数に設定して完了。

3. LINE Bot (LIFF) を作る

LINE Things を準備するために LINE Bot を作って LIFF の設定を行う。
この辺は LINE Developers のページでポチポチっと。

4. LINE Things を設定する

LINE Bot (LIFF) から LINE Things の サービスUUID を作る。
この辺はイマイチ理解できていないが本来であれば cURL 等で叩いて取得する。
今回はのびすけさんのツールを使って取得

5. M5StickC にコードを書きこむ

Arduino IDE を開いて、M5StickC にコードを書きこむ。
すると「LINE アプリ」の「LINE Things」に【手順.4】で作った「LINE Things デバイス」が表示される。
これをペアリングすることで「M5StickC」から「LINE Things」経由で「API Gateway」に到達することができる。
という感じっぽい

実行!

f:id:chibi929:20190725091656j:plain

そして大きい方のボタンを押すと・・・ Amazon Connect 経由で電話がかかってきて、カウント値を教えてくれます。

トラブルシューティング

M5StickC にコードを書きこんでも何も表示されない

Arduino IDE で初書き込みだー!と喜んでいたら、何も表示されない。。。
初書き込みまさかの失敗!?
本当ならボタンを押せばカウントアップされるはず。。。

どうやら、稀に良くあるらしいとのこと。
そんな時は一度 Hello World で刺激を与えてみて!ということだった。

ということで、とりあえず Hello World を書き込み。
Hello World は出る。

f:id:chibi929:20190725093629j:plain

この後、再度、メインコードを書きこむことで、無事に完了。
どうやら、刺激が足りなかったらしい。

obniz ファン meetup vol.2 に登壇しました

obniz-fan.connpass.com

にて、登壇してきました。

経緯

chibi929.hatenablog.com

この記事です。
先日、obniz にプルリクを出したのがキッカケです。

そして T シャツをいただきましたので、これは着て行くしかない。
ただ着て一般参加で座っていても格好悪いだろうと、登壇側で立つことにしました。

登壇を決意するまで

プルリクを出した頃、丁度 obniz ファン というグループを見つけました。そこで、なんと meetup vol.2 が開催されるという情報が、しかもまだ登壇者募集中、あと2名残ってる!!

しかし、私は人前で喋るのが苦手です。足は震えるし声は震えるし、とても怖い。ただ、LT 等に登壇する際には とりあえず手を挙げろ!(参加表明しろ) と良く聞きます。さて、悩む。。。 T シャツを着て立ちたいが、果たして話せるのだろうか?しかもいつもの LT よりも長い 10 分の LT。登壇したいけど怖いどうしよう。。。他の登壇者は戦車作るとか言ってるし怖ぇ。。。そんな感じで登壇が決定してもないのに緊張して寝れない。

とりあえずポチる なんて 勇気 は出ず、試しにマインドマップを使って、自分の話したいことはなんだろうか?というのを挙げまくってみた。うーーん。内容が薄い。スライド作りも苦手だし、こんなんで10分持つのだろうか?そんなこんなで2〜3日過ぎてしまい「一般枠満員+登壇枠はまだ1名ある」という情報が流れてくる。

あ、これはやばい、せっかくのチャンスが無くなるかもしれない。グループのコメント欄に登壇表明の文字列を打ち始めた。そして、送信ボタンで再び止まり、1回閉じる。再び とりあえず手を挙げろ という話を思い出し、開く。

そして、もう目を瞑って勢いよくポチる!

そんなこんなで登壇

登壇資料はこちら

speakerdeck.com

動画はこちら

www.youtube.com

登壇した感想

  • メッチャ楽しい!
  • 言いたいこと言えた!
  • 皆さん優しい!

聞いてくださった優しい皆さまありがとうございました。

準備はとても大変だったけど最初のマインドマップからアウトラインを作って「一番言いたいこと」の為の「前振り」や「流れ」を作ることができました。

まとめ

  • 一番緊張したのはポチる前
    • とりあえずポチる の気持ちがわかったかもしれない
  • リハで時間オーバーして内容削るの大変
    • 社内 LT の準備でもそうだったけど黙読だと早口だし。。。
  • やったらやったで楽しい!とても良い経験になった!

obniz にプルリクを出した話

f:id:chibi929:20190605182221p:plain

先日、obniz にプルリクを出しました。
https://github.com/obniz/obniz/pull/172

そしてマージされ、リリースされました!
https://github.com/obniz/obniz/releases/tag/v2.1.0

本人のスペック

IoT は全然できません。
obniz だからこそLチカやモーターが動かせているようなものです。。。
アノードやカソードも obniz で初めて知りました。
(正確にいうとデジモンのゲームで単語だけは聞いたことありました。)

ずっと C++Java(Android) を触っていて、
ここ最近 Web アプリケーション開発に携わるようになり、
Frontend, Backend 等の知識がなんとなく身について来た感じです。

※ちなみにスマホアプリ開発時代は API や Cloud も全くイメージ沸かなかった。。。

何故、プルリクを出そうと思ったか

簡潔にいうと、今までの経歴が C/C++, Java(Android) と来て、
型の無い JavaScript を気持ち悪いと思いつつ、
Web アプリケーション開発で TypeScript を触って JavaScript と少し仲良しになった。

でも、TypeScript で書いていると any な型がどうしても辛い。
型を作りたくなる病になるわけです。

そんなこんなでやっぱり型が欲しい!

ハンズオンに参加する際は HTML に直接 JS を書くようなコードを書きますが、
自分でコードを整理する際は、やっぱりファイルを分けたりします。
そして TypeScript 化したり Webpack を導入したり・・・。

obniz は、当初 TypeScript を導入しても any 型のまま扱っていました。
ですが、ソースコードを共有したり、時間が経ってから再び触ったりすると型が欲しくなっちゃうんですよね。

どう対応していたかというと、自分のプロジェクト内に interface を作るだとか hoge.d.ts とか作って、必要最低限のみで any 型を無理矢理キャストして使う感じです。

import * as Obniz from 'obniz';

interface Obniz {
  wired(name: string, options: any): any
}

interface LED {
  on(): void;
  off(): void;
}

const obniz: Obniz = new Obniz('1234-5678');
obniz.onconnect = () => {
  const led: LED = obniz.wired('LED', {anode: 0, cathode: 1});
  led.on();
}

必要分定義して、こんな感じだったりです。
時には index.d.ts とか作ってみたり。

徐々に使用するパーツが増えてくる・・・

IoT には疎いので、ハンズオンで学んだことくらいしか出来ませんが、
百均で「電飾」や「ミニプラレール」を買ってきたりして遊んでいます。
でも HTML で操作するにも API 経由で操作するにもやっぱり TypeScript で書きたい!!

キノコなどの仲間内でも obniz を購入する人が増えたり、
TypeScript を使うようになった人が増え、型定義が無いことが辛みになってくる。

じゃあ、途中まで型定義あるから、
少し定義不足があってもみんなが小さいプルリクをたくさん出せるように
土台だけでも作るか!そんなノリで始めた型定義生活。

型定義と過ごした日々...

一つ目の難関 (new)

トランスパイル後の以下のような形になる定義の仕方...

var Obniz = require('obniz');
var obniz = new Obniz('1234-5678');

試行錯誤を繰り返す。。。

定義1 (NG)

export class Obniz {}

定義が、上記の場合

import * as Obniz from ('obniz');
const obniz = new Obniz.Obniz('1234-5678');

----- トランスパイル後 -----

var Obniz = require("obniz");
var obniz = new Obniz.Obniz('1234-5678');

となってしまうので違う。
もしくは、

import { Obniz } from 'obniz';
const obniz = new Obniz('1234-5678');

----- トランスパイル後 -----

var obniz_1 = require("obniz");
var obniz = new obniz_1.Obniz('1234-5678');

となってしまって、違う。。。

定義2 (NG)

export interface ObnizStatic {
  hello(): void;
}

declare const Obniz: ObnizStatic;

export default Obniz;

axios を真似てこんな感じの定義だと、

import Obniz from 'obniz';
const obniz = new Obniz('1234-5678');  // new できないよエラー

定義3 (OK)

そういえば、Node で Error を作る時に、
new Error() するし、変わった型定義だったなーと思い、Error の定義を見てみることに。

interface Error {
    name: string;
    message: string;
    stack?: string;
}

interface ErrorConstructor {
    new(message?: string): Error;
    (message?: string): Error;
    readonly prototype: Error;
}

declare var Error: ErrorConstructor;

declare しているのが varError で型は ErrorConstructor という interface
new の戻り値で Error interface を返している。。。

new はこうやって定義するんだな!

--

そして、Express は以下のように使うなー。。。
と思って定義を見てみることに。

import * as express from 'express';
const app = express();

定義はこんな感じ。
export = e ...! これか...!!

declare function e(): core.Express;
export = e;

そして出来上がったのがこれ。

interface Obniz {}

interface ObnizConstructor {
  new (id: string, options?: ObnizOptions): Obniz;
}
declare const Obniz: ObnizConstructor;

export = Obniz;

二つ目の難関 (wired)

obniz.wired() は、第一引数のパーツ名に合わせて、戻り値の型が変わります。 これは document.createElement() を参考にしました。

createElement<K extends keyof HTMLElementTagNameMap>(tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K];

こちらはそれほど迷わずにクリア!

三つ目の難関 (パーツライブラリ)

私は IoT には疎いので、使うパーツは2~3種類です。
Light 系や Motor 系

その辺はまぁ良かったのですが。。。
パーツライブラリの数が多いこと多いこと。
こんなに充実していたとは。。。

公式パーツライブラリ には 63 種類のパーツが載っています。
開発中なのかパーツライブラリに載っていないパーツも少なからずありました。
とりあえず、公式パーツライブラリに載ってないので wired 的にはコメントアウトしておきましたが。。。

途中で挫折しそうになりながらもなんとか。。。

テスト

とりあえず初めの段階で、手元でフォークしたリポジトリを npm install して動作確認。
ts ファイルで LED や DC Motor を動かしてみる。
そして、最後にも同じことをやる。

自分の持っているパーツではこの程度しかテストできないので、
この時点でプルリクを出そうとも考えたが、最低限全体的に型エラーにならないことを確認したい。

実コードには手を入れていなく、型定義だけなのでユニットテストは違う。
どうしようか考えた結果、パーツライブラリに載っている全てのサンプルコードを ts ファイルで記述して型エラーにならなければ良いだろう。と考えた。

とりあえず test ディレクトリ以下に ts ファイルを作って、
パーツライブラリに載っているサンプルコード全ての ts ファイルに記述した。 型エラーになる項目を検出することをテストとしました。

そして型定義を直す。
ざっと15ファイル程度に定義ミスを発見できました。

そしてプルリクに至る。

最後に

思った以上のパーツが対応していて、そして全てサンプルコードがある。
そして、ほぼ全ての I/F を知った。
IoT が疎い私でもパーツライブラリに載っている配線を真似すればなんでもできそうな気がする!
そんな気持ちになりました。

Unity - ブロック崩しチュートリアルで学んだこと

はじめに

本記事は自分の理解のために雑にまとめたもの。

参考 URL

http://tutorial.unity3d.jp/archive/my-first-unity/
http://baba-s.hatenablog.com/entry/2018/01/16/212800
http://baba-s.hatenablog.com/entry/2018/01/16/212900
http://baba-s.hatenablog.com/entry/2018/01/16/213000

第一回

まずは、各オブジェクトの大きさや配置などの設定。
パドルの操作とボールの制御を行う。

  • Cube を使って豆腐を「直方体」にして壁を作る
    • GameObject > 3D Object > Cube
  • インスペクタビューの Transform を使って位置や大きさの調整
    • Position, Rotation, Scales

カメラ

  • シーンビューのカメラの向きを変更する
    • シーンビューのカメラだけだとゲームビューは変わらない
    • Cube と同じように Transform する

自機

  • 壁と同じく Cube を使って自機となる「直方体」を作成&配置

パドルを操作できるようにする

  • C# Script を追加する
    • Assets > Create > C# Script
public class PaddleController : MonoBehaviour
{
    public float accel = 1000;

    private void Update()
    {
        var force = transform.right * Input.GetAxisRaw("Horizontal") * accel;
        GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
    }
}

// Input.GetAxisRaw("Horizontal") により、
// 水平方向 (Horizontal) のユーザー入力を -1 ~ 1 の正規化された範囲で取得している
// ユーザー入力はキーボードでもジョイスティックでも OK

// ForceMode.Impulse は質量を考慮して動作に反映される
  • C# Script をドラッグ&ドロップで Paddle に設定する
    • Add Component した状態と同じになる。

パドルに物理特性を追加する

  • インスペクタビューから Add Component を押下して Rigidbody を追加する
    • ボール(Sphere)Regidbody という機能を追加した感じ
  • Regidbody のパラメータを設定する

ボール

  • ボールも同じノリで Sphere を選択して作成&配置
    • GameObject > 3D Object > Sphere

ボールに物理特性を追加する

  • インスペクタビューから Add Component を押下して Rigidbody を追加する
    • ボール(Sphere)Regidbody という機能を追加した感じ
  • Regidbody のパラメータを設定する

ボールに初速度を与える

  • C# Script を追加する
    • Assets > Create > C# Script
  • GameObject 起動時に速度を与える
public class BallController : MonoBehaviour
{
    public float speed = 10;
    
    private void Start()
    {
        var force = (transform.forward + transform.right) * speed;
        GetComponent<Rigidbody>().AddForce(force, ForceMode.VelocityChange);
    }
}

// transform.forward はボールの正面 (Z方向) を示す単位ベクトル
// transform.right はボールの右方向 (X方向) を示す単位ベクトル
// これらを足して Speed を掛け合わせることで右斜めのベクトルを得ている
  • C# Script をドラッグ&ドロップで Sphere に設定する
    • Add Component した状態と同じになる

ボールをバウンドさせる

今のままだとボールが跳ね返らない

  • Physic Material をボールに設定する
    • Assets > Create > Physic Material
    • Physic Material は物理パラメータを管理するもの

第二回

ターゲットとなるブロックを作成する

ブロックの作成と配置

  • 壁と同じノリで Cube を追加して Block という名前にする
  • C# ScriptBlock に追加する
public class BlockController : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        Destroy(gameObject);
    }
}

// OnCollisionEnter は、Rigidbody で動作しているオブジェクトが接触したときに呼ばれる処理
// 引数の collision には接触対象オブジェクトが入っている

// Destroy メソッドで gameObject、
// つまりコンポーネントを実行したオブジェクトつまり接触したブロックを削除している

Block を複製する

  • Empty なゲームオブジェクトを作成して Blocks という名前にする
    • GameObject > Create Empty
    • 今回は、ディレクトリ的(グループ化)な扱いに利用する
  • BlocksBlock をドラッグ&ドロップする
  • Block を選択して Ctrl + D で複製
  • 複製した Block それぞれにX座標を設定する
  • Blocks には Z座標を設定して全ての Block を制御する

Blocks を複製する

  • 更に Blocks を複製して5行6列なブロック群を作る
    • 複製した Blocks にはそれぞれZ座標を設定する

ゲームオーバーの実装

  • 下側の壁に C# Script を追加する
public class BottomWallController : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        Destroy(collision.gameObject);
    }
}

// ブロックの時とは異なり、接触対象の gameObject をデストロイしている
// つまり、ボールをデストロイしている

第三回

サウンドを付ける

チュートリアル用の *.unitypackage をインポートする

ダウンロードした sound.unitypackage には、BGM や SE が格納されているので、 Custom Package としてインポートする。

SE の実装

  • C# Script を追加する
public class HitPlaySound : MonoBehaviour
{
    public AudioClip sound;

    private void OnCollisionEnter( Collision collision )
    {
        AudioSource.PlayClipAtPoint( sound, transform.position );
    }
}

// AudioClip は音を登録する変数
// AudioSource.PlayClipAtPoint にて音を再生
// 音の発生源は第二引数で指定

SE を設定する

  • 壁の GameObject を選択して、上記で追加したスクリプトをインスペクタビューの Add Component へドラッグ&ドロップ
  • 先ほどインポートした壁の音となる SE ファイルを C# ScriptAudio Clip へドラッグ&ドロップ

ブロック

  • ブロック全ての GameObject を選択して、同様にスクリプトをインスペクタビューの Add Component へドラッグ&ドロップ
  • 先ほどインポートした壁の音となる SE ファイルを C# ScriptAudio Clip へドラッグ&ドロップ

パドル

  • 上記に同じ

下側の壁

  • 4つの壁のうち下側の壁にはゲームオーバー用の SE を設定する

BGM の設定

  • Main Camera に BGM を設定する
    • 選択状態にして Add ComponentAudio Source を追加する
    • Audio Clip に BGM もドラッグ&ドロップ
    • 音がデカイ場合は Volume で調整

ブロックの色を変更

  • Material を作成する
    • Assets > Create > Material
  • Mterial のカラーを設定する
  • 全てのブロックを選択して上記で作成した Material をインスペクタビューへドラッグ&ドロップ