キャラクタを複数描画:Three.jsで3Dブラウザゲームを作る その3

サンプルプログラム

Nengaです。今回はキャラクターの複数描画をご紹介いたします。

前回までのサンプルではキャラクタは1体のみ表示していましたが,キャラクタのデータを配列化することで複数のキャラクターを用意できます。

これで主人公キャラクターだけでなく,敵キャラクターも表示させることができるようになります。

キャラクターが増えることでゲームの世界が広くなります。

 

スポンサーリンク

サンプルプログラム:Three.jsのフォント描画

サンプルプログラムを置きましたのでダウンロードお願いいたします。↓

 <サンプルプログラムをダウンロード> 

 

ダウンロードいただけたら,zip展開の上,jsの中にある「script.js」をローカルサーバーで実行方お願いいたします。ローカルサーバーでの実行方法は下記記事のとおりです。

サンプルのデモはこちらになります。


↑タップでデモ開始です。

サンプルプログラムのキャラクター複数描画について

サンプルプログラムではキャラクターを3体ロードしています。

①,②,③でそれぞれ個別にコントロールすることが可能です。

CHARA3Dクラス

class CHARA3D{
    constructor(ID){
        this.ID=ID;
        this.model=null;
        this.animations=null;
        this.animMixer=null;
        this.loading=false;
    }
・・・

キャラクター単体の情報を1つにまとめるクラスとして,CHARA3Dクラスを作ります。

N3Dlib-00.jsにあり,modelがキャラクタのポリゴンやテクスチャなどを,animations・animMixerがアニメーション関連を格納する変数です。

※IDとloadingは未使用の残骸です。あとで消しておきます。。

CHARA3Dの使い方

script.jsの27~28行目で変数宣言します。余裕をもって最大256体のキャラクターを使えるよう用意しておきます。

※「そんなに余分に確保して大丈夫?」と感じるかもしれませんが,本当に使う分以外はカラのデータなので,掛かる負荷はほとんど増えません。(ループの回数が増えるくらい)

//キャラ
let modelMax=256;
let chara=[];

初期化は56~58行目で行なっています。ループ文を使って256体をすべて初期化します。

    //キャラを初期化
    for(let i=0;i<modelMax;i++){
        chara[i]=new CHARA3D(i);
    }

キャラのロードです。86~118行目で実施しています。

    //キャラロード
    let num;
    num=0;
    loadGltf(num,’./data/pegi.glb’);
    num=1;
    loadGltf(num,’./data/pegi.glb’);
    num=2;
    loadGltf(num,’./data/chiyu.glb’);
 
    let waitLoadingModel = setInterval(function() {//モデルのロード完了までウエイト
        let bool=true;
        for(let i=0;i<modelMax;i++){
            if(chara[i].loading && (!chara[i].model || !chara[i].animMixer))bool=false;
        }
        if(bool){
            let num,scaleMaster;
            num=0;
            scaleMaster=0.2;
            chara[num].model.scale.set(scaleMaster,scaleMaster,scaleMaster);
            
            num=1;
            scaleMaster=0.3;
            chara[num].model.position.set(0,0,-2);
            chara[num].model.scale.set(scaleMaster,scaleMaster,scaleMaster);

            num=2;
            scaleMaster=0.5;
            chara[num].model.position.set(0,0,2);
            chara[num].model.rotation.set(0,3.14159,0);
            chara[num].model.scale.set(scaleMaster,scaleMaster,scaleMaster);

            clearInterval(waitLoadingModel);            
        }
    }, 100);

ここで,ロード関数の後にそれぞれのキャラクターについてスケールやポジションをセットしますが,ウエイトを噛ませています。

これはエラー回避のためです。モデルデータのロードがどうも要時間のようでロード直後にスケール等をセットしようとすると未ロードのところに変数を書き込もうとしてしまうことを防止しています。

 

またロード関数 loadGltf() ですが,CHARA3Dクラスに持たせずscript.js内の関数として定義しています。

function loadGltf(num,filename){
    chara[num].loading=true;
    TweenMax.to(‘.loader’,0.1,{opacity:1});
    let gltfLoader = new GLTFLoader();
    gltfLoader.load(filename,function(gltf){
        chara[num].model = gltf.scene;//←CHARA3Dクラスでやろうとするとここでコケる
        chara[num].animations = gltf.animations;

        for(let i = 0; i < chara[num].model.children.length; i++){
            let mesh = chara[num].model.children[i];

            for(let j = 0; j < mesh.children.length; j++){
                if(j == 0){
                    let mesh_child = mesh.children[j];
                    mesh_child.castShadow = true;
                }
                if(mesh.children[j].material){//カリング
                    mesh.children[j].material.side = THREE.FrontSide;
                }
            }
        }
        if(chara[num].animations && chara[num].animations.length) {
            chara[num].animMixer = new THREE.AnimationMixer(chara[num].model);

            for (let i = 0; i < chara[num].animations.length; i ++) {
                let animation = chara[num].animations[i];
                let action = chara[num].animMixer.clipAction(animation) ;
                action.clampWhenFinished = true;
                action.play();
            }
        }
        scene.add(chara[num].model);
    });
}

これもエラー対策です。文中にあるgltf.sceneが,どうも別の変数にいったん置き換えてしまうとうまく動作せず,苦肉の策としてこのようにしています。どなたか改善方法がわかりましたらご教示くださいませ・・・。

 

アニメーションの更新は250~254行目で行なっています。

    for(let i=0;i<modelMax;i++){
        if(chara[i].animMixer){
            chara[i].animMixer.update(frameTime);//0.01
        }
    }

キャラクターぶん実行要なので,for文で実施します。

 

キャラクター複数描画のしくみ

このように,CHARA3Dクラスにモデルデータ(ポリゴンやテクスチャ)・アニメーション情報をまとめ,そのCHARAクラスのインスタンスcharaを配列として宣言することで・・・

chara[0]:キャラクター①

chara[1]:キャラクター②

chara[2]:キャラクター③

・・・とキャラクター情報を複数用意し,個別に制御できるようにしました。

 

まとめ

Three.jsでキャラクターを複数描画するサンプルと,使用方法をご紹介させていただきました。

(1)CHARA3Dクラスにモデル(ポリゴンやテクスチャ)とアニメーション情報を格納します。

(2)CHARA3Dクラスのインスタンスcharaを配列で複数作成します。

(3)chara[0~256]に情報をセットし,それぞれを個別にコントロールできます。

 

キャラクターのロード文についてはscript.jsで定義していますが,CHARA3Dクラス内に入れることができれば,もう少しスマートな処理にできると思います。

 

お疲れさまでした。次回も何か機能追加して,ご紹介させていただきたく存じます。

サンプルプログラムの参考にさせていただいたサイト

・株式会社スタイルリンク 様(http://www.hp-stylelink.com/news/2013/11/20131126.php
 

Nenga

コメント

タイトルとURLをコピーしました