chapter 07 color - ric.co.jp ·...

54
7.1 Canvas とは ……………………………………………… 170 7.2 四角形の描画 …………………………………………… 174 7.3 パスの作成と描画 ……………………………………… 177 7.4 画像の描画 ……………………………………………… 182 7.5 回転、移動など ………………………………………… 188 7.6 文字の表示 ……………………………………………… 194 7.7 Canvas を使ったリアルタイムゲームの作成 …… 200 7.8 Canvas を使ったノベルシステムの作成 ………… 208 キャンバスに描画する Canvas7 Chapter この章ではCanvasの使い方について説明します。また、 Canvas を使ってリアルタイムゲームと簡単なノベルシステム を作成します。なお、 Canvasのピクセル単位での処理に関し ては別途、 11章のWeb Workers で説明しています。 [編集部註]本章では、カラー表現に関する記述が含まれています。 本文では モノクロ画像で掲載しておりますが、下記 URL のサポートサイトにカラー画像は 掲載しておりますので、詳しくはこちらをご覧下さい。 http://www.ric.co.jp/book/contents/pdfs/897_support.pdf

Upload: others

Post on 01-Nov-2019

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

7.1 Canvasとは ……………………………………………… 170

7.2 四角形の描画 …………………………………………… 174

7.3 パスの作成と描画 ……………………………………… 177

7.4 画像の描画 ………………………………………………182

7.5 回転、移動など …………………………………………188

7.6 文字の表示 ……………………………………………… 194

7.7 Canvasを使ったリアルタイムゲームの作成 ……200

7.8 Canvasを使ったノベルシステムの作成 …………208

キャンバスに描画する [Canvas]

7Chapter

 この章ではCanvasの使い方について説明します。また、Canvasを使ってリアルタイムゲームと簡単なノベルシステムを作成します。なお、Canvasのピクセル単位での処理に関しては別途、11章のWeb Workersで説明しています。

[編集部註]本章では、カラー表現に関する記述が含まれています。本文ではモノクロ画像で掲載しておりますが、下記URLのサポートサイトにカラー画像は掲載しておりますので、詳しくはこちらをご覧下さい。http://www.ric.co.jp/book/contents/pdfs/897_support.pdf

Page 2: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

指定座標にペンを移動moveTo(x,y)

(x,y)

ペン位置から指定座標まで直線のパスを作成lineTo(x,y)

(x,y)

四角形のパスを作成rect(x,y,width,height)

枠だけの四角形を描画strokeRect(x,y,width,height)

(x,y)

width

height

塗り潰された四角形を描画fillRect(x,y,width,height)

四角形の範囲を消去clearRect(x,y,width,height)

線のスタイルstrokeStyle

パスの枠を描画stroke()

塗りのスタイルfillStyle

パスを塗り潰すfill()

正円/円弧のパスを作成arc(x,y,r,startA,endA,anticlockwise)

(x,y)

startA

endA

r

anticlockwise

パスの新規作成beginPath()

パスを閉じるclosePath()

座標点がパス内にあるか調べるisPointInPath(x,y)

(x,y)

円弧のパスを作成arcTo(x1,y1,x2,y2,r)

(x1,y1)(x2,y2)

r

3 次ベジエ曲線のパスを作成bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)

(cp1x,cpy1) (cp2x,cpy2)

(x,y)

2 次ベジエ曲線のパスを作成quadraticCurveTo(cpx,cpy,x,y)

(cpx,cpy)

(x,y)

パスをクリップ領域にするclip()

コンテキストを取得getContext(contextID)

Canvas

いずれか 1つを指定

2d

webgl

contextID

一目でわかる「Canvas」のしくみ ❶

166

Page 3: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

線端形状を指定lineCap

butt round square

線幅を指定(単位はピクセル [px])lineWidth

影のずれ具合(オフセット)を指定

shadowOffsetXshadowOffsetY

shadowOffsetX

shadowOffsetY

影のぼかしを指定shadowBlur影のぼかしを指定 影の色を指定

shadowColor

描画モードを指定globalCompositeOperation

不透明度を指定globalAlpha

連結方法を指定lineJoin

bevel round miter

角のとがり具合を指定miterLimit

パターンを作成createPattern(image,repetition)

no-repeat

repeat-y

repeat

repeat-x

直線的なグラデーションを作成createLinearGradient(x0,y0,x1,y1)

(x1,y1)

(x0,y0)

中間点の位置と色を指定addColorStop(offset,color)

color

offset

color

円形グラデーションを作成createRadialGradient(x0,y0,r0,x1,y1,r1)

r1r1r0r0

(x0,y0)(x0,y0)

(x1,y1)(x1,y1)

移動translate(x,y)

(x,y)

回転rotate(rad)

rad

+

-

拡大縮小/スケーリングscale(x,y)

167

Chapter 7キャンバスに描画する

[Canvas ]一目でわかる「

Can

vas 」のしくみ ①

Page 4: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

一目でわかる「Canvas」のしくみ ❷

指定座標に通常の文字を描画fillText(text,x,y,maxWidth)

(x,y)

maxWidth

Sample

文字幅を持つオブジェクトを返す

mtx = measureText(text)mtx.width

Sample

指定座標に袋文字を描画strokeText(text,x,y,maxWidth)

(x,y)

maxWidth

文字のフォントを CSS 形式で指定font

Sample

italic bold 24px Times

行揃えを指定textAlign

SampleSample

SampleSample

Sample

left

center

right

start

end

ベースラインを指定textBaseline

Abcdfg 描画Abcdfg 描画Abcdfg 描画Abcdfg 描画Abcdfg 描画Abcdfg 描画

top

hanging

middle

alphabetic

ideographic

bottom

変形行列を追加transform(m11,m12,m21,m22,dx,dy)変形行列を新規に設定setTransform(m11,m12,m21,m22,dx,dy)

m11 m21 dxm12 m22 dy0 0 1

image画像を描画

drawImage(image, dx, dy)drawImage(image, dx, dy, dw, dh)drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

swdw

shdh

(sx,sy)(sx,sy)(dx,dy)

Canvas 情報を保存save()

CanvasasCanvas 情報を復元restore()

Canvasas

strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline

strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline保存情報

スタック

保存情報

保存情報

薄い文字は省略可能なパラメータ

width

168

Page 5: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

薄い文字は省略可能なパラメータ

ピクセルデータを読み出しgetImageData(x,y,w,h)

(x,y)

w

h

空のピクセルデータを作成createImageData(width,height)

imagewidth

height

imageピクセルデータを描画putImageData(image,x,y,sx,sy,w,h)

w

h

(sx,sy)(sx,sy)(x,y)

Canvas 内容を URL 形式 (data:~) に変換toDataURL(type)

Canvasasdata:image/png;base64,ZM/PRAHS...

addColorStop(offset,color)arc(x,y,r,startA,endA,anticlockwise)arcTo(x1,y1,x2,y2,r)beginPath()bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)clearRect(x,y,width,height)clip()closePath()createImageData(width,height)createLinearGradient(x0,y0,x1,y1) createPattern(image,repetition)createRadialGradient(x0,y0,r0,x1,y1,r1)drawImage(image, dx, dy, dw, dh)drawImage(image, dx, dy)drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)fill()fillRect(x,y,width,height)fillStylefillText(text,x,y,maxWidth)fontgetImageData(x,y,w,h)globalAlphaglobalCompositeOperationisPointInPath(x,y)lineCaplineJoin

lineTo(x,y)lineWidthmeasureText(text)miterLimitmoveTo(x,y)putImageData(image,x,y,sx,sy,w,h)quadraticCurveTo(cpx,cpy,x,y)rect(x,y,width,height)restore()rotate(rad)save()scale(x,y)setTransform(m11,m12,m21,m22,dx,dy)shadowBlurshadowColorshadowOffsetXshadowOffsetYstroke()strokeRect(x,y,width,height)strokeStylestrokeText(text,x,y,maxWidth)textAligntextBaselinetransform(m11,m12,m21,m22,dx,dy)translate(x,y)

toDataURL(type)getContext(contextId)

169

Chapter 7キャンバスに描画する

[Canvas ]一目でわかる「

Can

vas 」のしくみ ②

Page 6: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

170

Canvasとは7.1

Section

 この章ではCanvasを使って隕石を破壊するリアルタイムゲームと、画像と文字を表示するノベルシス

テムを作成します。

 隕石を破壊するゲームは上から落下してくる隕石をタップしてレーザーで破壊するものです。隕石を

破壊すると爆風が広がります。ノベルゲームはあらかじめ用意されたシナリオファイルを読み込みシーン

に合わせて画像と文字を表示します。

 作成するリアルタイムゲームとノベルシステムの画面は図7.1.1のようになります。

 実際にこれらのプログラムを作成する前にCanvasについて説明します。

 Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を

描画するものがあります。Android標準ブラウザではWeb GL (3D)はサポートされていないので、こ

こでは2D(平面、二次元描画)のグラフィックスを使ってゲームを作成します(*1)。

 2D描画に関してはW3Cのページに仕様が公開されています。

 Android 2.x ~ 4で使えるメソッドとプロパティを表7.1.1に示します。また、パソコン版Google

ChromeとAndroid 2.x ~ 4およびFirefoxでのCanvas関連のメソッド/プロパティ対応に関しては

「付録4 canvas要素のメソッド/プロパティ比較表」を参照してください。

http://www.w3.org/TR/2dcontext/

●HTML Canvas 2D Context●

*1 Firefox、Google ChromeではWebGLによる3D描画が可能です。

Page 7: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

171

Chapter 7キャンバスに描画する

[Canvas ]7.1C

anvas と

図7.1.1本章で作成するリアルタイムゲームとノベルシステム

#img images/waterfall.jpg

#bgm bgm/star.mp3

「ねじだる」の次に現れるのが「霧ヶ滝」です。

エメラルドグリーンの滝壺は非常にきれいで

濁りがありません。

#wait

文字表示用に黒の半透明の四角形を表示

シナリオファイルシーンに応じて対応する文字を表示 (26 文字×5行 )

シーンに応じて対応する画像を表示

隕石。上から回転しながら落下。

■隕石破壊ゲーム

砲台から発射されたレーザータップした位置まで描画される

スコア表示

隕石を破壊した時の爆風

♪♬♪音楽

senario.txt

■ノベルシステム

Page 8: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

172

表7.1.1Androidの標準ブラウザで使えるメソッドとプロパティ

arc 円を描く。

arcTo 円弧を描く。

beginPath パスの作成

bezierCurveTo 3次ベジエ曲線

clearRect 四角形の範囲を消去

clearShadow 影を消去

clip パスをクリッピング範囲にする。

closePath パスを閉じる。

createImageData ピクセルデータ領域を作成

createLinearGradient 直線的なグラデーションを作成

createPattern パターンを作成

createRadialGradient 円形グラデーションを作成

drawImage 画像を描画

fi ll パスを塗り潰し

fi llRect 四角形の範囲を塗り潰し

fi llStyle 塗り潰しスタイルを設定

fi llText 塗り潰した文字を描画

font 文字のサイズやフォントを一括指定(CSSの fontと同じ)

getImageData Canvas内のピクセルデータの取得

globalAlpha 不透明度(0が完全な透明で 1が完全な不透明)

globalCompositeOperation 合成モード(指定可能なモードについては表 7.1.2を参照)

isPointInPath 指定した点がパス内にあるか調べる。

lineCap 線端形状

lineJoin 線端結合方法

lineTo 現在の座標から指定した座標まで直線のパスを作成

lineWidth パスの線幅

measureText 文字の横幅をピクセル数で返す。

miterLimit 線端結合時の限界値

moveTo 指定座標に移動

putImageData ピクセルデータを描画

quadraticCurveTo 2次ベジエ曲線

rect 四角形のパスを作成

restore Canvasの状態を戻す。

rotate 回転

save Canvasの状態を保存

scale 拡大縮小/スケール設定

setTransform 新規に変形マトリクスを設定

Page 9: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

173

Chapter 7キャンバスに描画する

[Canvas ]7.1C

anvas と

shadowBlur 影のぼかし具合

shadowColor 影の色

shadowOffsetX 影の横のずれ具合(オフセット)

shadowOffsetY 影の縦のずれ具合(オフセット)

stroke パスを線で描画

strokeRect 線だけの四角形を描画

strokeStyle 線のスタイル

strokeText 線だけの文字を描画(アウトライン文字)

textAlign 行揃え

textBaseline 文字のベースライン

transform 現在の変形マトリクスに新たな変形を追加

translate 移動

 本章で作成するリアルタイムゲームはCanvasの以下の機能を使って処理しています。また、ノベル

システムでは以下のうち(1)(4)(7)を使用しています。

 以後のセクションで、これらの機能について説明していきます。

(1) 画面の消去(clearRect)

(2) 直線の描画(beginPath,strokeStyle,moveTo, lineTo)

(3) 円の描画(arc)

(4) 画像の描画(drawImage)

(5) 回転機能(rotate, translate)

(6) 文字描画(font, fi llText)

(7) 半透明処理(globalAlpha)

表7.1.2合成モード

合成モード

source-atop destination-out

source-in* destination-over

source-out* lighter

source-over copy*

destination-atop* xor

destination-in*

*仕様とは異なる描画結果になる(Android 2.x /標準ブラウザの場合)

Page 10: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

174

四角形の描画7.2

Section

 このセクションではCanvasと描画機能について説明します。なお、Canvas機能の説明に関する以

後のセクションではjQuery Mobileは使用していません。純粋にJavaScriptだけを使用しています。

 まず、四角形を描く方法について説明します。CanvasはHTML要素だけでは何も描画することが

できません。同じグラフィック機能を扱うSVG(Scalable Vector Graphics) は要素を記述すれば描く

ことができますが、CanvasではJavaScriptが必須となります。

●canvas要素を用意する 描画するまでには手順が必要になります。最初にHTMLでcanvas要素を用意します。widthで横

幅、heightで縦幅を指定します。CSSで指定することもできますが表示結果が異なる場合があるので

HTMLのwidth、height属性で指定する方が確実です。また、以下の例ではJavaScriptからアク

セスしやすくするためにID名myCanvasを指定しています。

●Java Script側の処理 HTMLの準備はこれで終わりです(*1)。次にJavaScript側の処理です。まず、canvas要素にアク

セスしやすくするために変数にcanvasへの参照を入れておきます。

<canvas id="myCanvas" width="300" height="400"></canvas>

var canvasObj = document.getElementById("myCanvas");

*1 Androidでは、どの機種であってもCanvasを利用できますが、もしIE8などパソコンの古いブラウザを対象にする場合には以下のようにフォールバック機構を利用してメッセージ等を表示することができます。

<canvas id="myCanvas" width="300" height="400">

お使いのブラウザは対象外です。</canvas>

Page 11: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

175

Chapter 7キャンバスに描画する

[Canvas ]7.2四角形の描画

 次に、使用するCanvasの2D機能のコンテキスト(オブジェクト)を指定します。これは以下のように

getContext("2d")とすることでCanvasの機能にアクセスできるオブジェクトが変数に入ります。

 ここまで来たら、ようやくCanvasに描画できるようになります。赤色の四角形を描いてみましょう。

fi llStyleプロパティに塗り潰す色を指定します。色指定はCSS3と同じものを利用できます。

 四角形を描くメソッドはrect以外はそのままcanvasに描画/消去の処理が行われます。rectの場合

は、実行しても何も描画されず「パス」だけが生成されます。Canvasには「直接描画する」ものと「パス

を作成した後で描画する」タイプの2つがあります。前者は四角形といったシンプルな図形だけが対応

しています。後者は複雑な図形を描画するのに利用されます。

 次のセクションでは「パスを作成した後で描画する」方法について説明します。

 パラメータはX座標、Y座標、横幅、縦幅の順番になります。四角形を描くメソッドは表7.2.1に示

すものがあります。いずれもパラメータは同じです。実際のプログラムはサンプル7.2.1になります。

 塗り潰された四角形の場合は以下のようにfi llRect()を使います。

var context = canvasObj.getContext("2d");

context.fi llStyle = "red";

context.fi llRect(20, 30, 200, 250);

表7.2.1四角形を描くメソッド

clearRect(x, y, 横幅 , 縦幅)

fi llRect(x, y, 横幅 , 縦幅)

strokeRect(x, y, 横幅 , 縦幅)

rect(x, y, 横幅 , 縦幅)

図7.2.1

Page 12: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

176

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1">

    <title>Canvasサンプル</title>

  </head>

  <body>

    <canvas id="myCanvas" width="300" height="400"></canvas>    <script src="js/draw.js"></script>

  </body>

</html>

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.fi llStyle = "red"; // 赤色context.fi llRect(20, 30, 200, 250); // 塗り潰した四角形

●サンプル7.2.1●

●サンプル7.2.1 draw.js●

Page 13: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

177

Chapter 7キャンバスに描画する

[Canvas ]7.3パスの作成と描画

パスの作成と描画7.3

Section

 このセクションではパスの作成と描画について説明します。パスという用語はディレクトリパスのようにも

使われることがありますが、Canvasでのパスは「複数の座標点で構成された図形」を示します。複数

の座標点で構築することができるため、より複雑な図形を描くことができます。パスを構築するメソッドに

は表7.3.1のものがあります。

 パスを使う場合にはあらかじめbeginPath()を呼び出します。このメソッドにより以前のパスは消去さ

れ新たなパスが生成されます。beginPath()を実行した時点では座標点は何もありません。

 簡単なところで直線を2本描画してみます。直線を描画するには開始点と終了点の2つが必要にな

ります。まず、開始点はmoveTo()で指定し、終了点はlineTo()で指定します。線を描画するには

stroke()メソッドを使います。

 実際のプログラムはサンプル7.3.1になります。山形になった赤い直線が描画されます。なお、線の

色はstrokeStyleプロパティに設定します。CSS3のカラー指定と同じものを使うことができます。

表7.3.1パスを構築するメソッド

arc(x, y, 半径 , 開始角度 , 終了角度 , 描画方向)

arcTo(x1, y1, x2, y2, 半径)

bezierCurveTo(制御点座標 1x, 制御点座標 1y, 制御点座標 2x, 制御点座標 2y, x, y)

lineTo(x, y)

moveTo(x, y)

quadraticCurveTo(制御点座標 x, 制御点座標 y, x, y)

rect(x, y, 横幅 , 縦幅)

Page 14: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

178

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1">

    <title>Canvasサンプル</title>

  </head>

  <body>

    <canvas id="myCanvas" width="400" height="400"></canvas>

    <script src="js/draw.js"></script>

  </body>

</html>

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.strokeStyle = "red"; // 赤色context.beginPath();

context.moveTo(10, 350);context.lineTo(150, 10);context.lineTo(290, 350);context.stroke();

●サンプル7.3.1●

●サンプル7.3.1 draw.js●

図7.3.1山形の直線が描画される。

Page 15: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

179

Chapter 7キャンバスに描画する

[Canvas ]7.3パスの作成と描画

●オープンパスとクローズパス beginPath()によって作成されたパスには2種類あります。1つはオープンパスと呼ばれるもので始点

と終点がつながっていないものです。もう1つがクローズパスと呼ばれるもので始点と終点がつながって

いるものです。サンプル7.3.1は始点と終点がつながっていないのでオープンパスになります。

 図形をクローズパスにするにはclosePath()を使います。このメソッドを実行すると始点と終点が自動

的に結ばれパスが閉じられます。サンプル7.3.1を修正してクローズパスにしたものがサンプル7.3.2で

す。クローズパスにしたので三角形が描かれています。

 また、線が太くなっています。線の太さはlineWidthで指定することができます。4を入れると4ピク

セル幅の太さになります。なお、CSSとは異なり単位の指定はできません。

図7.3.2クローズパスにしたので三角形が描かれている。

 HTML文は、サンプル7.3.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.strokeStyle = "red"; // 赤色context.lineWidth = 4;

context.beginPath();

context.moveTo(10, 350);

context.lineTo(150, 10);

●サンプル7.3.2●

●サンプル7.3.2 draw.js●

次頁へ続く

Page 16: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

180

●より複雑な図形を作成するには 他のメソッドと組み合わせることで、より複雑な図形も作成することができます。サンプル7.3.3は円弧

と直線を組み合わせて、ソフトクリームのような形をした図形を描画しています。

 HTML文は、サンプル7.3.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.strokeStyle = "red"; // 赤色context.lineWidth = 20;

context.beginPath();

context.arc(120, 200, 80, 0, Math.PI, true);context.lineTo(120, 300);context.lineTo(200, 200);context.closePath();

context.stroke();

context.lineTo(290, 350);

context.closePath();context.stroke();

●サンプル7.3.3●

●サンプル7.3.3 draw.js●

図7.3.3円弧と直線を組み合わせた図形

Page 17: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

181

Chapter 7キャンバスに描画する

[Canvas ]7.3パスの作成と描画

●重なった部分をくり抜くには Canvasではパスの作成した向き(ベクトル方向)が異なる場合、重なった部分はくり抜かれます。こ

れを利用するとドーナツのような形も簡単にできます(*1)。

 サンプル7.3.4ではサンプル7.3.2で描画した三角形を、もう1つ描いています。ただし、パスの作成

方向は逆にしてあります。このため、重なった部分はくり抜かれて表示されます。

図7.3.4重なった部分はくり抜かれる(くり抜かれた部分は透明になっている)。

 HTML文は、サンプル7.3.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.fi llStyle = "red"; // 赤色context.beginPath();

context.moveTo(10, 350); // 上向きの三角のパスを作成context.lineTo(150, 10); // 時計回りにパスを作成context.lineTo(290, 350);context.closePath(); // パスを閉じる(重要)context.moveTo(70, 350); // 位置を少し右にして上向きの三角のパスを作成context.lineTo(350, 350); // 反時計回りにパスを作成context.lineTo(210, 10);context.closePath();

context.fi ll();

●サンプル7.3.4●

●サンプル7.3.4 draw.js●

*1 Android 1.6 ~ 4まではarc()のバグでドーナツ型を表示できません。このためドーナツ型にするには、自前で円を描くプログラムを作成する必要があります。

Page 18: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

182

画像の描画7.4

Section

 このセクションでは画像の描画について説明します。

 Canvasに画像を描画するにはdrawImage()を使います。このdrawImage()はパラメータの数によっ

て、描画結果が変わります。描画パターンは表7.4.1に示すように3つあります。

表7.4.1drawImageのパラメータ

(1)drawImage(image, dx, dy) 指定座標に元画像のサイズで描画

(2)drawImage(image, dx, dy, dw, dh) 指定座標に指定サイズで描画

(3)drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) 元画像の一部を指定した座標に指定したサイズで描画

image : 画像オブジェクト

sx : 描画元の X座標 dx : 描画先の X座標

sy : 描画元の Y座標 dy : 描画先の Y座標

sw : 描画元の横幅 dw : 描画先の横幅

sh : 描画元の縦幅 dh : 描画先の縦幅

●指定座標に元画像のサイズで描画 まず、表7.4.1(1)drawImage(image, dx, dy)の場合から説明します。Canvasに画像を描画す

るにはdrawImage()を使うのですが、その際描画する画像データは読み込みが完了している必要が

あります。画像データが読み込まれていない場合には何も描画されません。このため、Imageオブジェ

クトが読み込まれたら発生するloadイベントを捕捉します。手軽なのはonloadプロパティにイベントハン

ドラを設定しておくことです。

 イベントハンドラ内でdrawImage()を使ってCanvasに描画を行います。実際のプログラムはサン

プル7.4.1になります。読み込んだ画像を座標(0, 0)に元画像と同じサイズで描画しています。なお、

context.drawImage(imageObj, 0, 0);とある部分はcontext.drawImage(this, 0, 0);としても同じ

です。

Page 19: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

183

Chapter 7キャンバスに描画する

[Canvas ]7.4画像の描画

図7.4.1drawImage()による描画

元画像 (image) Canvas(1)drawImage(image, dx, dy)

(dx, dy)

元画像 (image) Canvas(2)drawImage(image, dx, dy, dw, dh)

(dx, dy)

dh

dw

元画像 (image) Canvas(3)drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

(dx, dy)

dh

dw

sh

sw

(sx, sy)(sx, sy)

Page 20: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

184

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1">

    <title>Canvasサンプル</title>

  </head>

  <body>

    <canvas id="myCanvas" width="300" height="400"></canvas>

    <script src="js/draw.js"></script>

  </body>

</html>

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

imageObj.onload = function(){

  context.drawImage(imageObj, 0, 0); // (0,0)に描画}

●サンプル7.4.1●

●サンプル7.4.1 draw.js●

 もしかしたらサンプル7.4.1のように処理するのは面倒だと

感じる人がいるかもしれません。もし、HTMLファイル内に

Canvasに描画する画像データを用意しておくことができるので

あれば別の方法もあります。それはdrawImage()の最初のパ

ラメータにimg要素を指定するという方法です。

 実際のプログラムはサンプル7.4.2のようになります。ページ

のレイアウトや状況によりけりですが、この方がシンプルでわか

りやすい上に、画像を変更する場合にスクリプトを操作しなくて

もよいというメリットもあります。

図7.4.2HTMLにimg要素を指定してあれば、その要素を指定して描画することができる。

Page 21: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

185

Chapter 7キャンバスに描画する

[Canvas ]7.4画像の描画

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1">

    <title>Canvasサンプル</title>

  </head>

  <body>

    <canvas id="myCanvas" width="300" height="400"></canvas>

    <img src="images/waterfall.jpg" width="1" height="1" id="photo">

    <script src="js/draw.js"></script>

  </body>

</html>

window.onload = function(){

  var canvasObj = document.getElementById("myCanvas");

  var context = canvasObj.getContext("2d");

  var imageObj = document.getElementById("photo");  context.drawImage(imageObj, 0, 0); // (0,0)に描画}

●サンプル7.4.2●

●サンプル7.4.2 draw.js●

●指定座標に指定サイズで描画 次に表7.4.1(2)drawImage(image, dx, dy, dw, dh)の

場合ですが、パラメータに横幅と縦幅を指定することができま

す。サンプル7.4.3では座標(0, 0)から横幅150ピクセル、縦

幅200ピクセルで画像を描画します。

図7.4.3画像が指定した幅で描画されている(元サイズの半分)。

Page 22: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

186

●元画像の一部を指定した座標に指定したサイズで描画 最後の表7.4.1(3)drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)の場合は、やや複雑

でパラメータがたくさんあります。元画像の転送先座標とサイズ、そしてCanvasの描画先の座標とサ

イズを一括して指定します。サンプル7.4.4の場合は、元画像の(70, 260)から横幅40ピクセル、縦幅

60ピクセルの範囲をCanvasの座標(50, 70)に横幅160ピクセル、縦幅240ピクセルを描画します。

 サンプル7.4.4では元画像の一部を拡大して描画していることになります。

 HTML文は、サンプル7.4.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

  context.drawImage(imageObj, 0, 0, 150, 200);}

●サンプル7.4.3●

●サンプル7.4.3 draw.js●

図7.4.4元画像の一部が拡大されて描画される。

Page 23: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

187

Chapter 7キャンバスに描画する

[Canvas ]7.4画像の描画

 HTML文は、サンプル7.4.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

imageObj.onload = function(){

  context.drawImage(imageObj, 70, 260, 40, 60, 50, 70, 160, 240);}

●サンプル7.4.4●

●サンプル6.4.4 JavaScript(storage.js)●

Page 24: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

188

回転、移動など7.5

Section

 このセクションではCanvasの回転と移動、拡大縮小について説明します。

 Canvasでは表7.5.1に示す変形機能が用意されています。transform()およびsetTransform()は

rotate()、translate()、scale()による変形処理を一括して指定できます。

 Canvasでは特定の図形や画像を回転させる機能はなく、表7.5.1に示すメソッドを使うと以後に描画

される全ての図形や文字に対して変形が適用されます。

表7.5.1Canvasの変形機能

rotate(角度) 回転

translate(横の移動量 , 縦の移動量) 移動

scale(横の倍率 , 楯の倍率) 拡大縮小

setTransfrom(m11, m12, m21, m22, 横の移動量 , 縦の移動量) 変形マトリックスを設定(以前の設定は消去される)

transfrom(m11, m12, m21, m22, 横の移動量 , 縦の移動量) 現在の変形マトリクスに新たな変形を追加

●画像を回転する まず、画像を回転させてみます。回転はrotate()でパラメータには回転角度をラジアンで指定します。

ラジアンなのでMath.PI*2とするとちょうど一回転することになります。角度からラジアンに変換したい場

合には以下の計算式を使います。

 rotate()のパラメータが正数の場合は時計回りに、負数の場合は反時計回りに回転します。サンプ

ル7.5.1では時計回りに20度画像を回転させています。

• m11 ~ m22は以下の変形マトリクス

  m11 m21 dx

  m12 m22 dy

   0   0  1

角度 × π ÷ 180

http://himaxoff.blog111.fc2.com/blog-entry-86.html

http://www.w3.org/TR/2dcontext/#dom-context-2d-transform

Page 25: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

189

Chapter 7キャンバスに描画する

[Canvas ]7.5回転、移動など

図7.5.1画像がCanvasの左上を基準にして時計回りに20度回転した。

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1">

    <title>Canvasサンプル</title>

  </head>

  <body>

    <canvas id="myCanvas" width="300" height="400" style="border:1px solid black;"></canvas>

    <script src="js/draw.js"></script>

  </body>

</html>

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

imageObj.onload = function(){

  context.rotate(20 * Math.PI / 180);  context.drawImage(imageObj, 0, 0);

}

●サンプル7.5.1●

●サンプル7.5.1 draw.js●

Page 26: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

190

 サンプル7.5.1を実行すると画像は回転して表示されますが、回転の中心がCanvasの左上になって

います(原点)。回転の中心の位置を変更したい場合にはtranslate()を使います。translate()は横と

縦の移動量を指定します。これにより回転の中心が指定した座標になります。

 サンプル7.5.2ではCanvasの座標(150, 200)に原点を移動させた後、rotate()を使って回転させて

います。注意しないといけないのは、移動と回転の中心の順番が変われば結果が異なるという点です。

図7.5.2Canvasの中心(150, 200)を基準にして画像が回転する。

 HTML文は、サンプル7.5.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

imageObj.onload = function(){

  context.translate(150, 200);  context.rotate(20 * Math.PI / 180);

  context.drawImage(imageObj, 0, 0);

}

●サンプル7.5.2●

●サンプル7.5.2 draw.js●

Page 27: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

191

Chapter 7キャンバスに描画する

[Canvas ]7.5回転、移動など

●Canvasの状態を保存、復元するメソッド translate()によって原点を移動させ回転させた後には、元の状態に戻しておく必要があります。元

に戻さないと以後に描画される図形や画像、文字の描画結果が意図しないものになる場合があるため

です。原点の移動量や回転、拡大縮小率などを操作していくと、元に戻す場合には逆の処理を行わ

なければいけません。しかし、変形処理が複雑になった場合には簡単に元の状態に戻すのは難しいで

しょう。

 そこで、便利なのが以下の表7.5.2に示すCanvasの状態を保存、復元するメソッドです。

表7.5.2Canvasの状態を処理するメソッド

save() Canvasの状態を保存

restore() Canvasの状態を復元

 save()はCanvasの状態を保存すると書きましたが、これはCanvasで描画される表7.5.3に示すプ

ロパティ値と変形マトリクスを保存するものです。Canvasに描かれているピクセルデータを保存するわ

けではありません(*1)。また、パスなどはリセットされず残ったままになります。

表7.5.3保存されるプロパティ

strokeStyle

fi llStyle

globalAlpha

lineWidth

lineCap

lineJoin

miterLimit

shadowOffsetX

shadowOffsetY

shadowBlur

shadowColor

globalCompositeOperation

font

textAlign

textBaseline

*1 Android 4以降ではCanvasの内容をtoDataURL()メソッドを使って読み出すことができます。これによりdataURL形式としてピクセルデータを取得できます。dataURL形式はテキストなのでCanvas内容をLocal Storageに保存することもできます。

Page 28: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

192

 save()により保存された内容を元に戻すにはrestore()を使います。なお、save()は入れ子(ネスト)に

して使うことができます。Canvasを使ったライブラリなどを開発する際には必須の機能です。

 サンプル7.5.3がsave()、restore()を使ったプログラムです。基本的には変形前にsave()で状態保

存し、処理が終わったらrestore()で戻します。save()、restore()がなければ2番目に描画される画像

は回転して描画されてしまいます。

図7.5.31枚目の画像は回転して描画されるが、2枚目は元の状態になっているため回転せずに描画されている。

 HTML文は、サンプル7.5.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

imageObj.onload = function(){

  context.save();  context.translate(75, 100);

  context.rotate(45 * Math.PI / 180);

  context.drawImage(imageObj, -75, -100);

  context.restore();  context.drawImage(imageObj, 150, 200);

}

●サンプル7.5.3●

●サンプル7.5.3 draw.js●

Page 29: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

193

Chapter 7キャンバスに描画する

[Canvas ]7.5回転、移動など

●画像を拡大・縮小する 最後に拡大縮小です。拡大縮小はscale()メソッドを使います。パラメータには横と縦の倍率を指定

します。1.0を指定すると100%となります。0.5なら50%、2.0なら200%になります。

 サンプル7.5.4では図形を回転させた後に横を200%、縦を50%の縮尺にしてから画像を描画してい

ます。

図7.5.4画像が回転、変形して描画される。

 HTML文は、サンプル7.5.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

var imageObj = new Image();

imageObj.src = "images/waterfall.jpg"; // 画像のURL

imageObj.onload = function(){

  context.save();

  context.translate(75, 100);

  context.rotate(45 * Math.PI / 180);

  context.scale(2, 0.5);  context.drawImage(imageObj, -75, -100);

  context.restore();

}

●サンプル7.5.4●

●サンプル7.5.4 draw.js●

Page 30: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

194

文字の表示7.6

Section

 このセクションでは文字の描画について説明します。

 Canvasでは以下の表7.6.1に示す文字描画に関する機能が用意されています。なお、Canvasに

描画される文字の方向はcanvas要素に指定されているスタイルシートのdirectionとunicode-bidiに

依存します。

表7.6.1Canvasの文字描画機能

font フォントを設定

fi llText(表示文字 , x, y) 塗り潰された文字を描画

strokeText(表示文字 , x, y) アウトライン文字を描画

measureText(表示文字) 文字の横幅を求める

textAlign 行揃え

textBaseline ベースライン

●文字描画の基本 描画する文字のフォントやサイズなどはfontプロパティに一括して設定します。fontプロパティには

CSSのfontプロパティと同じ内容を指定することができます。例えば「italic bold 64px Times」と設定

すればTimesフォントで64ピクセルの太字の斜体で文字が描画されます。

 また、描画する文字の色はfi llText()の場合はfi llStyleプロパティに設定されたカラーになります。

strokeText()の場合はstrokeStyleプロパティに設定されたカラーになります。

 fi llText()、strokeText()とも最初のパラメータに描画する文字列を指定します。なお、画面からは

み出しても自動的に改行はされません。また、描画位置を示す座標は文字のベースラインが基準になり

ます。

 2番目と3番目には文字を描画する座標を指定します。行揃えはtextAlignで「start, end, left,

right, center」のいずれかを指定します。

 サンプル7.6.1が塗り潰された文字を描画、サンプル7.6.2がアウトライン文字を描画するプログラム

になります。

Page 31: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

195

Chapter 7キャンバスに描画する

[Canvas ]7.6文字の表示

図7.6.1赤色で文字が描画される。

図7.6.2アウトライン文字が描画される。

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1">

    <title>Canvasサンプル</title>

  </head>

  <body>

    <canvas id="myCanvas" width="300" height="400"></canvas>

    <script src="js/draw.js"></script>

  </body>

</html>

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.fi llStyle = "red";

context.font = "italic bold 64px Times"context.fi llText("Android", 20, 100);

●サンプル7.6.1●

●サンプル7.6.1 draw.js●

Page 32: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

196

 HTML文は、サンプル7.6.1と同じコードなので省略します。

 HTML文は、サンプル7.6.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.strokeStyle = "red";

context.font = "italic bold 64px Times"

context.strokeText("Android", 20, 100);

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.fi llStyle = "yellow";

context.strokeStyle = "red";

context.font = "italic bold 64px Times"

context.fi llText("Android", 20, 100);context.strokeText("Android", 20, 100);

●サンプル7.6.2●

●サンプル7.6.3●

●サンプル7.6.2 draw.js●

●サンプル7.6.3 draw.js●

●文字にアウトラインを付ける 塗り潰された文字にアウトラインを描画する場合にはサンプル7.6.3のように別々に描画します。

図7.6.3黄色い文字に赤いアウトラインが描画される。

Page 33: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

197

Chapter 7キャンバスに描画する

[Canvas ]7.6文字の表示

●影を付ける Canvasでは描画する図形や文字に影(シャドウ)を付けることができます。ただし、Android 2.x ~

3ではshadowOff setYプロパティに描画方向が逆になるという不具合があります。Android 4以降で

は正常な動作になっています。

 影は以下の表7.6.2に示す機能があります。clearShadow()はCanvasに描画されている影を消す

のではなく、影を描画しないようにするメソッドです。

表7.6.2影に関する機能

shadowBlur 影のぼかし具合

shadowColor 影の色

shadowOffsetX 影の横方向のずれ(オフセット)

shadowOffsetY 影の縦方向のずれ(オフセット)

clearShadow() 影を消去

 実際に文字に影を描画するプログラムがサンプル7.6.4です。塗り潰された黄色い文字に青い影が

描画されます。その後、clearShadow()を使って影の描画を行わないようにしているため、アウトライン

文字には影は描画されていません。

図7.6.4青い影が描画される。

Page 34: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

198

 HTML文は、サンプル7.6.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.shadowBlur = 5;context.shadowColor = "blue";context.fi llStyle = "yellow";

context.strokeStyle = "red";

context.font = "italic bold 64px Times"

context.fi llText("Android", 20, 100);

context.clearShadow();context.strokeText("Android", 20, 100);

●サンプル7.6.4●

●サンプル7.6.4 draw.js●

●不透明度を指定する 文字の不透明度を指定して描画することもできます。Canvasでは不透明度を設定するには2つの

方法があります。1つはglobalAlphaプロパティに不透明度0.0 ~ 1.0を設定する方法です。これは全

ての描画機能に対して不透明度が設定されます。

 もう1つの方法がfi llStyleやstrokeStyleプロパティにCSSのrgba()形式で不透明度含めたカラー

値を設定するものです。この場合、カラーまたは枠の色に関してのみ不透明度が反映され、他には影

響を与えません。

 サンプル7.6.5、サンプル7.6.6とも文字を半透明にして描画しますが、結果は同じになります。

図7.6.5黄色い文字の不透明度を70%にしているため、重なった部分は半透明になっている。

Page 35: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

199

Chapter 7キャンバスに描画する

[Canvas ]7.6文字の表示

 HTML文は、サンプル7.6.1と同じコードなので省略します。

 HTML文は、サンプル7.6.1と同じコードなので省略します。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.font = "italic bold 64px Times"

context.fi llStyle = "red";

context.fi llText("Android", 20, 100);

context.globalAlpha = 0.7;context.fi llStyle = "yellow";

context.fi llText("Android", 17, 97);

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.font = "italic bold 64px Times"

context.fi llStyle = "red";

context.fi llText("Android", 20, 100);

context.fi llStyle = "rgba(255, 255, 0, 0.7)";context.fi llText("Android", 17, 97);

●サンプル7.6.5●

●サンプル7.6.6●

●サンプル7.6.5 draw.js●

●サンプル7.6.6 draw.js●

Page 36: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

200

Canvasを使ったリアルタイムゲームの作成

7.7Section

 このセクションではCanvasを使ったリアルタイムゲームの作成について説明します。

●ゲームの概要 章の始めにも少し説明しましたが、ここで作成するゲームは上空から回転しながら落下してくる隕石を

タップして破壊するものです。タップすると中央の砲台からタップした位置までレーザービームが瞬時に

発射されます。隕石を破壊すると半透明の爆風が広がっていき、やがて消えます。隕石をタップする

際に画面下であれば、より高得点になります。隕石が完全に落下するとゲームオーバーになります。

 まとめると以下のようになります。

図7.7.1実際のゲーム画面

(1) 隕石は上から回転しつつ落下

(2) 隕石が画面下まで落下するとゲームオーバー

(3) 画面をタップすると中央の砲台からレーザービームが出る。

(4) 隕石をタップしたら爆風を出す。その後、再度隕石を上から落下させる。

Page 37: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

201

Chapter 7キャンバスに描画する

[Canvas ]7.7C

anvas を

使ったリアルタイムゲームの作成

(1) 初期設定

(2) ページ読み込み後のゲーム開始処理

(3) ビームの発射処理

(4) 隕石の移動や爆風などの処理

●プログラムの構成と処理の流れ 今回は最初にゲームのプログラムを見てもらいましょう。以下が実際のゲームのプログラムになります。

このプログラムは大きく分けると以下の4つになっています。

 これらの処理の説明の前にHTMLとCSS部分について説明しておきます。このCanvasの章では

Canvasに画像を描画する時にはdrawImage()を使うと説明しました。今回のゲームでも図7.7.1を見

ればわかるように背景を描画しています。

 普通に考えると背景もCanvasに描画することになります。一般的には、そのようになりますが、ここ

ではプログラムの負荷を下げて処理速度を向上させるため、Canvasの背景はスタイルシートを使って

表示しています。HTMLファイルの以下の部分がCanvasに背景を設定している部分です。

 Canvas自体は何も描画しなければ「透明」ですので、このようにすると背景が表示されることになりま

す。このCSS部分の処理はブラウザが行いますので、下手にJavaScriptを使って自前で処理するより

も高速ですし、そもそも背景を描画するプログラムが不要になります。HTML5でゲーム等を作成する

のであれば、このような背景との合成方法、利用方法も覚えておくとよいでしょう。

canvas {  position: absolute; top:10px; left:10px; border:1px solid black;

  background-image: url(images/bg.png);

}

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1, user-scalable=no">

    <title>隕石落下防止ゲーム</title>

    <link rel="stylesheet" href="css/jquery.mobile.css">

    <style>

      canvas {      position: absolute; top:10px; left:10px; border:1px solid black;

●サンプル7.7.1●

次頁へ続く

Page 38: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

202

      background-image: url(images/bg.png);

      }

      #main { height: 350px; }    </style>

    <script src="js/jquery.js"></script>

    <script src="js/shoot.js"></script>

    <script src="js/jquery.mobile.js"></script>

  </head>

  <body>

    <div data-role="page" id="content">

      <div data-role="content" id="main">         <canvas id="myCanvas" width="300" height="350"></canvas>

      </div>

    </div>

  </body>

</html>

var g = { // ゲーム関係の情報を入れるグローバルオブジェクト  canvasW : 0, // Canvasの横幅  canvasH : 0, // Canvasの縦幅  stoneImg : new Image(), // 隕石の画像オブジェクト  stoneSize : 32, // 隕石の幅  context : null, // Canvasの2Dコンテキスト  timerID : null, // タイマー変数  fl ag : false, // タップしたかどうかのフラグ。true=タップした  tapx : 0, // タップしたX座標  tapy : 0, // タップしたY座標  ix : 0, // 隕石のX座標  iy : 0, // 隕石のY座標  dy : 0, // 隕石の移動量(落下量)  bx : 0, // 爆風のX座標  by : 0, // 爆風のY座標  bCounter : 1000, // 爆風のカウンタ変数  score : 0, // スコア  rad : 0 // 隕石の回転角度(ラジアン)};

$(function(){

  // Canvas関係の読み込みとイベント、タイマー設定  var canvasObj = document.getElementById("myCanvas");

  g.canvasW = canvasObj.width;

  g.canvasH = canvasObj.height;

  g.context = canvasObj.getContext("2d");

  g.stoneImg.src = "images/stone.png";

  g.stoneImg.onload = function(){ // 隕石の画像データを読み込み完了後にゲーム開始    g.ix = Math.random() * 200 + 50; // 隕石の出現範囲    g.iy = -g.stoneSize;

●サンプル7.7.1 shoot.js●

Page 39: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

203

Chapter 7キャンバスに描画する

[Canvas ]7.7C

anvas を

使ったリアルタイムゲームの作成

    g.dy = Math.random() * 5 + 2;

    g.timerID = setInterval("moveStone()", 100);

  }

  canvasObj.addEventListener("touchstart", startBeam, false);

});

// タップしたらビームを発射function startBeam(evt){

  // タップされた座標を求める  g.tapx = evt.touches[0].pageX;

  g.tapy = evt.touches[0].pageY;

  g.fl ag = true;

  // 判定。2点間の距離で判定する  var absx = Math.abs(g.tapx - g.ix);

  var absy = Math.abs(g.tapy - g.iy);

  var d = Math.sqrt(Math.pow(absx, 2) + Math.pow(absy, 2));

  if (d > 50){ return; } // 50pxより大きい場合は何もしない  g.score = g.score + Math.fl oor(g.iy);

  g.bx = g.tapx; // 爆風の座標を設定  g.by = g.tapy;

  g.bCounter = 0;

  g.ix = Math.random() * 200+50;

  g.iy = -g.stoneSize;

  g.dy = Math.random() * 5 + 2 + g.score/1000; // 落下速度を計算}

// 隕石移動&描画function moveStone(){

  g.context.clearRect(0,0, g.canvasW, g.canvasH); // Canvas内容を消去  g.iy = g.iy + g.dy; // 隕石を移動(落下)  g.context.save(); // コンテキストを保存しておく  var centerX = g.ix + g.stoneSize/2;

  var centerY = g.iy + g.stoneSize/2;

  g.context.translate(centerX, centerY); // 隕石の中心に移動  g.context.rotate(g.rad); // 回転させる  g.context.translate(-centerX, -centerY); // 元に戻す  g.rad = g.rad + Math.PI / 9;

  g.context.drawImage(g.stoneImg, g.ix, g.iy);

  g.context.restore(); // 保存したコンテキストを元に戻す  // 隕石が完全に落下したか調べる  if (g.iy > g.canvasH){

    clearInterval(g.timerID);

    alert("Game Over"); // 隕石が落下したのでゲームオーバー  }

  // タップされた場合は一度だけレーザービームを描画する  if (g.fl ag){

    g.context.lineWidth = 3;

    g.context.strokeStyle = "yellow";

    g.context.beginPath();

    g.context.moveTo(150, 327);

次頁へ続く

Page 40: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

204

    g.context.lineTo(g.tapx, g.tapy);

    g.context.stroke();

    g.fl ag = false;

  }

  // 爆風があるなら処理する  if (g.bCounter < 10){

    g.context.beginPath();

    g.context.fi llStyle = "yellow";

    g.context.globalAlpha = 0.7; // 不透明度を70%にする    g.context.arc(g.bx, g.by, g.bCounter*10, 0, Math.PI*2, false); // 円を描く    g.context.fi ll();

    g.context.globalAlpha = 1.0;

    g.bCounter = g.bCounter + 1;

  }

  // スコアを表示する  g.context.font = "normal bold 22px Times";

  g.context.fi llStyle = "red";

  g.context.fi llText("SCORE "+g.score, 10, 20);

}

7.7.1 初期設定とゲーム開始処理

●初期設定 まず、(1)の初期設定部分です。これはグローバル変数(オブジェクト)gを用意し、その中にゲーム

で使われる情報を格納するようにしています。どのプロパティが何を示しているかはプログラム内のコメン

トに記載してあります。

●ゲーム開始処理 次に(2)のページが読み込まれた後、ゲームを開始する部分です。$(function(){ ~で示される部分

が該当します。ここではCanvasの横幅や縦幅、コンテキストを読み出してします。その後、隕石の画

像を読み込みます。隕石の画像が完全に読み込まれたら隕石の落下開始位置を設定します。設定が

終わったらインターバルタイマーを使って隕石の移動処理を行うmoveStone()関数を0.1秒ごとに呼び出

します。

 Android端末では処理速度にばらつきがあるため、インターバルタイマーの間隔を短くしても効果が

ないことがあります(*1)。

 最後にCanvasにタッチされた場合に呼び出す関数(イベントリスナー)を設定します。タッチされた場

合にはstartBeam()関数が呼び出されます。

*1 作成するゲームによりけりですが別解としてsetRequestAnimationFrame()を使う方法もあります。

Page 41: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

205

Chapter 7キャンバスに描画する

[Canvas ]7.7C

anvas を

使ったリアルタイムゲームの作成

7.7.2 レーザービームの処理

●ビームの発射処理 次に(3)のレーザービームの処理です。レーザービームはタップした位置の座標を取得し、画面下中

央の砲台からタップした位置までレーザービームを描画します。レーザービームは直線ですのでlineTo()

を使って描画することになります。が、実際にはstartBeam()関数内にはレーザービームを描画する処

理がありません。

 レーザービームの描画処理はmoveStone()関数内で行うようにしています。なぜ、このようになって

いるのでしょうか? それはAndroid 2.xとAndroid 3以降では画面の書き換えタイミングが異なってい

るためです。Android 2.xであればstartBeam()関数内でlineTo()を使って描画しても問題なく画面

に表示されます。

 ところが、Android 3以降では画面の描画タイミングが異なるため、startBeam()関数内で処理して

も表示される場合もあれば、されない場合もあります。そこで、レーザービームが発射された事だけを

示すフラグ(g.fl ag)をtrueにしています。

 次にタップした場所が隕石と同じ場所かどうか調べます。正確にタップするというのはAndroidでは

難しいため、隕石から50ピクセル以内であればヒットしたことにしています。これが以下の部分になりま

す。2点間の距離で判別しています。より正確に判定するのでれば、隕石の中心座標から行うとよいで

しょう。

var absx = Math.abs(g.tapx - g.ix);

var absy = Math.abs(g.tapy - g.iy);

var d = Math.sqrt(Math.pow(absx, 2) + Math.pow(absy, 2));

if (d > 50){ return; } // 50pxより大きい場合は何もしない

 隕石がタップされたらスコアを加算します。スコアは隕石を下でタップすれば高得点になるのでY座標

を加算するスコアにします。なお、このゲームではY座標は小数値になることがあるのでMath.fl oor()

を使って整数値にしています。

 最後に隕石をタップした場合に広がる爆風の処理です。レーザービームと同様にstartBeam()関数

内では処理せず、以下のように爆風のサイズを示すカウンタを設定するようにしています。

g.score = g.score + Math.fl oor(g.iy);

g.bCounter = 0;

Page 42: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

206

7.7.3 隕石の移動と描画処理

●隕石の移動・爆風ほかの処理 最後に(4)の隕石の移動と爆風の処理です。まず、Canvasの内容を消去します。これは、以前の

セクションでも解説したclearRect()メソッドを使います。Canvasの内容は消去されますが、CSSで設

定した背景画像はそのままです。もし、CSSで背景画像を設定していない場合は、この後背景画像の

描画処理を行うことになります。リアルタイムゲームでは、そのような処理を追加するだけで速度が遅くなっ

てしまいますので、そのような方法は避けるのがよいでしょう。

 隕石の落下処理は簡単で隕石のY座標に移動量を加算するだけです。

 この隕石は単純に落下するのではなく回転しながら落下してきます。回転は以前のセクションで説

明したようにrotate()メソッドを使います。translate()を使って隕石の中心を回転するようにします。

Canvasの状態を保存、復元するsave()、restore()を忘れないようにしておきます。忘れると描画され

る画像などがおかしくなってしまいます。

 隕石が完全に下まで落下したかどうかはCanvasの高さを超えたかどうかを調べます。落下していた

らインターバルタイマーを止めた後にゲームオーバーのメッセージを出します。今回のゲームではアラート

ダイアログを使っていますが、Canvas内にGame Overの文字を描画してもよいでしょう。

g.context.clearRect(0,0, g.canvasW, g.canvasH); // Canvas内容を消去

g.iy = g.iy + g.dy; // 隕石を移動(落下)

g.context.save(); // コンテキストを保存しておくvar centerX = g.ix + g.stoneSize/2;

var centerY = g.iy + g.stoneSize/2;

g.context.translate(centerX, centerY); // 隕石の中心に移動g.context.rotate(g.rad); // 回転させるg.context.translate(-centerX, -centerY); // 元に戻すg.rad = g.rad + Math.PI / 9;

g.context.drawImage(g.stoneImg, g.ix, g.iy);

g.context.restore(); // 保存したコンテキストを元に戻す

if (g.iy > g.canvasH){

  clearInterval(g.timerID);

  alert("Game Over"); // 隕石が落下したのでゲームオーバー}

Page 43: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

207

Chapter 7キャンバスに描画する

[Canvas ]7.7C

anvas を

使ったリアルタイムゲームの作成

 ここまで来れば残っている処理はレーザービームの描画、爆風の描画、スコアの表示だけです。こ

れまでのセクションでの説明を理解していれば難しい部分はありません。爆風が広がる処理ですが、カ

ウンタを1つずつ増やしていき10未満の場合のみarc()を使って黄色い円を描画しています。

 なお、Android 2.x以降では爆風は半透明になりますが、Android 1.6端末では爆風は半透明にな

りません。

 隕石の数を増やしてみる、爆風を複数表示するように改良してみるのもよいでしょう。

if (g.bCounter < 10){

  g.context.beginPath();

  g.context.fi llStyle = "yellow";

  g.context.globalAlpha = 0.7; // 不透明度を70%にする  g.context.arc(g.bx, g.by, g.bCounter*10, 0, Math.PI*2, false); // 円を描く  g.context.fi ll();

  g.context.globalAlpha = 1.0;

  g.bCounter = g.bCounter + 1;

}

Page 44: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

208

Canvasを使ったノベルシステムの作成

7.8Section

 このセクションではCanvasを使ったノベルシステムの作成について説明します。ノベルシステムは

Canvasを2枚重ねて表示します。一枚が画像を表示するCanvasで、もう1つが文字を表示する

Canvasです。Canvasを2枚重ねることで、文字を書き換える際に背景の画像の書き換えを考慮しなく

てもよいというメリットがあります。

●ノベルシステムとシナリオファイル ノベルシステムは、あらかじめ用意されたシナリオファイルに従って画像と文字を表示していくものです。

ノベルゲームであれば条件分岐なども必要になりますが、ここで作成するシステムはそのような機能はあ

りません。単純に画像とテキストを表示しBGMを演奏するだけのものです。

 シナリオファイルはテキストで構成されており、何もしなければ文字がそのままCanvas上に描画されま

す。ただし、Canvas上に表示される文字は26文字×5行です。この文字数を超えても自動的にスクロー

ルして表示する機能はありません。このため、一度に表示される文字は26文字×5行に収める必要が

あります。

 一定数文字を表示したらタップされるのを待つ、画像を切り換える、といった処理はシナリオファイル

内に専用のコマンドを埋め込むことで実現します。ここで作成するノベルシステムでは表7.8.1に示すコ

マンドを用意しています。今回のシステムでは行頭に#があるものをコマンドとして処理します。

 以下の例ではimagesフォルダにあるschool.jpgを表示しbgmフォルダにあるopening.mp3を演奏し

ます。その後「ようこそ!」という文字を表示して画面がタップされるのを待ちます。

表7.8.1使用できるコマンド

img URLURLにある画像を表示。ネットワーク上にあるものであれば何でも使用できる。なお、画像は合成できるので PNG形式で透明情報が含まれていれば背景に人物を重ねて表示することもできる。

wait 画面がタップされるのを待つ。

bgm URL URLにある音楽を演奏する。Android 2.x~ 3では多重演奏できるが Android 4では単独演奏のみ。

end 処理を終了。最後の画面が表示されたままになる。

Page 45: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

209

Chapter 7キャンバスに描画する

[Canvas ]7.8C

anvas を

使ったノベルシステムの作成

 ノベルシステムでは、このようなシナリオデータを読み込み処理します。実際のプログラムがサンプル

7.8.1になります。Canvas部分に関しては、これまでの説明で十分理解できるでしょう。また、BGM演奏

もAudioオブジェクトを生成した後、play()メソッドで再生しているだけです。

●シナリオファイルの読み込みと解析処理 ここではシナリオファイルを読み込み処理する部分について説明します。

 まず、シナリオファイルは以下のようにして非同期通信を利用して読み込ます。シナリオファイル名は

senario.txtとしています。シナリオデータはsplit()を使って一行単位で分けて配列変数storyに入れて

おきます。これは解析処理を簡単にするためです。なお、改行コードはLF(アスキーコード10番)を

想定しています(String.fromCharCode(10)の部分)。

 シナリオデータを読み込んだら解析開始の行番号を0にします(pointer = 0の部分)。その後、実際

に解析を行うメソッドを呼び出します(nsFunc.main()の部分)。

図7.8.1ノベルシステムの画面

#img images/school.jpg

#bgm bgm/opening.mp3

ようこそ!#wait

$.get("./senario.txt", null, function(data){

  story = data.split(String.fromCharCode(10));

  pointer = 0;

  nsFunc.main();

});

Page 46: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

210

 解析を行う部分は以下のブロックです。

 最初にendコマンドを処理します。endコマンドであれば何もする必要がないためreturnで関数から

抜けます。

 endコマンド以外であれば解析する行を示すポインタ(pointer++)を進めます。もし、空行であれば

特に処理せずにポインタを進めます。

 次にbgmコマンドであればコマンドの後に続くURLの曲を演奏します。解析処理は以後に説明する

画像表示と同じなので省略します。

 次にタップを待つwaitコマンドです。この場合は何もせず関数から抜けます。タップしたら次に進ま

せるには以下のようにCanvasでtapイベントが発生したら解析処理を呼び出すようにします。

 次にimgコマンドです。imgコマンドの場合は半角空白で区切られた後に続く文字をURLとして処

理する必要があります。これは一行のデータをsplit(" ")とし空白単位で切り分けます。配列の2番目に

格納されるのがURLになるので、これを画像オブジェクトのsrcに入れます。後はCanvasに描画すれ

ばできあがりです。

while(true){

  var text = story[pointer];

  if (text.indexOf("#end") > -1){ endFlag = true; return; }  pointer++;

  if (text.charCodeAt(0) < 32){ continue; }  if (text.indexOf("#bgm") > -1){ nsFunc.bgm(text); continue; }  if (text.indexOf("#wait") > -1){ return; }  if (text.indexOf("#img") > -1){ nsFunc.image(text); continue; }  contextText.fi llStyle = "white";

  contextText.font = "11px bold";

  contextText.fi llText(text, 10, linePointer, 300);

  linePointer = linePointer + 18; // 行間隔は18ピクセル}

image : function(text){

  var data = text.split(" "); // 空白区切り  var imageObj = new Image();

  imageObj.src = data[1]; // 2番目が画像のURL

  imageObj.onload = function(){

    contextBG.drawImage(this, 0, 0);

  }

},

$("#textCanvas").bind("tap", nsFunc.main);

Page 47: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

211

Chapter 7キャンバスに描画する

[Canvas ]7.8C

anvas を

使ったノベルシステムの作成

 最後に文字表示です。いずれのコマンドでもない場合はCanvasに文字を表示します。そして、い

ずれかのコマンドが見つかるまで解析処理を行います。

 他にコマンドを追加して条件分岐やローカルストレージへの保存を行うのも面白いでしょう。ちなみに

#evalコマンドを追加し、以後に続く文字列をJavaScriptコードとして実行させるという手法もあります。

この方法だとシステムに変更を加えることなく複雑な処理も実現できます。

図7.8.2最初の画面

図7.8.3

画面をタップすると画像と文字、または文字だけが切り替わる(①~④)。

図7.8.4

① ②

Page 48: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

212

図7.8.8

タップすることで次々と画像と文字が切り替わる(①~④)。

図7.8.7bgmコマンドにより音楽の演奏が開始される。

図7.8.5 図7.8.6

③ ④

Page 49: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

213

Chapter 7キャンバスに描画する

[Canvas ]7.8C

anvas を

使ったノベルシステムの作成

図7.8.9 図7.8.10

図7.8.11 図7.8.12endコマンドを処理すると終了する。なお、Endの文字は透明のPNG画像になっており、描画済みの背景画像に重ねて表示している。

③②

Page 50: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

214

var story, contextBG, contextText, canvasW, canvasH, pointer;

var endFlag = false;

$(function(){

  // シナリオデータを読み込む  $.get("./senario.txt", null, function(data){

    story = data.split(String.fromCharCode(10));

    pointer = 0;

    nsFunc.main();

  });

  // Canvasを初期化し塗り潰す  var canvasBgObj = document.getElementById("bgCanvas");

  canvasW = canvasBgObj.width;

  canvasH = canvasBgObj.height;

  contextBG = canvasBgObj.getContext("2d");

  var canvasTextObj = document.getElementById("textCanvas");

  contextText = canvasTextObj.getContext("2d");

●サンプル7.8.1 novel.js●

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content= "initial-scale=1, user-scalable=no">

    <title>ノベルシステム</title>

    <link rel="stylesheet" href="css/jquery.mobile.css">

    <style>

      canvas { position: absolute; top:50px; left:10px; }      #main { height: 400px; }    </style>

    <script src="js/jquery.js"></script>

    <script src="js/novel.js"></script>

    <script src="js/jquery.mobile.js"></script>

  </head>

  <body>

    <div data-role="page" id="content">

      <div data-role="header">

        <h1>ノベルシステム</h1>

      </div>

      <div data-role="content" id="main">         <canvas id="bgCanvas" width="300" height="400"></canvas>

        <canvas id="textCanvas" width="300" height="400"></canvas>

      </div>

    </div>

  </body>

</html>

●サンプル7.8.1●

Page 51: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

215

Chapter 7キャンバスに描画する

[Canvas ]7.8C

anvas を

使ったノベルシステムの作成

  nsFunc.clearText();

  $("#textCanvas").bind("tap", nsFunc.main);

});

var nsFunc = {  // 解析する  main : function(){

    if (endFlag == true){ return; }    var linePointer = 320; // 文字を表示する開始Y座標    nsFunc.clearText();

    while(true){

      var text = story[pointer];

      if (text.indexOf("#end") > -1){ endFlag = true; return; }      pointer++;

      if (text.charCodeAt(0) < 32){ continue; }      if (text.indexOf("#bgm") > -1){ nsFunc.bgm(text); continue; }      if (text.indexOf("#wait") > -1){ return; }      if (text.indexOf("#img") > -1){ nsFunc.image(text); continue; }      contextText.fi llStyle = "white";

      contextText.font = "11px bold";

      contextText.fi llText(text, 10, linePointer, 300);

      linePointer = linePointer + 18; // 行間隔は18ピクセル    }

  },

  // 文字表示用のCanvasをクリア  clearText : function(){

    contextText.save();

    contextText.clearRect(0,0, canvasW, canvasH);

    contextText.fi llStyle = "black";

    contextText.globalAlpha = 0.65;

    contextText.fi llRect(0, 300, canvasW, 100);

    contextText.restore();

  },

  // 指定された画像を表示  image : function(text){

    var data = text.split(" "); // 空白区切り    var imageObj = new Image();

    imageObj.src = data[1]; // 2番目が画像のURL

    imageObj.onload = function(){

      contextBG.drawImage(this, 0, 0);

    }

  },

  // 指定された曲を演奏  bgm : function(text){

    var data = text.split(" "); // 空白区切り    var audioObj = new Audio(data[1]); // 2番目がBGMのURL

    audioObj.play();

  }

}

Page 52: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

216

#img images/title.jpg

ここは木曽谷。木曽の山奥には、いろいろな滝があります。今回は南木曽町にある柿其渓谷の滝を紹介しましょう。#wait

【………… 省 略 …………】

#img images/waterfall.jpg

#bgm bgm/star.mp3

「ねじだる」の次に現れるのが「霧ヶ滝」です。エメラルドグリーンの滝壺は非常にきれいで濁りがありません。#wait

【………… 省 略 …………】

#img images/end.png

以上で終わりです。#end

●サンプル7.8.1 senario.txt●

Page 53: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

217

Chapter 7キャンバスに描画する

[Canvas ]7.8C

anvas を

使ったノベルシステムの作成

Canvas関係のバグColumn

【バグ】shadowOffsetYプロパティ 

 shadowOffsetYプロパティはAndroid 2.x, 3では、通常とは逆方向に影が描画されてしまうバグがあります。正数を指定すると下方向に影が描画されるはずが、上方向に描画されてしまいます。このバグはAndroid 4では修正されています。

var canvasObj = document.getElementById("myCanvas");

context = canvasObj.getContext("2d");

context.fi llStyle = "red";

context.shadowBlur = 5;

context.shadowOffsetX = 4;

context.shadowOffsetY = 8;context.shadowColor = "orange";

context.font = "32px Times";

context.fi llText("Android", 10, 60);

●コード●

図7.8.13Android 2.xでは影が上方向に描画がされている。本来は下方向に描画されなければならない。

図7.8.14Android 4では影が正しく下方向に描画がされている。

次頁へ続く

Page 54: Chapter 07 color - ric.co.jp · Canvasは2D(平面)に自由にグラフィックを描くことができるものと、WebGLを使って3D(立体)を 描画するものがあります。Android標準ブラウザではWeb

218

【バグ】arcメソッド 

 Canvasでは描画する方向(ベクトル)が異なっている場合、重なったパスの内部はくり抜かれます。このため、arc()メソッドの最後のパラメータで時計回りに描画するか、反時計回りに描画するかを指定するフラグがあります。しかし、Android 1.6~ 4.0の全てにおいて最後のパラメータが正しく反映されません。 このため、ドーナツ型の図形を描こうとしても、ただの塗り潰された丸になってしまいます。通常のパスを構築した場合は正常に処理されるのでarc()メソッドのバグでしょう。

var canvasObj = document.getElementById("myCanvas");

var context = canvasObj.getContext("2d");

context.fi llStyle = "red"; // 赤色context.beginPath();

context.arc(120, 200, 60, 0, Math.PI*2, true);

context.closePath();

context.arc(180, 200, 60, 0, Math.PI*2, false);

context.closePath();

context.fi ll();

●コード●

図7.8.15Android 4 (Galaxy Nexus) での実行結果。重なった部分がくり抜かれない。

図7.8.16iOSでの実行結果。これが正しい結果。パソコンのブラウザでも同様の結果になる。