This site requires JavaScript, please enable it in your browser!
Greenfoot back
MusicPenguin
MusicPenguin wrote ...

2014/7/9

I'm having some issues with some Move methods...

1
2
MusicPenguin MusicPenguin

2014/7/9

#
I have a 4x4 grid of 60 pixel wide cells. My issue is if I have more than one instance of this class (Tile) on the grid and I move them around it works just as to be expected for most of it but if there are two Tiles horizontally aligned and I chose either left or right, they flip flop. It works just fine if I chose up or down. For give me for the broken thoughts for I am about to pass out. private int direction 0 = left, 1 = right, 2 = up, 3 = down
public int getNumOfEmptyCellsInFront(){
        System.out.println("getNum() direction = " + direction);
        int count = 0;
        switch (direction){
            case 0: 
                for (int i = getX() - 1; i > -1; i--){
                    if ( getWorld().getObjectsAt(i, getY(), Tile.class).isEmpty()){
                        count += 1;
                    }
                }
                
                return count;
            
            case 1:
                for (int i = getX() + 1; i < 4; i++){
                    if ( getWorld().getObjectsAt(i, getY(), Tile.class).isEmpty()){
                        count += 1;
                    }
                }
                
                return count;
            
            case 2:
                for (int i = getY() - 1; i > -1; i--){
                    if ( getWorld().getObjectsAt(getX(), i, Tile.class).isEmpty()){
                        count += 1;
                    }
                }
                
                return count;
            
            case 3:
                for (int i = getY() + 1; i < 4; i++){
                    if ( getWorld().getObjectsAt(getX(), i, Tile.class).isEmpty()){
                        count += 1;
                    }
                }
                
                return count;
            
            default: break;
        }
        return 0;
    }
    
    public void slideTile(){
        switch (direction){
            case 0: 
                for (int x = getX() - 1; x > (getX() - 1) - getNumOfEmptyCellsInFront(); x--){
                    setLocation(x, getY());
                    if (getNumOfEmptyCellsInFront() > 1){
                        
                    }
                }
                
                direction = -1;
                break;
            
            case 1:
                for (int x = getX() + 1; x < (getX() + 1) + getNumOfEmptyCellsInFront(); x++){
                    setLocation(x, getY());
                    if (getNumOfEmptyCellsInFront() > 1){
                        
                    }
                }
                
                direction = -1;
                break;
            
            case 2:
                for (int y = getY() - 1; y > (getY() - 1) - getNumOfEmptyCellsInFront(); y--){
                    setLocation(getX(), y);
                    if (getNumOfEmptyCellsInFront() > 1){
                        
                    }
                }
                
                direction = -1;
                break;
            
            case 3:
                for (int y = getY() + 1; y < (getY() + 1) + getNumOfEmptyCellsInFront(); y++){
                    setLocation(getX(), y);
                    if (getNumOfEmptyCellsInFront() > 1){
                        
                    }
                }
                
                direction = -1;
                break;
            
            default: 
                direction = -1;
                break;
        }
    }
any help or suggestion is appreciated.
danpost danpost

2014/7/9

#
Please include your 'act' method (or the code that calls these methods; explain where the code is located).
danpost danpost

2014/7/9

#
It is possible you have concurrent modification issues. That is, by moving one Tile object, you change the state of (the number of empties counted by) another Tile that has yet to be moved. You would either need to have them move in an order that prevents this (moving the one closest to the end they are moving toward first and working away from that end) or determine and save the distance each is to move first -- then move them all by their saved distances.
MusicPenguin MusicPenguin

2014/7/9

#
Thank you so much for the reply! I'll post the rest of the methods in a while. But here is the general setup: Act() SetDirection > wallCheck > getEmpty > slideTile Only set direction is called from act. Everything else is nested
MusicPenguin MusicPenguin

2014/7/9

#
    public void act() 
    {
        if (!isDown){
            setKeyDirection();
        }
        if (isDown && !(Greenfoot.isKeyDown("left") || Greenfoot.isKeyDown("right") 
                || Greenfoot.isKeyDown("up") || Greenfoot.isKeyDown("down"))){
            isDown = false;
        }
    }
