CocosCreatorでシューティングゲームを作る詳しい解説

CocosCreatorでシューティングゲームを作る詳しい解説

シーン設定

ゲームリソース

砲塔の回転

メカニズムは前のハンドル インスタンスの車と同じで、touchmove を使用してタッチ イベントをリッスンします。

  1. タッチ位置を取得
  2. signAngle メソッドを使用して、位置と cc.v2(1,0) 位置の角度差を調べます (負の符号を追加することを忘れないでください。反時計回りの比較は負で、反時計回りの角度の値は正です)。
  3. 求めた角度が最終的な角度です。

 オンロード(){
        //90 度に初期化します this.node.angle=90;
        this.node.on('touchstart',this.onTouchStart,this);
        this.node.on('touchmove',this.onTouchMove,this);
        this.node.on('touchend',this.onTouchEnd,this);
        this.node.on('touchconcel',this.onTouchConcel,this);
    }
   
    onTouchStart(e:cc.Event.EventTouch){
        //開始位置を取得します this.starPos=this.node.parent.convertToNodeSpace(e.getLocation());
        //銃口の初期角度を取得します。this.starAngle=this.node.angle;

    }
    onTouchEnd(e:cc.Event.EventTouch){

    }
    onTouchMove(e:cc.Event.EventTouch){
        //タッチポイントの現在の位置を取得します。let pos:cc.Vec2=this.node.parent.convertToNodeSpace(e.getLocation());

        //角度を取得します //角度は時計回りに負、反時計回りに正です let sweep_radian=pos.signAngle(this.starPos); //starPose p に対する pos の角度は、s に対する時計回りに正です let sweep_angle=sweep_radian*180/Math.PI; //角度をラジアンに変換します //砲塔が最終角度を指すようにします let angle=this.starAngle-sweep_angle;
      
        //角度を 45 〜 135 の間に制限します。if (angle<45) angle=45;
        角度>135の場合、角度=135;

        cc.log("銃口スイング: "+sweep_angle+"最終角度位置: "+angle);
        this.node.angle=角度;
    }

動的に生成された弾丸

  1. ノードcc.Nodeを生成し、コンポーネントaddComponent(cc.Sprite)を追加します。
  2. コンポーネントのプロパティと画像のspriteFrameに値を割り当てる
  3. コンポーネントを親ノードの下にマウントする
  4. 位置、角度などを設定します。
  5. 動きを制御するには、新しく作成したスクリプトをインポートし、動的に生成されたノードのコンポーネントに追加します。
 onTouchEnd(e:cc.Event.EventTouch){
        これを起動します。
    }
    タッチキャンセル(e:cc.Event.EventTouch){

    }

    火(){

        if(this.bulleteicon==null) を返します。
        bullet:cc.Node=new cc.Node(); とします。
        sprite:cc.Sprite=bullet.addComponent(cc.Sprite); とします。
        sprite.spriteFrame=this.bulleteicon;
        

        // 射撃システムノードにマウント bullet.parent=this.node.parent;

        //親ノードの相対位置を設定します。let ration=this.node.angle*Math.PI/180;
        direction=cc.v2(Math.cos(ration),Math.sin(ration)) とします。
        ノードの角度を指定します。
        r=100とします。
        bullet.setPosition(cc.v3(r*direction.x,r*direction.y,0));
       
        //追加のスクリプト コンポーネント let script=bullet.addComponent(Buletet);
         script.explodeImg=this.explodeImg;
         script.direction=方向;

    }
 始める () {
         this.schedule(this.onTimer,0.01);
    }

    オンタイマー(){
        y>300の場合
            this.unschedule(this.onTimer);
            これを爆発させる();
           
            戻る;
        }
        dx = this.direction.x * 5 とします。
        dy=this.direction.y*5 とします。
        y は dy を表します。
        this.node.x+=dx;
    }

    爆発()

        sp:cc.Sprite=this.getComponent(cc.Sprite); とします。
        sp.spriteFrame=this.explodeImg;
      
        //弾丸を縮小します this.node.scale=0.1;
        //爆発アニメーション効果イージングシステム let self=this;
        cc.tween(このノード)
            .to(0.5,{スケール:1,不透明度:0})
            .call(関数(){
                自己.afterExplode();
            })
            。始める();

            
    }

    afterExplode(){
        このノードを破棄します。
    }

