collision and found a bug in PointInPoly ?
Monkey Forums/Monkey Programming/collision and found a bug in PointInPoly ?
| ||
| As you probably already know, i'm busy with the png tracer bla bla. AND I solved IT a few days ago ! :) I'm testing it very good before i'm posting it. And yesterday I was testing the next step collision checks. And what happend was this: ![]() The method PointInPoly is a second collision option, not what I want for the main goal, but I can use that later. But it does not do what it says, or the Mouse coordinates are wrong ? When I touch a line from the left, it says its inside the verts[] (that wrong) When I touch a line from the right, it says its not inside the vers[] (that good) When the mouse is inside the verts[] is oke ! But behind that method I was searching for this function: If PointHitTheLineOrIsInsidePoly(MouseX(),MouseY(),verts) Then If PointInPoly(MouseX(),MouseY(),verts) Then hit = True Else hit = False End '' Found this at monkey forums, at several places Function PointInPoly:Bool(x:Float, y:Float, poly:Float[]) Local i:Int, j:Int, c:Bool Local v1:Bool, v2:Bool, v3:Bool, v4:Bool, v5#, v6#, v7# c = False Local p_count% = (poly.Length() / 2) For i = 0 To p_count-1 j = (i+1) Mod p_count v1 = (poly[i*2+1] <= y) v2 = (y < poly[j*2+1]) v3 = (poly[j*2+1] <= y) v4 = (y < poly[i*2+1]) v5 = (poly[j*2]-poly[i*2]) * (y-poly[i*2+1]) v6 = (poly[j*2+1]-poly[i*2+1]) If v6 = 0.0 Then v6 = 0.0001 v7 = poly[i*2] If (((v1 And v2) Or (v3 And v4)) And (x < v5 / v6 + v7)) Then c = Not c Next Return c End I can create lines from the points like this either. Function distanceToPoly:Bool(p:Point,points:Stack<Point>) 'For Local point:Point = Eachin points For Local i:Int = 0 Until points.Length()-1 Print distToSegment(p,points.Get(i),points.Get(i+1)) If distToSegment(p,points.Get(i),points.Get(i+1))<=0 Then Return True End Next Return False End Function distance:Float(x1:Int, y1:Int, x2:Int, y2:Int) Local x:Float=Sqrt(((x1 - x2)*(x1 - x2)) + ((y1 - y2)*(y1 - y2)) ) Return x End Function Function sqr:Float(x:Float) Return (x * x) End Function dist2:Float(v:Point, w:Point) Return sqr(v.x - w.x) + sqr(v.y - w.y) End ' p = point to check ' v = start point line ' w = end point line Function distToSegmentSquared:Float(p:Point, v:Point, w:Point) Local l2:Float = dist2(v, w) If (l2 = 0) Then Return dist2(p, v) End Local t:Float = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2 If (t < 0) Then Return dist2(p, v) End If (t > 1) Then Return dist2(p, w) End Return dist2(p, New Point(v.x + t * (w.x - v.x),v.y + t * (w.y - v.y) )) End Function distToSegment:Float(p:Point, v:Point, w:Point) Return Sqrt(distToSegmentSquared(p, v, w)) End edit: the blue line is a visual line, i'm checking against only the corner points that are inside the blue line. In this example there are 12 points that creating this figure. There are in counter / anti clockwise order |
| ||
| If you need a good PointInPoly, that works with concave polygons, you can use this: |
| ||
| Thanks, I will check this later today. I always wondering how people can create methods like this haha. |
| ||
| I think the one I posted originates form : http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html and http://paulbourke.net/geometry/polygonmesh/ |
| ||
| Your code is maybe working, but not now at the moment I think that there is something else that I have to check first. Because several other similar algorithms din't work either. So i'm going to take one step back and going to create a simple convex box, and hide the default cursor and use one pixel point as the cursor. That way I can exactly see in osx what the program does. And in the final game I want to hide the default cursor as well and make a custom one for the desktop target. I found this on the internet, but don't know how to get the variable window in osx at the moment. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); game programming is like solving one big puzzle haha |
| ||
| @GC-Martijn: A bit off topic, but use 'HideMouse'. If you want to do it directly, you could use 'SetMouseVisible' (Use "BBGame.Game()"). This is effectively the exact same thing as doing it natively. Finally, if you want to do it directly using GLFW3, you can use 'glfwSetInputMode' like this: I recommend doing it using Mojo or the standard BBGame functionality, though. |
| ||
| Thanks for the info, what I do is checking this page http://www.monkey-x.com/docs/html/Index.html using some keywords. Yesterday my keywords where: cursor & pointer haha HideMouse() is the thing I need ;) EDIT: @Difference The funny thing is that your code does the opposite what is oke, because I can use both methods to check if there is a collision. I have to rename them, and make one whole function from it, but its working ;) If PointInPoly(MouseX(),MouseY(),verts) Or IsInsidePoly(verts,MouseX(),MouseY()) Then hit = True Else hit = False End |
| ||
| @Difference The funny thing is that your code does the opposite what is oke, because I can use both methods to check if there is a collision. I made a test program for you below. IsInsidePoly() is behaving as it should. |
| ||
| @Differcence Nope, I tested the code again and its not working correct, but I made a fix. First hide the cursor and draw a dot, was helping me in osx because the cursor shadow din't show exactly where my mouse was. Then check all the lines , including the bottom corners (left and right) using your code, some bottom corners din't work, and some lines. check it with this code. I don't know how to optimize my polycheck more at the moment, but its working.= :)
Strict
Import mojo
Function Main:Int()
New MyApp
Return 0
End
Class MyApp Extends App
Field poly1:Float[26]
Field inside:int
Field hit:Bool
Method OnCreate:Int()
HideMouse()
poly1[0] = 22.0
poly1[1] = 130.0
poly1[2] = 31.0
poly1[3] = 130.0
poly1[4] = 31.0
poly1[5] = 45.0
poly1[6] = 210.0
poly1[7] = 45.0
poly1[8] = 210.0
poly1[9] = 130.0
poly1[10] = 219.0
poly1[11] = 130.0
poly1[12] = 219.0
poly1[13] = 45.0
poly1[14] = 240.0
poly1[15] = 45.0
poly1[16] = 240.0
poly1[17] = 1.0
poly1[18] = 1.0
poly1[19] = 1.0
poly1[20] = 1.0
poly1[21] = 45.0
poly1[22] = 22.0
poly1[23] = 45.0
poly1[24] = 22.0
poly1[25] = 129.0
Return 0
End
Method OnRender:Int()
Cls(255,255,255)
If hit Then
SetColor(255,0,0)
Else
SetColor(0,0,255)
End
Local n2:Int = poly1.Length - 2
For Local n:Int = 0 Until poly1.Length Step 2
DrawLine poly1[n2],poly1[n2+1],poly1[n],poly1[n+1]
n2 = n
Next n
SetColor(0,0,255)
DrawPoint(MouseX(),MouseY())
Return 0
End
Method OnUpdate:Int()
If KeyHit(KEY_SPACE) Then
EndApp()
End
If PolyCollision(poly1,MouseX(),MouseY()) Then
hit = True
Else
hit = False
End
Return 0
End
End
' not working if the cursor is on the right side on the line
Function IsInsidePoly:Int(polypoints:Float[],x:Float,y:Float)
Local j:Int = polypoints.Length()-2
Local oddNodes:Int
For Local i:Int =0 Until polypoints.Length() Step 2
If (polypoints[i+1]< y And polypoints[j+1]>=y ) Or (polypoints[j+1]< y And polypoints[i+1]>=y)
If (polypoints[i]<=x Or polypoints[j]<=x)
If (polypoints[i]+(y-polypoints[i+1])/(polypoints[j+1]-polypoints[i+1])*(polypoints[j]-polypoints[i])<x)
oddNodes = 1 ~ oddNodes
Endif
Endif
Endif
j=i
Next
Return oddNodes
End Function
' 0 = no collision
' 1 = line collion
' 2 = point inside
Function PolyCollision:Int(polypoints:Float[],x:Float,y:Float)
Local j:Int = polypoints.Length()-2
Local cn:Int = 0
Local cn2:Int = 0
For Local i:Int=0 Until polypoints.Length() Step 2
If i<=polypoints.Length()-3 And (((polypoints[i+1] <= y) And (polypoints[i+3] > y)) Or
((polypoints[i+1] > y) And (polypoints[i+3] <= y))) Then
Local vt:Float = (y - polypoints[i+1]) / (polypoints[i+3] - polypoints[i+1])
If (x < polypoints[i] + vt * (polypoints[i+2] - polypoints[i])) Then
cn = 1 ~ cn
End
Elseif (polypoints[i+1]<y And polypoints[j+1]>=y) Or (polypoints[j+1]< y And polypoints[i+1]>=y)
If (polypoints[i]<=x Or polypoints[j]<=x)
If (polypoints[i]+(y-polypoints[i+1])/(polypoints[j+1]-polypoints[i+1])*(polypoints[j]-polypoints[i])<x)
cn2 = 1 ~ cn2
Endif
Endif
End
' corners at the bottem
If polypoints[i]=x And polypoints[i+1]=y Then
cn = 1 ~ cn
End
j=i
Next
Return (cn&1)+(cn2&1)
End Function
|
