# チュートリアル[ゲーム要素に数学を加えてみようその2] ### 目次 > #### Step0 まずは準備 > #### Step1 クマに動きを追加しよう。(正弦の場合) > #### Step2 クマに動きを追加しよう。(余弦の場合) > #### Step3 システムにボタンを追加しよう ## Step0 まずは準備 ## 数学の動き ゲームを作っていくときにキャラクターに変わった動きをさせたいときがあります。 このような動きを簡単に作るためには数学のグラフの動きを再現することが必要です。 ゲームの動きで波のような動きをさせたいときがあると思います。波の動きを作るときに役に立つのが三角関数です。 三角関数とは,平面三角法における,角の大きさと線分の長さの関係を記述する関数の族および,それらを拡張して得られる関数の総称です。 ## 実際に使ってみよう 今回はこちら用意した学習支援システムで学習を行います。 以下の部分をクリックしてみてください。 [学習システム](https://) するとログイン画面が出ます。 ![](https://i.imgur.com/uQ9xF8k.png) 皆さんの机の上にあるメモを見てユーザIDとパスワードを入力してください。 今回のチュートリアルに沿って、9つの問題があると思います。 上から順番にやっていきましょう。 ## Step1 クマに動きを追加しよう。(正弦の場合) まずは下のコードのような骨組みを用意しましょう。 ```javascript= enchant(); var game; //ゲーム画面設定 var GameWidth = 500; var GameHeight = 320; //円周率 var pi = Math.PI /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ //➀ここに動きの処理を追加する }); window.onload = function() { game = new Game(GameWidth, GameHeight); game.preload('images/chara1.png','images/masu_三角関数.png' ,'images/next.png'); game.onload = function() { //背景画像を設定 var bg= new Sprite(500, 320); bg.image = game.assets["images/masu_三角関数.png"]; game.rootScene.addChild(bg); /* クマをつくる */ bear = new Bear(-4, -4); //線を作る sprite = new Sprite(500, 320); //Surfaceを作ります surface = new Surface(500, 320); //spriteのimageにsurfaceを代入します sprite.image = surface; //コンテキストを取得します context = surface.context; //シーンにサーフェスを追加する ' game.rootScene.addChild(sprite); var input = new Entity(); var input_down = new Entity(); //入力テキスト作成 input._element = document.createElement('input'); input._element.setAttribute('type','text'); input._element.setAttribute('maxlength','5'); input._element.setAttribute('value','0'); input.width = 30; input.height = 20; input.x = 50; input.y = 20; //rootSceneに追加 game.rootScene.addChild(input); // ラベルを作成 var myLabel = new Label("π"); myLabel.x = 80; // X座標 myLabel.y = 20; // Y座標 // ラベルを画面に表示 game.rootScene.addChild(myLabel); //開始ボタンの作成 input_button = new Sprite(124, 30); input_button.x = 100; input_button.y = 22; input_button.image = game.assets['images/next.png']; //開始ボタンを画面に表示 game.rootScene.addChild(input_button); //開始ボタンをタッチしたとき入力値を計算してクマの停止座標を決める input_button.addEventListener('touchstart', function() { bear.input_x = input._element.value; var input_up = Number(bear.input_x);//分子の値を取得する var input_down = 1; //分母の値を取得する //入力値に’/’が含まれているときに’/’を境に分子と分母を取得する if ( bear.input_x.indexOf('/') != -1){ input_up = Number(before_cut(bear.input_x));//分子の値を取得する input_down = Number(after_cut(bear.input_x));//分母の値を取得する } input_num = input_up/input_down;//分子÷分母を行う }); }; game.start(); }; //決められた値より前を取り出す before_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.substring(0, index); return str; } //決められた値より後を取り出す after_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.slice(index + 1); return str; } ``` クマの画像が表示されていれば大丈夫です 基本的にはその1と一緒ですが、背景を三角関数用にしています ![](https://i.imgur.com/ag5YmrP.png) これにクマの動きを追加していきます。 ### 三角関数(正弦とは) 三角関数とは,平面三角法における,角の大きさと線分の長さの関係を記述する関数の族および,それらを拡張して得られる関数の総称である.三角関数の一つがsin(正弦)である.sinθは下図の場合b/cで求めることができる. ![](https://i.imgur.com/pP9Hxy5.png) 表に主なものをまとめる(πは円周率である) ![](https://i.imgur.com/ul56esh.png) sinθなどの三角関数を定義するとき,θは角度を意味している. しかし,三角関数を,ある数θに対応する数を与える式,とより抽象的にみるならば, θの意味を角度に限定する必要はない. このため,変数をθで表さず,y=sinxのようにxで表すことも多く, 以下でもそのように扱っていく. θの単位はラジアンであり,πラジアン=180°となっている. そのため,-π/2は-90°,π/6は30°を示す. また、三角関数を表す際には,sin(-π/2)=-1,sin180°= 0のように表記することができる. ## sinの動きをする関数を作成しよう enchant.jsではsin()を表すときに以下の関数を利用します ```javascript= 与えたい変数 = Math.sin(値); ``` これをもとにsinカーブを描くための関数を作成します。 ```javascript= //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, ``` これをもとにクラスBearは以下のようになります ```javascript= /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; //三角関数の係数 this.A = 1; this.a = 0; this.b = 1; if(this.b%2!=0){ plus = 1; } else{ plus = -1; } game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ onenterframe: function() { //クマの動作を行う this.y = plus*this.sin_graph(this.x-GameHeight/2)+GameHeight/2;//関数の値をゲーム座標に移す this.x += 1; //線を描画する //Spriteを作ります //線の描画を始める context.beginPath(); //パスを開始 context.moveTo(this.ox-1, this.oy-1); context.lineTo(this.x-1, this.y-1); context.closePath(); //パスを終了 context.stroke(); //パスを描画する //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; }, //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, }); ``` 今回の場合 A=1, a=0, b=1なので式はy=sin(x)になります 実際に動きを見てみましょう ![](https://i.imgur.com/R15aFcf.gif) ではy=sin(3x),y=sin(x-π/2),y=2sin(x-π/2)の時どのようになるか確認してみましょう ## 挑戦してみよう それではthis.A,this.a,this.bの値を変更して以下のグラフを作ってみましょう。 (1)y=sin(2x)の式の動きを作ってみよう (2)y=sin(x-π/2)の式の動きを作ってみよう (3)y=2sin(x-π/2)の式の動きを作ってみよう <details> <summary>完成コードは以下のようになります</summary> ```javascript= enchant(); var game; //ゲーム画面設定 var GameWidth = 500; var GameHeight = 320; //円周率 var pi = Math.PI /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; //三角関数の係数 this.A = 1; this.a = 0; this.b = 1; if(this.b%2!=0){ plus = 1; } else{ plus = -1; } game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ onenterframe: function() { //クマの動作を行う this.y = plus*this.sin_graph(this.x-GameHeight/2)+GameHeight/2;//関数の値をゲーム座標に移す this.x += 1; //線を描画する //Spriteを作ります //線の描画を始める context.beginPath(); //パスを開始 context.moveTo(this.ox-1, this.oy-1); context.lineTo(this.x-1, this.y-1); context.closePath(); //パスを終了 context.stroke(); //パスを描画する //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; }, //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, }); window.onload = function() { game = new Game(GameWidth, GameHeight); game.preload('images/chara1.png','images/masu_三角関数.png' ,'images/next.png'); game.onload = function() { //背景画像を設定 var bg= new Sprite(500, 320); bg.image = game.assets["images/masu_三角関数.png"]; game.rootScene.addChild(bg); /* クマをつくる */ bear = new Bear(-4, -4); //線を作る sprite = new Sprite(500, 320); //Surfaceを作ります surface = new Surface(500, 320); //spriteのimageにsurfaceを代入します sprite.image = surface; //コンテキストを取得します context = surface.context; //シーンにサーフェスを追加する ' game.rootScene.addChild(sprite); var input = new Entity(); var input_down = new Entity(); //入力テキスト作成 input._element = document.createElement('input'); input._element.setAttribute('type','text'); input._element.setAttribute('maxlength','5'); input._element.setAttribute('value','0'); input.width = 30; input.height = 20; input.x = 50; input.y = 20; //rootSceneに追加 game.rootScene.addChild(input); // ラベルを作成 var myLabel = new Label("π"); myLabel.x = 80; // X座標 myLabel.y = 20; // Y座標 // ラベルを画面に表示 game.rootScene.addChild(myLabel); //開始ボタンの作成 input_button = new Sprite(124, 30); input_button.x = 100; input_button.y = 22; input_button.image = game.assets['images/next.png']; //開始ボタンを画面に表示 game.rootScene.addChild(input_button); //開始ボタンをタッチしたとき入力値を計算してクマの停止座標を決める input_button.addEventListener('touchstart', function() { bear.input_x = input._element.value; var input_up = Number(bear.input_x);//分子の値を取得する var input_down = 1; //分母の値を取得する //入力値に’/’が含まれているときに’/’を境に分子と分母を取得する if ( bear.input_x.indexOf('/') != -1){ input_up = Number(before_cut(bear.input_x));//分子の値を取得する input_down = Number(after_cut(bear.input_x));//分母の値を取得する } input_num = input_up/input_down;//分子÷分母を行う }); }; game.start(); }; //決められた値より前を取り出す before_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.substring(0, index); return str; } //決められた値より後を取り出す after_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.slice(index + 1); return str; } ``` </details> ## Step2 ゲームのキャラに関数y=acos(bx-c) の動きを付けよう ## 三角関数(余弦とは) 三角関数とは,平面三角法における,角の大きさと線分の長さの関係を記述する関数の族および,それらを拡張して得られる関数の総称である.三角関数の一つがcos(余弦)である.cosθは下図の場合a/cで求めることができる. ![](https://i.imgur.com/pP9Hxy5.png) 表に主なものをまとめる(πは円周率である) ![](https://i.imgur.com/DTl3s6f.png) y=sinxのグラフをx軸方向に−π/2平行移動させた表になっていることが分かる. cosθなどの三角関数を定義するとき,θは角度を意味している. しかし,三角関数を,ある数θに対応する数を与える式,とより抽象的にみるならば, θの意味を角度に限定する必要はない. このため,変数をθで表さず,y=cosxのようにxで表すことも多く, 以下でもそのように扱っていく. θの単位はラジアンであり,πラジアン=180°となっている. そのため,-π/2は-90°,π/6は30°を示す. また、三角関数を表す際には,cos(-π/2)= 0,cos180°= -1のように表記することができる. ## cosの動きをする関数を作成しよう enchant.jsではcos()を表すときに以下の関数を利用します ```javascript= 与えたい変数 = Math.cos(値); ``` これをもとにcosカーブを描くための関数を作成します。 ```javascript= //三角関数でグラフを作る //cos関数の場合 cos_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.cos(this.b*x-this.a*pi);//y=Acos(bx-a) y *=59;//yの調整 return y ; }, ``` これをもとにクラスBearは以下のようになります ```javascript= /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; //三角関数の係数 this.A = 1; this.a = 0; this.b = 1; if(this.b%2!=0){ plus = 1; } else{ plus = -1; } game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ onenterframe: function() { //クマの動作を行う this.y = plus*this.cos_graph(this.x-GameHeight/2)+GameHeight/2;//関数の値をゲーム座標に移す this.x += 1; //線を描画する //Spriteを作ります //線の描画を始める context.beginPath(); //パスを開始 context.moveTo(this.ox-1, this.oy-1); context.lineTo(this.x-1, this.y-1); context.closePath(); //パスを終了 context.stroke(); //パスを描画する //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; }, //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, //cos関数の場合 cos_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.cos(this.b*x-this.a*pi);//y=Acos(bx-a) y *=59;//yの調整 return y ; }, }); ``` 実際に動きを見てみましょう ![](https://i.imgur.com/1zUsTbn.png) sinグラフとの違いは確認できましたか?sinの時と見比べてみましょう。 ![](https://i.imgur.com/CmLo2gv.png) ## 挑戦してみよう それではthis.A,this.a,this.bの値を変更して以下のグラフを作ってみましょう。 (1)y=cos(2x)の式の動きを作ってみよう (2)y=cos(x-π/2)の式の動きを作ってみよう (3)y=cos(2x-π/2)の式の動きを作ってみよう <details> <summary> ```javascript= enchant(); var game; //ゲーム画面設定 var GameWidth = 500; var GameHeight = 320; //円周率 var pi = Math.PI /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; //三角関数の係数 this.A = 1; this.a = 0; this.b = 2; if(this.b%2!=0){ plus = 1; } else{ plus = -1; } game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ onenterframe: function() { //クマの動作を行う this.y = plus*this.cos_graph(this.x-GameHeight/2)+GameHeight/2;//関数の値をゲーム座標に移す this.x += 1; //線を描画する //Spriteを作ります //線の描画を始める context.beginPath(); //パスを開始 context.moveTo(this.ox-1, this.oy-1); context.lineTo(this.x-1, this.y-1); context.closePath(); //パスを終了 context.stroke(); //パスを描画する //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; }, //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, //cos関数の場合 cos_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.cos(this.b*x-this.a*pi);//y=Acos(bx-a) y *=59;//yの調整 return y ; }, }); window.onload = function() { game = new Game(GameWidth, GameHeight); game.preload('images/chara1.png','images/masu_三角関数.png' ,'images/next.png'); game.onload = function() { //背景画像を設定 var bg= new Sprite(500, 320); bg.image = game.assets["images/masu_三角関数.png"]; game.rootScene.addChild(bg); /* クマをつくる */ bear = new Bear(-4, -4); //線を作る sprite = new Sprite(500, 320); //Surfaceを作ります surface = new Surface(500, 320); //spriteのimageにsurfaceを代入します sprite.image = surface; //コンテキストを取得します context = surface.context; //シーンにサーフェスを追加する ' game.rootScene.addChild(sprite); var input = new Entity(); var input_down = new Entity(); //入力テキスト作成 input._element = document.createElement('input'); input._element.setAttribute('type','text'); input._element.setAttribute('maxlength','5'); input._element.setAttribute('value','0'); input.width = 30; input.height = 20; input.x = 50; input.y = 20; //rootSceneに追加 game.rootScene.addChild(input); // ラベルを作成 var myLabel = new Label("π"); myLabel.x = 80; // X座標 myLabel.y = 20; // Y座標 // ラベルを画面に表示 game.rootScene.addChild(myLabel); //開始ボタンの作成 input_button = new Sprite(124, 30); input_button.x = 100; input_button.y = 22; input_button.image = game.assets['images/next.png']; //開始ボタンを画面に表示 game.rootScene.addChild(input_button); //開始ボタンをタッチしたとき入力値を計算してクマの停止座標を決める input_button.addEventListener('touchstart', function() { bear.input_x = input._element.value; var input_up = Number(bear.input_x);//分子の値を取得する var input_down = 1; //分母の値を取得する //入力値に’/’が含まれているときに’/’を境に分子と分母を取得する if ( bear.input_x.indexOf('/') != -1){ input_up = Number(before_cut(bear.input_x));//分子の値を取得する input_down = Number(after_cut(bear.input_x));//分母の値を取得する } input_num = input_up/input_down;//分子÷分母を行う }); }; game.start(); }; //決められた値より前を取り出す before_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.substring(0, index); return str; } //決められた値より後を取り出す after_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.slice(index + 1); return str; } ``` </summary> </details> ## Step3 システムにボタンを追加しよう ゲームにxの値を入力してその位置でクマが止まるようにします。 そのために入力エリアと開始ボタンを作成します。 ```javascript= // ラベルを作成 var input = new Entity(); var input_down = new Entity(); //入力テキスト作成 input._element = document.createElement('input'); input._element.setAttribute('type','text'); input._element.setAttribute('maxlength','5'); input._element.setAttribute('value','0'); input.width = 30; input.height = 20; input.x = 50; input.y = 20; //rootSceneに追加 game.rootScene.addChild(input); // ラベルを作成 var myLabel = new Label("π"); myLabel.x = 80; // X座標 myLabel.y = 20; // Y座標 // ラベルを画面に表示 game.rootScene.addChild(myLabel); //開始ボタンの作成 input_button = new Sprite(124, 30); input_button.x = 100; input_button.y = 22; input_button.image = game.assets['images/next.png']; //開始ボタンを画面に表示 game.rootScene.addChild(input_button); //開始ボタンをタッチしたとき入力値を計算してクマの停止座標を決める input_button.addEventListener('touchstart', function() { bear.input_x = input._element.value; var input_up = Number(bear.input_x);//分子の値を取得する var input_down = 1; //分母の値を取得する //入力値に’/’が含まれているときに’/’を境に分子と分母を取得する if ( bear.input_x.indexOf('/') != -1){ input_up = Number(before_cut(bear.input_x));//分子の値を取得する input_down = Number(after_cut(bear.input_x));//分母の値を取得する } input_num = input_up/input_down;//分子÷分母を行う bear.stop_x = Math.round(262+input_num*pi*32);//クマの停止座標をゲーム座標に合わせる bear.flag = true;//クマの動作を開始する }); ``` ボタンには分数が入力されたときにもちゃんと取得できるような処理が追加されています。 yの値を出す際に綺麗な数値が出るように配列を使って表を作ります。 ```javascript= //sin表 table_sin = {"0" : "0", "1/6": "1/2", "1/4": "√2/2", "1/3": "√3/2", "1/2": "1", "2/3": "√3/2", "3/4": "√2/2", "5/6": "1/2", "1" : "0", "7/6": "-1/2", "5/4": "-√2/2", "4/3": "-√3/2", "3/2": "-1", "5/3": "-√3/2", "7/4": "-√2/2", "11/6": "-1/2", "2": "0", "-1/6": "-1/2", "-1/4": "-√2/2", "-1/3": "-√3/2", "-1/2": "-1", "-2/3": "-√3/2", "-3/4": "-√2/2", "-5/6": "-1/2", "-1" : "0", "-7/6": "1/2", "-5/4": "√2/2", "-4/3": "√3/2", "-3/2": "1", "-5/3": "√3/2", "-7/4": "√2/2", "-11/6": "1/2", "-2": "0", "-5/2": "-1", } //cos表 table_cos = {"0" : "1", "1/6": "√3/2", "1/4": "√2/2", "1/3": "1/2", "1/2": "0", "2/3": "-1/2", "3/4": "-√2/2", "5/6": "-√3/2", "1" : "-1", "7/6": "-√3/2", "5/4": "-√2/2", "4/3": "-√3/2", "3/2": "0", "5/3": "1/2", "7/4": "√2/2", "11/6": "√3/2", "2": "1", "-1/6": "√3/2", "-1/4": "√2/2", "-1/3": "1/2", "-1/2": "0", "-2/3": "-1/2", "-3/4": "-√2/2", "-5/6": "-√3/2", "-1" : "-1", "-7/6": "-√3/2", "-5/4": "-√2/2", "-4/3": "-√3/2", "-3/2": "0", "-5/3": "1/2", "-7/4": "√2/2", "-11/6": "√3/2", "-2": "1", "-5/2": "0", } ``` 小数の値を分数に直す関数も作っておきましょう。 ```javascript= //小数を分数に直す change_bunnsu = function(decimal) { var addend; //加数 var i = 1; //カウンタ+分母 if (decimal % 1.0 == 0.0) { return decimal; //変数decimalが整数の場合 } else { addend = decimal; //少数を加数として代入 do { decimal += addend; //元の少数を足し続ける i++; //分母でもあるカウンタ変数i } while (decimal % 1.0 != 0.0); //1.0で割り切れるようになるまで→整数に成るまで answer = decimal + "/" + i; } return answer; } ``` これに合わせてクラスBearも変えていきましょう。 ```javascript= /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; //三角関数の係数 this.A = 1; this.a = 0; this.b = 1; if(this.b%2!=0){ plus = 1; } else{ plus = -1; } game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ onenterframe: function() { if(this.flag){ //クマの動作を行う this.y = plus*this.sin_graph(this.x-GameHeight/2)+GameHeight/2;//関数の値をゲーム座標に移す this.x += 1; //クマがstop_xのx位置に来たとき if(this.x == Math.floor(this.stop_x)){ answer = change_bunnsu(this.b*input_num-this.a); //sin表から入力されたxの値からyの値を出す alert("座標はx:"+this.input_x+"π y:"+table_sin[answer]); this.flag = false; } //線を描画する //Spriteを作ります //線の描画を始める context.beginPath(); //パスを開始 context.moveTo(this.ox-1, this.oy-1); context.lineTo(this.x-1, this.y-1); context.closePath(); //パスを終了 context.stroke(); //パスを描画する //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; } }, //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, //cos関数の場合 cos_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.cos(this.b*x-this.a*pi);//y=Acos(bx-a) y *=59;//yの調整 return y ; }, }); ``` これで好きなグラフに対して好きな位置で停止させることができるようになりました。気になる式のxの時のyの値を確認してみましょう。 ## 挑戦してみよう それでは式を組み立ててx座標を入力してその時のy座標の値を確認してみましょう。 (1)y=sin(2x) x座標 π/2 (2)y=cos(x-π/2) x座標 π (3)y=2sin(x-π/2) x座標 π/4 実際に自分で式を入れてあっているかどうか確認してみましょう。 <details> <summary>最終コードは以下のようになります。</summary> ```javascript= enchant(); var game; //ゲーム画面設定 var GameWidth = 500; var GameHeight = 320; //円周率 var pi = Math.PI //sin表 table_sin = {"0" : "0", "1/6": "1/2", "1/4": "√2/2", "1/3": "√3/2", "1/2": "1", "2/3": "√3/2", "3/4": "√2/2", "5/6": "1/2", "1" : "0", "7/6": "-1/2", "5/4": "-√2/2", "4/3": "-√3/2", "3/2": "-1", "5/3": "-√3/2", "7/4": "-√2/2", "11/6": "-1/2", "2": "0", "-1/6": "-1/2", "-1/4": "-√2/2", "-1/3": "-√3/2", "-1/2": "-1", "-2/3": "-√3/2", "-3/4": "-√2/2", "-5/6": "-1/2", "-1" : "0", "-7/6": "1/2", "-5/4": "√2/2", "-4/3": "√3/2", "-3/2": "1", "-5/3": "√3/2", "-7/4": "√2/2", "-11/6": "1/2", "-2": "0", "-5/2": "-1", } //cos表 table_cos = {"0" : "1", "1/6": "√3/2", "1/4": "√2/2", "1/3": "1/2", "1/2": "0", "2/3": "-1/2", "3/4": "-√2/2", "5/6": "-√3/2", "1" : "-1", "7/6": "-√3/2", "5/4": "-√2/2", "4/3": "-√3/2", "3/2": "0", "5/3": "1/2", "7/4": "√2/2", "11/6": "√3/2", "2": "1", "-1/6": "√3/2", "-1/4": "√2/2", "-1/3": "1/2", "-1/2": "0", "-2/3": "-1/2", "-3/4": "-√2/2", "-5/6": "-√3/2", "-1" : "-1", "-7/6": "-√3/2", "-5/4": "-√2/2", "-4/3": "-√3/2", "-3/2": "0", "-5/3": "1/2", "-7/4": "√2/2", "-11/6": "√3/2", "-2": "1", "-5/2": "0", } /* 独自クラスBearの定義 */ Bear = Class.create(Sprite, { initialize: function(x, y) { Sprite.call(this, 32, 32); this.image = game.assets['images/chara1.png']; this.x = x; this.y = y; //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; this.frame = 0; //三角関数の係数 this.A = 1; this.a = 0; this.b = 1; game.rootScene.addChild(this); }, /* enterframeイベントのリスナーを設定 */ onenterframe: function() { if(this.flag){ //クマの動作を行う this.y = this.sin_graph(this.x-GameHeight/2)+GameHeight/2;//関数の値をゲーム座標に移す this.x += 1; //クマがstop_xのx位置に来たとき if(this.x == Math.floor(this.stop_x)){ answer = change_bunnsu(this.b*input_num-this.a); //sin表から入力されたxの値からyの値を出す alert("座標はx:"+this.input_x+"π y:"+table_sin[answer]); this.flag = false; } //線を描画する //Spriteを作ります //線の描画を始める context.beginPath(); //パスを開始 context.moveTo(this.ox-1, this.oy-1); context.lineTo(this.x-1, this.y-1); context.closePath(); //パスを終了 context.stroke(); //パスを描画する //1つ前の座標を保存する this.ox = this.x; this.oy = this.y; } }, //三角関数でグラフを作る //sin関数の場合 sin_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.sin(this.b*x-this.a*pi);//y=Asin(bx-a) y *=59;//yの調整 return y ; }, //cos関数の場合 cos_graph : function(x){ x/=this.width;//xの調整 var y = this.A*Math.cos(this.b*x-this.a*pi);//y=Acos(bx-a) y *=59;//yの調整 return y ; }, }); window.onload = function() { game = new Game(GameWidth, GameHeight); game.preload('images/chara1.png','images/masu_三角関数.png' ,'images/next.png'); game.onload = function() { //背景画像を設定 var bg= new Sprite(500, 320); bg.image = game.assets["images/masu_三角関数.png"]; game.rootScene.addChild(bg); /* クマをつくる */ bear = new Bear(-4, -4); //線を作る sprite = new Sprite(500, 320); //Surfaceを作ります surface = new Surface(500, 320); //spriteのimageにsurfaceを代入します sprite.image = surface; //コンテキストを取得します context = surface.context; //シーンにサーフェスを追加する ' game.rootScene.addChild(sprite); var input = new Entity(); var input_down = new Entity(); //入力テキスト作成 input._element = document.createElement('input'); input._element.setAttribute('type','text'); input._element.setAttribute('maxlength','5'); input._element.setAttribute('value','0'); input.width = 30; input.height = 20; input.x = 50; input.y = 20; //rootSceneに追加 game.rootScene.addChild(input); // ラベルを作成 var myLabel = new Label("π"); myLabel.x = 80; // X座標 myLabel.y = 20; // Y座標 // ラベルを画面に表示 game.rootScene.addChild(myLabel); //開始ボタンの作成 input_button = new Sprite(124, 30); input_button.x = 100; input_button.y = 22; input_button.image = game.assets['images/next.png']; //開始ボタンを画面に表示 game.rootScene.addChild(input_button); //開始ボタンをタッチしたとき入力値を計算してクマの停止座標を決める input_button.addEventListener('touchstart', function() { bear.input_x = input._element.value; var input_up = Number(bear.input_x);//分子の値を取得する var input_down = 1; //分母の値を取得する //入力値に’/’が含まれているときに’/’を境に分子と分母を取得する if ( bear.input_x.indexOf('/') != -1){ input_up = Number(before_cut(bear.input_x));//分子の値を取得する input_down = Number(after_cut(bear.input_x));//分母の値を取得する } input_num = input_up/input_down;//分子÷分母を行う bear.stop_x = Math.round(262+input_num*pi*32);//クマの停止座標をゲーム座標に合わせる bear.flag = true;//クマの動作を開始する }); }; game.start(); }; //決められた値より前を取り出す before_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.substring(0, index); return str; } //決められた値より後を取り出す after_cut = function(value) { // 1.切り出す元となるテキスト取得 var str = value; // 2.切り出す基準となるテキスト取得 var cut_str = "/"; // 3.基準となる文字列の位置を取得 var index = str.indexOf(cut_str); // 4.基準文字列から後の文字列を切り出して表示 str = str.slice(index + 1); return str; } //小数を分数に直す change_bunnsu = function(decimal) { var addend; //加数 var i = 1; //カウンタ+分母 if (decimal % 1.0 == 0.0) { return decimal; //変数decimalが整数の場合 } else { addend = decimal; //少数を加数として代入 do { decimal += addend; //元の少数を足し続ける i++; //分母でもあるカウンタ変数i } while (decimal % 1.0 != 0.0); //1.0で割り切れるようになるまで→整数に成るまで answer = decimal + "/" + i; } return answer; } ``` </details>