このバグ:

  1. インポートされたクラス名はファイル名と異なります。ファイル名を変更してもコード内のクラス名は自動的に変更されないので、2回変更する必要があることに注意してください。
  2. setposition() メソッドを使用する場合、パラメータは cc.v3 のコンストラクタ内に記述されます。パラメータの位置に注意してください。

衝突計算

弾丸とターゲットの相対位置を計算し、射程距離以内であればターゲットに当たったと判断してヒット動作を行い、そうでない場合はターゲットに当たっていないと判断して不ヒット動作を行います。

スクリプトはターゲットノードを渡し、ターゲット属性を追加する必要がある。

   @property(cc.SpriteFrame)
    爆発画像: cc.SpriteFrame = null;
    
    方向: cc.Vec2 = null;

    ターゲット: cc.Node = null;
    オンロード() {

    }

    始める() {
        this.schedule(this.onTimer, 0.01);
    }

    オンタイマー() {
        (this.node.y > 350)の場合{
            if (this.isHit()) {
                //爆発効果を再生します this.explode();
                console.log("ターゲットをヒット");
            }
            それ以外 {
                console.log("ターゲット外");
                this.disMiss();
            }
            this.unschedule(this.onTimer);
            戻る;
        }
        dx = this.direction.x * 5 とします。
        dy = this.direction.y * 5 とします。
        this.node.y += dy;
        this.node.x += dx;
    }

    //ヒットしたかどうかを判定する isHit(): boolean {
        targetPos: cc.Vec2 = this.geWorldLocation(this.target); とします。
        selfPos: cc.Vec2 = this.geWorldLocation(this.node); とします。
        距離を Math.abs(targetPos.x - selfPos.x) とします。
        console.log("ターゲット x=" + targetPos.x + " 、箇条書き x=" + selfPos.x);

        (距離<50)の場合{
            true を返します。

        }
        それ以外 {
            false を返します。
        }

    }
    爆発() {

        sp: cc.Sprite = this.getComponent(cc.Sprite); とします。
        spriteFrame を this.explodeImg に追加します。

        //弾丸を縮小します this.node.scale = 0.1;
        // 爆発アニメーション効果イージングシステム let self = this;
        cc.tween(このノード)
            .to(0.5, { スケール: 1, 不透明度: 0 })
            .call(関数() {
                自己.disMiss();
            })
            。始める();


    }

    geWorldLocation(ノード: cc.Node): cc.Vec2 {
        pos = node.getPosition() とします。
        //これは node.parent であることに注意してください。メソッドの呼び出し元は、現在のノードの座標系である必要があります。 return node.parent.convertToWorldSpaceAR(pos);

    }

    却下する() {
        このノードを破棄します。
    }

このバグ:

ワールド座標を取得する際には、親ノードの座標系は呼び出されず、現在のノードの座標系が使用されるため、返される値は現在の座標系自体の値のままとなります。ワールド座標を変換するためのメソッド呼び出し元は、現在のノード (通常はその親ノード) の座標系であることに注意してください。 node.parent.convertToWorldSpaceAR(pos); を返します(アンカーポイントを原点として)

効果を高める

ターゲット ノードの下にスクリプトを追加して、動きを制御し、左右に移動し、弾が当たったときにテキスト プロンプト効果を追加します。