MusicPenguin MusicPenguin

2014/7/9

#
    public void setKeyDirection(){
        if (Greenfoot.isKeyDown("left")){
            //setLocation(getX() - 1, getY());
            isDown = true;
            direction = LEFT;
        }else if (Greenfoot.isKeyDown("right")){
            //setLocation(getX() + 1, getY());
            isDown = true;
            direction = RIGHT;
        }else if (Greenfoot.isKeyDown("up")){
            //setLocation(getX(), getY() - 1);
            isDown = true;
            direction = UP;
        }else if (Greenfoot.isKeyDown("down")){
            //setLocation(getX(), getY() + 1);
            isDown = true;
            direction = DOWN;
        }
        if (!wallCheck()){
            if (getNumOfEmptyCellsInFront() > 0){
                slideTile();
            }else{
                direction = -1;
            }
        }else{
            direction = -1;
        }
    }
danpost danpost

2014/7/9

#
Your problem is exactly what I though it might be:
danpost wrote...
It is possible you have concurrent modification issues. That is, by moving one Tile object, you change the state of (the number of empties counted by) another Tile that has yet to be moved. You would either need to have them move in an order that prevents this (moving the one closest to the end they are moving toward first and working away from that end) or determine and save the distance each is to move first -- then move them all by their saved distances.
MusicPenguin MusicPenguin

2014/7/9

#
I have changed my code to only calculate the number of empties right after the direction is set. Now it seems to work in all directions except when the first instance is behind the second instance and touching the wall (see below). How would I go about fixing this problem? I looked at setActOrder() but that only affects different classes. view the code as plain so it doesn't look distorted.
 -------------------
|        |        |        |       |
 -------------------
|        |        |        |       |
 -------------------
| [ 2 ] | [ 4 ] |        |       |
 -------------------
|        |        |        |       |
 -------------------

set direction = Right

this is what should happen:

 -------------------
|        |        |        |        |
 -------------------
|        |        |        |        |
 -------------------
|        |        | [ 2 ] | [ 4 ] |
 -------------------
|        |        |        |        |
 -------------------

but this is what happens:

 -------------------
|        |        |        |        |
 -------------------
|        |        |        |        |
 -------------------
|        |        |        | [ 2 ] |
 -------------------
|        |        |        |        |
 -------------------

the four is underneath the 2
danpost danpost

2014/7/9

#
Please show the Tile class code as it is now.
MusicPenguin MusicPenguin

2014/7/9

#
public class Tile extends Actor
{   
    public static final int LEFT = 0, RIGHT = 1, UP = 2, DOWN = 3, TILE_SIZE = 56;
    
    private static final int tileXCoordinate = 22, tileYCoordinate = 33;
    private boolean isDown = false;
    private int direction = -1;
    private int numOfEmptyCellsInFront = 0;
    
    public Tile(){
        setIndividualImage();
    }
    
    public void p(){
        System.out.println(this + " instance");
    }
    
    public void p(String s){
        System.out.println(this + " " + s);
    }
    
    /*
     * 
     */
    public void act() 
    {
        if (!isDown){
            setKeyDirection();
        }
        if (isDown && !(Greenfoot.isKeyDown("left") || Greenfoot.isKeyDown("right") 
                || Greenfoot.isKeyDown("up") || Greenfoot.isKeyDown("down"))){
            isDown = false;
        }
    }
    
    private void setIndividualImage(){
        GreenfootImage IMG = new GreenfootImage(TILE_SIZE, TILE_SIZE);
        setImage(IMG);
        IMG.setColor(java.awt.Color.BLACK);
        IMG.fill();
        IMG.setColor(java.awt.Color.WHITE);
        IMG.setFont(new java.awt.Font("Verdana", java.awt.Font.PLAIN, 20));
        IMG.drawString(Integer.toString(((Greenfoot.getRandomNumber(2) + 1) * 2)), tileXCoordinate, tileYCoordinate);
    }
    
