3

そのため、JPanel でスネークを全面的に移動する際に問題が発生しています。これは JPanel の問題でも障害でもありません。Snake を本来のように動かすことができません。問題の場所はわかっていますが、問題なく正しく動作させる方法がわかりません。

問題: スネークは互いに約 10 ピクセル離れているはずですが、互いに約 1 ピクセル離れて凝集しています。

これが本来の姿です。

これが本来の姿です。

まとまるとこんな感じ

まとまるとこんな感じ

私は考えられるいくつかの異なる方法を試し、何日もかけて取り組んできました。

Snake は 1px の速度で動き続けるはずなので、滑らかなアニメーションです。とにかく動かされているので、頭は影響を受ける必要はありません。しかし、ループが頭に追いつくと、頭の位置が検出され、体に位置が与えられます。

スネークの移動。

int playerVel = 1;

 public void MovePlayer(){
    //Move the snake tail
    if(IsMoving()){
        //Move the head by its velocity
        if(left){
            X[0] -= playerVel;
        }
        else if(right){
            X[0] += playerVel;
        }
        else if(up){
            Y[0] -= playerVel;
        }
        else if(down){
            Y[0] += playerVel;
        }

        for(int i = getSizeWithArmor(); i > 0; i--){
            //Issue is when the for loop finishes counting down it located the Head's position that is 1 px away, and the rest of the body clumps up to it.
            int newLocX = X[i] - X[i-1];
            int newLocY = Y[i] - Y[i-1];

            if(newLocX != 0){
                if(newLocX == 10 || newLocX == -10){
                    X[i] = X[i-1];
                }
                else if(newLocX > 0){
                    X[i] = X[i-1] + 10;
                }
                else if(newLocX < 0){
                    X[i] = X[i-1] - 10;
                }
                else{
                    X[i] = X[i-1];
                }
            }

            if(newLocY != 0){
                if(newLocY == 10 || newLocY == -10){
                    Y[i] = Y[i-1];
                }
                else if(newLocY > 0){
                    Y[i] = Y[i-1] + 10;
                }
                else if(newLocY < 0){
                    Y[i] = Y[i-1] - 10;
                }
                else{
                    Y[i] = Y[i-1];
                }
            }
        }
    }
}

編集1:

どんな助けでも大歓迎です!詳細を追加する必要がある場合は、お気軽にお知らせください。

編集2:

    Move    X[0]    X[1]    X[2]    X[3]    X[4]    X[5]
    -----------------------------------------------------

    1       60      50      40      30      20      10
    2       61      51      41      31      21      11  
    3       62      52      42      32      22      12 
    4       63      53      43      33      23      13 
    5       64      54      44      34      24      14 
    6       65      55      45      35      25      15 
    7       66      56      46      36      26      16 
    8       67      57      47      37      27      17

私がやろうとしていることです。しかし、ヘビが長くなるにつれて、適応しなければなりません。

編集3:

これが Player のクラス全体です。プレーヤー クラスは、すべての移動と自己調整を処理します。

クラスプレーヤー:

public class Player implements Runnable{
//Info about the Player
private int[] X;
private int[] Y;
private int[] size;
private int blockPickup;
private int points;
private int armor;
private int blockSize = 10;

//Speeds
private int playerVel = 1;
private int speedDelay = 100;

//Direction the player is moving
private boolean up = false;
private boolean down = false;
private boolean right = false;
private boolean left = false;
private boolean inGame = false;
private boolean gamePaused = false;

private int boardWidth;
private int boardHeight;
private int allSpaces;

public void AddBlock(){
    size = new int[getSizeWithArmor() + 1];

    points++;
    blockPickup++;
}
private void AddBlock(int increase){
    size = new int[getSizeWithArmor() + increase];
    points++;
}

public void AddArmor(){
    armor++;
    AddBlock(1);
}

public void RemoveArmor(){
    armor--;
    size = new int[getSizeWithArmor() - 1];
}

public int getArmor(){
    return armor;
}
public int getSizeWithArmor(){
    return size.length;
}

public int getSizeWithoutArmor(){
    return size.length - armor;
}

public void ResetSize(){
    size = new int[1 + getArmor()];
}

public int getPoints(){
    return points;
}
public void IsGamePlaying(boolean playing){
    inGame = playing;
}
public void IsGamePaused(boolean pause){
    gamePaused = pause;
}

public void Reset(){
    points = 0;
    armor = 0;
    blockPickup = 0;

    ResetSize();
    InitPlayer();
}

public Image Head(){
    if(up){
        return headUp;
    }
    else if(down){
        return headDown;
    }
    else if(right){
        return headRight;
    }
    else if(left){
        return headLeft;
    }
    else{
        return headRight;
    }
}

public void InitPlayer(){
    for(int i = 0; i <= getSizeWithArmor(); i++){
        X[i] = (boardWidth / 2) - (i * blockSize);
        Y[i] = boardHeight / 2;
    }
}

public void SetDirection(int key){
    if(key == KeyEvent.VK_UP && !down){
        up = true;
        left = false;
        down = false;
        right = false;
    }
    else if(key == KeyEvent.VK_DOWN && !up){
        up = false;
        left = false;
        down = true;
        right = false;
    }
    else if(key == KeyEvent.VK_LEFT && !right){
        up = false;
        left = true;
        down = false;
        right = false;
    }
    else if(key == KeyEvent.VK_RIGHT && !left){
        up = false;
        left = false;
        down = false;
        right = true;
    }
}

public void MovePlayer(){
    //Move the snake tail
    if(IsMoving()){
        //Move the head by its velocity

        for(int i = getSizeWithArmor(); i > 0; i--){

            int newLocX = X[i] - X[i-1];
            int newLocY = Y[i] - Y[i-1];

            //Block going left
            if(newLocX > 0){
                if(newLocX == -1){

                }
                else if(newLocX < -1){
                    X[i] = X[i-1] + 10;
                }
            }
            //Block going right
            else if(newLocX < 0){
                X[i] = X[i-1] - 10;
            }

            //Block going up
            if(newLocY > 0){
                Y[i] = Y[i-1] + 10;
            }
            //Block going down
            else if(newLocY < 0){
                Y[i] = Y[i-1] - 10;
            }
        }

        if(left){
            X[0] -= playerVel;
        }
        else if(right){
            X[0] += playerVel;
        }
        else if(up){
            Y[0] -= playerVel;
        }
        else if(down){
            Y[0] += playerVel;
        }
    }
}

public boolean IsMoving(){
    if(up || down || left || right){
        return true;
    }
    else{
        return false;
    }
}

public int getX(int i){
    return X[i];
}

public int getY(int i){
    return Y[i];
}

public void paint(Graphics2D g){
    for(int i = 0; i < getSizeWithArmor(); i++){
        if(i == 0){
            g.drawImage(Head(), X[0], Y[0], null);
        }
        else if(getArmor() >= i){
            g.drawImage(armorImage, X[i], Y[i], null);
        }
        else{
            g.setColor(Color.YELLOW);
            g.fillRect(X[i], Y[i], blockSize, blockSize);
        }
    }
}

@Override
public void run() {
    try{
        while(inGame){
            if(!gamePaused){
                MovePlayer();
                Thread.sleep(20);
            }
        }
    }
    catch(Exception e){
        System.err.println("Player has encoundered an error: "+e.getMessage());
    }
}
}

私の Board クラスは、このクラスに変更を加えるために必要なすべてのデータを呼び出します。このクラスが非常に組織化されていないことをお詫び申し上げます。私はそれを再編成して、その中のがらくたの多くを減らすために戻っていません。また、多くのコードが冗長で不要であることもわかっています。私はそのすべてを修正することに取り組んでいます。現在、ヘビの体の問題を修正しようとしています。

編集4:

私はそれの一部を理解しました。右と下にスムーズにアニメーション化するようにしました。ただし、左または上に移動すると、崩壊し、再び問題を引き起こし始めます。前に動いていたのか、どの方向に動いていたのかを確認する必要があるようです。