テキストのヒント:

 応援(){
        //ノードを作成してマウントします。let node: cc.Node = new cc.Node();
        node.parent = this.node.parent; // 両方とも同じレベルにあり、同じ親オブジェクトを持ちます let label: cc.Label = node.addComponent(cc.Label);
        label.string = "+10 ポイント";

        //位置、透明度などを設定します。node.setPosition(cc.v3(0, 250, 0));
        ノードの不透明度 = 200;
        ノードの色を新しいcc.Color(255, 0, 0);

        //アニメーション cc.tween(node)
            .to(0.5, {スケール: 1.5 })
            .to(0.2, { 不透明度: 0 })
            .call(関数() {
                ノードを破棄します。
            })
            。始める();

    }

ターゲットの動き

 更新 (dt) {
         速度を3とします。
         if(this.isLeft){
             速度=-速度;
         }
         this.node.x+=速度;
         if(this.isLeft&&this.node.x<-350){
             this.isLeft = false;
         }
         if(!this.isLeft&&this.node.x>350){
            this.isLeft が true である。
        }
    }

弾薬庫の表示を追加

  1. 弾丸画像を一括生成するための弾薬庫ノードを追加しました (位置はウィジェット コンポーネントを使用して設定できます)
  2. 箇条書きを減らすメソッドを追加し、箇条書き画像のアクティブ プロパティを設定することで箇条書きを減らします。
  3. 砲塔の射撃メソッドで弾丸を減らすメソッドを呼び出す

呼び出し方法は 2 つあります。1 つは砲塔スクリプト内で弾薬庫ノードを取得して呼び出す方法です。もう 1 つは、パブリック クラス (静的変数) を設定し、onLoad() メソッド内でノードを初期化して直接呼び出す方法です。後者を使用してください。

 @property(cc.SpriteFrame)
    箇条書きアイコン: cc.SpriteFrame = null;
    容量: 数 = 10;
    在庫数: 数値 = 10;


    オンロード() {

        スペース: number = this.node.width / this.capacity;
        (i = 0 とします; i < this.capacity; i++) {
            //画像を生成します。let bulleteNode: cc.Node = new cc.Node();
            bulleteSprite を追加します: cc.Sprite = bulleteNode.addComponent(cc.Sprite);
            bulletSprite.spriteFrame = this.bulleteIcon;
            このノードに子を追加します(bulleteNode)。

            //位置を設定する bulleteNode.x += space * i + 10;
            箇条書きノード.y = 0;

        }

    }

    始める() {

    }

    消費(数値: 数値) {
        this.stockNumber -= num;
        (this.stockNumber < 0)の場合{
            this.stockNumber = 0;
        }
        これを表示します。
    }

    画面() {
        ノードを作成します: cc.Node[] = this.node.children;
        console.log(ノードの長さ);
        for(let i=0;i<nodes.length;i++){
            if(i>=this.stockNumber){
                ノード[i].active=false;
            }
           
        }
    }

共通パブリッククラス

  //静的クラス、グローバル変数、共通クラス内のすべての共通変数とクラスを定義します static ammo:Ammo=null;

    オンロード() {
        Common.ammo=cc.find('Canvas/Ammunition').getComponent('Ammo');
        console.log(Common.ammo);
    }

バグは次のとおりです:

cc.find() メソッドでは、除算にスラッシュを使用することを忘れないでください。

弾切れプロンプトスコア

  1. マスクレイヤーを作成し、スクリプトクラスをCommonクラスにインポートし、activeプロパティをfalseに設定します。
  2. ResultDialog スクリプトに show メソッドを追加し、その active プロパティを true に設定して、スコアを画面に表示します。
  3. Bullete(弾の動きを制御するスクリプト)で、弾の数が <= 0 かどうかを判定し、Common の show メソッドを呼び出してスコアプロンプトボックスを表示します。

