Hello Guest

Author Topic: GetTileAtPositon reporting strange results  (Read 7413 times)

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
GetTileAtPositon reporting strange results
« on: April 08, 2015, 10:35:43 pm »
I am currently performing a ray cast from a character towards the mouse, checking the position of the raycast hit, running that position through GetTileAtPosition, then removing the tile that is at the reported coordinates.

If I know the ray is hitting the top of the tile (8,0) and each tile is 1 world unit by 1 world unit and my collision is reporting it hit at coordinates ( 7.5, 1.0, 0.0) and I pass that vector through GetTileAPosition most of the time I get tile (8,1) which I don't want. I sort of get it though, the tile takes up the space from (7.00 to 7.99, 0.00 to .99) or something similar so hitting the top of the tile (8,0) hits at world y coordinate 1.0 so GetTileAtPosition thinks it is hitting the tile above what I actually hit. This is a problem by itself and is made worse by the fact every now and then the hit will still be at (7.5, 1.0, 0.0) and GetTileAtPosition actually returns 8,0 and deletes the tile I want.

EDIT - even though the hit is reporting 7.5, 1.0, 0.0 the float values are actually a little different. So a raycast that reports it hit (7.5, 1.0, 0) might actually hit (7.5, .93215, 0). Another time a hit reporting (7.5, 1.0, 0) might have float values at (7.5, .9501 0.0).

I tested a little more and for that occasional time when the tile I want to delete is deleted, the GetTileFRACAatPosition is returning .999999 as they y. When it is not deleting the one I want it is returning 1.

It just happens certain raycasts will report a hit at a vector that if passed through GetTileFRACAtPosition will report for the example above a Y value .999999 even while almost any other hit on that tile will report a Y of 1.0.

So whenever I hit the top of a tile or the right side of the tile 99% of the time when I get the vector of the raycasthit and pass it through a GetTileAtPosition or GetTileFracAtPosition it reports the tile either above what I hit or the tile to the right of what I hit.
« Last Edit: April 09, 2015, 01:03:12 am by woca »

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #1 on: April 12, 2015, 10:11:16 pm »
Anyone have any idea or run into this issue? It's frustrating hitting the top or right of a collider and having the GetTileAt functions return the tile above or to the right of the tile hit. Any help with this would be great.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #2 on: April 12, 2015, 11:32:06 pm »
You could take the tile frac and process it the way you want it to behave. eg, add a larger window, or wrap around at the center of the tile vs the borders. That should help get the results you want from this.

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #3 on: April 13, 2015, 07:59:08 am »
My post might have been poorly worded. There is really two problems.

First is if a tile has a collider around it, a raycast that hits the right of the tile or the top of the tile reports a position that if passed through either GetTileAt functions will report the tile to the right or above the tile hit.

The second issue is that that last issue actually only happens at the vast majority of possible angles. Occasionally a raycast that hits the right or top of a tile will report a position that if passed through either GetTileAt functions reports the tile that was hit.

If I'm hitting the farthest right tile on my tilemap and hitting it's right side, 99% of the time both GetTileAt functions will return false. Then once in a while I'm at an OK spot such that the raycast goes and hits and the hit vector when passed through GetTileAt functions returns true.

Currently when I raycast I test if my the raycast start postion is above or to the right of the raycast hit position. If so I adjust the raycast hit vector so it is a little bit left and a little bit further down so I can pass the vector to GetTileAt functions and have it return the proper tile. Well once a tilemap starts to rotate this solution isn't viable. I haven't sat down and worked out the geometry, I'm hoping some sin and cos math based on the angle of rotation will solve this.

I'm not sure how to deal with this in terms of what to do with Tk2D or if there is anything you can do to help prevent this issue. I don't understand enough about Unity's engine and how it handles space. Is a tile that is 1 world unit by 1 world that has its bottom left at the origin taking up (0,0) to (1,1) or is it at (0,0) to (.9999999999, .999999999)

I can troubleshoot this more if you need more information or want more clear examples. I can set up a demo scene if needed. I just see this as a serious issue and was hoping that either others ran into it or it was something on my end and I could feedback here. I am a little shocked if the two issues I pointed out exist for all tk2d games because I haven't seen posts about it.

I hope this doesn't sound like a complaint about tk2d, it is great. If I have to work out a function that takes raycast hits and makes sure the hit vector is actually going to report the tile hit that is OK. I just was hoping to figure out the problem here, whether it is was with 2ktd or unity or with the way i made the map.



I was just testing some more and had a GetTileAt report Y as 8(I cleared the log and lost actual number) and GetTileAtFrac reported the Y as 9 flat.



