Java-Gaming.org Hi !
Featured games (81)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (575)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  java slick2d - gettileproperty returns true when it shouldn't  (Read 2157 times)
0 Members and 1 Guest are viewing this topic.
Offline Desbrina

Senior Newbie


Exp: 3 years



« Posted 2014-04-24 11:30:24 »

I'm trying to implement some collision detection to a test game i've been making.
I've used TiledMap to create the map and set a property on one of the tiles to blocked=true
This tile is then drawn on layer 0.

I then check to see if the tile exists in the direction the player is moving, using the following code

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
    if (input.isKeyDown(Input.KEY_DOWN)) {
                sprite = down;
                sprite.update(delta);
                int tileID = map.map.getTileId((int) x / map.map.getTileWidth(), (int) y / map.map.getTileHeight() + 1, 0);
                String value = map.map.getTileProperty(tileID, "blocked", "false");
                if (value.equals("true")) {
                    y += delta * 0.1f;
                    System.out.println("Tile ID: " + (int) (x / map.map.getTileWidth()) + ", " + (int) (y / map.map.getTileHeight() + 1) + " Try to walk down. Tile value below the player is:" + value);
                }
   
            }


this is repeated for each direction.

The problem i'm running into is its picking up the blocked property for incorrect tiles
You can understand better with this video. The yellow tiles are the collision/blocked tiles
http://youtu.be/FqEmjAbiKQU
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #1 - Posted 2014-04-24 15:11:44 »

map.map.getTileWidth()? Shouldnt that be map.getTileWidth()?

Also, depending on how your character movement works, your tileID fetcher probably isnt grabbing the correct tile and then checking the one below it. I was literally walking out the door so I can't really get too deep into it, but here's how I fetch the X/Y my character is standing on. You can use this, then shift it up/down/left/right by 1 to get the tile ID you want to check.

entityX/Y = player's X/Y on the map. If depending on how you handle figuring out where your player is standing this may need changed, but it gets you the idea.
1  
2  
   public int getEntityTileLocationX() {return (Math.round(entityX)/map.getTileHeight());}
   public int getEntityTileLocationY() {return (Math.round(entityY)/map.getTileWidth());}


then...

1  
   int tileID = map.getTileId(getEntityTileLocationX(), getEntityTileLocationY() + 1, 0);


I'll try to help more when I get back if this doesnt help you. Cheesy

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #2 - Posted 2014-04-24 16:18:37 »

its map.map since my maps are drawn in a custom map class which has a variable called map which holds the tiledmap data.

Using your code, i'm still getting the same issue
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #3 - Posted 2014-04-24 21:23:28 »

its map.map since my maps are drawn in a custom map class which has a variable called map which holds the tiledmap data.

Using your code, i'm still getting the same issue

ah, I see. This is a bit off-topic, but you can just extend TiledMap in your custom map class so you can access all the methods inside TiledMap without having to init the TiledMap separately. But I'm unsure of how your code design is setup, so I don't know if that's an option.

Back on topic though; it sounds like something isn't quite working out with your player's X and Y coordinates in relation to the map. Have you tried doing something like this *outside* if your IF statement, and seeing if the tile the character us standing on is in fact the correct TileID? This might help you figure out if the math is even working out in the first place before you bother with collision detection.

1  
System.out.println(map.getTileId(getEntityTileLocationX(), getEntityTileLocationY(), 0));


My best guess is the values you're feeding it aren't actually the player's X/Y in relation to the map so you're randomly bumping into objects elsewhere. IE: Your player may be at say 256,256on the *screen* so it's looking at 256,256 on the *map* when it should be looking at something like say 512,512 because it's not factoring in the fact the map is rendering starting at something like -256,-256. Kinda hard to explain; I hope you get what I am saying here.

To check if I'm right, you could forcefully render the map at 0,0 and then comment out all your map/camera movement code, then just move the player around and see if collision is working correctly.

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #4 - Posted 2014-04-24 21:47:20 »

The map is already rendered at 0,0.

It does seem as though I'm getting the screen and world positions mixed up, since when i used the System.out.println it is giving incorrect tile ids, some places its showing 0, when it should be 95 (even though tiled says its 94), other places its 95 when it should be 0
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #5 - Posted 2014-04-29 13:49:12 »