ResultDialog スクリプト (スコア プロンプト ボックスを制御)

 オンロード(){
         let replay:cc.Node=cc.find('Canvas/プロンプトボックスの終了/別のゲームをプレイ');
         console.log(リプレイ);
         replay.on('touchstart',this.dismiss,this);

         this.node.on('touchstart',this.onTouchdisable,this);
         this.node.on('touchmove',this.onTouchdisable,this);
         this.node.on('touchend',this.onTouchdisable,this);
   
     }

     //プロンプトボックスを表示 show(){
        アクティブノードを true に設定します。  
        scoreNode を設定します: cc.Node = cc.find('score box/score', this.node);
        scoreLabel を作成します: cc.Label = scoreNode.getComponent(cc.Label);   
        scoreLabel.string = Common.score + 'ポイント';   
       
        
     }

     //プロンプトボックスを非表示にする ignore(){
         this.node.active=false;
     }

     //マスクが表示されているときにシールドの onTouchdisable を有効にする (e: cc.Event.EventTouch) {
         e.stopPropagation();
     }
    始める () {

    }

一般的なスクリプト

 //静的クラス、グローバル変数、共通クラス内のすべての共通変数とクラスを定義します static ammo:Ammo=null;
    静的スコア:数値 = 0;
    静的結果ダイアログ: ResultDialog = null;
  

    オンロード() {
        Common.resultdialog=cc.find('Canvas/End prompt box').getComponent('ResultDialog');
        Common.ammo=cc.find('Canvas/Ammunition').getComponent('Ammo');
    }

Bullete方式でスコアを上げる

  if (this.isHit()) {
                //爆発効果を再生します this.explode();
                //+10 ポイントを表示します this.cheer();
                //合計スコア +10
                共通スコア += 10;
                console.log("ターゲットをヒット");
            }

ゲーム再開

このゲームは比較的単純です。再開するには、弾薬庫ノードをリセットするだけです。そのため、リセット メソッドは Ammo スクリプトに配置されます。パブリック クラスに Ammo オブジェクトを作成し、静的メソッドを設定して、スコアをリセットし、Ammo のリセット メソッドを呼び出します。

弾薬庫スクリプトを追加しました

 リセット(){
        this.stockNumber=this.capacity;
        これを表示します。
    }

共通スクリプトを変更する

 //静的クラス、グローバル変数、共通クラス内のすべての共通変数とクラスを定義します static ammo:Ammo=null;
    静的スコア:数値 = 0;
    静的結果ダイアログ: ResultDialog = null;
  

    オンロード() {
        Common.resultdialog=cc.find('Canvas/End prompt box').getComponent('ResultDialog');
        Common.ammo=cc.find('Canvas/Ammunition').getComponent('Ammo');
        console.log(Common.ammo);
    }
    静的リセットゲーム() {
        共通スコア=0;
        Common.ammo.reset();
    }

詳細を追加する

ゲームサウンドの追加と砲塔の起動の変更

1. 砲塔スクリプトにプロパティを追加

 //サウンド効果 @property(cc.AudioClip)
    audioFire: cc.AudioClip = null;
    @property(cc.AudioClip)
    audioExplode: cc.AudioClip = null;

    //砲塔画像 @property(cc.SpriteFrame)
    アイコンノーマル: cc.SpriteFrame = null;
    @property(cc.SpriteFrame)
    アイコンアクティブ: cc.SpriteFrame = null;