public void MovePlayer(){
    //Move the snake tail
    if(IsMoving()){
        //Move the head by its velocity

        for(int i = getSizeWithArmor(); i > 0; i--){
            int newLocX = X[i] - X[i-1];
            int newLocY = Y[i] - Y[i-1];

            //Figure out the last direction it was going in
            if(newLocX != 0 && newLocY != 0){

            }

            //Block going left
            if(newLocX > 0){
                if(newLocX > 0 && newLocX <= 10){
                    X[i] -= 1;
                }
                else if(newLocX > 10){
                    X[i] = X[i-1] - 10;
                }
            }
            //Block going right
            else if(newLocX < 0){
                if(newLocX < 0 && newLocX >= -10){
                    X[i] += 1;
                }
                else if(newLocX < -10){
                    X[i] = X[i-1] + 10;
                }
            }
            //Block going up
            else if(newLocY > 0){
                if(newLocY == 1){
                    Y[i] -= 1;
                }
                else if(newLocY > 1){
                    Y[i] = Y[i-1] - 10;
                }
            }
            //Block going down
            else if(newLocY < 0){
                if(newLocY < 0 && newLocY >= -10){
                    Y[i] += 1;
                }
                else if(newLocY < -10){
                    Y[i] = Y[i-1] + 10;
                }
            }

        if(left){
            X[0] -= playerVel;
        }
        else if(right){
            X[0] += playerVel;
        }
        else if(up){
            Y[0] -= playerVel;
        }
        else if(down){
            Y[0] += playerVel;
        }
    }
}
4

1 に答える 1

2

この JSFiddle (以下の表を生成)は、ループが想定どおりに動作していないことを示しています。の仮想 x 位置から始めて[50, 40, 30, 20, 10, 0]、10 回の反復後に次のようになります。

moves   X[0]    X[1]    X[2]    X[3]    X[4]    X[5]
----------------------------------------------------
0       50      40      30      20      10      0
1       51      41      40      30      20      10
2       52      42      31      40      30      20
3       53      43      32      41      40      30
4       54      44      33      42      31      40
5       55      45      34      43      32      41
6       56      46      35      44      33      42
7       57      47      36      45      34      43
8       58      48      37      46      35      44
9       59      49      38      47      36      45
10      60      50      39      48      37      46

私はそれで遊んでいますが、このコードを修正してピースを本来の方法で移動する良い方法を思いつきません。数学や単一の for ループでできるよりも少し複雑だと思います。1 つの可能性は、各ブロックが移動する方向を保存することです。

また、各ブロックの目的地 (つまり、10 ステップのどこにあるのか) を把握し、補間してスムーズに移動させることもできます。この方法には、アニメーションに取り組む前に、ブロックが適切な場所に到達していることを確認できるという利点があります。見栄えを気にする前に、ゲーム ロジックが機能することを確認してください。


これはあなたがやろうとしていることにより近いと思い ます(移動回数のない行が宛先配列です):

moves  X[0]    X[1]    X[2]    X[3]    X[4]    X[5]    X[6]    X[7]    X[8]    X[9]    X[10]
--------------------------------------------------------------------------------------------
0      50      40      30      30      30      20      20      20      30      40      50
       50      40      30      30      30      20      20      20      30      40      50
1      51      41      31      30      30      21      20      20      29      39      49
2      52      42      32      30      30      22      20      20      28      38      48
3      53      43      33      30      30      23      20      20      27      37      47
4      54      44      34      30      30      24      20      20      26      36      46
5      55      45      35      30      30      25      20      20      25      35      45
6      56      46      36      30      30      26      20      20      24      34      44
7      57      47      37      30      30      27      20      20      23      33      43
8      58      48      38      30      30      28      20      20      22      32      42
9      59      49      39      30      30      29      20      20      21      31      41
10     60      50      40      30      30      30      20      20      20      30      40
       60      50      40      30      30      30      20      20      20      30      40
11     61      51      41      31      30      30      21      20      20      29      39
12     62      52      42      32      30      30      22      20      20      28      38
13     63      53      43      33      30      30      23      20      20      27      37
14     64      54      44      34      30      30      24      20      20      26      36
15     65      55      45      35      30      30      25      20      20      25      35
16     66      56      46      36      30      30      26      20      20      24      34
17     67      57      47      37      30      30      27      20      20      23      33
18     68      58      48      38      30      30      28      20      20      22      32
19     69      59      49      39      30      30      29      20      20      21      31
20     70      60      50      40      30      30      30      20      20      20      30
       70      60      50      40      30      30      30      20      20      20      30
21     71      61      51      41      31      30      30      21      20      20      29

またはグラフィカルに:

ここに画像の説明を入力

私はそれを Java に翻訳しようとしますが、私の Java は錆びていて、あなたのコードにプラグインすることができないので、完璧であるとは保証できません. 重要な部分はロジックです。また、これは x 値のみを対象としていますが、y 値を追加するのは簡単であることに注意してください。

のコピーである宛先配列が必要ですX:

int[] dests = (int[])X.clone();

次に、 内MovePlayerで、ブロックが目的地に到達した場合 (したがって新しい目的地が必要な場合) にのみ、移動方向に基づいて設定します。

if(IsMoving() && X.equals(dests)) {
    for(int i = dests.length - 1; i > 0; i--) {
        if(X[i] != X[i-1])
            dests[i] = X[i-1];
    }

    if(left) {
        dests[0] = X[0] - 10;
    } else if(right) {
        dests[0] = X[0] + 10;
    }
}

最後に、ブロックを目的地に向かってインチングします。

for(var i = 0; i < X.length; i++) {
    X[i] += Integer.signum(dests[i] - X[i]);
}

signum[-1, 0, 1]引数の符号に応じていずれかを返します。

于 2012-11-30T20:18:19.853 に答える