ホームページ ウェブフロントエンド htmlチュートリアル HTML がキャンバスを使用して弾幕機能を実装する方法

HTML がキャンバスを使用して弾幕機能を実装する方法

Jun 04, 2018 pm 03:00 PM
canvas html 成し遂げる

この記事では、HTML での弾幕機能の実装方法を中心に紹介します。興味のある方は参考にしていただければ幸いです。

はじめに

最近、大きな仕事をしていたときに弾幕プレイヤーを作る必要がありました。他の人のソースコードを借りて自分で再実装したデモは次のとおりです

主な機能は

弾幕の色、速度、種類を設定
弾幕を表示

既知の欠陥:

全画面表示できない

キャンバスがアダプティブではない

カスタムプレーヤーコントロールがない
再生時間に応じて対応する弾幕が表示されない
弾幕をホバーさせることができない
既知の不具合は将来的に解決される予定 改善。インターネット上で見つかる弾幕プレイヤーのソース コードは、通常、ローリング弾幕のみを作成し、静的な弾幕を作成しません。ここでは、特別に静的な弾幕の実装を追加しました。

キャンバスはテキストとテキストスクロール効果を描画します

プレーヤー全体の核となるのは、キャンバス内のテキストを描画し、テキストスクロールをアニメーション化することです。これは自分でのみ実現できます。常に画面をクリアしてからテキストを書き直すという考え方です。画面のクリアと書き換えの頻度が 24fps に達すると、アニメーションがスムーズになります。

まず、HTMLファイルにvideoビデオタグとキャンバスタグを追加します

<p id="barrageplayer">
    <canvas id="cv_video" width="900px" height="450px"></canvas>
    <video id="v_video" src="test.MP4" controls type="video/mp4"></video>
</p>
ログイン後にコピー

キャンバスタグの位置スタイルをposition:absoluteに設定すると、ビデオとキャンバスが重なって弾幕のように見えますプレイヤー。次に、弾幕関連のコンテンツをキャンバスに追加します。まず、キャンバスの関連情報を取得し、

var c=document.getElementById("cv_video");
//获取画布大小
var c_height=c.height;
var c_width=c.width;
//获取画布
ctx=c.getContext("2d");
//设置字体样式
ctx.font="25px DengXian";
画布信息已经获取和设置,巧妇难为无米之炊,接着我们就要构造弹幕对象,使用的构造模式是动态原型模式
//弹幕对象
function Barrage(content,color,type,speed){
    this.content=content;
    this.color=color;
    this.type=type;
    this.speed=speed;
    if(this.type=="default"){
        this.height=parseInt(Math.random()*c_height)+10;
    }else if (this.type=="static top"){
        this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;
    }else if (this.type=="static bottom"){
        this.height=parseInt((c_height/2)+Math.random()*c_height/2)+10;
    }
    if(typeof this.move!="function"){
        Barrage.prototype.move=function(){
            if(this.type=="default"){
                this.left=this.left-this.speed;
            }
        }
    }
}
ログイン後にコピー

によって構築された弾幕オブジェクトは、コンテンツを含むさまざまなパラメータを初期化します。 move() メソッドは、起動されるたびに 1 ピクセルの単位速度で左にスクロールします。

弾幕オブジェクトの構築が完了したら、テーマとアニメーション制作を入力し、コードを直接入力します

//循环擦写画布实现动画效果
setInterval(function(){
    ctx.clearRect(0,0,c_width,c_height);
    ctx.save();
    for(var i=0;i<msgs.length;i++){
        if(msgs[i]!=null){
            if(msgs[i].type=="default"){
                handleDefault(msgs[i]);
            }else{
                handleStatic(msgs[i]);
           }
        }
    }
},20)
ログイン後にコピー

