3

所以我在 JPanel 中全面移动我的 Snake 时遇到了一些问题。现在这不是 JPanel 的问题或错误,我只是无法像应有的那样移动 Snake。我知道问题出在哪里,但我只是想不出一种方法让它正常工作而不会出现问题。

问题:Snake 应该彼此相距约 10 px,但它却聚集成彼此相距约 1 px。

这就是它应该看起来的样子。

这就是它应该看起来的样子。

这是它结块时的样子

这是它结块时的样子

我尝试了几种我能想到的不同方法,并且我已经为此工作了好几天。

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 循环要复杂一些。一种可能性是存储每个块移动的方向。

您还可以计算出每个块的目的地(即,在 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 回答