5

私は小さな JavaScript ゲームを構築していますが、オンラインでチュートリアルやその他のものを見た後、うまくいきません。トラブルを避けるために、ここに問題が発生した可能性があると思われる部分を示します (実際の問題については、以下でもう少し詳しく説明します)。

今のところ非常に基本的なループで実行され、プレイヤーが撃ったボルトを保持するための配列があります。

var playerBolts=new Array(); //Holds all the bolt objects that the player shoots  

setInterval(function(){
    updateGame(); 
    drawGame();
},25);

これは、プレイヤーが撃ったときに作成されるボルト オブジェクトです。

function bolt(facing,playerX,playerY){ //The bolt object is shot from the player's current position
    this.facingLeft=facing; //The direction at which the bolt moves, if left, true
    this.x=playerX; //The x position of the bolt
    this.y=playerY; //The y position of the bolt
    if(facingLeft==true){ 
        this.xSpeed=-3; //The horizontal speed at which the bolt is moving
    }
    else if (facingLeft==false){
        this.xSpeed=3;  
    }
    this.ySpeed=0; //The vertical speed at which the bolt is moving
    this.W=3; //The width of the bolt's model
    this.H=3; //The height of the bolt's model
    this.color="red"; //The color of the bolt's model
    this.update=update; 
    function update(){ //Updates the bolt's properties
        this.x=this.x+this.xSpeed;
        this.y=this.y+this.ySpeed;
    }       
    this.draw=draw;
    function draw(){ //Draws the bolt's model to the canvas
        context.fillStyle=this.color;
        context.fillRect(this.x, this.y, this.W, this.H);
    }
}

「プレーヤー」がシュートすると、プレーヤー オブジェクトの shotBolt メソッドが呼び出されます。

function player(){ //The player object
    this.facingLeft=true; //If the player's character is facing left, true
    this.x=100; //The x position of the player
    this.y=100; //The y position of the player
    this.shootBolt=shootBolt;
    function shootBolt(){ //Shoots a bolt, creating a new bolt object and adding it to the playerBolts array       
      playerBolts.push(bolt(this.facingLeft,this.x,this.y));
    }
}

問題は、次のボルトが次のショットごとに速くなることです。発砲すればするほど、彼らは速くなります。また、連射すると複数のボルトが見えるはずですが、撃つたびに前のボルトが消えてしまいます。

これで、ゲームは update 関数と draw 関数をループします。を使用しました

function updateGame(){ //The main update phase
    player1.update(); //Updates the player's properties
    playerBolts.forEach(function(bolt){ //Updates all active bolts's properties
        this.update();
    });
}
function drawGame(){ //The main drawing phase
    context.fillStyle="white"; 
    context.fillRect(0,0,canvasW,canvasH); //Clears the canvas for the next frame
    player1.draw(); //Draws the player
    playerBolts.forEach(function(bolt){ //Draws all bolt's model to the canvas
        this.draw();
    });     
}

そうそう...「プッシュ」を使用してオブジェクトを配列に追加する方法、「forEach」メソッドに関係があると思います(ただし、forループも試しました)。何が間違っているのかわからず、ソースを調べましたが、これはうまくいくはずですか? 十分な情報がない場合は、いつでもすべてを投稿できます (十分に文書化された 119 行のみ)。

ありがとうございました。

4

3 に答える 3

4

に問題があると思われますthisbolt以下を呼び出してオブジェクトを構築しています。

bolt(this.facingLeft, this.x, this.y)

ただし、bolt関数内ではthis、新しく作成されたボルトを参照しているかのように使用しています。残念ながら、そうではありません。代わりに、次のようなボルトを作成してみてください。

new bolt(this.facingLeft, this.x, this.y)

そのようにすると、thisinside ofboltは新しく作成されたオブジェクトを参照します。

さらに、これthisも間違っている可能性があります。

playerBolts.forEach(function(bolt){ //Draws all bolt's model to the canvas
    this.draw();
});

奇妙な理由により、thisループ関数内にボルトがある場合とない場合があります ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEachを参照)。安全のために、代わりにこれを試してください:

playerBolts.forEach(function(bolt){ //Draws all bolt's model to the canvas
    bolt.draw();
});

ところで、このnew問題は非常に一般的です。コンストラクター関数を作成して、 の有無にかかわらず動作するようにすることを習慣にしていますnew。これを行うには、 を使用する代わりに、 を操作する代わりに新しいオブジェクトを返すthisだけです。JSはひどく紛らわしいので、これははるかに優れたアプローチだと思います。boltthisthis

function bolt(facing,playerX,playerY){ //The bolt object is shot from the player's current position
    var theBolt = {
        facingLeft: facing,           //The direction at which the bolt moves, if left, true,
        x: playerX,                   //The x position of the bolt
        y: playerY,                   //The y position of the bolt
        xSpeed: facingLeft ? -3 : 3,  //The horizontal speed at which the bolt is moving
        ySpeed: 0,                    //The vertical speed at which the bolt is moving
        W: 3,                         //The width of the bolt's model
        H: 3,                         //The height of the bolt's model
        color: 'red',                 //The color of the bolt's model
        update: update,
        draw: draw
    };
    function update(){ //Updates the bolt's properties
        theBolt.x = theBolt.x + theBolt.xSpeed;
        theBolt.y = theBolt.y + theBolt.ySpeed;
    }       
    function draw(){ //Draws the bolt's model to the canvas
        context.fillStyle = theBolt.color;
        context.fillRect(theBolt.x, theBolt.y, theBolt.W, theBolt.H);
    }

    return theBolt;
}
于 2013-06-13T00:43:30.903 に答える
1

問題はfunction bolt(facing,playerX,playerY){、 new を作成しないことboltです。以前と同じ場所に変数を設定するだけです。

function bolt(facing,playerX,playerY){ //The bolt object is shot from the player's current position
    this.facingLeft=facing; //The direction at which the bolt moves, if left, true
    ...

-新しいオブジェクトを呼び出さないboltため、毎回同じ場所から呼び出すため、設定したすべての変数は何this度も何度もオーバーライドされ続けます。

于 2013-06-13T00:42:35.730 に答える
0

他の人が言ったように、あなたの問題は、毎回新しいボルトを作成するのではなく、単にボルト関数を呼び出すことです。したがって、関数の「this」はグローバル オブジェクトを参照するため、複数回更新されるボルトは 1 つだけになります。

また、次のとおりです。

> if(facingLeft==true){ 
>     this.xSpeed=-3; //The horizontal speed at which the bolt is moving
> }
> else if (facingLeft==false){
>     this.xSpeed=3;  
> }

?: 条件演算子(別名三項演算子)を使用して置き換えることができます。

this.xSpeed = facingLeft? -3 : 3;

そして、あなたが持っている場所:

> this.update=update; 
> function update(){ //Updates the bolt's properties
>     this.x=this.x+this.xSpeed;
>     this.y=this.y+this.ySpeed;
> }

関数式を使用して、関数を直接割り当てることができます。

// Update the bolt's properties
this.update = function () {
    this.x = this.x + this.xSpeed;
    this.y = this.y + this.ySpeed;
}

さらに良いことに、関数をコンストラクターのプロトタイプに配置して、すべてのインスタンスが同じ関数を継承するようにします。

bolt.prototype.update = function () {
    ...
}

描画方法も同様です。また、コードにもう少し空白を入れると、コードが読みやすくなります。:-)

于 2013-06-13T00:53:36.173 に答える