20msごとに消去を実行し、ctx.clearRect(0,0,c_width,c_height);を変換します。画像全体 現在のキャンバスをクリアし、ctx.save() を使用して現在のキャンバスを保存し、弾幕リストを走査します (msgs は弾幕リストです。弾幕が送信されるたびに、弾幕インスタンスがリストに追加されます)。弾幕のデフォルト スタイルと静的スタイルの弾幕は別々に処理されます。デフォルトスタイルの弾幕の場合は以下のメソッドで処理されます

//处理默认弹幕样式
function handleDefault(barrage){
    if(barrage.left==undefined||barrage.left==null){
        barrage.left=c.width;
    }else{
         if(barrage.left<-200){
            barrage=null;
        }else{
            barrage.move()
            ctx.fillStyle=barrage.color;
            ctx.fillText(barrage.content,barrage.left,barrage.height)
            ctx.restore();
        }
    }  
}
ログイン後にコピー

まず、弾幕インスタンスにleft属性が設定されていない場合は、キャンバスの幅を与えます。弾幕インスタンスがキャンバスから出た場合、メモリーを節約するために null を設定します。そうでない場合は、弾幕インスタンスの move() メソッドを呼び出して left 属性の値を変更し、テキストの色を設定して、新しいテキストを書き込みます。最初のレベルを復元し、キャンバスを復元します。これで 1 フレームのアニメーションが完成します。

静的弾幕の実装方法は以下の通りです

//处理静止弹幕样式
function handleStatic(barrage){
    ctx.moveTo(c_width/2,barrage.height);
    ctx.textAlign="center";
    ctx.fillStyle=barrage.color;
    ctx.fillText(barrage.content,c_width/2,barrage.height);
    if(barrage.left==undefined||barrage.left==null){
        barrage.left=c.width;
    }else{
        if(barrage.left<-200){
            ctx.fillText("",c_width/2,barrage.height);                
            barrage=null;
            //ctx.restore();
            ctx.clearRect(0,0,c_width,c_height);        
        }else{
            barrage.left=barrage.left-6;
        }
    }
}
ログイン後にコピー

まず、キャンバスの基点をキャンバスの中心に移動します。このとき、新しいキャンバスが生成されることに注意してください。元のキャンバスの () このメソッドはこのキャンバスには適用されなくなりました。次に、テキストの配置を中央揃えに設定し、テキストのスタイルを設定して、テキストを塗りつぶします。静止弾幕なので緩和する必要はありませんが、定期的に静止弾幕も消えるフラグを立てる必要があります。ここで追加の属性を占有しないようにするために、 left 属性をフラグとして直接使用します。 left 属性もデクリメントしますが、 left がしきい値に達した場合、 ctx.clearRect() メソッドを使用します。弾幕をクリアします。このようにして、静的弾幕の処理が実現される。

色やスタイルの設定に一定の基礎を持っている人は、ここでは詳しく説明しませんが、実行可能なコード部分を見て理解するだけで十分です。

概要

このプロジェクトは主にテキスト描画とテキストイージングアニメーションにキャンバスを使用します。使用される主なメソッドは

canvasDom.getContext()
canvas.save()/canvas.restore()
canvas.clearRect()
canvas.moveTo()
ログイン後にコピー

です。save()とrestoreについては豊富な経験があることがわかりました。 ()は理解不能ですが、キャンバスの状態を変更すると、現在のキャンバスは元のキャンバスではなくなるので、キャンバスの状態を変更する前に、キャンバスの状態を保存して、キャンバスの状態を切り替えて作業を終了します。 . 、元のキャンバスの状態に戻って作業を続けます。たとえば、静的な弾幕に対処してキャンバスの基点を変更すると、元のキャンバスのクリア方法は現在のキャンバスに適用されなくなり、現在のキャンバスでは別のクリア方法のみを使用できます。その後、元のキャンバスに戻ります。

