漫画「ハルロック」の"ぼっち・the・LED"簡易版をPC上に再現してみました

ぼっち・the・LED

 漫画雑誌モーニングで絶賛連載中の電子工作漫画「ハルロック」で主人公の電波系女子大生はるさんの発明品です。仕組み自体は簡単で、以下漫画の最終ページの解説参照下さい。

 ただ、実際にハード的に大量のLEDを点灯させるのはかなり大変なのと、作った後の処置も困ってしまうのでお手軽にPC上に再現してみることにしました。

ぼっち・the・LED on PC完成品動画


仕様

  • 日本限定。漫画だと世界対応
  • "ぼっち"というツイートが含まれているツイートを対象。漫画だと各国語対応かな?
  • クロールするツイート件数はTwitter APIの限界まで(180件くらい) 。漫画だと数万件ツイート
  • TweetクロールにはPC使用、漫画だとRaspberry Pi
  • ハードはPCのみ。漫画だとArduino MEGAと外部回路(カウンタとトランジスタ)を使って60個の3色LEDをドライブ

感想

 こうやってみると漫画に比べて全然しょぼしょぼですね。漫画では数万件のツイートを分析したことになっていますが、TwitterのAPI制限は作者が気づかなかったのか、解決方法がグレーなので敢えて描かなかったのか。個人的には後者だとよいなと思っています。あと位置情報つけている人少なかった。位置情報Nullしか返ってこないので最初何か間違っているのかと思いちょっとハマりました。位置情報つきのツイートって0.2%くらいしかないみたいです。
 そして、ハードで再現するのはあれはほんとうに大変な作業だと思います。モジャアっていうのはハードやっている人なら誰しも心当たりがあるんじゃないかなと思いますw
 しかし、キテレツ大百科と違って自分で漫画の発明品っぽいものが作れてしまうのが楽しいですね。また作れそうなものが漫画で出て来たら再現してみようかなと思います。

関連記事

WEB漫画『ネコマン』 第8話「電波系ネコマン」 - karaage. [からあげ]
今連載している本格的な電子工作漫画は「ハルロック」と「ネコマン」だけ!(多分)

 簡単な作り方を知りたい人は、続きを読むをクリックして下さい

使用したもの

  • Macbook Pro Retina
  • Processing2.1.2
  • twitter4j for processing
  • google mapper for processing

 Macで作りましたが、多分Windowsでも同じ手順で動くと思います。ただ確認できていないのと試す環境が無いので、ノークレーム、ノーリターンでお願いいたします。

準備すること

Processingのインストール

 google先生に聞いてみよう!各環境でのインストールの仕方を優しく教えてくれるよ(多分)。基本はダウンロードしてダブルクリックして、クリック連打です。

twitter4j for Processingインストール

Twitter API 1.1(Twitter4j-3.0.5) + Processingでつぶやく - へんてこ
 最新のtwitterAPI1.1に対応したtwitter4jライブラリを上記の記事のリンクからダウンロード。Processingのソースコードを保存するフォルダにcodeというフォルダを作って twitter4jで始まる.jar拡張子のファイルをぶちこんでやりましょう。これでProcessingでtwitterのAPIが使用できるようになります。

Twitter APIを使用するためのキーを取得

TwitterのAPIを使用するために必要なキーを取得する手順 - Hello API
 プログラムでtwitterのAPIを使用する必要がありますが、そのためにキーの取得が必要になります。上記のサイトの説明が分かりやすいかなと思います。
 自分は何故かUnko Tweetという名前でキーを取得済でしたw全然記憶がないのですが、昔何かをつくろうとしたのでしょう。

googleMapperインストール

http://googlemapper.pt.vu
 上記のリンクのDownloadというところからgoogleMapper.jarをダウンロードして、twitter4jと同じくcodeフォルダの中にぶちこんでやりましょう。

