JS が WeChat の「クソ爆弾」機能を実装

JS が WeChat の「クソ爆弾」機能を実装

みなさんこんにちは、Qiufengです。最近、WeChatは新しい機能をリリースしました(WeChat 8.0.6にアップデートされました)。最も人気の機能は間違いなく「うんこ爆発」機能であり、さまざまなグループがうんこ爆発機能を使い始めています。

皆さんはそのような経験をしたことがあるでしょうか。私も子供の頃(つまり、まだ小学生だった頃)、春節にこのような邪悪な楽しみを試しました。WeChat がオンライン版を作るとは思っていませんでした。製品の開発者自身もこの機能的な発明を嘲笑した。しかし、誰もが楽しめる機能を作れれば、その製品の価値は高まります。

以前、WeChat 8.0 がアップデートされたとき、「WeChat 8.0 で「爆発」する花火の絵文字効果を実現する方法をお教えします」というタイトルの記事も書きました。前回の記事では、これを実装するためにcanvasを使用しました。記事の最後に、同様の機能はlottieを通じて実現できるというコメントがありました。実は、私はこれにかなり興味があるのですが、試したことがありませんでした。今回は、この機能を実現するために、新しい方法lottieを使用したいと思います。

効果体験:

https://example.qiufeng.blue/wechat-feces/3-2-feces.html

Githubアドレス:

https://github.com/hua1995116/node-demo/tree/master/wechat-feces

ステップの内訳

どのオブジェクトも小さなオブジェクトで構成されているため、上記の機能を実現したい場合は、当然ながら段階的に実行する必要があります。上記の機能を大まかに以下の4つのステップに分解しました。それぞれそれほど難しくはなく、フロントエンド初心者でも簡単に実装できると言えます。

1. 爆弾を投下する

このステップでは、二次関数の知識を使用して軌道パス(y = $x^2$ に類似)を記述し、 tween.jsを使用してトゥイーンアニメーションを実行します。

2. 爆弾爆発

lottieを使用してアニメーションを実現します。

3. うんちが膨らんだ

cssアニメーションの使用

4. 誰もが衝撃を受ける

cssアニメーションの使用

要約する

上記は、私たちが話したい一般的なアイデアです。おそらく、それらの実装のいくつかはすでにご存知でしょうから、いくつかはスキップしてもかまいません。上記のアイデアを念頭に置いて、実践してみましょう。

具体的な実装

1. 爆弾を投下する

よく観察すると、爆弾の軌道は実際には放物線になっていることがわかります。この機能を実現したい場合は、簡単に二次関数を考えることができます。

まず、二次関数の定義を見てみましょう。

一般的に、y=ax²+bx+c (a≠0) (a、b、c は定数) の形式の関数は二次関数と呼ばれます。

画像で表現するとこんな感じです。

明らかに、これは私たちが望む軌道に非常に似ています。

通常の直交座標系では、y 軸が垂直上向き、x 軸が水平右向きになるためです。 DOM の配置では、左上が (0, 0)、水平右が正の x 軸、垂直下が正の y 軸になります。座標系は、単に x 軸に沿って反転されます。

したがって、二次関数を決定するだけで、軌道を取得できます。二次関数の一般項には 3 つの未知数があるため、二次関数を決定するには 3 つの点を知るだけで十分です。二次関数が次のようになると仮定しましょう。

3 つの点は (0,H)、(H,0)、(3H, 3H) です。一般項を代入すると次の式が得られます。

次に解決する

得る:

したがって、全体の軌道を描くには、爆弾の最高点の高さを「たわごと」から取得するだけで済みます。

ここで、爆弾が 10px × 10px の小さな正方形で、開始点が (300, 300)、終了点が (0, 100) H=100 に設定されているとします。このとき、得られる 2 次関数は次のようになります。

次の軌道アニメーションを取得できます。

アニメーションの各フレームをレンダリングするために、有名なトゥイーン アニメーション ライブラリ Tween.js を使用しました。トゥイーン (アニメーション) は、オブジェクトのプロパティをスムーズに変更できる概念です。どのプロパティを変更するか、トゥイーンの実行が終了したときにそれらのプロパティが持つべき最終値、それに要する時間を指定するだけで、トゥイーン エンジンが開始点から終了点までの値を計算します。

var coords = { x: 300 }; // 開始点は x = 300 です
var tween = 新しい TWEEN.Tween(座標)
	.to({ x: 0 }, 1000) // 終了点は x = 0 で、アクションは 1 秒で完了します。easing(TWEEN.Easing.Linear.None) // 一定速度

