今回はcannon.jsで駄菓子屋10円ゲームをつくります。Cannon.js はオープンソースの JavaScript 3D物理エンジンです。Three.js (WebGL) と組み合わせて使用されることが多いのですが、今回は2Dで作ります。
Contents
基本的な使い方
今回作成するアプリで使う機能だけ解説します。
物体が重力の影響をうけるようにするにはWorldオブジェクトを生成して以下のように設定します。
|
1 2 |
const world = new CANNON.World(); world.gravity.set( 0, -9.8, 0 ); |
箱や球を生成するときは以下のようにします。
幅10、高さ20、奥行き30の箱を生成する
|
1 2 3 4 5 6 7 8 9 |
const body = new CANNON.Body({ mass: 0, // 0 を指定すると重力の影響をうけない shape: new CANNON.Box(new CANNON.Vec3(10 / 2, 20 / 2, 30 / 2)), position: new CANNON.Vec3(10, 20, 30), // 箱の中心座標は(10, 20, 30)とする material: new CANNON.Material({ restitution: 0.5, // 反発係数 }), }); world.addBody(body); |
半径10の球を生成するときは以下のようにします。
|
1 2 3 4 5 6 7 8 9 10 |
const body = new CANNON.Body({ mass: 0.01, // kg shape: new CANNON.Sphere(10), position: new CANNON.Vec3(0, 0, 0), // 中心の座標 material: new CANNON.Material({ restitution: 0.4, // 反発係数 friction: 1.0, // 摩擦係数 }), world.addBody(body); }); |
なにかがぶつかったときに処理をしたいときは以下のようにします。
|
1 2 3 |
body.addEventListener('collide', () => { // ここにやりたいことを書く }); |
とりあえずこれだけあれば今回は充分です。でははじめてみましょう。
HTML部分
HTML部分を示します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>鳩でもわかる駄菓子屋10円ゲーム</title> <meta name = "viewport" content = "width=device-width, initial-scale = 1.0"> <link rel="stylesheet" href="./style.css"> <link rel="shortcut icon" type="image/x-icon" href="https://lets-csharp.com/wp-content/themes/cool_black/favicon.ico"> </head> <body> <div id = "container"> <h1>鳩でもわかる駄菓子屋10円ゲーム</h1> <div id = "main"> <div id = "canvas-outer"></div> <div id = "start-buttons"> <button id = "start">START</button> </div> </div> <div id = "control-buttons"> <button id = "shot">Shot</button> <div id = "power"></div> </div> <div id = "volume-controller"></div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script> <script src="./index.js"></script> </body> </html> |
style.css
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
body { background-color: black; color: white; } h1 { font-size: 20px; color: magenta; text-align: center; } #container { width: 360px; margin-left: auto; margin-right: auto; } #main { position: relative; height: 430px; } #canvas-outer { display: block; position: absolute; left: 0px; top: 0px; } #start-buttons { position: absolute; width: 100%; height: 40px; left: 0px; top: 260px; text-align: center; } #start { height: 60px; width: 200px; font-weight: bold; font-size: x-large; } #control-buttons { height: 40px; border: 1px solid #000; background-color: #000; display: none; } #shot { height: 40px; width: 100px; } #power { display: inline-block; height: 30px; width: 200px; border: 1px solid #000; vertical-align: middle; margin-left: 10px; overflow: hidden; } |
グローバル変数の定義
以下のグローバル変数を定義します。
index.js
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
const CANVAS_WIDTH = 360; // canvasのサイズ const CANVAS_HEIGHT = 430; const BALL_RADIUS = 16; // ボール(10円玉だが球体とする)の半径 const LEFT_X = 40; // 左右の壁のX座標 const RIGHT_X = CANVAS_WIDTH - 40; const TOP_Y = 460; const POWER_CANVAS_WIDTH = 200; // パワーゲージ描画用のcanvasのサイズ const POWER_CANVAS_HEIGHT = 30; const POWER_MAX = 800; // 10円玉を打ち出すときの強さの最大値 const world = new CANNON.World(); let ball; // ボール、コース、穴、左右・下の壁、ゴールの描画、当たり判定用のオブジェクトを格納する変数 let courses = []; let holes = []; let wall; let goal; let power = 0; // 10円玉を打ち出す強さ // DOM要素 const $container = document.getElementById('container'); const $canvas_outer = document.getElementById('canvas-outer'); const $start_buttons = document.getElementById('start-buttons'); const $control_buttons = document.getElementById('control-buttons'); const $canvas = document.createElement('canvas'); $canvas_outer.appendChild($canvas); const ctx = $canvas.getContext('2d'); const $power = document.getElementById('power'); const $power_canvas = document.createElement('canvas'); $power.appendChild($power_canvas); const power_ctx = $power_canvas.getContext('2d'); // 描画に使用するイメージ const wallImage = new Image(); wallImage.src = './images/wall.png'; const ballImage = new Image(); ballImage.src = './images/ball.png'; const backImage = new Image(); backImage.src = './images/hatoko.png'; const outImage = new Image(); outImage.src = './images/out.png'; const goalImage = new Image(); goalImage.src = './images/goal.png'; // 効果音 const selectSound = new Audio('./sounds/select.mp3'); const shotSound = new Audio('./sounds/shot.mp3'); const goalSound = new Audio('./sounds/goal.mp3'); const deadSound = new Audio('./sounds/dead.mp3'); const gameoverSound = new Audio('./sounds/gameover.mp3'); const sounds = [selectSound, shotSound, goalSound, deadSound, gameoverSound]; |
その他の処理は次回とします。