After further investigation , the bottom right corner x and y according to tiledmap is 16,16 but ingame its being registered as 15,15
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #6 - Posted 2014-04-29 15:07:17 »

Did you take into account the map starts at tile 0,0, not 1,1? Cheesy

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #7 - Posted 2014-04-29 15:14:56 »

Yes. Tiledmap starts at 0,0 as well, though for some reason when its being put on screen, its being started at -1,-1

I managed to get the following image. The red areas are where the collisions should be happening. That's also where drawing the player at 0,0 puts it, though because of the camera it becomes 80,0. the coloured tiles along the top edge mark each tile across




EDIT: I've narrowed it down my draw map method, specifically where it draws the map. If i manually set it to draw the map at 16,16 i don't get the error, though the map doesn't scroll, it jumps instead, though i do if it specify 0,0
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #8 - Posted 2014-04-29 15:51:38 »

Hmmm.. Can you show us the map and player (and camera if you have it) rendering code? Sounds like something is goofed up in the math somewhere.

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #9 - Posted 2014-04-29 15:53:01 »

Sure, here is the player

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pokemon.statebased;

import org.newdawn.slick.Animation;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tests.xml.Entity;

/**
 *
 * @author Ceri
 */

public class Player extends Entity {

    private Animation sprite, up, down, left, right;
    private float x = 0, y = 0;
    private final MapClass map;
    private final Camera cam;

    public Player(MapClass m, Camera ca) throws SlickException {
        map = m;
        cam = ca;

        Image[] movementUp = {new Image("Images/Player/u1.png"), new Image("Images/Player/u2.png"), new Image("Images/Player/u3.png"), new Image("Images/Player/u4.png")};
        Image[] movementDown = {new Image("Images/Player/d1.png"), new Image("Images/Player/d2.png"), new Image("Images/Player/d3.png"), new Image("Images/Player/d4.png")};
        Image[] movementLeft = {new Image("Images/Player/l1.png"), new Image("Images/Player/l2.png"), new Image("Images/Player/l3.png"), new Image("Images/Player/l4.png")};
        Image[] movementRight = {new Image("Images/Player/r1.png"), new Image("Images/Player/r2.png"), new Image("Images/Player/r3.png"), new Image("Images/Player/r4.png")};
        int[] duration = {100, 100, 100, 100};

        up = new Animation(movementUp, duration, false);
        down = new Animation(movementDown, duration, false);
        left = new Animation(movementLeft, duration, false);
        right = new Animation(movementRight, duration, false);

        // Original orientation of the sprite. It will look right.
        sprite = right;
    }

    public int getEntityTileLocationX() {  
        System.out.println("X: " + Math.round(this.getX()) / map.map.getTileHeight());
        return (Math.round(this.getX()) / map.map.getTileHeight());
    }

    public int getEntityTileLocationY() {
        System.out.println("Y: " + Math.round(this.getY()) / map.map.getTileWidth());
        return (Math.round(this.getY()) / map.map.getTileWidth());
    }

    public void update(GameContainer container, int delta) throws SlickException {
        Input input = container.getInput();
        if (input.isKeyDown(Input.KEY_UP)) {
            sprite = up;
            y -= delta * 0.1f;
            sprite.update(delta);
        } else if (input.isKeyDown(Input.KEY_DOWN)) {
            sprite = down;
            y += delta * 0.1f;
            sprite.update(delta);
        } else if (input.isKeyDown(Input.KEY_LEFT)) {
            sprite = left;
            x -= delta * 0.1f;
            sprite.update(delta);
        } else if (input.isKeyDown(Input.KEY_RIGHT)) {
            sprite = right;
            x += delta * 0.1f;
            sprite.update(delta);
            int tileID = map.map.getTileId(getEntityTileLocationX(), getEntityTileLocationY(), 0);
            String value = map.map.getTileProperty(tileID, "blocked", "false");
            System.out.println("Tile X: " + getEntityTileLocationX() + " Tile Y: " + getEntityTileLocationY() + " Tile ID: " + tileID + " Blocked: " + value);
        }
    }

    public void draw() {
        System.out.println("X: " + (x - cam.cameraX) + " Y: " + (y - cam.cameraY));
        sprite.draw(x - cam.cameraX, y - cam.cameraY);
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }
}


Here is the camera
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pokemon.statebased;

/**
 *
 * @author Ceri
 */