画像スイッチ

 onTouchStart(e: cc.Event.EventTouch) {メソッドの最後に追加 //砲塔の画像をアクティブに切り替えます this.node.getComponent(cc.Sprite).spriteFrame = this.iconActive;
 onTouchEnd(e: cc.Event.EventTouch) {メソッドが最後に追加されました //画像の復元 this.node.getComponent(cc.Sprite).spriteFrame = this.iconNormal;
      }

効果音再生

fire(){ メソッドの後に追加します // 弾丸の爆発音を弾丸スクリプトに送信します script.audioExplode = this.audioExplode;
 if (this.audioFire != null) {
            cc.audioEngine.play(this.audioFire, false, 1);
        }
    }

オーディオを再生する方法: ==cc.audioEngine.play(this.audioFire, false, 1); ==2番目のパラメータはループ再生するかどうか、3番目のパラメータは音量です

箇条書きスクリプト

//属性を追加 @property(cc.SpriteFrame)
爆発画像: cc.SpriteFrame = null;
if(this.audioExplode!=null){ を追加します。
	cc.audioEngine.play(this.audioExplode,false,1);
}

以上がCocosCreatorでシューティングゲームを作る方法の詳しい説明です。CocosCreatorシューティングゲームの詳細については、123WORDPRESS.COMの他の関連記事に注目してください!

以下もご興味があるかもしれません:
  • Unity は物理エンジンを使用してマルチロータードローンの飛行をシミュレートします
  • Android 向け 2D 物理エンジン Box2d を使用する簡単な例
  • CocosCreator ソースコードの解釈: エンジンの起動とメインループ
  • CocosCreator 一般的なフレームワーク設計リソース管理
  • CocosCreatorでリストを作成する方法
  • CocosCreator の新しいリソース管理システムの分析
  • CocosCreator スケルトンアニメーション ドラゴンボーン
  • CocosCreatorでクールなレーダーチャートを描く方法
  • CocosCreator MVCアーキテクチャの詳細な説明
  • CocosCreator で物理エンジン ジョイントを使用する方法

<<:  Linux での grep コマンドの使い方の詳細な説明

>>:  MySQL 高可用性ソリューション MMM (MySQL マルチマスター レプリケーション マネージャー)

推薦する

ディレクトリスクロール効果を実現するネイティブJS

これはネイティブ JS で実装されたテキスト スクロール効果です。この効果は通常、ニュース、ダイナミ...

Dockerでボリュームを管理する2つの方法

前回の記事では、Dockerの基礎知識であるローカルディレクトリのマウント方法を紹介しました。今日は...

nginx 用の zabbix 5.0 をインストールして展開する方法

目次実験環境インストールと展開データベースをインストールして設定します (ここでは mariadb ...

MySQL インデックス プッシュダウンを 5 分で学ぶ

目次序文インデックス プッシュダウンとは何ですか?インデックスプッシュダウン最適化の原理インデックス...

MySQLデッドロック問題の詳細な分析

序文私たちのビジネスがまだ初期段階にあり、同時実行の度合いが比較的低い場合、数年間はデッドロックの問...

Element PlusはAffixを実装します

目次1. コンポーネントの紹介2. ソースコード分析2.1 テンプレート2.2 スクリプト2.3 実...

JavaScriptプロトタイプチェーンの詳細な説明

目次1. コンストラクタとインスタンス2. プロパティプロトタイプ3. プロパティ __proto_...

MySQLのインデックス

序文早速本題に入りましょう。これからお話しするのは次のマインドマップです。まずは印象をつかんでくださ...

虫眼鏡効果を実現するJavaScript

この記事では、虫眼鏡効果を実現するためのJavaScriptの具体的なコードを参考までに紹介します。...

HTML におけるブロックコメントの使用に関する詳細な紹介

HTML の一般的なコメント: <!--XXXXXXXX--> (XXXXXXXX はコ...

ウェブページの色特性の分類

色特性の分類あらゆる色は、赤、緑、青の三原色から構成されます。三原色の中で暖色なのは赤だけなので、作...

nginx 503 サービスが一時的に利用できない問題を解決する方法

最近、ウェブサイトを更新すると、503 Service Temporarily Unavailabl...

jsでシンプルなパズルゲームを実現する

この記事では、簡単なパズルゲームを実装するためのjsの具体的なコードを参考までに共有します。具体的な...

グループ化されたクエリでのGROUP BYの使用とSQL実行順序の説明

SQL では、GROUP BY は SELECT の結果のデータをグループ化するために使用されます。...

MySQL 8.0.23 のインストールと設定方法のグラフィックチュートリアル (Win10 の場合)

この記事では、MySQL 8.0.23のインストールと設定方法を参考までに紹介します。具体的な内容は...