« Last Edit: April 13, 2015, 08:19:55 am by woca »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #4 on: April 13, 2015, 09:09:36 am »
Quote
I was just testing some more and had a GetTileAt report Y as 8(I cleared the log and lost actual number) and GetTileAtFrac reported the Y as 9 flat.

This is impossible, GetTileAt uses GetTileAtFrac and simply drops the fractional bit. GetTileAt will return the tile rounded down. As I mentioned, you might get better results for your use case if you round.

If you're using raycasts - make sure you're not using a perspective camera, and if you are and you're using 3d colliders, make sure they're really really thin.

GetTileAtFrac is really really accurate - I'd expect it to be far more accurate than physics. If a tile is at 0..1, then yes anything less than 1 (its floating point so the usual stuff about that applies) is considered in that tile as far as GetTile is concerned.

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #5 on: April 13, 2015, 09:38:42 am »
Unfortunately it is possible and here is a photo of the log and the code. Camera is orthographic and as for colliders, they are 3D and polygons so that the top can be hit so it works with A* PathFinding Project.

I have the map under a parent object and the parent is rotated 90 on the X axis

http://imgur.com/xbfP5NG

Code: [Select]
//mouse temp is mouse position, the ray is shot from the character to the mouse
Vector3 dir = mouseTemp - character.transform.position;