import java.awt.geom.Point2D;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.tiled.TiledMap;

public class Camera {

    /**
     * the map used for our scene
     */

    protected TiledMap map;

    /**
     * the number of tiles in x-direction (width)
     */

    protected int numTilesX;

    /**
     * the number of tiles in y-direction (height)
     */

    protected int numTilesY;

    /**
     * the height of the map in pixel
     */

    protected int mapHeight;

    /**
     * the width of the map in pixel
     */

    protected int mapWidth;

    /**
     * the width of one tile of the map in pixel
     */

    protected int tileWidth;

    /**
     * the height of one tile of the map in pixel
     */

    protected int tileHeight;

    /**
     * the GameContainer, used for getting the size of the GameCanvas
     */

    protected GameContainer gc;

    /**
     * the x-position of our "camera" in pixel
     */

    public float cameraX;

    /**
     * the y-position of our "camera" in pixel
     */

    public float cameraY;

    protected Point2D.Float currentCenterPoint = new Point2D.Float(0, 0);

    int tileOffsetX = 0;
    int tileOffsetY = 0;

    //calculate the index of the leftmost tile that is being displayed
    int tileIndexX = 0;
    int tileIndexY = 0;
   
    int offSetX, offSetY;

    /**
     * Create a new camera
     *
     * @param gc the GameContainer, used for getting the size of the GameCanvas
     * @param map the TiledMap used for the current scene
     */

    public Camera(GameContainer gc, TiledMap map) {
        this.map = map;

        this.numTilesX = map.getWidth();
        this.numTilesY = map.getHeight();

        this.tileWidth = map.getTileWidth();
        this.tileHeight = map.getTileHeight();

        this.mapWidth = this.numTilesX * this.tileWidth;
        this.mapHeight = this.numTilesY * this.tileHeight;

        this.gc = gc;
    }

    /**
     * "locks" the camera on the given coordinates. The camera tries to keep the
     * location in it's center.
     *
     * @param x the real x-coordinate (in pixel) which should be centered on the
     * screen
     * @param y the real y-coordinate (in pixel) which should be centered on the
     * screen
     * @return
     */

    public Point2D.Float centerOn(float x, float y) {
        //try to set the given position as center of the camera by default
        cameraX = x - gc.getWidth() / 2;
        cameraY = y - gc.getHeight() / 2;

        //if the camera is at the right or left edge lock it to prevent a black bar
        if (cameraX < 0) {
            cameraX = 0;
        }
        if (cameraX + gc.getWidth() > mapWidth) {
            cameraX = mapWidth - gc.getWidth();
        }

        //if the camera is at the top or bottom edge lock it to prevent a black bar
        if (cameraY < 0) {
            cameraY = 0;
        }
        if (cameraY + gc.getHeight() > mapHeight) {
            cameraY = mapHeight - gc.getHeight();
        }

        currentCenterPoint.setLocation(cameraX, cameraY);
        return currentCenterPoint;
    }

    /**
     * "locks" the camera on the center of the given Rectangle. The camera tries
     * to keep the location in it's center.
     *
     * @param x the x-coordinate (in pixel) of the top-left corner of the
     * rectangle
     * @param y the y-coordinate (in pixel) of the top-left corner of the
     * rectangle
     * @param height the height (in pixel) of the rectangle
     * @param width the width (in pixel) of the rectangle
     */

    public void centerOn(float x, float y, float height, float width) {
        this.centerOn(x + width / 2, y + height / 2);
    }

    /**
     * "locks the camera on the center of the given Shape. The camera tries to
     * keep the location in it's center.
     *
     * @param shape the Shape which should be centered on the screen
     */

    public void centerOn(Shape shape) {
        this.centerOn(shape.getCenterX(), shape.getCenterY());
    }

    /**
     * draws the part of the map which is currently focussed by the camera on
     * the screen
     *
     * @param layer the layer number
     */

    public void drawMap(int layer) {
        this.drawMap(0, 0, layer);
    }

    /**
     * draws the part of the map which is currently focussed by the camera on
     * the screen.<br>
     * You need to draw something over the offset, to prevent the edge of the
     * map to be displayed below it<br>
     * Has to be called before Camera.translateGraphics() !
     *
     * @param offsetX the x-coordinate (in pixel) where the camera should start
     * drawing the map at
     * @param offsetY the y-coordinate (in pixel) where the camera should start
     * drawing the map at the layer
     * @param layer
     */

