はじめに
こんにちは。デザイナーの@nagatです。
「Aucfan Advent Calendar 2020」も23日目。もうすぐクリスマスですねー><
突然ですが、イベントの実行委員や定例会議の司会を、手っ取り早く決めるときルーレットやクジを使うケースって多いですよね?
完全ランダムで担当者を決めてくれるので、ネット上で公開されている無料のルーレットツールはプライベートでもとても重宝しています^^
ただ、実行時に相手にバレず担当者を狙い撃ちできる八百長モード搭載のルーレットツールって探しても無いんですよねー。
ネタに困っていたので作りました!
注)ただの一発ネタの記事です。
要求される仕様
- webブラウザで実行できる
- ルーレット候補を自由にtextareaに入力できる
- 完全ランダムの公平なルーレットができる
- 特定の相手を指定できるモードが搭載されている
- 八百長モード実行時に相手にバレない
使用したもの
- gulp
- webpack
- html
- css(scss)
- JavaScript
まずはランダム性のある公平なルーレット機能を作る
骨組みはhtmlとcssで作り、ルーレット機構はJavaScriptで作成します。
こういう自作ツールは、裏で何してるか分からないので、
公平性を出すためにツール名は「絶対に八百長しないRoulette」と名付けました^^
タイトルはcssアニメーションを使用して、虹色に怪しく輝きます。
登場する名前は 苗字のトレンドランキング から適当に入力しています。
ルーレット自体の機構はスライダーで有名なSwiper.jsを無理やりルーレットぽい挙動に動かしてそれっぽく作ります。
画面のtextareaに改行を入れながら候補を入力し、「はじめる」ボタンを押下することでルーレットが開始されます。
また、本来カルーセル等に使うSwiper.jsでルーレットぽく無理やり作成しているので、ルーレット実行時に乱数を使用して__候補の順番を入れ替えることで__ランダム性を出しています。
/**
* エントリーリストの取得
* @return {Array.<String>} エントリーネームと画像ナンバーの配列
*/
getEntryList() {
let t = this;
let entryTxtareaElem;
let entryListVal;
let entryNameList;
let entryListData;
entryListData = {
all: [],
};
entryTxtareaElem = $(t.config.entryTxtarea);
entryListVal = t.trimText(entryTxtareaElem.val());
entryNameList = entryListVal.split(/\n/);
entryNameList.forEach((elem, i) => {
let num;
if ((i + 1) < 10) {
num = '0' + (i + 1);
} else {
num = i + 1;
}
entryListData.all[i] = {
name: elem,
imgNum: num,
};
});
entryListData.all = t.shuffle(entryListData.all);
return entryListData;
}
/**
* 配列内の要素をシャッフル
* @param {Array} array シャッフルする対象の配列
* @return {Array} シャッフルされた配列
*/
shuffle([...array]) {
for (let i = array.length - 1; i >= 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
テキストだけだと寂しいので、イケメンや美女の写真を適当に入れてみました。
確定する寸前に遅延をかけてちょっと焦らし演出を付けました。
まずは、公平性のあるルーレットが完成しました!
八百長するぞ
八百長モードの流れ
- textarea内でキーボード入力実行で八百長モード発動
- textarea内の候補リストから八百長対象となる候補を除外する
- 八百長対象以外の候補のリストでルーレットを回す
- ルーレットの途中で確定演出(茶番)を入れる
- すべてのスライダー要素を八百長対象の写真とテキストに入れ替える(大いなる力)
- フィニッシュ(無慈悲)
キーボード入力実行で八百長モード発動
八百長モードを有効にしてルーレットを回すにしても、開始時点で相手に八百長行為がバレてはいけません。
なので、八百長モード有効のトリガーをボタンクリックではなくキーボード入力にします。
textareaにキャレットを乗せている状態で、
Macは ⌘ + Enter
で発火。
Windowsは Ctrl + Enter
で発火。
キャレットが表示されている行の名前の人が八百長の餌食 対象になる人です。
let t = this;
let entryData;
$('textarea').on('keydown', (event) => {
if ((event.ctrlKey || event.metaKey) && event.keyCode === 13) {
let self = event.currentTarget;
let selin = self.selectionStart;
let val1 = self.value;
let val2 = val1.substr(0, selin);
let matchLine = val2.match(/\n/g);
let row = 0;
if (matchLine) {
row = matchLine.length;
} else {
row = 0;
}
// 候補リストの取得
entryData = t.getEntryList(row);
// ルーレットの実行
t.playing();
}
});
八百長対象となる候補を除外する
先述したとおり、ランダム性はスライダーの並び替えで出しているので、八百長の対象者をルーレット実行時に制御できません。。。
なので、一旦八百長対象者をリストから除外します。
/**
* エントリーリストの取得
* @return {Array.<String>} エントリーネームと画像ナンバーの配列
*/
getEntryList(yaochoNum) {
let t = this;
let entryTxtareaElem;
let entryListVal;
let entryNameList;
let entryListData;
entryListData = {
pickup: [],
all: [],
};
entryTxtareaElem = $(t.config.entryTxtarea);
entryListVal = t.trimText(entryTxtareaElem.val());
entryNameList = entryListVal.split(/\n/);
entryNameList.forEach((elem, i) => {
let num;
if ((i + 1) < 10) {
num = '0' + (i + 1);
} else {
num = i + 1;
}
entryListData.all[i] = {
name: elem,
imgNum: num,
};
});
if (yaochoNum != null && typeof yaochoNum != 'undefined') {
t.yaochoMode = true;
entryListData.pickup[0] = entryListData.all[yaochoNum];
entryListData.all = entryListData.all.filter((value) => {
return value.name != entryListData.all[yaochoNum].name;
});
} else {
t.yaochoMode = false;
entryListData.pickup[0] = null;
}
entryListData.all = t.shuffle(entryListData.all);
return entryListData;
}
確定演出を入れる
八百長対象者が居ないリストを、八百長対象者にすべて差し替える動作を、ゲームのガチャみたいな確定演出を入れて誤魔化します。
カットインは写真だけじゃ物足りなかったので、テキストも入れてみる。
今回のルーレット一番の見どころ。
大いなる力ですべての要素が渡辺さん(仮名)に入れ変わる瞬間。
うおおおおおおおおおおおおおおおおおおおおお
フィニッシュ
「絶対に八百長しないRoulette」はこちら
9名までなら画像が表示されます。
あ、画像のプリロード入れるの忘れてた... (;´Д`)
おまけ
候補リストに「肉」って入れたら、フィニッシュの画面でオデコに丁度収まった^^;
さいごに
当社ではコーディングが好きなデザイナーを募集中です!
当社に興味を持っていただける方がいらっしゃれば、お気軽にお話だけでも聞きに来てください!