lecture:design_with_prototyping:p5.js編:22.commentableをつくる

commentableを作る

commentable(コメンタブル)は馬場が2020年4月からオンライン授業用に開発を始めたチャットシステムです.詳しくはgithubをご参照ください.

このページではコメンタブルみたいなシステムを実際に作成してみようと思います.コメンタブル自体は至ってシンプルなシステムになっています.

  • 配信者と視聴者の2つにユーザが分かれる
    • 配信者:視聴者が投稿したコメントがp5のcanvas上にアニメーションされる
    • 視聴者:リアクションボタンやテキストボックスを利用して配信者側にメッセージを送信できる

というものです.細かな機能がその他にもありますが,基本的にはこの構成になっています.配信者側は OBSという配信用ソフトを利用して配信者用ページを開き,canvas画面をそのまま配信ページにのっけて,zoom等で放送しています.

コメンタブルはnode.jsを利用しているので,まずはnode.jsを利用してシンプルなチャットシステムを開発するところから始めましょう.これに関してはすでに別ページに記事があるので,そちらを参照してください.

まずは上記内容をしっかり理解した上で次に進めていきます.

上記のチャットシステムではcommentableのように配信側と視聴者側がないため,同じファイルを利用しているため,まずはこの修正から始めます.現在のファイル構成は

├── public
│   ├── index.html
│   ├── p5.js
│   ├── p5.sound.min.js
│   ├── sketch.js
│   └── style.css
└── server.js

となっているかと思います(node.js類のファイルは省いて表示しています).ここにファイルを追加してpublicフォルダ以下を以下の構成にします.なお,broadcast内のファイルはpublicフォルダ内にあるファイルをそのままコピーしています.

├── broadcast
│   ├── index.html
│   ├── p5.js
│   ├── p5.sound.min.js
│   ├── sketch.js
│   └── style.css
├── index.html
├── p5.js
├── p5.sound.min.js
├── sketch.js
└── style.css

上記ファイル構成に変更した後,ブラウザからアクセスしてそれぞれ http://localhost:3000 http://localhost:3000/broadcast で同じページが開くことを確認しましょう.

では最初に視聴者側のファイル修正から行います.視聴者側に必要な機能はテキストを送信することに加えて,リアクションボタンを追加します.文字色を変えたり音声読み上げとかもありますが,一旦はなるべくシンプルに作成して,プロトタイピングのループを一度回して「動作させること」に集中しましょう.

すでにsimplechatのexampleが手元では動いていおり,このページではテキストボックス,名前ボックスに入力した内容をサーバ側に送信することができます.canvasは必要ないので省きます.またこれら機能の他,リアクションボタンをまずは素のhtml(cssできれいにしていないただのタグ)で作っていきます.ただしbootstrapを利用していきます.bootstrapとはtwitter社が提供しているライブラリで,cssやjavascript等,モダンなウェブサイトを構築するために必要な機能がセットになっています.

index.html
<!DOCTYPE html>
<html lang="en">
 
<head>
  <script src="p5.js"></script>
  <script src="p5.sound.min.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="style.css">
  <meta charset="utf-8">
 
</head>
 
<body>
  <div class="container-sm">
    <div class="input-group mb-3">
      <span class="input-group-text" id="basic-addon1">お名前</span>
      <input type="text" id="name" class="form-control" placeholder="匿名" aria-label="Username"
        aria-describedby="basic-addon1">
    </div>
 
    <hr>
    <div class="btn-group" role="group" aria-label="Basic outlined example">
      <button type="button" id="button_reaction01" class="btn btn-outline-primary">👍</button>
      <button type="button" id="button_reaction02" class="btn btn-outline-primary">🎉</button>
      <button type="button" id="button_reaction03" class=" btn btn-outline-primary">👊</button>
    </div>
 
    <hr>
 
    <div class=" input-group mb-3">
      <button class="btn btn-outline-secondary" type="button" id="send">Send</button>
      <input type="text" id="message" class="form-control" placeholder="" aria-label="Example text with button addon"
        aria-describedby="button-addon1">
    </div>
 
    <script src="/socket.io/socket.io.js"></script>
    <script src="sketch.js"></script>
  </div>
 
