将Snake的身体移动到整个板上会导致身体结块

时间:2012-11-30 19:02:43

标签: java swing user-interface animation

所以我在使用JPanel移动我的Snake时遇到了一些问题。现在不是JPanel的问题或错误,我只是不能像现在这样移动Snake。我知道问题出在哪里,但我无法想办法让它在没有问题的情况下正常工作。

问题:蛇应该彼此相距大约10 px,但是它们彼此相距大约1 px。

这就是它的外观。

This is how it is supposed to look.

这就是它凝聚时的样子

This is how it looks when it clumps up

我尝试了几种不同的方法,我已经研究了好几天了。

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:

这是全班的玩家。玩家类负责所有移动,并协调自己。

班主任:

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;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

This JSFiddle (which generates the table below)表明你的循环没有表现出它的表现。从[50, 40, 30, 20, 10, 0]的假设x位置开始,这是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个步骤中的哪个位置?)然后进行插值以使其平滑移动。这种方法的优势在于,您可以在处理动画之前确保块到达正确的位置 - 确保游戏逻辑正常工作,然后再担心它看起来有多好。


认为 this is closer到你要做的事情(没有多少动作的行是目标数组):

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

或图形化:

enter image description here

我会尝试将其翻译成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]中的一个,具体取决于参数的符号。