RaycastHit hit;
if (Physics.Raycast (character.transform.position, dir, out hit, 1000)) {

Debug.Log ("Raycast collision detected");

Vector3 rayc = hit.point;

foreach (tk2dTileMap s in maps) {
Debug.Log (s.name);
int x;
int z;
float jx;
float jy;

                                        //these for loops are my temporary solution I was talking about, not in use now though
if (rayc.x < character.transform.position.x) {
//rayc.x = rayc.x - (float).001;
}
if (rayc.z < character.transform.position.z) {
//rayc.z = rayc.z - (float).001;
}

if (s.GetTileAtPosition (rayc, out x, out z)) {
                                                //Show the coordinates of the raycast hit position
Debug.Log ("rayc x " + rayc.x);
Debug.Log ("rayc y " + rayc.y);
Debug.Log ("rayc z " + rayc.z);
                                               
                                                //show the coordinates of the tile map
Debug.Log("X " + x);
Debug.Log("Y " + z);

                                                //show the coordinates of the tile map
if(s.GetTileFracAtPosition(rayc,out jx ,out jy)){

Debug.Log("JX " + jx + "\nJY " + jy);

}
}
}
« Last Edit: April 13, 2015, 09:46:34 am by woca »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #6 on: April 13, 2015, 09:49:36 am »
Quote
   public bool GetTileAtPosition(Vector3 position, out int x, out int y)
   {
      float ox, oy;
      bool b = GetTileFracAtPosition(position, out ox, out oy);
      x = (int)ox;
      y = (int)oy;
      return b;
   }

GetTileAtPosition simply calls GetTileFracAtPosition.
If they differ, its because Debug.Log is rounding differently.

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #7 on: April 13, 2015, 10:04:22 am »
OK, that issue aside, I still have the problem of when I hit the top of a tile or the right of a tile passing that raycast hit's vector through either GetTileAt function returns the tile on top of or to the right of the tile I hit.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #8 on: April 13, 2015, 10:56:10 am »
How are you doing raycasts? are you using 2d or 3d colliders? perspective? I also don't understand the issue - surely you interpret GetTileAtFrac to suit your needs. Simply rounding  based on 0.5f should make the difference.

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #9 on: April 13, 2015, 12:21:48 pm »
All the codes is below. I am using 3D Polygon colliders that cover the entire tile. Camera is orthographic.

Here is an album showing the issue. And it got weirder - most of the time I have the issue when hitting the right side of a tile or the top of a tile. Well in this example I set up that was supposed to show the issue when hitting the right side of a tile I had the problem hitting the left side of the tile and hitting the right side worked fine.

16 pixels per unit. Each tile is 16 pixels. The tilemap is a child of an object and that object is rotated 90 on x axis.

rayc is the vector of the raycast hit
rayc.x
rayc.y - this is 0 each time because I rotated the parent on the X axis 90 degrees
rayc.z

X - the x value returned from GetTileAtPosition(rayc)
Y - the y value returned from GetTileAtPosition(rayc)

fracX - the float x value returned from GetTileAtFracPosition(rayc)
fracY - the float y value returned from GetTileAtFracPosition(rayc)



Image 1 - Shows the setup before any raycasting. I will first raycast at (0,0)

Image 2 - After 5 hits on the right part of the tile, the tile is removed. I have a class that gives each tile health based on the tile ID and it's coordinates on the tilemap. So tile (0,0) has 5 health, so does tile (5,0) which will be hit next. The log shows 5 of the same message, I raycasted 5 times, hit the block 5 times, and then the block was set to a white tile and the map was rebuilt.

Image 3 - I am raycasting towards tile (5,0) and in the log you can see the rayc.x is 5, X is 4, fracX is 5. I use the X value, not the fracX value, when identifying the tile to remove health from. So this is not a debugger rounding error. You can see that I tried raycasting 58 times and still the tile was there.

Image 4 - Remember how I said there were two issues? Issue one was the GetTileAtPosition returning the wrong thing. Issue 2 was that 99% of the time the wrong thing is returned. Well around 150 raycasts later (you can see the number of collapsed logs at 178) I got the right coordinates 5 times and the tile was removed. So really 97% of the time I am getting the wrong value.


So there it is documented. And it is strange because this time the issue was hitting the left side of a tile, not hitting the right side of a tile. I did not test hitting the top or bottom of a tile.

The code below is what is used. You can see how I got all the Debog Logs. Also, you can see that the health section is at the bottom and I use the values from GetTileAtPosition and it returns the X value as int X and the Y value as int y.

Code: [Select]
if (Input.GetMouseButtonDown (0)) {
Debug.Log ("Raycast try");
Vector3 dir = mouseTemp - character.transform.position;

RaycastHit hit;


if (Physics.Raycast (character.transform.position, dir, out hit, 1000)) {

Debug.Log ("Raycast collision detected");

Vector3 rayc = hit.point;


int k = -1;

foreach (tk2dTileMap s in maps) {
Debug.Log (s.name);
k = k + 1;
int x;
int y;
float jx;
float jy;

if (s.GetTileAtPosition (rayc, out x, out y)) {

Debug.Log ("rayc x " + rayc.x);
Debug.Log ("rayc y " + rayc.y);
Debug.Log ("rayc z " + rayc.z);

if(s.GetTileFracAtPosition(rayc,out jx ,out jy)){
Debug.Log("X " + x+"\nY " + y);
Debug.Log("\nfracX " + jx + "\nfracY " + jy);
Debug.Log("\nfracY " + jy);
}

int health = tij [k].tilehealth [new Vector2 (x, y)] - 1;
if (tij [k].tilehealth [new Vector2 (x, y)] == 1) {
s.SetTile (x, y, 0, 57);
s.Build ();
}
if (tij [k].tilehealth [new Vector2 (x, y)] > 1) {
tij [k].tilehealth [new Vector2 (x, y)] = health;

}

}

}
}
}
« Last Edit: April 13, 2015, 12:37:21 pm by woca »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #10 on: April 13, 2015, 01:18:40 pm »
You're raycasting from the top of a tile down (on the XY plane), the likelihood is the floating point value of the hit result will be above the tile by a tiny fraction and will end up in the tile above, or above right's space. Your raycast is returning incorrect values - you will need to project your raycast result forward to more accurately get the correct tile hit. As I said before, physics raycasts are not particularly accurate.

Debug.Logs round the values, they're not very useful in situations like these unless you ToString("0.00000000").

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #11 on: April 13, 2015, 10:08:20 pm »
I did the Debug.Log and formatted the strings so it had like 30 extra characters on the float and still had the same results. I tried passing rayc.x and fracX through mathf.floor and this showed the fraction was 4.something

Originally the log would show the formatted strings as
rayc.x 5.000000000000000000000000
x 4
fracX 5.0000000000000000000000000

Using mathf.floor on rayc.x and fracX
rayc.x 4.000000000000000000000000
x 4
fracX 4.0000000000000000000000000

So that issue is with the debugger. I don't know what it is doing with its rounding.

I was also no longer using the mouse and character for the raycast. I generated the direction from set vectors

Vector3 xj =new Vector3((float)(.5),0,(float).5);
Vector3 yh = new Vector3((float)8.5,0,(float).5);


Here is a picture

So right now if this is just a raycast issue still my plan is to take the normal of the hit and then reverse it and move in that direction a little. Now if the tilemap rotates I should still get the right tile.
« Last Edit: April 13, 2015, 10:19:46 pm by woca »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #12 on: April 13, 2015, 11:04:41 pm »
Quote
So right now if this is just a raycast issue still my plan is to take the normal of the hit and then reverse it and move in that direction a little. Now if the tilemap rotates I should still get the right tile.
Yes, you'll need to do something like that if you want to rely on raycast.

woca

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: GetTileAtPositon reporting strange results
« Reply #13 on: April 13, 2015, 11:13:36 pm »
Changing the ray based on the normal worked.

And I learned the debugger is an awful liar for no reason! I am still confused by it showing the rounded result even doing the .ToString(format) with a format asking for 70 characters after the decimal.

Thanks for all the help!
« Last Edit: April 13, 2015, 11:32:02 pm by woca »