    public void drawMap(int offsetX, int offsetY, int layer) {
        //calculate the offset to the next tile (needed by TiledMap.render())
        tileOffsetX = (int) -(cameraX % tileWidth);
        tileOffsetY = (int) -(cameraY % tileHeight);

        //calculate the index of the leftmost tile that is being displayed
        tileIndexX = (int) (cameraX / tileWidth);
        tileIndexY = (int) (cameraY / tileHeight);
       
        offSetX = offsetX;
        offSetY = offsetY;
    }

    /**
     * Translates the Graphics-context to the coordinates of the map - now
     * everything can be drawn with it's NATURAL coordinates.
     */

    public void translateGraphics() {
        gc.getGraphics().translate(-cameraX, -cameraY);
    }

    /**
     * Reverses the Graphics-translation of Camera.translatesGraphics(). Call
     * this before drawing HUD-elements or the like
     */

    public void untranslateGraphics() {
        gc.getGraphics().translate(cameraX, cameraY);
    }

}


and here is the mapclass
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pokemon.statebased;

import java.util.HashMap;
import org.newdawn.slick.Animation;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;

/**
 *
 * @author Ceri
 */

public class MapClass {

    public TiledMap map;
    private static Camera camera;
    private final GameContainer gc;
    private HashMap<String, Animation> autos = new HashMap<>();

    public MapClass(String file, GameContainer g) throws SlickException {
        map = new TiledMap(file);
        gc = g;
        //SpriteSheet flower = new SpriteSheet("Images/Animations/Flower.png", 16, 16);
        Animation flowerAnimation = new Animation();
        flowerAnimation.setAutoUpdate(true);
        /*flowerAnimation.addFrame(flower.getSprite(0, 0), 300);
        flowerAnimation.addFrame(flower.getSprite(1, 0), 300);
        flowerAnimation.addFrame(flower.getSprite(2, 0), 300);
        autos.put("Flower", flowerAnimation);*/

    }

    public void drawAnimations() {
        Animation a = autos.get("Flower");
        a.drawFlash(210f, 222f, 16f, 16f);
    }

    public void setCamera(Camera c) {
        camera = c;
    }

    public void drawMap(int layer) {
        map.render(
                camera.tileOffsetX + camera.offSetX,
                camera.tileOffsetY + camera.offSetY,
                camera.tileIndexX,
                camera.tileIndexY,
                (gc.getWidth() - camera.tileOffsetX) / camera.tileWidth + 1,
                (gc.getHeight() - camera.tileOffsetY) / camera.tileHeight + 1, layer, false);
        //drawAnimations();
    }
}
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #10 - Posted 2014-04-29 22:04:28 »

Try replacing draw() with this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
    public void drawMap(int layer) {
        map.render(
                camera.tileOffsetX + camera.offSetX,
                camera.tileOffsetY + camera.offSetY,
                camera.tileIndexX,
                camera.tileIndexY,
                (gc.getWidth() - camera.tileOffsetX) / camera.tileWidth,
                (gc.getHeight() - camera.tileOffsetY) / camera.tileHeight, layer, false);
        //drawAnimations();
    }


I think whats going on is it is shifting the *visible* location of the map down/right by 1, but when it calculates the player's location with getEntityTileLocationY()/X() it's not factoring that in so the player's tile is always 1,1 off.
1  
2  
(gc.getWidth() - camera.tileOffsetX) / camera.tileWidth + 1,
(gc.getHeight() - camera.tileOffsetY) / camera.tileHeight + 1, layer, false);



- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #11 - Posted 2014-04-29 22:17:33 »

Doesn't make any difference. I have found though that
1  
2  
(camera.tileOffsetX + camera.offSetX) + 16,
(camera.tileOffsetY + camera.offSetY) + 16,


seems to work

How do i make it so that when the tile is over .5 (like 9.5, 7.5) its still picked up as being 9, 7 etc but still allow movement to 9.99
At the moment when the tile is .5 or over its classing it as the next tile up, so 7.5 becomes 8. I've tried using math.floor but it stops the movement at the whole number
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #12 - Posted 2014-04-29 22:39:06 »

Doesn't make any difference. I have found though that
1  
2  
(camera.tileOffsetX + camera.offSetX) + 16,
(camera.tileOffsetY + camera.offSetY) + 16,


seems to work

How do i make it so that when the tile is over .5 (like 9.5, 7.5) its still picked up as being 9, 7 etc but still allow movement to 9.99
At the moment when the tile is .5 or over its classing it as the next tile up, so 7.5 becomes 8. I've tried using math.floor but it stops the movement at the whole number

Well, +16/+16 is just correcting the error elsewhere though. You're rendering something else offshifted by 16/16 and recorrecting it when you render the map (I think)

The code I use to get the player's exact location at all times (based on his feet position) is this, but I also allow the player to walk in front of objects, only stopping when his *feet* hit them.
1  
2  
   public int getEntityTileLocationX() {return (Math.round(entityX+16)/32);}
   public int getEntityTileLocationY() {return (Math.round(entityY+28)/32);}


But, I'm thinking this is more what you want for your needs, it should register what tile you're standing on regardless of where you're standing on it. I'm assuming based on your code that your character is 16x16. If not, change +8 to +16 (or half the width/height of the sprite)
1  
2  
   public int getEntityTileLocationX() {return (Math.floor(entityX+8)/map.map.getTileHeight());}
   public int getEntityTileLocationY() {return (Math.floor(entityY+8)/map.map.getTileWidth());}


Math.floor(x) is basically the same as Math.round, except instead of rounding to the nearest whole number, it'll round down no matter what. IE 1.9 == 1, where as Math.round(x) 1.9 ==  2.

There's also Math.ceil(x), that always rounds up. IE: 1.1 == 2

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #13 - Posted 2014-04-29 22:55:35 »

those three classes are the only classes that do any rendering on the map.

My character sprite is 32x32, all tiles are 16x16

At the moment i'm trying to make it so that the player can't step on the collision tile at all, though can still appear on top of it. I can make more advanced ones at a later stage


Basically allow the player to move in the posistions in the image. The Red F blocks are where the player can't move at all, but can still appear over the top of them like in the one facing up
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #14 - Posted 2014-04-29 23:24:14 »

Then you'd want to use something like my first one that track's the feet position where entityX+16 and entityY+28 is the coordinates of your characters feet. My guess is for you, that's somewhere around the same place mine is anyway, give or take a few pixels.But the fact you're using a 32x32 character in a 16x16 could complicates things a bit. But I'm pretty sure you can still just offshift the X/Y coordinates to where the character's feet are, and divide by tileHeight/Width (or just /16).

1  
2  
3  
 
   public int getEntityTileLocationX() {return (Math.round(entityX+16)/16);}
   public int getEntityTileLocationY() {return (Math.round(entityY+28)/16);}


That should give you the tile somewhere around the center of his feet, as seen here:


- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #15 - Posted 2014-04-29 23:27:28 »

thanks, i'll have a  go in the morning and let you know how i get on
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #16 - Posted 2014-04-30 22:17:28 »

ok, i have up and down working without an issue mostly, though i had to change it to
1  
2  
3  
4  
5  
6  
7  
public int getEntityTileLocationY() {
        if (sprite == down) {
            return (Math.round(this.getY() + 32) / 16);
        }

        return (Math.round(this.getY() + 20) / 16);
    }


With left and right, i can way to halfway outside the walls (though it happens no matter what the values in (this.getX() + 16) are set to) and then get stuck, can't move in either direction.

this is what i mean, the green box around the player is the sprites background. i coloured so i could easily see where the sprites bounds were.
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #17 - Posted 2014-04-30 22:52:17 »

mhmm, are you sure you're checking the tile to your left/right and not directly at your feet? Looking at the image, it seems to be just checking your feet position at Y:32/X:16 in relation to the sprite (center of his feet) and not checking the tile to his left or right.

You need something like this (based off your current code). Although I'd recommend taking the IF statements out of getTileLocation. But if you want it to be in there, it should be something like this:


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
public int getEntityTileLocationX() {
        if (sprite == left) { //if he's moving left
            return (Math.round(this.getX() - 16) / 16);
        }
        if (sprite == right) { //If he's moving right
            return (Math.round(this.getX() + 16) / 16);
        }

        return (Math.round(this.getX() + 16) / 16); //I assume this is to check at his feet if he's not moving
        }


Keep in mind though, that if "up", "down", "left", and "right" are always running even if you're not actually moving it could really confuse the system. It would be better to put it in your movement code. Here's my actual-working code from my game, as-is, just to give you an idea of where I am coming from. Pay close attention to the collision detection stuff. (Even though I use a totally different system than you for actual collision detection, it shouldn't matter though)

I comment'ed it all up to show you whats going on.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
   public void moveEntityNorth() throws SlickException{
      position = "movingNorth"; //position is the animation to play
      setPosition(position); //This is unneeded for you, this just makes sure all my sprite's layers are ALL moving the same way.
      if (collisionCtrl.checkCollision(getEntityExactLocationX()+7, getEntityExactLocationY()+27, collisionImage, true, false)){ //Collision check that returns true/false if I can move. Mine actually DOES check feet position at all times because of how my system works. Yours should add +-16 in whatever axis you need to check (IE: for north you'd add -16 on X)
         canMoveNorth=false; //Can't move!
      }else{
         canMoveNorth=true; //Can move!
      }
      if(canMoveNorth()){ //If the above check allows me to move
         canMoveReset(); //Ignore this
         entityY -= entitySpeed; //Move me!
      }
      idleDetection = 0; //Ignore this, part of my animation reset code.
   }




- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #18 - Posted 2014-05-01 00:11:07 »

Ok, i have all directions mostly working. I say mostly because i've ran into a problem when the player is between two tiles, they can still way over (or appear to) collision tiles

This screenshot show the player walking over the tv, which is set as a collision tile. The player shouldn't be able to walk over the bottom half of the tv, just under the top half


Edit: Forgot the latest version of the code

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
public int getEntityTileLocationX() {
        if (sprite == left)
            return (Math.round(this.getX() + 22) / 16);
        else
            return (Math.round(this.getX() + 8) / 16);
    }

    public int getEntityTileLocationY() {
        if(sprite == up)
            return (Math.round(this.getY() + 32) / 16);
        else
            return (Math.round(this.getY()+15) / 16);
    }

    public int getTileID(int x, int y) {
        return map.map.getTileId(getEntityTileLocationX() + x, getEntityTileLocationY() + y, 0);
    }

    public String getTileValue(int tileID) {
        return map.map.getTileProperty(tileID, "blocked", "false");
    }

and
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
public void update(GameContainer container, int delta) throws SlickException {
        Input input = container.getInput();
        if (input.isKeyDown(Input.KEY_UP)) {
            sprite = up;
            sprite.update(delta);
            String value = getTileValue(getTileID(0, -1));
            if (!"true".equals(value)) {
                y -= delta * 0.1f;
            }
        } else if (input.isKeyDown(Input.KEY_DOWN)) {
            sprite = down;
            sprite.update(delta);
            String value = getTileValue(getTileID(0, 1));
            if (!"true".equals(value)) {
                y += delta * 0.1f;
            }
        } else if (input.isKeyDown(Input.KEY_LEFT)) {
            sprite = left;
            sprite.update(delta);
            String value = getTileValue(getTileID(-1, 0));
            if (!"true".equals(value)) {
                x -= delta * 0.1f;
            }
        } else if (input.isKeyDown(Input.KEY_RIGHT)) {
            sprite = right;
            sprite.update(delta);
            String value = getTileValue(getTileID(1, 0));
            if (!"true".equals(value)) {
                x += delta * 0.1f;
            }
        }
    }
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #19 - Posted 2014-05-01 01:19:53 »

Since your movement isn't tile-by-tile, you may need to check for collision boxes on 4 points instead of just one, find the 4 corners of your sprite (IE: 0,0, 32,0, 0,32 and 32,32.. or the points around your feet) and check all 4 positions.

There is a completely alternative way of doing all this, but it's much more complicated. You could just draw rectangles around all your blocked tiles, then draw one around your character's feet and check if they intersect. But that would involve rewriting your entire collision system.

Basically it works like this:
- When your map loads, you run a for loop that checks your entire map tile by tile for the "blocked" property
- Every time it finds one, it creates a collision box rectangle over that spot
- Create a collision box rectangle at your character's feet
- have a for loop that checks the player's collision box against all the other collision boxes on the map.
- If any of the intersect, a collision has happened. Stop the player from moving and bounce him back 1 pixel so he isn't stuck.

That system will work a lot better than the 4-point idea I suggested, but will take a while to implement.

Example code:
Searching for properties then creating objects to act as collision boxes:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
   static TiledMap map = null;
   static public ArrayList <CollisionControl> collisionBoxArray = new ArrayList<CollisionControl>();

   int[] tileId[amountOfMapLayersHere];
   for (int x = 0; x < map.getWidth(); x++) {
      for (int y = 0; y < map.getHeight(); y++) {
         for (int l = 0; l < tileID.length; l++) {
            tileId[l] = map.getTileId(x, y, l);
            if (!(tileId[l] == 0)){ //not needed, just stops if there's no tile there to save a tiny amount of CPU usage.
               if (map.getTileProperty(tileId[l], "blocked", "false")){
                  collisionBoxArray.add (new CollisionControl(x,y,mapX,mapY));
               }
            }
         }
      }
   }



Very basic collision box object:
CollisionControl.class
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
package core;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Shape;

public class CollisionControl {
   int x2 = 0;
   int y2 = 0;
   
   private Shape collisionBox;
   
   public CollisionControl(int x, int y, int mapX, int mapY) throws SlickException{
      collisionBox = new Rectangle(mapX+10*16, mapY+10*16,16,16);
      x2 = x;
      y2 = y;
   }
   
   public void render(Graphics g, int mapX, int mapY) throws SlickException{
      g.draw(collisionBox); //Draw the box
   }
   
   public void update(int mapX, int mapY) throws SlickException{
      collisionBox.setX(mapX+x2*16); //Update box's location on the map
      collisionBox.setY(mapY+y2*16); //Update box's location on the map
   }

   //Just some get methods
   public Shape getCollisionBox(){return collisionBox;}
   public int getCollisionBoxX(){return x2;}
   public int getCollisionBoxY(){return y2;}
   
}


Then, stick this somewhere to render the boxes so you can see them (they dont need to be seen to work)
1  
2  
3  
4  
   COLLISION BOX RENDER
   for (int i = 0; i < mapParserArray.size(); i++) {
      mapParserArray.get(i).render(g,mapctrl.getMapX(),mapctrl.getMapY());
   }


..and here's a basic idea on whats needed to render a collision box (well, circle) for the player:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public class Player{
   public Shape playerBox;
   
   public void init(MapController mapctrl) throws SlickException{
      playerBox = new Circle(getPlayerX()+16,getPlayerY()+16,8); //Creates it
   }  

   public void render(MapController mapctrl, Graphics g) throws SlickException{
      g.draw(playerBox); //Draws the circle.
   }  

   
   public void update(MapController mapctrl, GameContainer gc) throws SlickException{
      playerBox.setCenterX(getPlayerX()+16); //Repositions it
      playerBox.setCenterY(getPlayerY()+16); //Repositions it
   }
}


Put this in an update() method somewhere, to update the locations of all those collision boxes you created:
1  
2  
3  
      for (int i = 0; i < mapParserArray.size(); i++) {
         mapParserArray.get(i).update(getMapX(),getMapY());
      }


..and finally, this is the intersect code to check if your player is overlapping a box.
1  
2  
3  
4  
5  
6  
   for (int i = 0; i < mapParserArray.size(); i++) {
      if(playerBox.intersects(mapParserArray.get(i).getCollisionBox())){
         //DON'T allow movement code here.
         break;
      }
   }


Note that this is all untested code, I just ripped it all out of a old program I made forever ago and removed anything unrelated. But at least it'll give you an idea on where to start rewriting the entire collision system if you want to go that route.

EDIT: Fixed a small code error

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #20 - Posted 2014-05-01 19:23:52 »

Ok, that seems to be the easiest in the long run. Just a quick question
1  
collisionBoxArray.add (new CollisionControl(x,y,mapX,mapY));

where does the mapX and mapY values come from?
Offline Rayvolution

JGO Kernel


Medals: 216
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #21 - Posted 2014-05-01 19:54:59 »

It's the current location of the exact top left corner of the entire map in relation to the screen/camera (not just the tiles you're rendering).

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #22 - Posted 2014-05-02 22:40:58 »

OK, i have the players collision box set up with a bit of modifying because of the camera code, and i can see it being drawn round the characters feet. I am having trouble working out how to find the mapX and mapY values though.
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #23 - Posted 2014-05-03 21:58:05 »

Ok, i have the collisions working from every direction. Stopping the player in the correct place and moving it backwards to stop it getting stuck. I just need help on how to get the maps coordinates, not the screens, at the moment the collisions are being drawn in the center of the screen. The tile x/y values are correct when i check the array
Offline Desbrina

Senior Newbie


Exp: 3 years



« Reply #24 - Posted 2014-05-04 22:15:15 »

Ok, this is what i have so far for the map class
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pokemon.statebased;

import java.util.HashMap;
import org.newdawn.slick.Animation;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;

/**
 *
 * @author Ceri
 */

public class MapClass {

    public TiledMap map;
    private static Camera camera;
    private final GameContainer gc;
    private HashMap<String, Animation> autos = new HashMap<>();
    public String mapName;

    public MapClass(String mapName, String file, GameContainer g) throws SlickException {
        this.mapName = mapName;
        map = new TiledMap(file);
        gc = g;
        //SpriteSheet flower = new SpriteSheet("Images/Animations/Flower.png", 16, 16);
        Animation flowerAnimation = new Animation();
        flowerAnimation.setAutoUpdate(true);
        /*flowerAnimation.addFrame(flower.getSprite(0, 0), 300);
         flowerAnimation.addFrame(flower.getSprite(1, 0), 300);
         flowerAnimation.addFrame(flower.getSprite(2, 0), 300);
         autos.put("Flower", flowerAnimation);*/

    }

    public int getMapX() {
        int tileOffset = camera.tileOffsetX;
        int x = tileOffset * 16;
        return x;
    }

    public int getMapY() {
        int tileOffset = camera.tileOffsetY;
        int y = tileOffset * 16;
        return y;
    }
   
    public void updateCollisions() throws SlickException
    {
        for (int i = 0; i < DataSingleton.getInstance().collisionBoxArray.size(); i++) {
            DataSingleton.getInstance().collisionBoxArray.get(i).update(getMapX(), getMapY());
        }
    }

    public void updateMap(TiledMap map) throws SlickException {
        this.map = map;
        this.updateCollisions();
    }

    public void drawAnimations() {
        Animation a = autos.get("Flower");
        a.drawFlash(210f, 222f, 16f, 16f);
    }

    public void setCamera(Camera c) throws SlickException {
        camera = c;
        this.collisions();
    }

    public void collisions() throws SlickException {
        for (int x = 0; x < map.getWidth(); x++) {
            for (int y = 0; y < map.getHeight(); y++) {
                int tileID = map.getTileId(x, y, 0);
                String value = map.getTileProperty(tileID, "blocked", "false");
                if ("true".equals(value)) {
                    DataSingleton.getInstance().collisionBoxArray.add(new CollisionControl(x, y, this.getMapX(), this.getMapY()));
                }
            }
        }
    }

    public void drawMap(int layer, Graphics g) throws SlickException {
        map.render(
                (camera.tileOffsetX + camera.offSetX),
                (camera.tileOffsetY + camera.offSetY),
                camera.tileIndexX,
                camera.tileIndexY,
                (gc.getWidth() - camera.tileOffsetX) / camera.tileWidth + 1,
                (gc.getHeight() - camera.tileOffsetY) / camera.tileHeight + 1, layer, false);
        //drawAnimations();
       
        this.updateCollisions();

        for (int i = 0; i < DataSingleton.getInstance().collisionBoxArray.size(); i++) {
            DataSingleton.getInstance().collisionBoxArray.get(i).render(g, this.getMapX(), this.getMapY());
        }
    }
}

The code for updating the collisions when the player moves


Now whats happening is the collision boxes are being drawn in the right place, but when the player moves they're not updating correctly, and if the player steps on the box its being ignored

This is what i mean
https://www.youtube.com/watch?v=hgCdD7o1r9Y
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (35 views)
2014-10-17 03:59:02

Norakomi (26 views)
2014-10-16 15:22:06

Norakomi (24 views)
2014-10-16 15:20:20

lcass (26 views)
2014-10-15 16:18:58

TehJavaDev (50 views)
2014-10-14 00:39:48

TehJavaDev (52 views)
2014-10-14 00:35:47

TehJavaDev (40 views)
2014-10-14 00:32:37

BurntPizza (63 views)
2014-10-11 23:24:42

BurntPizza (36 views)
2014-10-11 23:10:45

BurntPizza (76 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!