ソースコード

 ソースコード公開します。上記の作業をしてやった上でコピペして、consumerKey, consumerSecret, accessToken, accessSecretのところに取得したTwitterキー情報を入力して実行すれば動くと思います。動くといいな。

import twitter4j.conf.*;
import twitter4j.internal.async.*;
import twitter4j.internal.org.json.*;
import twitter4j.internal.logging.*;
import twitter4j.http.*;
import twitter4j.internal.util.*;
import twitter4j.api.*;
import twitter4j.util.*;
import twitter4j.internal.http.*;
import twitter4j.*;
import googlemapper.*;

GoogleMapper gMapper;
PImage mapImage;

Twitter twitter;
Query query = null;
QueryResult queryResult = null;
String queryWord = "ぼっち";       //検索ワード
String resultWord = " ";      //検索したツイートを格納するところ
PImage icon = null;           //その人のイメージ画像
String username = null;       //user name
int mapon = 0;

GeoLocation geoloc;
double lat;
double lon;

PFont font = createFont("MS Gosic", 20);
int count=1;
int searchMaxNumb = 500;
  String consumerKey = "****";      //****を自分のTwitter APIキーに書き換えてね☆
  String consumerSecret = "****";      //****を自分のTwitter APIキーに書き換えてね☆
  String accessToken = "****";      //****を自分のTwitter APIキーに書き換えてね☆
  String accessSecret = "****";      //****を自分のTwitter APIキーに書き換えてね☆
 
 
void setup(){
  size(1280, 720);
  frameRate(30);
 
  ConfigurationBuilder cb = new ConfigurationBuilder();
  cb.setOAuthConsumerKey(consumerKey);
  cb.setOAuthConsumerSecret(consumerSecret);
  cb.setOAuthAccessToken(accessToken);
  cb.setOAuthAccessTokenSecret(accessSecret);
 
  twitter = new TwitterFactory(cb.build()).getInstance();
  query = new Query(queryWord);

  double mapCenterLat = 38;               // 緯度
  double mapCenterLon = 135;              // 経度
  int    zoomLevel = 6;                         // ズームレベル
  String mapType = GoogleMapper.MAPTYPE_HYBRID;  // 表示の種類
  int    mapWidth = width;                       // 横サイズ 
  int    mapHeight = height;                     // 縦サイズ
 
  gMapper  = new GoogleMapper(mapCenterLat, mapCenterLon, zoomLevel, mapType, mapWidth, mapHeight);
 
  //Get Map
  mapImage = gMapper.getMap(); 
}
 
void draw(){
  background(255);
  image(mapImage, 0, 0); // display map
  query.count(count);
  SearchTweet();

  count++;
  if(count > searchMaxNumb){
    count = 0;
  }
  println("count="+count);

  if(mapon == 1){
    image(icon, (int)(gMapper.lon2x(lon)), (int)(gMapper.lat2y(lat)), 50, 50);
//    fill(0);
//    textSize(32);
//    text(username, (int)(gMapper.lon2x(lon)), (int)(gMapper.lat2y(lat))+100);
//    text(resultWord, (int)(gMapper.lon2x(lon)), (int)(gMapper.lat2y(lat))+200);
  }
}

void SearchTweet(){
  try{
    queryResult = twitter.search(query);
  }
  catch(TwitterException e){
    println(e.getStatusCode());
  }
  if(queryResult != null){
    for(Status status:queryResult.getTweets()){
      println("count="+count);
      println("username=" + status.getUser().getScreenName());
      println("resultword=" + status.getText());

      geoloc = status.getGeoLocation();
      if(geoloc!=null){
        mapon = 1;
        resultWord = status.getText();                                             //get tweet
        icon = loadImage(status.getUser().getOriginalProfileImageURL(), "png");    //get image
        username = status.getUser().getScreenName();                               //get name取得
        lat = geoloc.getLatitude();
        lon = geoloc.getLongitude();
      }
    }
  }
}