実行可能なコード

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style type="text/css">
    .pickp{
        width: 30px;
        height: 30px;
        cursor: pointer;
        border: 2px solid gray;
        display: inline-block;
    }
    #white{
        background: white;
    }
    #red{
        background:#ff6666;
    }
    #yellow{
        background:#ffff00;
    }
    #blue{
        background:#333399;
    }
    #green{
        background:#339933;
    }
    #cv_video{
        position: absolute;
        z-index: 1;
    }
    #barrageplayer{
        position: relative;
        display: block;
        width: 900px;
        height: 500px;
    }
    #v_video{
        position: absolute;
        width: 100%;
        height: 100%;
        z-index: 0;
    }
</style>
<body>
    <p id="barrageplayer">
        <canvas id="cv_video" width="900px" height="450px"></canvas>
        <video id="v_video" src="test.MP4" controls type="video/mp4"></video>
    </p>
    <p id="barrageinput">
        <p>
            <input type="text" id="smsg" placeholder="请输入弹幕内容"/>
            <button id="send"> 发送</button>
        </p>
        <p id="colorpick">
            <p class="pickp" id="white"></p>
            <p class="pickp" id="red"></p>
            <p class="pickp" id="yellow"></p>
            <p class="pickp" id="blue"></p>
            <p class="pickp" id="green"></p>
        </p>
        <p id="typepick">
            <input type="radio" name="type" value="default">默认
            <input type="radio" name="type" value="static top">静止顶部 
            <input type="radio" name="type" value="static bottom">静止底部
        </p>
        <p id="speedpick">
            <input type="radio" name="speed" value="1">1X
            <input type="radio" name="speed" value="2">2X
            <input type="radio" name="speed" value="3">3X
        </p>
        <p id="stylepick"></p>
    </p>
    <script>
        var c=document.getElementById("cv_video");
        var typeDom=document.getElementsByName("type");
        var speedDom=document.getElementsByName("speed");
        var colorpick=document.getElementById("colorpick");
        var smsg=document.getElementById("smsg");
        var color="#white";
        var speed=1;
        var type="default";
        var msgs=[];
        //获取画布大小
        var c_height=c.height;
        var c_width=c.width;
        //获取画布
        ctx=c.getContext("2d");
        ctx.font="25px DengXian";
        //处理颜色选择
        colorpick.addEventListener(&#39;click&#39;,function(event){
            switch(event.target.id){
                case "white":
                    color="white";
                    break;
                case "red":
                    color="#ff6666";
                    break;
                case "yellow":
                    color="#ffff00";
                    break;
                case "green":
                    color="#339933";
                    break;
                case "blue":
                    color="#333399";
                    break;
            }
        })
        //处理发送弹幕
        document.getElementById("send").onclick=function(){
            var text=smsg.value;
            for(var i=0;i<typeDom.length;i++){
                if(typeDom[i].checked){
                    type=typeDom[i].value;
                    break;
                }
            }
            for(var i=0;i<speedDom.length;i++){
                if(speedDom[i].checked){
                    speed=2*parseInt(speedDom[i].value);
                    break;
                }
            }
            var tempBarrage=new Barrage(text,color,type,speed);
            msgs.push(tempBarrage);
        }
        //
        //弹幕功能部分代码
        //
        //弹幕对象
        function Barrage(content,color,type,speed){
            this.content=content;
            this.color=color;
            this.type=type;
            this.speed=speed;
            if(this.type=="default"){
                this.height=parseInt(Math.random()*c_height)+10;
            }else if (this.type=="static top"){
                this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;
            }else if (this.type=="static bottom"){
                this.height=parseInt((c_height/2)+Math.random()*c_height/2)+10;
            }
            if(typeof this.move!="function"){
                Barrage.prototype.move=function(){
                    if(this.type=="default"){
                        this.left=this.left-this.speed;
                    }
                }
            }
        }
        //循环擦写画布实现动画效果
        setInterval(function(){
            ctx.clearRect(0,0,c_width,c_height);
            ctx.save();
            for(var i=0;i<msgs.length;i++){
                if(msgs[i]!=null){
                    if(msgs[i].type=="default"){
                        handleDefault(msgs[i]);
                    }else{
                        handleStatic(msgs[i]);
                    }
                }
            }
        },20)
    //处理默认弹幕样式
    function handleDefault(barrage){
        if(barrage.left==undefined||barrage.left==null){
            barrage.left=c.width;
        }else{
            if(barrage.left<-200){
                barrage=null;
            }else{
                barrage.move()
                ctx.fillStyle=barrage.color;
                ctx.fillText(barrage.content,barrage.left,barrage.height)
                ctx.restore();
            }
        }  
    }
    //处理静止弹幕样式
    function handleStatic(barrage){
        ctx.moveTo(c_width/2,barrage.height);
        ctx.textAlign="center";
        ctx.fillStyle=barrage.color;
        ctx.fillText(barrage.content,c_width/2,barrage.height);
        if(barrage.left==undefined||barrage.left==null){
            barrage.left=c.width;
        }else{
            if(barrage.left<-200){
                ctx.fillText("",c_width/2,barrage.height);                
                barrage=null;
                //ctx.restore();
                ctx.clearRect(0,0,c_width,c_height);        
            }else{
                barrage.left=barrage.left-6;
            }
        }
    }
    </script>