上記の定義を使用すると、 onUpdateで各変更のx値を取得し、上記の二次関数を通じて y を取得して、小さな正方形を更新できます。

tween.onUpdate(関数() {
    var x = 座標.x;
    変数 y = 1/120 * x * x - 11/6 * x + 100;
		box.style.setProperty('transform', 'translate(' + x + 'px, ' + y + 'px)');
})

この時点で、完成したエフェクトにはまだ何かが欠けています。絵画と同じように、スケルトンを描いただけで、それをラップして色を付けるだけです。次に、次の2つのことを行うだけで、エフェクトを確認できます〜

1. 四角形を爆弾に置き換えます。爆弾の形状は非常に単純なので、PS を使用してレイヤーから切り取ることができます。

2. 動きの角度を変更します。

このセクションの完全なコード: https://github.com/hua1995116/node-demo/blob/master/wechat-feces/1-2-animation.html

2. 爆弾爆発

それでは爆弾爆発のエフェクトについてお話しします。前述の通り、アニメーションを書くのにlottieを使いたいのですが、 lottieとは何でしょうか?

Lottie は、AE で作成されたアニメーション (bodymovin を使用して json 形式にエクスポートする必要があります) を解析できるライブラリで、Web、iOS、Android、React Native をサポートしています。 Web 側では、lottie-web ライブラリはエクスポートされたアニメーション json ファイルを解析し、アニメーションを svg または canvas の形式でページに描画できます。

次に、https://lottiefiles.com/ にアクセスして、 json爆発特殊効果ファイルを見つけました。

書き方は非常に簡単です。lottie lottieインポートしてbodymovin.loadAnimationメソッドを呼び出すだけです。

<script src="https://cdn.bootcdn.net/ajax/libs/lottie-web/5.7.8/lottie.min.js"></script>
</head>
<本文>
<div class="bodymovin"></div>
<スクリプト>
    定数アニメーション = window.bodymovin.loadAnimation({
        コンテナ: document.querySelector('.bodymovin'), // アニメーションを格納する DOM 要素 レンダラー: 'svg', // レンダリング方法、svg、キャンバス、html (軽量バージョンでは svg のみをレンダリングします)
        loop: true, // ループ再生するかどうか autoplay: true, // 自動再生するかどうか path: './bomb.json', // アニメーション json ファイル パス });
</スクリプト>

したがって、放物線が完成した直後に爆発効果を呼び出すだけでよく、 tween.jsにはイベント メソッドonCompleteも用意されています。 onCompleteコールバックで爆発アニメーションを開始するだけです。

tween.onComplete(関数() {
  // 爆発アニメーションを書き込む}) 

このセクションの完全なコード: https://github.com/hua1995116/node-demo/blob/master/wechat-feces/2-2-lottie.html

3. うんちが膨らんだ

3.1 形状

同様に、Bomb は PS を使用して、このように「baba」の透明なレイヤーを切り取ります。 (多少のバリがあっても問題ありません。実際のうんちはそれほど大きくないので、バリは見えにくいです。微調整で直すこともできます。)

.糞便{
  位置: 絶対;
  背景画像: url(./feces.jpg);
  背景サイズ: 100%;
  背景の位置: 中央;
  背景繰り返し: 繰り返しなし;
  幅: 80ピクセル;
  高さ: 80px;
  変換の原点: 中心;
}
// baba要素を作成する function createfeces(scale = 1) {
  定数 fece = document.createElement('div');
  fece.className = '糞便';
  // うんちは大きくなったり小さくなったり、方向があったりするので、値は予約されています。
  定数シンボル = Math.random() > 0.5 ? 1 : -1;
  fece.style.transform = `scale(${scale * 1.1}) rotate(${symbol * 20 * Math.random()}deg)`
  糞を返す;
}

3.2 場所

爆発からウンチが飛び出しているのがわかります。飛び出しているウンチは主に7つです。真ん中のウンチが一番大きく、中心から離れるにつれて小さくなっていきます。配置は円に似ていますが、それほど規則的ではありません。

したがって、まずこれを最も簡単な方法、つまり円で囲むことで実現できます。円は 360° なので、それを 6 つの等しい部分に分割するだけです。合計 6 個のボールを囲んでいるので、各ボール間の角度は 60° です。

上の爆弾はだいたい300*300の領域なので、中心の座標を(150,150)に設定し、70から230までのx点をランダムに生成して、y値を計算します。最初の点を決定した後、各点間の角度は60°で、残りの5つの点を計算できます。

中心点(150,150)を円の中心として計算するのは面倒なので、中心点を(0, 0)に移動させて計算し、最終的に計算した点をすべてx軸とy軸に沿って150ずつ移動させました。

// 生成される複数のうんちの位置を計算する // 渡されるパラメータ num は生成されるうんちの数です function randomPosition(num) {
  const radius = 80; // 円の半径 const randomX = Math.random() * radius // 0から半径までの任意のxを取る
  const y = Math.round(Math.sqrt(radius * radius - randomX * randomX)); // 円の第 1 象限の点を決定します const radian = Math.atan(y / randomX); // この点のラジアン値 const step = Math.PI * 2 / num; // 各糞の山のラジアン値 return new Array(num).fill(0).map((item, index) => {
    const r = (インデックス * ステップ + ラジアン)
    // ラジアンを 0 - 2 * PI に変換します
    const tr = r > Math.PI * 2 ? r - Math.PI * 2 : r < 0 ? r + Math.PI * 2 : r;
    戻る {
      x: 半径 * Math.sin(tr)、
      y: 半径 * Math.cos(tr)、
    }
  })
            
} 