    public void setKeyDirection(){
        if (Greenfoot.isKeyDown("left")){
            isDown = true;
            direction = LEFT;
        }else if (Greenfoot.isKeyDown("right")){
            isDown = true;
            direction = RIGHT;
        }else if (Greenfoot.isKeyDown("up")){
            isDown = true;
            direction = UP;
        }else if (Greenfoot.isKeyDown("down")){
            isDown = true;
            direction = DOWN;
        }
        
        setNumOfEmptyCellsInFront();
        
        if (!wallCheck() && getNumOfEmptyCellsInFront() > 0){
            p(Integer.toString(getNumOfEmptyCellsInFront()) + " " + direction);
            slideTile();
        }else{
            direction = -1;
        }
    }
    
    public boolean wallCheck(){
        switch (direction){
            case 0: return getX() == 0;
            
            case 1: return getX() == 3;
            
            case 2: return getY() == 0;
            
            case 3: return getY() == 3;
            
            default: return false;
        }
    }
    
    public void setNumOfEmptyCellsInFront(){
        numOfEmptyCellsInFront = 0;
        switch (direction){
            case 0: 
                for (int i = getX() - 1; i > -1; i--){
                    if ( getWorld().getObjectsAt(i, getY(), Tile.class).isEmpty()){
                        numOfEmptyCellsInFront += 1;
                    }
                }
                
                break;
            
            case 1:
                for (int i = getX() + 1; i < 4; i++){
                    if ( getWorld().getObjectsAt(i, getY(), Tile.class).isEmpty()){
                        numOfEmptyCellsInFront += 1;
                    }
                }
                
                break;
            
            case 2:
                for (int i = getY() - 1; i > -1; i--){
                    if ( getWorld().getObjectsAt(getX(), i, Tile.class).isEmpty()){
                        numOfEmptyCellsInFront += 1;
                    }
                }
                
                break;
            
            case 3:
                for (int i = getY() + 1; i < 4; i++){
                    if ( getWorld().getObjectsAt(getX(), i, Tile.class).isEmpty()){
                        numOfEmptyCellsInFront += 1;
                    }
                }
                
                break;
            
            default: break;
        }
    }
    
    public void slideTile(){
        switch (direction){
            case 0: 
                setLocation(getX() - getNumOfEmptyCellsInFront(), getY());
                
                direction = -1;
                break;
            
            case 1:
                setLocation(getX() + getNumOfEmptyCellsInFront(), getY());
                
                direction = -1;
                break;
            
            case 2:
                setLocation(getX(), getY() - getNumOfEmptyCellsInFront());
                
                direction = -1;
                break;
            
            case 3:
                setLocation(getX(), getY() + getNumOfEmptyCellsInFront());
                
                direction = -1;
                break;
            
            default: 
                direction = -1;
                break;
        }
    }
    
    public int getNumOfEmptyCellsInFront(){
        return numOfEmptyCellsInFront;
    }
MusicPenguin MusicPenguin

2014/7/9

#
You're right about one moving over the other and messing with the calculation of empties. I think I just need to move the tiles starting from the front but how would I do that?
danpost danpost

2014/7/9

#
I think you still do not understand. The distance that EVERY tile needs to move must be calculated before ANY tile is moved OR you must move them in a specific order determined by the direction of movement. Either way you go, the control must be placed at a higher level (not in the Tile class 'act' method) -- probably in your world class. This is because you are moving them as a group (all at once) and not individually without regard to the others. From your last post (which was not present before I started this post), you seem to now understand.
MusicPenguin MusicPenguin

2014/7/9

#
So it seems the easiest thing to do would be to create an abstract class in between Actor and Tile to do the calculations leaving Tile to be more of just visual.
danpost danpost

2014/7/9

#
MusicPenguin wrote...
So it seems the easiest thing to do would be to create an abstract class in between Actor and Tile to do the calculations leaving Tile to be more of just visual.
No. You will run into the same problem as the abstract class will still only deal with one Tile object at a time.
danpost danpost

2014/7/9

#
I had written code for a '2048' game which has this same type of tile movement. The only methods in the 'Tile' class are one for updating the image, one for doubling its value and one for getting its current value. All the keystroke detection and movement codes are in my 'Shifty' world class.
There are more replies on the next page.
1
2