</body>
</html>
ログイン後にコピー

概要: 上記がこの記事の全内容です。皆様の学習に役立つことを願っています。

関連するおすすめ:

H5+Canvasユースケース詳細説明

Vue+canvasを使ってモバイル手書きパッド機能を実装する方法

js+canvasスライディングパズル認証コード機能を実装

以上がHTML がキャンバスを使用して弾幕機能を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

HTMLの表の境界線 HTMLの表の境界線 Sep 04, 2024 pm 04:49 PM

HTML の表の境界線に関するガイド。ここでは、HTML でのテーブルの境界線の例を示しながら、テーブル境界線を定義する複数の方法について説明します。

HTML のネストされたテーブル HTML のネストされたテーブル Sep 04, 2024 pm 04:49 PM

これは、HTML でのネストされたテーブルのガイドです。ここでは、テーブル内にテーブルを作成する方法をそれぞれの例とともに説明します。

HTML 左マージン HTML 左マージン Sep 04, 2024 pm 04:48 PM

HTML マージン左のガイド。ここでは、HTML margin-left の概要とその例、およびそのコード実装について説明します。

HTML テーブルのレイアウト HTML テーブルのレイアウト Sep 04, 2024 pm 04:54 PM

HTML テーブル レイアウトのガイド。ここでは、HTML テーブル レイアウトの値と例および出力について詳しく説明します。

HTML 内のテキストの移動 HTML 内のテキストの移動 Sep 04, 2024 pm 04:45 PM

HTML でのテキストの移動に関するガイド。ここでは、概要、マーキー タグが構文でどのように機能するか、および実装例について説明します。

HTML 順序付きリスト HTML 順序付きリスト Sep 04, 2024 pm 04:43 PM

HTML 順序付きリストのガイド。ここでは、HTML 順序付きリストと型の導入とその例についても説明します。

PHPでHTML/XMLを解析および処理するにはどうすればよいですか? PHPでHTML/XMLを解析および処理するにはどうすればよいですか? Feb 07, 2025 am 11:57 AM

このチュートリアルでは、PHPを使用してXMLドキュメントを効率的に処理する方法を示しています。 XML(拡張可能なマークアップ言語)は、人間の読みやすさとマシン解析の両方に合わせて設計された多用途のテキストベースのマークアップ言語です。一般的にデータストレージに使用されます

HTML の onclick ボタン HTML の onclick ボタン Sep 04, 2024 pm 04:49 PM

HTML オンクリック ボタンのガイド。ここでは、それらの紹介、動作、例、およびさまざまなイベントでの onclick イベントについてそれぞれ説明します。

See all articles