alanhc 互動技術-week16

alanhc 互動技術-week16

December 26, 2019

多人遊戲的電子鼓v1

server 端程式 

處理socket及routing(express)

serverjs.js


let express = require('express');
let app = express();
let server = app.listen(3000);

app.use(express.static('public'))

console.log("My socket server is running");

let socket = require('socket.io');
let io = socket(server);
io.sockets.on('connection', newConnection);

let player=0;

let playerList=[];
let nowHost=0;

function newConnection(socket) {
    playerList.push(socket.id);
    player++;
   
    socket.broadcast.emit('players',player);
    socket.broadcast.emit('hoster name',playerList[nowHost]);

    socket.on('disconnect', ()=>{
        --player;
        socket.broadcast.emit('players',player);
        playerList = playerList.filter( (value, index, arr)=> value!=socket.id );
    });
    socket.on('send pattern', (patternIn)=>{
        socket.broadcast.emit('answer pattern',patternIn);
    });
    //console.log(playerList.length);
}

setInterval(function() {
    io.local.emit('players',player);
    io.local.emit('hoster name',playerList[nowHost]);
   
    //console.log(nowHost);
}, 100);

setInterval(function() {
    if (nowHost>playerList.length-2) nowHost=0;
    else nowHost++;
}, 4*4*1000);

let nowBeat=0;
setInterval(function() {
    nowBeat++;
    nowBeat%=8;
    io.local.emit('beat',nowBeat);
   
}, 500);

client端

public資料夾
  • index.html 處理首頁配置
  • player.js 處理播放音樂(Tone.js)
  • sketch.js主程式

index.html

<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
 
  <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/13.0.1/Tone.min.js" type="text/javascript"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"> </script>
  <script src="https://unpkg.com/p5.touchgui@0.5.2/lib/p5.touchgui.js"></script>
 
  <script language="javascript" type="text/javascript" src="sketch.js"></script>
  <script language="javascript" type="text/javascript" src="player.js"></script>
  <script language="javascript" type="text/javascript" src="serial.js"></script>
  <script >
   
  </script>
 

 
  <style> body { padding: 0; margin: 0; } </style>
</head>

<body>
</body>
</html>

player.js

let myPattern = [
    [0,0,0,0,0,0,0,0], //bd
    [0,0,0,0,0,0,0,0], //cr
    [0,0,0,0,0,0,0,0], //hh
    [0,0,0,0,0,0,0,0], //t1
    [0,0,0,0,0,0,0,0], //t2
]
let ansPattern = [
    [0,0,0,0,0,0,0,0], //bd
    [0,0,0,0,0,0,0,0], //cr
    [0,0,0,0,0,0,0,0], //hh
    [0,0,0,0,0,0,0,0], //t1
    [0,0,0,0,0,0,0,0], //t2
]

let bdrum;
let crash;
let hh_c;
let tom1;
let tom2;

//let totalBeat=0;
//Tone.Transport.scheduleRepeat(playBeat, "0.5s");
Tone.Buffer.on('load', play);

let img_bdrum;
let img_cymbals;
let img_drum;

function preload() {
    bdrum = new Tone.Player('assets/80s-Bdrum1.mp3');
    crash = new Tone.Player('assets/80s-CRASH1.mp3');
    hh_c = new Tone.Player('assets/80s-HHCLOSE1.mp3');
    tom1 = new Tone.Player('assets/80s-TOM1.mp3');
    tom2 = new Tone.Player('assets/80s-TOM2.mp3');
    bdrum.toMaster();
    crash.toMaster();
    hh_c.toMaster();
    tom1.toMaster();
    tom2.toMaster();
    img_bdrum = loadImage('assets/bdrum.png');
    img_cymbals = loadImage('assets/cymbals.png');
    img_drum = loadImage('assets/drum.png');
}


function play() {
    Tone.Transport.start();
}

function keyTyped() {
  if (key>0&&key<6) ansPattern[key-1][steps]=1;
 
}

function playBeat(steps, pattern) {
 
       

    if (pattern[0][steps] == 1) {
        bdrum.start();
    }
    if (pattern[1][steps] == 1) {
        crash.start();
    }
    if (pattern[2][steps] == 1) {
        hh_c.start();
    }
    if (pattern[3][steps] == 1) {
        tom1.start();
    }
    if (pattern[4][steps] == 1) {
        tom2.start();
    }
}
sketch.js


let socket;

