Finish Line end on intersection

Blitz3D Forums/Blitz3D Beginners Area/Finish Line end on intersection

If you look at my example code (no media) it will be clearer what i'm trying to do. I have a ball bounce around the screen, if i left-click a wall (or line) will start to expand outwards from the place where a clicked on the x axis. Same thing goes for right-clicking except it will expand on the y axis. Once the lines collide with the edge of the screen, they're set. If the lines aren't set the ball can break through them.
Now what i need is a way to determine if a wall collided with another wall, and then to set that side but continue the expansion of the other side until another collision if detect on that point.

Here's what ive got so far. Thanks for helping:

Graphics 800,600,32,2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

Type ball
	Field x,y
	Field xv,yv
End Type 

Type wall
	Field x,y,x2,y2
	Field wd,hg,placed1,placed2,axis ;(1 for x,2 for y)
End Type 

Setup()

While Not KeyDown(1)
	
	UpdateBalls()
	UpdateWalls()
	
	Draw()
	
Wend 
End 

Function Setup()
	
	b.ball=New ball
	b\x=Rand(100,700)
	b\y=Rand(100,500)
	b\xv=Rand(-5,5)
	b\yv=Rand(-5,5)
	
End Function

Function UpdateBalls()
	
	For b.ball=Each ball
		
		b\x=b\x+b\xv
		b\y=b\y+b\yv
		
		If b\x>=800 Then b\xv=-b\xv
		If b\x<=0 Then b\xv=-b\xv
		If b\y>=600 Then b\yv=-b\yv
		If b\y<=0 Then b\yv=-b\yv
		
		For w.wall=Each wall
		
			If LineOverlapCircle(w\x,w\y,w\x2,w\y2,b\x,b\y,5)=1 Then 
			If w\placed1=1 And w\placed2=1 Then 
			b\xv=-b\xv
			b\yv=-b\yv
			Else 
			Delete w
			Return 
			EndIf 
			EndIf 
				
		Next 
	Next 
	
End Function 

Function UpdateWalls()
	
p=GetMouse()

For w.wall=Each wall
		
		If w\placed1=0 And w\placed2=0
			If w\axis=1 Then 
				If Not w\x2>800 And w\placed2=0 Then w\x2=w\x2+2
				If Not w\x<0 And w\placed1=0 Then w\x=w\x-2
				If w\x<0 And w\x2>800 Then w\placed1=1:w\placed2=1
			Else 
				If Not w\y2>600 And w\placed2=0 Then w\y2=w\y2+2
				If Not w\y<0 And w\placed1=0 Then w\y=w\y-2
				If w\y<0 And w\y2>600 Then w\placed1=1:w\placed2=1
			EndIf 
			
			CheckWallCollisions()
			
		EndIf 
	
Next 

If MouseHit(1) Then 
		w.wall=New wall
		w\x=MouseX()
		w\y=MouseY()
		w\hg=1
		w\wd=1
		w\x2=MouseX()
		w\y2=MouseY()
	
		w\axis=1
		FlushMouse
		Return 
EndIf 
		
If MouseHit(2) Then 
		w.wall=New wall
		w\x=MouseX()
		w\y=MouseY()
		w\hg=1
		w\wd=1
		w\x2=MouseX()
		w\y2=MouseY()
		w\axis=2
		FlushMouse
		Return 
EndIf 

End Function

Function Draw()
Local draw

	Cls 
	
	For b.ball=Each ball
		Oval b\x,b\y,10,10,1
	Next 
	
	For w.wall=Each wall
		Line w\x,w\y,w\x2,w\y2
	Next 
	Flip
	
End Function 