次に、このアイデアに従って 6 つのうんちを描き、X 軸と Y 軸に沿ってそれぞれ 150 度移動します。

randomPosition(6).map(item => ({ x: item.x + 150, y: item.y + 150 })) // ここで6個以上を定義することもできます

ちょっとそれっぽいですが、全部同じ大きさなので、それを処理して中心からの距離に応じて大きさを拡大縮小する必要があります。ざっくりと一つ書いてみました。円の半径は80なので、80増えるごとにうんこの大きさは元の2/3になります。

const dis = Math.sqrt((end.x - 150) * (end.x - 150) + (end.y - 150) * (end.y - 150)); // 150度移動したので、中心点からの距離を計算する必要があります const r = Math.pow(2/3, dis / length); // 拡大縮小する比率

ただし、実際のシーンでは配置はよりランダムになるため、各うんちの位置にランダムな値を追加し、中央のうんちが左上隅に偏るようにし、特定のランダム値も追加しました。

関数 randomPosition(num) {
...
新しい配列(num).fill(0).map((item, index) => { を返します。
  const r = (インデックス * ステップ + ラジアン)
  const tr = r > Math.PI * 2 ? r - Math.PI * 2 : r < 0 ? r + Math.PI * 2 : r;
  戻る {
    // ランダムな値 x を追加します: length * Math.sin(tr) + (Math.random() > 0.5 ? 1 : -1) * 10 * Math.random(),
    y: 長さ * Math.cos(tr) + (Math.random() > 0.5 ? 1 : -1) * 10 * Math.random(),
  }
})
} 

3.3 角度

最後に、各馬場の角度を装飾するだけです。

関数createfeces(スケール) {
  定数 fece = document.createElement('div');
  fece.className = '糞便';
  const symbol = Math.random() > 0.5 ? 1 : -1; // -20 から 20 の間のランダムな角度を生成します fece.style.transform = `scale(${scale}) rotate(${symbol * 20 * Math.random()}deg)`
  fece.style.opacity = '0';
  糞を返す;
} 

3.4 アニメーション

これは爆弾を落とすのと同じようなものなので、詳しくは述べません。うんちは最初に爆弾の位置から出てきて、その後ゆっくりと下がってくるので、ここでは 2 つの Tween アニメーションを使用する必要があることに注意してください。

// 爆発穴から飛び出す初期登場のアニメーション function initFece(end) {
	...
  const start = { x: 0, y: 100, z: 0 }; // 爆発ポイント const tween = new TWEEN.Tween(start)
  .to({ ...終了, z: 1 }, 100)
  .easing(TWEEN.Easing.Linear.None)
  .onUpdate(関数() {
    fece.style.setProperty('top', `${start.y}px`);
    fece.style.setProperty('left', `${start.x}px`);
    fece.style.setProperty('不透明度', `${start.z}`);
  })
  .onComplete(関数() {
    initDown(start, fece).start(); // パンチアウトが完了し、落下する透明アニメーションを実行します})
  トゥイーンを返します。
}
// 落下して透明になるアニメーション function initDown(start, fece) {
  定数s = {
    y: 開始.y,
    o: 1、
  };
  定数e = { y: start.y + 80, o: 0 };
  const tween = 新しい TWEEN.Tween(s)
  .to(e, 2000 + 500 * Math.random())
  .easing(TWEEN.Easing.Quadratic.In)
  .onUpdate(関数() {
    fece.style.setProperty('top', `${sy}px`);
    fece.style.setProperty('不透明度', `${so}`);
  })
  .onComplete(関数() {
  })
  トゥイーンを返します。
}

