Web で物理アニメーション・その1 「canvas で絵を描いてみよう」

アニメーションを作ってみよう!

最近、動きがある Web ページが多くなりましたね。
ここ数年で Web は大分進化しました。
今では単純に動くだけのページだけではなく、 Web ページで本格的なゲームができたりします。

Web でゲーム、自分でも作ってみたいですよね?

ゲームを作る場合に大切になるのが「アニメーション」です。

今回はそんなアニメーションの中でも、
「物理」アニメーションにクロースアップしてみましょう。

ちなみに、今回は続き物で書こうかなと思っています。
せっかくなので最後に宿題も出しますので、是非やってみてくださいね。
(回答は次回の冒頭に記載します)

物理アニメーションとは?

まず、物理アニメーションとはどんなものか?と言うことなのですが…
そのまま、物質が物理計算に従って動いているように見えるアニメーションのことです。

とは言っても、正確にはそんな言葉が存在するかは分かりませんが…
一旦ここでは、そういう定義だとしましょう。

そんなものが何の役に立つのか?とお思いかもしれません。
確かに研究者が、コンピュータ上で実験するときにそんなことをするイメージはあるかと思いますが…

意外に身近なところで、皆さんがよく知っているテレビゲームも
物理アニメーションの集合体と言ってもよいでしょう。

例えば、キャラクターがジャンプする動作を考えてみましょう。
何の変哲も無いアニメーションのようですが、
たいていの場合はきちんとジャンプしたキャラクターは地面に戻ってきますよね。

ここで、キャラクターが地面に戻ってくるということはすなわち、
キャラクターに対して重力がかかっているということです。

当たり前のことのように感じますが、ジャンプ一つとってみても

  • ジャンプしたときの足の力を考えてキャラクターを上に飛ばし
  • キャラクターの重量を考慮して重力をかけ、キャラクターが途中から落下するようにし
  • 地面まで戻ってきたら、それ以上落下しないようにする

ざっくり考えてもこんな処理が内部では実行されているんですね。

物理アニメーションをやる前に – 画面に描画する方法を覚えよう

さて、早速物理アニメーションを…と言いたいところですが、
まずその前に、画面に絵を描く方法が分からなければいけないですよね。

ということで、今回はまず、画面上に絵を描く方法から学んでいきましょう。

canvas の準備

今回は Web 上でアニメーションを作りたいので、
もちろんブラウザで実行することになります。

ブラウザで絵を描くには、 canvas 要素が使えますね。

とりあえず画面はこんな感じで…

<!DOCTYPE html>
<html>
<head>
  <meta charset=”utf-8”>
  <title>Canvas Test</title>
</head>
<body>
  <canvas
    id=”canvas”
    width=”640”
    height=”480”
    style=”
      border: solid 1px #000000;
      box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
      border-radius: 3px;”
  ></canvas>
  <script src=”./index.js”></script>
</body>
</html>

canvas は初期状態では真っ白なので、
枠線をつけてわかりやすくしてみました。

現時点で画面はこんな感じ。

index.html と同じ所に index.js ファイルも設置しておけば、
そこから JavaScript を読み込んで実行するようにしてあります。

canvas に図形を描画してみる

とりあえず canvas は用意できたので、実際にここに簡単な図形を書いてみましょう。

ちなみに、一応画像なんかも読み込んで表示したりできますが、
今回は最終的にやりたいのは物理アニメーションなので
図形の描画のみやります。

長方形を書くのは以下のコード

const main = () => {
  // キャンバス要素の取得
  const canvas = document.getElementById(”canvas’);
  // キャンバスを操作する API を取得
  const ctx = canvas.getContext(’2d’);

  // 長方形を描画する
  // 線を引く作業を開始
  ctx.beginPath();

  // 座標 30, 30 へ移動
  ctx.moveTo(30, 30);
  // 座標 30, 120 まで直線を引く
  ctx.lineTo(30, 120);
  // 座標 360, 120 まで直線を引く
  ctx.lineTo(360, 120);
  // 座標 360, 30 まで直線を引く
  ctx.lineTo(360, 30);

  // 開始地点に戻って線を閉じる
  ctx.closePath();

  // 引いた線の内側を塗りつぶす
  ctx.fill();
};

document.addEventListener(’DOMContentLoaded’, main);

先にこれを実行した結果をお見せすると、こんなかんじ。

実際の処理の解説をしていきますね。

一番下の addEventListener は、画面の準備ができたら main の関数を実行してね、
というだけの内容なので良いとして、実際に main の関数の中身でやっていることを見ていきます。

  // キャンバス要素の取得
  const canvas = document.getElementById(’canvas’);
  // キャンバスを操作する API を取得
  const ctx = canvas.getContext(’2d’);

まず、html の方で作成した canvas を取得してきます。
canvas 要素は、描画内容を操作するための API を持っていますので、
それを getContext(’2d’) で取得して ctx 変数に格納しています。

なんとなくお気づきの方もいらっしゃるかと思いますが、 2d とあるので、
平面的に描画するための API ですね。

では 3d とやれば立体的な絵が描けるのか…?というと、
まだそこまでは用意されていないので、残念ながらできません。
(将来的にはできるようになるかもしれないですね!)

とりあえず、この後は ctx に対して操作することで、
canvas の描画内容を更新していくことができます。

  // 長方形を描画する
  // 線を引く作業を開始
  ctx.beginPath();

次に、線を今から引きますよと言う命令を出しておきます。

canvas で図形を描画する際には、次に示すように
ある座標からある座標まで線を引く、のような方法で命令をして描画していきます。

  // 座標 30, 30 へ移動
  ctx.moveTo(30, 30);
  // 座標 30, 120 まで直線を引く
  ctx.lineTo(30, 120);
  // 座標 360, 120 まで直線を引く
  ctx.lineTo(360, 120);
  // 座標 360, 30 まで直線を引く
  ctx.lineTo(360, 30);

  // 開始地点に戻って線を閉じる
  ctx.closePath();

コメントのとおりですが、筆を指定された座標へ持って行って、
線を書いているイメージ。

ちなみに、web の世界では左上が原点(すなわち座標が 0, 0)であり、
右方向が x 座標、下方向が y 座標になります。

こんな感じで、座標をとって 1 から順に線を引いていくのですね。

ちなみに最後、 ctx.lineTo(30, 30); でなく ctx.closePath(); となっていますが、
引いた線が閉じていない時は、自動で閉じるように命令できるんですね。
ということで、 ctx.lineTo(30, 30); と書いても OK。意味的には同じです。

ただ、ここまで実行してみても、画面上には何も表示されません。
(最後の ctx.fill(); を消して実行してみたら、画面が真っ白のままであることを確認できます)

これは、上の作業では実際に目に見える線を引いたわけではなく、
これから描画する「範囲を指定」しただけなのですね。

ということで、実際に長方形が見えるようにするには、
その範囲を塗りつぶしてしまいましょう。

  // 引いた線の内側を塗りつぶす
  ctx.fill();

これで塗りつぶしができました!
ということで、最初にお見せしたように長方形が描画されるということになりました。

もっと簡単に長方形をかく

上の操作で、canvas 上での描画の考え方について大体理解してもらえたのではないでしょうか。

ただ、長方形のような、描画する頻度が高い単純な図形は、
もう少し簡単にかけるといいのにな…という感じがしますよね。

そうです。きちんと方法がありますよ。

const main = () => {
  // キャンバス要素の取得
  const canvas = document.getElementById(’canvas’);
  // キャンバスを操作する API を取得
  const ctx = canvas.getContext(’2d’);

  // 長方形を描画する
  // 線を引く作業を開始
  ctx.beginPath();

  // 長方形を描画する
  ctx.fillRect(30, 30, 330, 90);
};

document.addEventListener(’DOMContentLoaded’, main);

すごく短くなりましたが、これでも先ほどと同じ図形が描画されます!

ポイントは

  // 長方形を描画する
  ctx.fillRect(30, 30, 330, 90);

ここですね。

ctx.fillRect(x 方向の開始点, y 方向の開始点, x 方向の長さ, y 方向の長さ);

これだけで、先ほど長々と書いたパスの指定をして塗りつぶしまでやってくれるのだから、とても便利です。

円(円弧)もかける

先ほどのパスの指定方法だと長方形のような直線的な図形は書けますが、
円のような曲線的な図形は難しいですよね。

直線のパスと同様、曲線のパスを描画する命令も存在します!

const main = () => {
  // キャンバス要素の取得
  const canvas = document.getElementById(’canvas’);
  // キャンバスを操作する API を取得
  const ctx = canvas.getContext(’2d’);

  // 線を引く作業を開始
  ctx.beginPath();

  // 円のパスを作成
  ctx.arc(120, 120, 40, 0, Math.PI * 2, true);

  // 塗りつぶしの色を指定
  ctx.fillStyle = ’rgb(33, 150, 253)’;

  // 塗りつぶしを実行
  ctx.fill();
};

document.addEventListener(’DOMContentLoaded’, main);

円のパスを作っているのは

  // 円のパスを作成
  ctx.arc(120, 120, 40, 0, Math.PI * 2, true);

この部分ですね。

引数が少し複雑ですが、

  // 円のパスを作成
  ctx.arc(x 方向の円弧の中心点, y 方向の円弧の中心点, 半径, 開始点, 終了点, 時計回り or 反時計回り);

ここで難しいのは 開始点終了点 ですね。

円のどこの部分から書き始めて、どこの部分で終わるか、と言う指定になります。
今回は円なので一週ぐるっと書いていますが、ここをうまく調整することで
半円なんかもつくれるようになるのですね。

ちなみに、角度はラジアンなので、 パイ Math.PI を使って計算してあげる必要があります。
詳しい説明は省きますが、サンプルの通りパイの 2 倍で一週分ですね。
2倍せずに使ったら半円になります。

  // 円のパスを作成
  ctx.arc(120, 120, 40, 0, Math.PI, true);

最後の 時計回り or 反時計回り は、 false だと反時計回り、 true だと時計回りで描画します。
今回は一週書いているのでどちらでもいいですね。

最後に、今回はちょっと色もつけてみました。

  // 塗りつぶしの色を指定
  ctx.fillStyle = ’rgb(33, 150, 253)’;

どんな色にするかは CSS での色指定と同じなので、
色々調べたい方はその方向で調べてもらったらよいかと。

宿題

さて、今回は canvas での図形描画方法について学びました。
物理アニメーション、ひいてはアニメーションを作るためには絵が描けなければ行けませんので、
まずは図形を書く作業をマスターしていきましょう。

というわけで、今回の宿題はこちら。

  • 三角形を一つ、canvas 上に描画してください

今後シミュレーションを作って行くに当たって、使うのは円の描画が主になりますが、
ここは一つ、自分でパスを作って描画する方法についておさらいしておきましょう。

canvas 上での描画の考え方をしっかりと把握しておきましょうね。

一応ヒントというか、考え方も。

  1. 長方形や円は簡単にかけましたが、三角形はどちらでもないので、パスを自分で作って描画する必要があります。

  2. 三角形と言えば下の画像のようなものを想像されるかと思います。

    …ですが、三角形の定義は、ざっくり言えば角が三つあればいいです。
    角が三つあれば、どんな形でも三角形ですね。
    (もちろん、自信がある方は上の画像のような三角形も書いてみてくださいね!)

それではまた次回!

Takato Ezaki

Takato Ezaki小中高の塾講師からエンジニア

投稿者プロフィール

福岡で Web 系のエンジニアをしています。

中高の理科教師免許を取り、起業に 2 年間トライした後エンジニアの道へ入りました。

化学反応の中では Belousov-Zhabotinsky 反応が大好きです。

この著者の最新の記事

関連記事

コメントは利用できません。

募集中!(o゜▽゜)o

エンジャパン
求む、社長!
follow us in feedly

コッチもヨロシク!



最近のネタ!

  1. 2019-12-7

    お小遣いを握りしめてガチャガチャをしにいく話【Agent Grow Advent Calendar 2019:7日目】

    (さらに…)…
  2. 2019-12-6

    2019年度エージェントグロー全社員総会の様子+二次会

    2019年度エージェントグロー全社員総会 さる2019年11月15日 (金) に行われました全社員…
  3. 2019-12-6

    ゲーム性があれば飽き性でも運動できた!【Agent Grow Advent Calendar 2019:6日目】

    この記事はAgent Grow Advent Calendar 2019 6日目の記事です。 はじ…
  4. 2019-12-5

    現代社会を生きる人々に贈るスッキリ映画5選【Agent Grow Advent Calendar 2019:5日目】

    この記事は Agent Grow Advent Calendar 2019 :5日目の記事です。…
  5. 2019-12-4

    来年の干支にちなんで世界の珍しいネズミと動物園をご紹介【Agent Grow Advent Calendar 2019:4日目】

    来年はネズミ年です。 この記事は Agent Grow Advent Calendar 2019 …
ページ上部へ戻る

当サイトに掲載されているコンテンツ(文書、画像等)は、許可なく複製・転用等する事を禁じます。

「フェアネス方式®」(登録6150741)は、日本国内における株式会社エージェントグローの登録商標です。

当サイトでは最低限必要と考えられる場合において、会社名/サービス名/商品名などを記載している場合があります。
これらはあくまでも説明の必要性に応じて用いているものであり、各社の権利等を侵害を目的とするものではございません。
不適切と考えられる場合には、当社お問い合わせフォームよりご連絡ください。

当サイトでは®や™などの表記を省略させていただいております。