Function LineOverlapCircle(x1#,y1#,x2#,y2#,cx#,cy#,Radius#)
	;'Calc Closest Point To circle center
	Local dx31#=cx#-x1#
	Local dx21#=x2#-x1#
	Local dy31#=cy#-y1#
	Local dy21#=y2#-y1#
	Local d#=((dx21#*dx21#)+(dy21#*dy21#))
	If d#<>0 Then d#=((dx31#*dx21#)+(dy31#*dy21#))/d#
	;'Clip To the line segments legal bounds
	If d#<0.0 Then d#=0
	If d#>1.0 Then d#=1
	Local dx#=cx#-(x1#+(dx21#*d#))
	Local dy#=cy#-(y1#+(dy21#*d#))
	If Radius# => Sqr((dx#*dx#)+(dy#*dy#))
		;'Line intersects circle
		Return 1 
	EndIf
	Return 0
End Function

Function linesIntersect(x1%,y1%, x2%,y2%, x3%,y3%, x4%,y4%)

	numeratorA#  = (x4-x3)*(y1-y3)-(y4-y3)*(x1-x3)
	numeratorB#  = (x2-x1)*(y1-y3)-(y2-y1)*(x1-x3)
	denominator# = (y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)

	If denominator = 0.0 Then
;		Text(10,20,"No intersection")
;		If numeratorA = 0.0 And numeratorB = 0.0 And denominator = 0.0 Then
;			Text(10,40,"Lines are coincident")
;		Else
;			Text(10,40,"Lines are parallel")
;		End If
		Return False
	Else
		Ua# = numeratorA/denominator
		Ub# = numeratorB/denominator
		range1% = Ua >= 0.0 And Ua <= 1.0
		range2% = Ub >= 0.0 And Ub <= 1.0
		If range1 And range2 Then
			intersectX% = Floor(x1 + Ua*(x2-x1)+.5)
			intersectY% = Floor(y1 + Ua*(y2-y1)+.5)
			Return True
		Else
;			Text(10,20,"No intersection")
			Return False
		End If
    End If
End Function

Function CheckWallCollisions()
End Function  


maybe if you create a ton of variables (within a type) holding the x values of each vertical line, and y value of each horizontal line, and say that if this line is complete then put it in the run for inter-line collisions. All inter-line collision runners will have their x and y (depending if they're vertical or horizontal) checked with the incomplete lines. It's kind of hard to explain. If the x of a vertical line is equal to the x of a horizontal line, then they are touching eachother. If the y of a horizontal line is equal to the y of a vertical line, then they are touching, and growth should stop. I didn't take time to look at your code, so this is all theoretical.

but how would you compare two of the same type against each other?
You can't do:
for w.wall=each wall
for w.wall=each wall
;check collisions
next 
next 


wait... or can you?

Graphics 800,600,32,2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

Type ball
	Field x,y
	Field xv,yv
End Type 

Type wall
	Field x,y,x2,y2,ox,oy
	Field wd,hg,placed1,placed2,axis ;(1 for x,2 for y)
End Type 

Setup()

While Not KeyDown(1)
	
	UpdateBalls()
	UpdateWalls()
	
	Draw()
	
Wend 
End 

Function Setup()
	
	b.ball=New ball
	b\x=Rand(100,700)
	b\y=Rand(100,500)
	b\xv=Rand(-5,5)
	b\yv=Rand(-5,5)
	
End Function

Function UpdateBalls()
	
	For b.ball=Each ball
		
		b\x=b\x+b\xv
		b\y=b\y+b\yv
		
		If b\x>=800 Then b\xv=-b\xv
		If b\x<=0 Then b\xv=-b\xv
		If b\y>=600 Then b\yv=-b\yv
		If b\y<=0 Then b\yv=-b\yv
		
		For w.wall=Each wall
		
			If LineOverlapCircle(w\x,w\y,w\x2,w\y2,b\x,b\y,5)=1 Then 
			If w\placed1=1 And w\placed2=1 Then 
			b\xv=-b\xv
			b\yv=-b\yv
			Else 
			Delete w
			Return 
			EndIf 
			EndIf 
				
		Next 
	Next 
	
End Function 

Function UpdateWalls()
	
p=GetMouse()

CheckWallCollisions()

For w.wall=Each wall
		
		If w\placed1=0 And w\placed2=0
			If w\axis=1 Then 
				If Not w\x2>800 And w\placed2=0 Then w\x2=w\x2+2
				If Not w\x<0 And w\placed1=0 Then w\x=w\x-2
				If w\x<0 And w\x2>800 Then w\placed1=1:w\placed2=1
			Else 
				If Not w\y2>600 And w\placed2=0 Then w\y2=w\y2+2
				If Not w\y<0 And w\placed1=0 Then w\y=w\y-2
				If w\y<0 And w\y2>600 Then w\placed1=1:w\placed2=1
			EndIf 
			
		
		EndIf 
	
Next 

If MouseHit(1) Then 
		w.wall=New wall
		w\x=MouseX()
		w\y=MouseY()
		w\hg=1
		w\wd=1
		w\x2=MouseX()
		w\y2=MouseY()
		w\ox=MouseX()
		w\oy=MouseY()
		w\axis=1
		FlushMouse
		Return 
EndIf 
		
If MouseHit(2) Then 
		w.wall=New wall
		w\x=MouseX()
		w\y=MouseY()
		w\hg=1
		w\wd=1
		w\x2=MouseX()
		w\y2=MouseY()
		w\axis=2
		FlushMouse
		Return 
EndIf 

End Function

Function Draw()
Local draw

	Cls 
	
	For b.ball=Each ball
		Oval b\x,b\y,10,10,1
	Next 
	
	For w.wall=Each wall
		Line w\x,w\y,w\x2,w\y2
	Next 
	Flip
	
End Function 

Function fLine(x,y,x1,y1,r=255,g=255,b=255)
; fLine will only draw horizonal or vertical lines, no diagonals
; Defaults to a white line.

argb=(b Or (g Shl 8) Or (r Shl 16) Or ($ff000000))

If x=x1
	If y>y1 Then t=y1:y1=y:y=t
	For n=y To y1
	WritePixel x,n,argb,BackBuffer()
	Next
EndIf

If y=y1
	If x>x1 Then t=x1:x1=x:x=t
	For n=x To x1
	WritePixel n,y,argb,BackBuffer()
	Next
EndIf 
End Function

Function LineOverlapCircle(x1#,y1#,x2#,y2#,cx#,cy#,Radius#)
	;'Calc Closest Point To circle center
	Local dx31#=cx#-x1#
	Local dx21#=x2#-x1#
	Local dy31#=cy#-y1#
	Local dy21#=y2#-y1#
	Local d#=((dx21#*dx21#)+(dy21#*dy21#))
	If d#<>0 Then d#=((dx31#*dx21#)+(dy31#*dy21#))/d#
	;'Clip To the line segments legal bounds
	If d#<0.0 Then d#=0
	If d#>1.0 Then d#=1
	Local dx#=cx#-(x1#+(dx21#*d#))
	Local dy#=cy#-(y1#+(dy21#*d#))
	If Radius# => Sqr((dx#*dx#)+(dy#*dy#))
		;'Line intersects circle
		Return 1 
	EndIf
	Return 0
End Function

Function linesIntersect(x1%,y1%, x2%,y2%, x3%,y3%, x4%,y4%)

	numeratorA#  = (x4-x3)*(y1-y3)-(y4-y3)*(x1-x3)
	numeratorB#  = (x2-x1)*(y1-y3)-(y2-y1)*(x1-x3)
	denominator# = (y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)

	If denominator = 0.0 Then
;		Text(10,20,"No intersection")
;		If numeratorA = 0.0 And numeratorB = 0.0 And denominator = 0.0 Then
;			Text(10,40,"Lines are coincident")
;		Else
;			Text(10,40,"Lines are parallel")
;		End If
		Return False
	Else
		Ua# = numeratorA/denominator
		Ub# = numeratorB/denominator
		range1% = Ua >= 0.0 And Ua <= 1.0
		range2% = Ub >= 0.0 And Ub <= 1.0
		If range1 And range2 Then
			intersectX% = Floor(x1 + Ua*(x2-x1)+.5)
			intersectY% = Floor(y1 + Ua*(y2-y1)+.5)
			Return True
		Else
;			Text(10,20,"No intersection")
			Return False
		End If
    End If
End Function

Function CheckWallCollisions()
Local x,y,axis,x2,y2

For w.wall=Each wall

x=w\x
y=w\y
axis=w\axis
x2=w\x2
y2=w\y2

For w.wall=Each wall

If w<>Null

If w\axis<>axis

	If w\axis=1 Then 
	If axis=2 Then 
	If w\x=x Or w\x=x-1 Or w\x=x+1 Then 
	w\placed1=1
	If w\x2=x2 Or w\x2=x2-1 Or w\x2=x2+1 Then 
	w\placed2=1
	EndIf 
	EndIf 
	EndIf 
	Else If axis=2 Then 
	If w\y=y Or w\y=y-1 Or w\y=y+1 Then 
	w\placed1=1
	If w\y2=y2 Or w\y2=y2-1 Or w\y2=y2+1 Then 
	w\placed2=1
	EndIf
	EndIf 
	EndIf 

EndIf 

EndIf 

Next 

Next 

End Function  


what's the problem with this? I get a memory access in debug mode.

I'm guessing your problem is re-using the 'w' variable in the nested loop. In your second loop use for v.wall = each wall and check that v <> w before proceeding.

p.s. A bit of indentation wouldn't go a miss!!!

ok, great! its kinda working now. But both sides stop once a collision is registered...
updated (and somewhat indented) code:

Function CheckWallCollisions()
Local x,y,axis,x2,y2

For v.wall=Each wall

x=v\x
y=v\y
axis=v\axis
x2=v\x2
y2=v\y2

For w.wall=Each wall

If w<>v

If w\axis<>axis

	If w\axis=1 Then 
	   If axis=2 Then 
	   If w\x=x Or w\x=x-1 Or w\x=x+1 Then 
	   w\placed1=1
	   If w\x2=x2 Or w\x2=x2-1 Or w\x2=x2+1 Then 
	   w\placed2=1
	   EndIf 
	   EndIf 
	   EndIf 
	Else If w\axis=2 Then 
	   If w\y=y Or w\y=y-1 Or w\y=y+1 Then 
	   w\placed1=1
	   If w\y2=y2 Or w\y2=y2-1 Or w\y2=y2+1 Then 
 	   w\placed2=1
	   EndIf
	   EndIf 
	   EndIf 

        EndIf 

EndIf 

Next 

Next 

End Function  


It seems like the collision data isn't cleared once the line is destroyed by the ball, seeing that growing lines will stop dead without colliding into anything.

i deleted the type instance. What more can i do?

Is there something i'm not getting about 2d collisions?

fuller wrote:
but how would you compare two of the same type against each other?

its really simple to compare a type against another u just simply upload it to a regular variable:
for bullet.bullet = each bullet
drawimage(bullet_image,bullet\x,bullet\y)
if imagescollide(bullet_image,bullet\x,bullet\y,bullet_image,bulletx,bullety)
print  "collision!"
endif
bullet\x=bulletx
bullet\y=bullety
next


ok, i got that now. But the lines are still colliding with the other already gone lines.


for bullet.bullet = each bullet
drawimage(bullet_image,bullet\x,bullet\y)
if imagescollide(bullet_image,bullet\x,bullet\y,bullet_image,bulletx,bullety)
print "collision!"
endif
bullet\x=bulletx
bullet\y=bullety
next



That's a pretty bad example as your only comparing the previous bullet coords to the current.

For b.bullet = Each bullet
	c.bullet = b
	While c <> Last bullet
		c = After c
		If ImagesCollide( bullet_image, b\x, b\y, Frame, bullet_image, c\x, c\y, Frame )
			;Handle collision
		EndIf
	Wend
Next


This method ensures that you only check each pair once.

@ Fuller, If you want help with your routines - post what code you have.

Stevie

ok, thank you:
Graphics 800,600,32,2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

Type ball
	Field x,y
	Field xv,yv
End Type 

Type wall
	Field x,y,x2,y2,ox,oy
	Field wd,hg,placed1,placed2,axis ;(1 for x,2 for y)
End Type 

Type block
Field x,y,x2,y2,w,h,placed,cont
End Type 

Global onone=0
Global ballsin=0

Setup()

While Not KeyDown(1)
	
	UpdateBalls()
	UpdateWalls()
	UpdateBlocks()
	
	Draw()
	
Wend 
End 

Function Setup()
	
	b.ball=New ball
	b\x=Rand(100,700)
	b\y=Rand(100,500)
	b\xv=Rand(-5,5)
	b\yv=Rand(-5,5)
	
End Function

Function UpdateBlocks()

If Not onone=1 Then 
If KeyHit(57)
	bl.block=New block
	bl\x=MouseX()
	bl\y=MouseY()
	bl\x2=MouseX()+1
	bl\y2=MouseY()+1
	onone=1
EndIf 
Else
If KeyHit(57) Then 
For bl.block=Each block
	bl\placed=1
	onone=0
Next 
EndIf 
EndIf 

For bl.block=Each block

If bl\placed<>1 Then
bl\x2=MouseX()
bl\y2=MouseY()
bl\w=bl\x2-bl\x
bl\h=bl\y2-bl\y
EndIf 

If bl\placed=1 Then 
	
ballsin=0
	
For b.ball=Each ball

If b\x>bl\x And b\x<bl\x2 And b\y>bl\y And b\y<bl\y2 Then 
If bl\cont=0 Then bl\cont=1
ballsin=ballsin+1
EndIf 

Next 

EndIf 

Next 

End Function 

Function UpdateBalls()
	
	For b.ball=Each ball
		
		b\x=b\x+b\xv
		b\y=b\y+b\yv
		
		If b\x>=800 Then b\xv=-b\xv
		If b\x<=0 Then b\xv=-b\xv
		If b\y>=600 Then b\yv=-b\yv
		If b\y<=0 Then b\yv=-b\yv
		
		For w.wall=Each wall
		
			If LineOverlapCircle(w\x,w\y,w\x2,w\y2,b\x,b\y,5)=1 Then 
			If w\placed1=1 And w\placed2=1 Then 
			b\xv=-b\xv
			b\yv=-b\yv
			Else 
			Delete w
			Return 
			EndIf 
			EndIf 
				
		Next 
	Next 
	
End Function 

Function UpdateWalls()
	
p=GetMouse()

CheckWallCollisions()

For w.wall=Each wall
		
		If w\placed1=0 Or w\placed2=0
			If w\axis=1 Then 
				If Not w\x2>800 And w\placed2=0 Then w\x2=w\x2+1
				If Not w\x<0 And w\placed1=0 Then w\x=w\x-1
				If w\x<0 Then w\placed1=1 
				If w\x2>800 Then w\placed2=1
			Else 
				If Not w\y2>600 And w\placed2=0 Then w\y2=w\y2+1
				If Not w\y<0 And w\placed1=0 Then w\y=w\y-1
				If w\y<0 Then w\placed1=1 
				If w\y2>800 Then w\placed2=1
			EndIf 
			
		
		EndIf 
	
Next 

If MouseHit(1) Then 
		w.wall=New wall
		w\x=MouseX()
		w\y=MouseY()
		w\hg=1
		w\wd=1
		w\x2=MouseX()
		w\y2=MouseY()
		w\ox=MouseX()
		w\oy=MouseY()
		w\axis=1
		FlushMouse
		Return 
EndIf 
		
If MouseHit(2) Then 
		w.wall=New wall
		w\x=MouseX()
		w\y=MouseY()
		w\hg=1
		w\wd=1
		w\x2=MouseX()
		w\y2=MouseY()
		w\axis=2
		FlushMouse
		Return 
EndIf 

End Function

Function Draw()
Local Draw

	Cls 
	
	For b.ball=Each ball
		Oval b\x,b\y,10,10,1
	Next 
	
	For w.wall=Each wall
		Line w\x,w\y,w\x2,w\y2
	Next 
	
	For bl.block=Each block
	Color 255,0,0
	Rect bl\x,bl\y,bl\w,bl\h,0
	Color 255,255,255
	Next 
	
	Text 0,0,ballsin
	Flip
	
End Function 

Function fLine(x,y,x1,y1,r=255,g=255,b=255)
; fLine will only draw horizonal or vertical lines, no diagonals
; Defaults to a white line.

argb=(b Or (g Shl 8) Or (r Shl 16) Or ($ff000000))

If x=x1
	If y>y1 Then t=y1:y1=y:y=t
	For n=y To y1
	WritePixel x,n,argb,BackBuffer()
	Next
EndIf

If y=y1
	If x>x1 Then t=x1:x1=x:x=t
	For n=x To x1
	WritePixel n,y,argb,BackBuffer()
	Next
EndIf 
End Function

Function LineOverlapCircle(x1#,y1#,x2#,y2#,cx#,cy#,Radius#)
	;'Calc Closest Point To circle center
	Local dx31#=cx#-x1#
	Local dx21#=x2#-x1#
	Local dy31#=cy#-y1#
	Local dy21#=y2#-y1#
	Local d#=((dx21#*dx21#)+(dy21#*dy21#))
	If d#<>0 Then d#=((dx31#*dx21#)+(dy31#*dy21#))/d#
	;'Clip To the line segments legal bounds
	If d#<0.0 Then d#=0
	If d#>1.0 Then d#=1
	Local dx#=cx#-(x1#+(dx21#*d#))
	Local dy#=cy#-(y1#+(dy21#*d#))
	If Radius# => Sqr((dx#*dx#)+(dy#*dy#))
		;'Line intersects circle
		Return 1 
	EndIf
	Return 0
End Function

Function linesIntersect(x1%,y1%, x2%,y2%, x3%,y3%, x4%,y4%)

	numeratorA#  = (x4-x3)*(y1-y3)-(y4-y3)*(x1-x3)
	numeratorB#  = (x2-x1)*(y1-y3)-(y2-y1)*(x1-x3)
	denominator# = (y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)

	If denominator = 0.0 Then
;		Text(10,20,"No intersection")
;		If numeratorA = 0.0 And numeratorB = 0.0 And denominator = 0.0 Then
;			Text(10,40,"Lines are coincident")
;		Else
;			Text(10,40,"Lines are parallel")
;		End If
		Return False
	Else
		Ua# = numeratorA/denominator
		Ub# = numeratorB/denominator
		range1% = Ua >= 0.0 And Ua <= 1.0
		range2% = Ub >= 0.0 And Ub <= 1.0
		If range1 And range2 Then
			intersectX% = Floor(x1 + Ua*(x2-x1)+.5)
			intersectY% = Floor(y1 + Ua*(y2-y1)+.5)
			Return True
		Else
;			Text(10,20,"No intersection")
			Return False
		End If
    End If
End Function

Function CheckWallCollisions()
Local x,y,axis,x2,y2

For v.wall=Each wall

x=v\x
y=v\y
axis=v\axis
x2=v\x2
y2=v\y2

For w.wall=Each wall

If v<>w
	
	If w<>Null
	
If w\axis<>axis

	If w\axis=1 Then 
		If axis=2 Then 
			If w\x=x Or w\x=x Or w\x=x Then w\placed1=1
			If w\x2=x2 Or w\x2=x2 Or w\x2=x2 Then w\placed2=1
		EndIf 
	Else If w\axis=2 Then 
		If axis=1 Then 
			If w\y=y=y Or w\y=y Or w\y=y Then w\placed1=1
			If w\y2=y2 Or w\y2=y2 Or w\y2=y2 Then w\placed2=1
		EndIf 
	EndIf 
	
EndIf 

EndIf 

EndIf 

Next 

Next 

End Function  
;~IDEal Editor Parameters:
;~F#B1#C9#DE#F2
;~C#Blitz3D



And here's a diagram of what i'm trying to achieve: