グラフィカルなルーレットを作る

このエントリーをはてなブックマークに追加

グラフィカルなルーレットです.
ボタンを押すと回転が始まります.
もう一度押すとゆっくり止まって音がなります.

回路

シンプルに,スピーカーとボタンをつないでいるだけです.

つないだピンの番号に応じて,プログラム内にてwiredの番号を変えます.

button = obniz.wired("Button", {signal:6 , gnd:7 });
speaker = obniz.wired("Speaker", {signal:0 , gnd: 1});

画像を回転させる

ルーレット画像を回転させます

HTMLで画像を回転させる場合,cssのtransformを使います.
たとえば,90度回転させる場合,下記のように書きます.

document.getElementById("roulette").style = "transform:rotate(90deg);";

ゆっくり回転を開始したり,止めたいので,speedという変数を作って,1フレームあたりの回転角度を決めています.

let speed = 0;
  let deg = 0;
  function rotate(){
    deg += speed;
      document.getElementById("roulette").style = "transform:rotate("+deg+"deg);";

  }
  setInterval(rotate,10);

音を鳴らす

やはりルーレットの番号が変わったときに音を鳴らしたいですよね.
このように書くと,440Hz(ドの音)で10ms間音を鳴らすことができます.

      speaker.play(440);
      await obniz.wait(10);
      speaker.stop(); 

ルーレットの番号が変わった時を知るには,先程のrotate関数内にてdegの値を確認する必要があります.

if( Math.floor((deg + speed) / (360/7.0)) -  Math.floor(deg / (360/7.0)) >= 1){
      onRouletteChange();
}

合わせるとこうなります.



  let speed = 0;
  let deg = 0;
  function rotate(){
    //on change value
    if( Math.floor((deg + speed) / (360/7.0)) -  Math.floor(deg / (360/7.0)) >= 1){
      onRouletteChange();
    }
    deg += speed;
      document.getElementById("roulette").style = "transform:rotate("+deg+"deg);";

  }
  setInterval(rotate,10);

  async function onRouletteChange(){
    if(!speaker){return;}
      speaker.play(440);
      await obniz.wait(10);
      speaker.stop(); 
  }

ボタンを押したらスタートする

ボタンを押されたことを検知するために,buttonStateという変数を作り,そこに現在のボタンの値を入れておきます.

button.onchange = function(pressed){
    buttonState = pressed;
  };

また,このプログラムでは,今どの常態かの把握のためにphase変数を作っています.

phaseが次のどれかになることで,現在の状態を把握しています.

const PHASE_WAIT_FOR_START = 0; 
const PHASE_ROTATE = 1;
const PHASE_STOPPING = 2;
const PHASE_STOPPED = 3;

たとえば,phasePHASE_WAIT_FOR_STARTのときにボタンが押されたら次のPHASE_ROTATEフェーズに行くようにします.

if(phase == PHASE_WAIT_FOR_START){
    speed = 0;
    if(buttonState){
       phase = PHASE_ROTATE;
    }
}

ボタンが押されたら速度を上げるにはこう書きます.

if(phase == PHASE_ROTATE){
    speed = speed+0.5;
}

逆に速度を落とすときはこうなります.ゆっくり止まって欲しいので,速度を上げるときより変化値を小さくしています.

if(phase == PHASE_STOPPING){    
    speed = speed-0.2;
}

これらを組み合わせて,ボタンを押したらスタートして,もう一度押したらゆっくり止まるルーレットを作ります.

Program

<!-- HTML Example -->

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://unpkg.com/obniz@1.6.1/obniz.js" crossorigin="anonymous"></script>
  <style>
 
#roulette {
  position : absolute ;
   padding:0px 0 0;
   width:300px;
}

#roulette  img {
   width:300px;
}
#wrapper{
   			position:absolute;
}
#hari {
  position : absolute ;
   top:-20px;
   left:134px;
  z-index : 10;
}
  </style>
</head>
<body>

<div id="obniz-debug"></div>
<h1>obniz roulette</h1>

  <div id="wrapper">
<div id="hari"><img src="https://web.obniz.io/wp-content/uploads/2018/07/pin-1.png"></div>

<div id="roulette"><img src="https://web.obniz.io/wp-content/uploads/2018/07/roulette@3x.png"/></div>

  </div>


<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
let button,speaker;
let buttonState = false;
obniz.onconnect = async function () {

  button = obniz.wired("Button", {signal:6 , gnd:7 });
  speaker = obniz.wired("Speaker", {signal:0 , gnd: 1});
  
  button.onchange = function(pressed){
    buttonState = pressed;
  };
  
  obniz.display.clear();
  obniz.display.print("Start Roulette");
  
}

const PHASE_WAIT_FOR_START = 0; 
const PHASE_ROTATE = 1;
const PHASE_STOPPING = 2;
const PHASE_STOPPED = 3;
let phase = PHASE_WAIT_FOR_START; 
let stopCount = 0;
  
obniz.repeat(async function(){
  if(!button){return;}
  
  if(phase == PHASE_WAIT_FOR_START){
    speed = 0;
  	if(buttonState){
       phase = PHASE_ROTATE;
      
       // wait for release button
      await new Promise((resolve)=>{
        setInterval(()=>{
        	if(!buttonState){
      			resolve();
      		}
        },10);
      });
    }
  }else if(phase == PHASE_ROTATE){
    speed = Math.min(speed+0.5, 5);
    
    if(buttonState){
      phase = PHASE_STOPPING;
      stopCount = 0;
    }
    
  }else if(phase == PHASE_STOPPING){
    
    speed = Math.max(speed-0.2,0);
    if(speed == 0 ){
    	phase = PHASE_STOPPED;
    }
    
  }else if(phase == PHASE_STOPPED){
    for(let i = 0; i < 15;i++){
    	speaker.play(440*3);
  		await obniz.wait(10);
  		speaker.stop(); 
  		await obniz.wait(100);
    }
    phase = PHASE_WAIT_FOR_START;
  }       
             
}, 100);
  
  
  let speed = 0;
  let deg = 0;
  function rotate(){
    if( Math.floor((deg + speed) / (360/7.0)) -  Math.floor(deg / (360/7.0)) >= 1){
      onRouletteChange();
    }
    deg += speed;
  	document.getElementById("roulette").style = "transform:rotate("+deg+"deg);";
    
  }
  setInterval(rotate,10);
  
  async function onRouletteChange(){
    if(!speaker){return;}
  	speaker.play(440);
  	await obniz.wait(10);
  	speaker.stop(); 
  }
  
</script>
</body>
</html>

今すぐ実行

HTMLがブラウザで開かれて実行されます。