Moddableで図形描画をしてみよう!(Poco, Outline)
本記事では、Moddableにて図形描画を行う方法を解説します。
入門として、「図形描画を扱うクラスを知る、2D座標空間の考えかたを知る」を目的としています!
やること
- Pocoを用いた図形描画
- Outlineを用いた図形描画
- 図形を組み合わせてスタックチャンのお顔を描画
スタックチャンはししかわが開発、公開している、 手乗りサイズのスーパーカワイイコミュニケーションロボットです。 作品ページ:https://github.com/stack-chan/stack-chan
コード
もし進めるなかで詰まったなどあれば参照ください
modのコード
import Poco from 'commodetto/Poco'
import { Outline } from 'commodetto/outline'
const poco = new Poco(screen)
const white = poco.makeColor(255, 255, 255)
const black = poco.makeColor(0, 0, 0)
const red = poco.makeColor(255, 0, 0)
export function onLaunch() {}
const EYE_X_OFFSET = 60
const EYE_Y_OFFSET = 20
const EYE_RADIUS = 10
const EYE_COLOR = black
function drawEyes(poco) {
// 目のアウトラインを作成
const path = new Outline.CanvasPath()
path.arc(0, 0, EYE_RADIUS, 0, 2 * Math.PI)
const outline = Outline.fill(path)
// 原点を中心に移動
poco.origin(poco.width / 2, poco.height / 2)
// 右目
poco.blendOutline(EYE_COLOR, 255, outline, poco.width / 2 + EYE_X_OFFSET, poco.height / 2 - EYE_Y_OFFSET)
// 左目
poco.blendOutline(EYE_COLOR, 255, outline, poco.width / 2 - EYE_X_OFFSET, poco.height / 2 - EYE_Y_OFFSET)
// 原点を戻す
poco.origin()
}
const MOUTH_Y_OFFSET = 20
const MOUTH_WIDTH = 90
const MOUTH_HEIGHT = 10
const MOUTH_COLOR = black
function drawMouth(poco) {
poco.origin(poco.width / 2, poco.height / 2)
poco.fillRectangle(
MOUTH_COLOR,
- MOUTH_WIDTH / 2,
MOUTH_Y_OFFSET,
MOUTH_WIDTH,
MOUTH_HEIGHT
)
poco.origin()
}
export function onRobotCreated(robot) {
robot.pause() // HACK: 顔と動きの更新を止めておく
poco.begin()
poco.fillRectangle(white, 0, 0, poco.width, poco.height)
drawEyes(poco)
drawMouth(poco)
poco.end()
}
Poco
Moddableで図形を描画する方法の一つとして、Pocoがあります。
Pocoはざっくりいうと、長方形を描画したり、テキストを描画したり、JPEG画像を扱ったり出来ます。
ドキュメントではサンプル画像が豊富にあるので、眺めてみるとイメージつくかと思います。
準備
本記事では、スタックチャンの開発環境を土台にmodとしてPocoを動かしています。
スタックチャン開発環境で動かす準備
まずはmodに必要なファイルを作成します
stack-chan/
└── firmware/
└── mods/
└── poco_study/
├── manifest.json
└── mod.js
{
"include": [
"$(MODDABLE)/examples/manifest_mod.json"
],
"modules": {
"*": "./mod"
}
}
import Poco from 'commodetto/Poco'
const poco = new Poco(screen)
export function onLaunch() {}
export function onRobotCreated(robot) {
robot.pause() // HACK: 顔と動きの更新を止めておく
poco.begin()
// ここに処理を記述していく
poco.end()
}
modのデバッグは下記コマンドで実行しています。
$ cd firmware
$ npm run debug --target=mac/m5stack
$ npm run mod --target=mac/m5stack ./mods/poco_work/manifest.json
座標空間を把握する
まずは座標空間を知ることから始めます。
- 左上が
(0, 0)
- x座標は、正の数であれば右方向、負の数であれば左方向
- y座標は、正の数であれば下方向、負の数であれば上方向
また、Poco経由で画面の横幅、縦幅を取得することが出来ます。
trace(`width: ${poco.width}, height: ${poco.height}`)
// width: 320, height: 240 ※M5Stack
これを利用して、画面の中心座標は(poco.width/2, poco.height/2)
で取得することが出来ます。
長方形の描画
長方形の描画にはfillRectangle
を用います。
引数の仕様はfillRectangle(color, x, y, width, height)
です。
poco.begin()
// 画面全体を覆う白い長方形を描画
poco.fillRectangle(white, 0, 0, poco.width, poco.height)
// 黒い長方形を描画
// (100, 100) から幅150, 高さ50の長方形を描画
poco.fillRectangle(black, 100, 100, 150, 50)
poco.end()
Outline
Moddableで図形を描画するもうひとつの方法として、Outlineがあります。
Outlineはざっくりいうと、パスで図形を作成する、Canvas 2Dっぽいことが出来ます
こちらもドキュメントではサンプル画像が豊富にあるので、眺めてみるとイメージつくかと思います。
円の描画
若干癖のある描画方法です。ざっくりいうと、Outlineで図形を定義して、Pocoで描画するイメージです。
- 円のパスを作成
- outlineを作成
- pocoを使用して描画
import Poco from 'commodetto/Poco'
import { Outline } from 'commodetto/outline'
const poco = new Poco(screen)
const white = poco.makeColor(255, 255, 255)
const black = poco.makeColor(0, 0, 0)
export function onLaunch() {}
export function onRobotCreated(robot) {
robot.pause() // HACK: 顔と動きの更新を止めておく
poco.begin()
// 画面全体を覆う白い長方形を描画
poco.fillRectangle(white, 0, 0, poco.width, poco.height)
// 中心に黒い円を描画
// 1. パスを作成
const path = new Outline.CanvasPath()
path.arc(0, 0, 50, 0, 2 * Math.PI)
// 2. outlineを作成
const outline = Outline.stroke(path) // 塗りつぶし
// const outline = Outline.stroke(path) // ストローク
// 3. poco.blendOutlineで描画
poco.blendOutline(black, 255, outline, poco.width / 2, poco.height / 2)
poco.end()
}
ちなみにストロークを選択すると塗りつぶしなしで描画されます。
スタックチャンのお顔を描画してみる
ここまでで、長方形と円を描画できるようになりました。
それでは、図形を組み合わせて、スタックチャンのお顔を描画してみましょう。
左右の目を描画
下記の図のイメージで描画します。
個人的には画面中央を基準に考えると計算が楽になる印象です。
処理としては、poco.origin
を用いて原点を画面中央にずらしています。
画面中央を基準にそれぞれ、
- 右目はx座標に60、y座標に-20移動した位置に描画します
- 左目はx座標に-60、y座標に-20移動した位置に描画します
const EYE_X_OFFSET = 60
const EYE_Y_OFFSET = 20
const EYE_RADIUS = 10
const EYE_COLOR = black
function drawEyes(poco) {
// 目のアウトラインを作成
const path = new Outline.CanvasPath()
path.arc(0, 0, EYE_RADIUS, 0, 2 * Math.PI)
const outline = Outline.fill(path)
// 原点を中心に移動
poco.origin(poco.width / 2, poco.height / 2)
// 右目
poco.blendOutline(EYE_COLOR, 255, outline, poco.width / 2 + EYE_X_OFFSET, poco.height / 2 - EYE_Y_OFFSET)
// 左目
poco.blendOutline(EYE_COLOR, 255, outline, poco.width / 2 - EYE_X_OFFSET, poco.height / 2 - EYE_Y_OFFSET)
// 原点を戻す
poco.origin()
}
この関数をonRobotCreated
で呼び出すと、スタックチャンの目が描画されます。
口を描画
下記の図のイメージで描画します。
画面中央を基準にx座標に口の長さ/2
、y座標に20移動した位置に描画します。
const MOUTH_Y_OFFSET = 20
const MOUTH_WIDTH = 90
const MOUTH_HEIGHT = 10
const MOUTH_COLOR = black
function drawMouth(poco) {
poco.origin(poco.width / 2, poco.height / 2)
poco.fillRectangle(
MOUTH_COLOR,
- MOUTH_WIDTH / 2,
MOUTH_Y_OFFSET,
MOUTH_WIDTH,
MOUTH_HEIGHT
)
poco.origin()
}
この関数をonRobotCreated
で呼び出すと、スタックチャンの口が描画されます。
スコブル カワイイ!!
振り返り
Moddableでの図形描画、座標空間の考え方のイメージが少しでも掴めれば幸いです。
もっと色々知りたい方へ
- 実践Moddable JavaScriptではじめるIoTアプリケーション:幅広くModdableについて学べるオススメ入門書です!
-
オリジナルのstack-chanソースコード:本記事で紹介した
Poco
Outline
はオリジナル実装でも使われています。ソースコード検索で探してみると勉強になるかと思います! -
Outline.SVGPath
:SVGを用いると、図形の組み合わせだけでは難しい複雑なパスの描画が可能になります!
Discussion