最終的な効果

このセクションの完全なコード: https://github.com/hua1995116/node-demo/blob/master/wechat-feces/3-2-feces.html

3.5 まとめ

このセクションはかなり長いので、知識をまとめてみましょう

  • まず、 1 = x² + y²の円軌道の特性を利用して初期位置を確立します。
  • ランダムな値を追加することで、分布の規則性が若干低下します。
  • うんちにランダムな角度を加える
  • 中心を爆発点に近づける
  • 出現と落下の連鎖アニメーションを追加する

4. 誰もが衝撃を受ける

この機能は、簡単な CSS アニメーションで実現できます。ここでは詳細には触れません。興味のある方は、実装してコメントに記入してください。

結論

これは純粋にこの効果についての好奇心からの調査であり、アニメーションの 100% 復元ではありません。私はアニメーションプログラマーではなく、上記のライブラリを使用するのは今回が初めてなので、文章があまり専門的ではないかもしれません(質問がある場合は、コメントセクションで誤りを指摘してください)。しかし、興味深いアイデアを提供したいと思っています。アニメーションを作成するときは、 lottieライブラリとtweenライブラリを使用して、複雑な問題を単純化し、不規則なものを規則的なものに変え、複雑なものを単純なものに変え、最後に段階的に深めることができます。また、この記事を校正していただいたNanxiにも感謝いたします。

JSを使用してWeChat「shit bombing」キャンペーンを実施する方法についての記事はこれで終わりです。より関連性の高いjs WeChat「shit bombing」キャンペーンコンテンツについては、123WORDPRESS.COMで以前の記事を検索するか、次の関連記事を引き続き参照してください。今後も123WORDPRESS.COMを応援してください。

<<:  MySQLは2つの日付間の日数、月数、年数を計算します

>>:  Linux で JDK をインストールして環境変数を設定する方法 (この記事で十分です)

推薦する

MySql カンマ連結文字列クエリの 2 つの方法

次の2つの関数は、 FIND_IN_SETと同じように使用されます。使用する場合、 FIND_IN_...

一般的なブラウザのユーザーエージェントの概要

1. 基礎知識: HTTP ヘッダー ユーザーエージェントユーザー エージェントは、ユーザー エージ...

CentOS 7 で NFS ファイル共有ストレージ サービスを構築するための完全な手順

序文NFS (Network File System) は、ネットワーク ファイル システムを意味し...

Windows 64 ビット版の MySQL 8.0.15 インストール チュートリアル

まず公式サイトにアクセスしてダウンロードし、MySQLダウンロードをクリックします。 ダウンロードし...

Mysqlはストアドプロシージャを通じて文字列を配列に分割します

文字列を配列に分割するには、次の 3 つの MySQL 関数を使用する必要があります。 REVERS...

スプレッド演算子のサンプルコードと JavaScript での応用

スプレッド演算子を使用すると、式をある時点で展開できます。スプレッド演算子は、複数のパラメーター (...

Linux でファイルの作成時間を取得する方法と実践的なチュートリアル

背景ファイルの作成時刻を取得する必要がある場合があります。例えば: 「xtrabackup スキーマ...

Mysql5.7 で JSON 操作関数を使用する手順

序文JSON は、言語に依存しないテキスト形式を使用する軽量のデータ交換形式で、XML に似ています...

Uniappがスライディングスコアリング効果を実現

この記事では、スライディングスコアリングを実装するためのuniappの具体的なコードを参考までに共有...

CSSインジェクションの知識の要約

最近のブラウザでは、CSS 内で JavaScript を実行することはできなくなりました。以前は、...

CSS 極座標のサンプルコード

序文このプロジェクトには、衛星測位用のグラフィックスを含むチャートの要件があり、北半球または南半球の...

Docker 大規模プロジェクトのコンテナ化変革

仮想化とコンテナ化は、クラウドベースのプロジェクトでは避けられない 2 つの問題です。仮想化は純粋な...

Bootstrapグリッドの垂直および水平配置の詳細な説明

目次1. Bootstrap グリッドレイアウト2. 垂直方向の配置2.1 行タグの垂直方向の配置を...

VirtualBox での CentOS 8.1 仮想マシンのインストールを最小限に抑える詳細なチュートリアル

1. 関連ツールと画像をダウンロードするダウンロードリンクバーチャルボックス: https://do...