</body>
 
</html>
sketch.js
var socket;
var chatlog = {
  name: '',
  message: ''
}
 
function setup() {
  noCanvas();
 
  select('#button_reaction01').mouseClicked(sendReaction);
  select('#button_reaction02').mouseClicked(sendReaction);
  select('#button_reaction03').mouseClicked(sendReaction);
 
  select('#send').mouseClicked(sendMessage);
  socket = io.connect(window.location.origin);
  socket.on('gotMessage', gotMessage);
}
 
function sendReaction() {
  // This == select('#button_reaction01')
  console.log(this.html());
  var chatdata = {
    name: select('#name').value(),
    message: this.html()
  }
  socket.emit('sendMessage', chatdata);
}
 
function sendMessage() {
  var chatdata = {
    name: select('#name').value(),
    message: select('#message').value()
  }
  console.log(chatdata);
  socket.emit('sendMessage', chatdata);
}
function gotMessage(chatdata) {
  console.log(chatdata);
  chatlog.name = chatdata.name;
  chatlog.message = chatdata.message;
 
}

配信者側では,p5のキャンバスだけを表示し,そこにユーザからのコメントやリアクションを載っけていきます.なお🎉とパンチの音は以下からダウンロードして利用してください.

index.html
<!DOCTYPE html>
<html lang="en">
 
<head>
  <script src="p5.js"></script>
  <script src="p5.sound.min.js"></script>
  <link rel="stylesheet" type="text/css" href="style.css">
  <meta charset="utf-8">
 
</head>
 
<body>
  <script src="/socket.io/socket.io.js"></script>
  <script src="sketch.js"></script>
</body>
 
</html>
sketch.js
var socket;
var chatlog = [];
var sound_cracker;
 
function preload() {
  sound_cracker = loadSound('./sounds/cracker.mp3');
}
 
function setup() {
  createCanvas(displayWidth, displayHeight);
  socket = io.connect(window.location.origin);
  socket.on('gotMessage', gotMessage);
  textSize(24);
 
  // 初期化
  for (let i = 0; i < 50; i++) {
    chatlog[i] = {
      name: '',
      message: '',
      alpha: 0,
      x: 0,
      y: 0
    }
  }
}
 
function gotMessage(chatdata) {
  console.log(chatdata);
  // メッセージを空いてる配列(alpha==0)に代入する
  for (let i = 0; i < 50; i++) {
    if (chatlog[i].alpha == 0) {
      chatlog[i].name = chatdata.name;
      chatlog[i].message = chatdata.message;
      chatlog[i].alpha = 255;
      chatlog[i].x = random(50, width - 50);
      chatlog[i].y = random(50, height - 50);
 
      if (chatlog[i].message == "🎉") {
        console.log("パン!")
        sound_cracker.play();
      }
      i = 50; // loopは終了
    }
  }
}
function draw() {
  background(220);
 
  //text(chatlog.name, width / 2, height / 2)
 
  for (let i = 0; i < 50; i++) {
    fill(0, 0, 0, chatlog[i].alpha);
    text(chatlog[i].message, chatlog[i].x, chatlog[i].y);
    if (chatlog[i].alpha > 0) {
      chatlog[i].alpha = chatlog[i].alpha - 1;
    }
  }
}

OBSをまだインストールしていない人は,まず最初にOBSをインストールしてください.

  • /home/users/2/lolipop.jp-4404d470cd64c603/web/ws/data/pages/lecture/design_with_prototyping/p5.js編/22.commentableをつくる.txt
  • 最終更新: 2021/06/16 10:10
  • by baba