2016-08-26 9 views
0

にレンダリング台無しそのsleepもの:。再帰呼び出しは、私は次のコードを持っている(無視ゲーム

function game_loop(snake){ 
    sleep(200); 

    background(200); 
    draw_borders(); 

    const r = snake_draw(snake_move(snake.x, snake.y)); 
    game_loop(r); 
} 

function setup() { 
    createCanvas(w, h); 
    frameRate(10); 
    noLoop(); 
} 

function draw() { 
    game_loop({x: snake_initial_x, y: snake_initial_y}); 
} 

function sleep(delay) { 
    var start = new Date().getTime(); 
    while (new Date().getTime() < start + delay); 
} 

function snake_move(x, y){ 
    const x_speed = 1; 
    const y_speed = 0; 

    return {x: x + x_speed, y: y + y_speed }; 
} 

function snake_draw(position){ 
    const snake_color = 255 ; 

    fill(snake_color); 
    rect(position.x * sqr_size, position.y * sqr_size, sqr_size, sqr_size); 

    return position; 
}; 

const border_color = 81; 

function draw_borders(){ 
    draw_row_borders(0); 
    draw_column_borders(1); 
} 

function draw_row_borders(x){ 
    if(x >= 0 && x < cols) { 
     fill(border_color); 
     rect(x * sqr_size, 0, sqr_size, sqr_size); 
     fill(border_color); 
     rect(x * sqr_size, (rows - 1) * sqr_size, sqr_size, sqr_size); 

     draw_row_borders(x + 1, 0); 
    } 
} 

function draw_column_borders(y){ 
    if(y >= 1 && y < rows - 1) { 
     fill(border_color); 
     rect(0, y * sqr_size, sqr_size, sqr_size); 
     fill(border_color); 
     rect((cols - 1) * sqr_size, y * sqr_size, sqr_size, sqr_size); 

     draw_column_borders(y + 1); 
    } 
} 

コードの最後の部分が必要ですが、私は念のためにそれらを追加していない

私の問題は、私はgame_loop(r)またはgame_loop(snake_draw(snake_move(snake.x, snake.y)))呼び出すとき、ゲームはすべてのレンダリングを停止していることですが、私はgame_loopconsole.log()を置けば、私はそれが(すなわち、関数を呼び出すsnake.x, snake.yを更新)働いていることがわかります。

なぜこの再帰呼び出しがすべてを混乱させるのですか?

私はp5jsフレームワークを使っています。

+0

通常、JavaScriptコードはイベントベース(すなわち、タイマーイベント)であり、ビジーウェイトを使用していません...あなたが使用しているフレームワークに、タイマー付きのゲームループを書く例があります。 –

+0

フレームワークは ' ** 'noLoop()'が呼び出されていない限り(私が呼び出した)、draw()は1秒間に60回、**描画されます。私が書いた 'game_loop()'はそれとは関係ありません! – csTroubled

+0

'game_loop()'(無限再帰)があなたのコードと何の関係もないのであれば、それをなぜ投稿に含めましたか? (また 'game_loop'があなたの' draw'から呼び出されています - それがどうしても関係ないことはわかりません) –

答えて

1

Javascriptとブラウザの描画メカニズムは、1つのスレッドで緊密に結合されています。 JavaScriptのループが長すぎると、描画プロセスがブロックされ、基本的にブラウザがハングアップします。

ほとんどのゲームフレームワークでは、「フレーム」あたり1回呼び出される何らかの種類の関数があります(update())。これは、特定のミリ秒後に関数を呼び出すsetInterval()またはrequestAnimationFrame()を使用するなど、さまざまな方法で行うことができます。

function update() { 
 
    console.log('updated'); 
 
} 
 

 
// call update function every 100 milliseconds 
 
setInterval(update, 100);

あなたはもう少し機能的なアプローチが必要な場合は、再帰的に代わりsetTimeout()を呼び出すことができます。

function update() { 
 
    console.log('updated'); 
 
    // perform game logic here 
 
    setTimeout(update, 500); // call update again in 500 milliseconds 
 
}

+0

'game_loop()'の再帰呼び出しの前に 'snake_draw()'が呼ばれているのですが、なぜなら 'game_loop()'は描画が完了した後ではなく、なぜですか?また、これは 'setInterval()'のようなものを使っている可能性が高いと私は理解していますが、私は関数型プログラミングでゲームを作ろうとしています。 – csTroubled

+0

無限再帰は「関数型プログラミング」ではありません... –

+0

これは、game_loopを書くための機能的な方法ですね。どのように私は、変更可能な状態なしで、ゲームのパラメータを更新するだろうか? – csTroubled

1

"機能的なスタイル" を取得するには - 次の反復のためのキャプチャパラメータをしてsetIntervalでそれをスケジュール:60回あたり、

function game_loop(r) { 
    // draw r 
    r = nextStep(r); // compute next immutable state 

    var next_iteration = function(){ 
     game_loop(r); // capture state 
    } 
    setInterval(next_iteration, 10); 
} 
0

処理は自動的にdraw()関数を呼び出します秒。 draw()関数の呼び出しはフレームであり、これがゲームロジックを配置する場所です。

あなた自身のゲームループを作成しようとしているようですが、これは不要で、処理が自動的にあなたのために自動的に実行されます。

draw()機能は、何かが実際に画面に描画される前に終了する必要があります。

draw()機能が終了しないので、画面に何も描画されません。プログラムの初めに、game_loop()関数を呼び出しています。しかし、game_loop()関数から、game_loop()関数を呼び出すと、game_loop()関数が呼び出されます。これは無限に続くので、最初のフレームを通過することはありません!

さらに一般的には、recursionと呼ばれ、ベースケース(再帰が永遠に続くことを止めるもの)がありません。実際には永遠に進まないでしょう。なぜなら、最終的にはスタックのオーバーフローが起こるからです。エラーです。このウェブサイトではありません!

問題を解決するには、再帰が永遠に続かないようにする基本ケースを追加するか、それを取り除くだけです。処理はすでにdraw()関数を1秒間に60回呼び出します。そのため、これを描画ループに使用します。

編集:もう少し見ると、個々のセクションを描画して次のセクションに戻って再帰を使用して蛇を描こうとしているのでしょうか?その場合は、ベースケースが必要です。見ているセクションをインクリメントして、セクションがまだスネークにあることを確認してください。

編集2:(それは処理の内部メカニズムに問題が発生した場合、私は驚かないだろうが)答えはsetInterval()かもしれない仕事を呼び出すことを言って、本当にそれを行うにはポイントがありません。処理はすでにあなたのためにゲームループを設定しています。ただそれを使用してください。

+0

OPは自動的に呼び出される 'draw'のデフォルト動作について明確に知っています([comment to Q](http://stackoverflow.com/questions/39157713/recursive-call-messes-up-rendering-in-game/39158047#comment65659002_39157713))しかし、不変のデータを持つ機能的なスタイルを探しています([他の答えに関するコメント](http://stackoverflow.com/questions/39157713/recursive-call-messes-up-rendering-in-game/39158047#39158047)) –

+0

@ AlexeiLevenkov良い点。私は私の答えを編集しました。ヘッドアップをありがとう。 –

関連する問題