let players;
let host;
let myId;
let serverIp='192.168.1.109:3000';
let state;
function setup() {
   

   
    createCanvas(windowWidth,windowHeight);
    background(220);
    socket = io('http://'+serverIp); //change server ip here
    socket.on('players', (num)=>{  players=num; });
    socket.on('hoster name', (hostInput)=>{ 
        host=hostInput;
        if (host==myId) {
            socket.emit('send pattern', myPattern);
        }
    });
    socket.on('answer pattern', (patternIn)=>{
        ansPattern=patternIn;
    });
    let init_myPattern=false;
    let init_ansPattern=false;
   
    socket.on('beat', (stepsIn)=>{
        havePlayed=false;
        playBeat(steps, ansPattern);
        steps=stepsIn;
     
        if (host!=myId) { // now is play mode
            state='play';
           
            myPattern= [
                [0,0,0,0,0,0,0,0], //bd
                [0,0,0,0,0,0,0,0], //cr
                [0,0,0,0,0,0,0,0], //hh
                [0,0,0,0,0,0,0,0], //t1
                [0,0,0,0,0,0,0,0], //t2
            ]
            init_myPattern=false;
           
           
        } else {         // now is host mode
            state='host';
            playBeat(steps, myPattern);
            ansPattern= [
                [0,0,0,0,0,0,0,0], //bd
                [0,0,0,0,0,0,0,0], //cr
                [0,0,0,0,0,0,0,0], //hh
                [0,0,0,0,0,0,0,0], //t1
                [0,0,0,0,0,0,0,0], //t2
            ]
            if (!init_myPattern) {
                myPattern= [
                    [0,0,0,0,0,0,0,0], //bd
                    [0,0,0,0,0,0,0,0], //cr
                    [0,0,0,0,0,0,0,0], //hh
                    [0,0,0,0,0,0,0,0], //t1
                    [0,0,0,0,0,0,0,0], //t2
                ]
                init_myPattern=true;
            }
           
           
        }
        //console.log(state);
       
    });
}


let steps;
let havePlayed;
function draw() {
    myId=socket.id;
   
    if (key>0 && key<6 && keyIsPressed && state=='host') {
        myPattern[key-1][steps]=1;
        if (!havePlayed) {
            playBeat(steps, myPattern);
            havePlayed=true;
        }
    }
    if (state=='host') background(255,0,0,10);
    else background(0,128,220);
    let spaceW=windowWidth/9;
    let spaceH=windowHeight/7;
    let shW=spaceW/2;
    let shH=spaceH;

    fill(0);
    textSize(16);
    text('online: '+players, shW, shH/3);
    text('Host  : '+host, shW, shH/2);
    text('state: '+ state, shW, shH/1.5);
   
   
    for (let i=0; i<8; i++) {
        for (let j=0; j<5; j++) {
            if (myPattern[j][i]==1) {
               
                let minW=Math.min(spaceH,spaceW);
                switch(j) {
                    default:
                    break; case 0:
                    image(img_bdrum, shW+spaceW*i, shH+spaceH*j, minW,minW);
                    break; case 1:case 2:
                    image(img_cymbals, shW+spaceW*i, shH+spaceH*j, minW,minW);
                    break; case 3: case 4:
                    image(img_drum, shW+spaceW*i, shH+spaceH*j, minW,minW);
                }
               
                fill(0,30);
            } else if (ansPattern[j][i]==1) {
               
                fill(150);
                let minW=Math.min(spaceH,spaceW);
                switch(j) {
                    default:
                    break; case 0:
                    image(img_bdrum, shW+spaceW*i, shH+spaceH*j, minW,minW);
                    break; case 1:case 2:
                    image(img_cymbals, shW+spaceW*i, shH+spaceH*j, minW,minW);
                    break; case 3: case 4:
                    image(img_drum, shW+spaceW*i, shH+spaceH*j, minW,minW);
                }
               
            }
            else {
                fill(255);
            }
           
            //rect(shW+spaceW*i, shH+spaceH*j, spaceW,spaceH); //draw player
           

        }
        fill(255,255,0,10);
        rect(shW+steps*spaceW,shH,spaceW,spaceH*5);
        stroke(0);
    }
}

device

#include "CurieIMU.h"

void setup() {
  Serial.begin(9600); // initialize Serial communication
  while (!Serial);    // wait for the serial port to open

  // initialize device
  Serial.println("Initializing IMU device...");
  CurieIMU.begin();

  // Set the accelerometer range to 2G
  CurieIMU.setAccelerometerRange(2);
}

void loop() {
  float ax, ay, az;

  CurieIMU.readAccelerometerScaled(ax, ay, az);

 
  Serial.print("a:\t");
  Serial.print(ax);
  Serial.print("\t");
  Serial.print(ay);
  Serial.print("\t");
  Serial.print(az);
  Serial.println();
}
後記:目前還在整合serial 及GUI聲音調整,未來會有更多

目前實驗到:

serial連線 https://editor.p5js.org/alanhc/sketches/ILrZMsoO7
深度學習訓練 https://editor.p5js.org/alanhc/sketches/FmNlDsPjv
介面調整及測試 https://editor.p5js.org/alanhc/sketches/Tpc-lw1Xi
可至15週筆記看實驗