Main Menu

Ray To Sprite Intersection

Started by kevin, July 27, 2005, 09:00:33 AM

Previous topic - Next topic

kevin

  Well another day another new command/feature.  RayHitSprite allows you check for intersections between a rays and a sprite.

The pic shows the ray intersecting the sprites assigned shape.  The command returns if an impact has occurred, plus the impact point to the user.   This could be used to bounce objects off sprites perhaps, create particles etc etc.. Whatever you can dream up.

Note: Code for PlayBASIC V1.083   (command params will probably change)





; ---------------------------------------------------------------------
;                   Detecting Ray To Sprite Intersections
; ---------------------------------------------------------------------
 SetFPS 60
 MakeBitmapFont 1,$ffffff


; Make a Green image
Cls $00ff00
GetImage 1,0,0,30,30
  preparefximage 1

; Create Two convex shapes,
CreateConvexShape 2,50,15
CreateConvexShape 3,30,15

; Merge Them to create a 'ring'
Mergeshape 3,2
ShiftShape 2,50,50
resizeshape 2,100,100
  CopyShape 2,1

; Create a second image
CreateImage 2,100,100

; tell PB to redirect all drawing to this image
RenderToImage 2
; clear it to the BLUE
cls $ff
; draw the previously created Ring shape to the
ink $223322
DrawShape 2,0,0,2
imagemaskcolour 2,Rgb(0,0,255)

; Randomly Draw 10,000 pixels, but only inside the shape
#trace off
lockbuffer  
 For lp =0 to 10000
  x#=rnd(GetImagewidth(2))
  y#=rnd(GetImagewidth(2))
  if pointhitshape(x#,y#,2,0,0)
   boxc x#,y#,x#+1,y#+1,1,rndrgb()
  endif  
 next
unlockbuffer
#trace on

;  prepare image #2 as FX iamge
preparefximage 2

; Tell PB to direct all drawing back to the screen
rendertoscreen

; Assign Shape #2, to Image #2
ImageShape 2,2


; Get the Width/height of screen
sw=getscreenwidth()
sh=getscreenHeight()

 
 
; Create a bunch of randomly positioned sprites
MaxSprites=25


RayX1#=rnd(getScreenwidth())
RayY1#=rnd(getScreenHeight())


; =====================================
; Start of the Main DO/LOOp
; =====================================

Do
 ; Clear the Screen to black
Cls FlashColour
ink $ffffff


If InitSprites=0
 InitSprites=true
 For lp=1 to MaxSprites
    ; CReate this sprite
  CreateSprite lp
    ; Assign Image #2 to this sprite
  SpriteIMage lp,2
    ; Set Sprites Draw Mode to Rotated
  SpriteDRawMode lp,2

     ; Enable Sprite Collision For this sprite
  SpriteCollision lp,true
     ; Enable this Sprites Collsion Class (the class/group it belong too)
  SpriteCollisionClass lp,3
    ; Set this sprites Collision mode to "SHAPE"
   ;  When in Shpe mode, PB uses the current assigned shape of it's image  
  SpriteCollisionMode lp,3

  SpriteFlashColour lp,rndrgb()
 ;Randomly Enable Sprite Collision Debug Mode      
;   SpriteCollisionDebug lp,true
  centerspritehandle lp
   ; Randomly Position this sprite on the screen
  PositionSpriteXYZ LP,Rnd(sw),rnd(sh),100

  ScaleSprite lp,0.50+(Rnd(150)/100)
 next
endif
 



  ; Run through and Turn/Rotate all the sprites
 For lp=1 to MaxSprites
  turnsprite lp,1+(lp*0.12)
  spritedrawmode lp,2
 
 next


; Draw all the sprites
 DrawOrderedSprites


; Display a message
Print "Ray To Sprite Intersection "


  ; Check If the Users Sprite Has Hit any of the rotating sprites
 T1=timer()
 ThisSprite=GetFirstSprite()
 HitCount=0

 Rayx2#=mousex()
 Rayy2#=mousey()
 
 Collision=0  
  repeat
   if RayHitSprite(rayx1#,rayy1#,rayx2#,rayy2#,ThisSprite)
    Collision=true
    rayx2#=Getintersectx#(0)
    rayy2#=Getintersecty#(0)
   endif
   ThisSprite=GetNextSprite(ThisSprite)
  until ThisSprite=0

  capturedepth 10

 line rayx1#,rayy1#,rayx2#,rayy2#
 
 if Collision
  circlec rayx2#,rayy2#,10,1,rgb(255,0,0)  
 endif
 

 T2=timer()
 t=t2-t1

 inc frames
 at#=at#+t
 print "Time:"+str$(at#/frames)


 if timer()>InputDelay
  If FunctionKeys(1)
   For lp=2 to MaxSprites
    spritecollisiondebug lp,1-getspritecollisiondebug(lp)
   next
   INputdelay=timer()+100
  endif

  If FunctionKeys(2)    
   For lp=2 to MaxSprites
    spritetransparent lp,1-getspritetransparent(lp)
   next
   INputdelay=timer()+100
  endif

  if Spacekey()
    InitSprites=false
    INputdelay=timer()+100
  endif
 endif


 
 if mousebutton()
  RayX1#=mousex()
  RayY1#=Mousey()
 endif



; Show the Screen
Sync

; Loop back to the previous DO statement to keep the demo running
loop





kevin

#1
Still working my way through this.  Had to update the Ray to circle intersection code today, since the version was too buggy.   But now that's all fixed and working very well.

This picture is of a little ray trace styled function. The user draws a line and the line will then bounce off anything it hits.  This is limited to 25 rebounds though.    But that's a enough to see the effect in action


Will post a demo later.  





; ---------------------------------------------------------------------
;                   Detecting Ray To Sprite Intersections
; ---------------------------------------------------------------------
;  SetFPS 60
 MakeBitmapFont 1,$ffffff


; Make a Green image
Cls $00ff00
GetImage 1,0,0,30,30
  preparefximage 1

; Create Two convex shapes,
CreateConvexShape 2,50,15
CreateConvexShape 3,30,15

; Merge Them to create a 'ring'
Mergeshape 3,2
ShiftShape 2,50,50
resizeshape 2,100,100
  CopyShape 2,1

; Create a second image
CreateImage 2,100,100

; tell PB to redirect all drawing to this image
RenderToImage 2
; clear it to the BLUE
cls $ff
; draw the previously created Ring shape to the
ink $223322
DrawShape 2,0,0,2
imagemaskcolour 2,Rgb(0,0,255)

; Randomly Draw 10,000 pixels, but only inside the shape
#trace off
lockbuffer  
 For lp =0 to 10000
  x#=rnd(GetImagewidth(2))
  y#=rnd(GetImagewidth(2))
  if pointhitshape(x#,y#,2,0,0)
   boxc x#,y#,x#+1,y#+1,1,rndrgb()
  endif  
 next
unlockbuffer
#trace on

;  prepare image #2 as FX iamge
preparefximage 2

; Tell PB to direct all drawing back to the screen
rendertoscreen

; Assign Shape #2, to Image #2
ImageShape 2,2


; Get the Width/height of screen
sw=getscreenwidth()
sh=getscreenHeight()

 
 
; Create a bunch of randomly positioned sprites
MaxSprites=25


RayX1#=rnd(getScreenwidth())
RayY1#=rnd(getScreenHeight())


; =====================================
; Start of the Main DO/LOOp
; =====================================

Do
; Clear the Screen to black
Cls FlashColour
ink $ffffff


If InitSprites=0
 InitSprites=true
 For lp=1 to MaxSprites
   ; CReate this sprite
  CreateSprite lp
   ; Assign Image #2 to this sprite
  SpriteIMage lp,2
   ; Set Sprites Draw Mode to Rotated
  SpriteDRawMode lp,2

    ; Enable Sprite Collision For this sprite
  SpriteCollision lp,true
    ; Enable this Sprites Collsion Class (the class/group it belong too)
  SpriteCollisionClass lp,3
 
   ; Set this sprites Collision mode to "SHAPE"
  SpriteCollisionMode lp,2
 
  SpriteFlashColour lp,rndrgb()
;Randomly Enable Sprite Collision Debug Mode      

;   SpriteCollisionDebug lp,true
  centerspritehandle lp

  ; Randomly Position this sprite on the screen
  PositionSpriteXYZ LP,Rnd(sw),rnd(sh),100

  Scale#=0.50+(Rnd(150)/100)
  ScaleSprite lp,Scale#

  SpriteCollisionRadius lp,50*Scale#
 next
endif
 



 ; Run through and Turn/Rotate all the sprites
 For lp=1 to MaxSprites
  turnsprite lp,1+(lp*0.12)
  spritedrawmode lp,2
 next


; Draw all the sprites
 DrawOrderedSprites


; Display a message
    Print "Ray To Sprite Intersection"

 ; Check If the Users LIne Ray hits the scenes sprites
   T1=timer()
  Ray_Trace(Rayx1#,Rayy1#,Mousex(),Mousey())
 t=timer()-t1

 inc frames
 at#=at#+t
 print "Time:"+str$(at#/frames)

 

 if timer()>InputDelay

; =================================
; When the F1 key is pressed, Turn all
; the sprites collisin Debug info on/off
; =================================
  If FunctionKeys(1)
   For lp=1 to MaxSprites
    spritecollisiondebug lp,1-getspritecollisiondebug(lp)
   next
   INputdelay=timer()+100
  endif

; =================================
; When the F2 key is pressed, Toggle the
; sprites to Solid/Transparent mode
; =================================
  If FunctionKeys(2)    
   For lp=1 to MaxSprites
    spritetransparent lp,1-getspritetransparent(lp)
   next
   INputdelay=timer()+100
  endif

  if Spacekey()
    InitSprites=false
    INputdelay=timer()+100
  endif
 endif

 
 if MouseButton()
  RayX1#=mousex()
  RayY1#=Mousey()
 endif

; Show the Screen
Sync


; Loop back to the previous DO statement to keep the demo running
loop




Psub Ray_Trace(Rayx1#,Rayy1#,Rayx2#,Rayy2#)

Intersection=false
  MaxRebounds=0
LastSpriteHit=0

Lockbuffer
; Set the INk colour to White..
Circlec Rayx1#,RayY1#,3,1,rgb(255,0,0)
ink rgb(255,255,255)

repeat
 Collision=False


 ThisSprite=GetFirstSprite()
  repeat
   If ThisSprite<>LastSpriteHit
    if RayHitSprite(rayx1#,rayy1#,rayx2#,rayy2#,ThisSprite)
     Collision=true
     RayX2#=Getintersectx#(0)
     RayY2#=Getintersecty#(0)
     ThisSpriteHit=ThisSprite
    endif
   endif
   ThisSprite=GetNextSprite(ThisSprite)
  until ThisSprite=0

; draw the Ray
  line RayX1#,RayY1#,RayX2#,RayY2#
 
; if there wasa collision, Lets reflect it
  If Collision=True
    LastSpriteHit=ThisSpritehit
   
  ; Calc reflection Direction
    WallAngle#=AtanFull(GetNormaly#(0),GetNormalx#(0))
    RayAngle#=GetAngle2d(RayX2#,RayY2#,RayX1#,RayY1#)
    ReflectAngle#=WrapAngle(WallAngle#,WallAngle#-RayAngle#)
         
  ; Set the Imapct point as the new starting point
    RayX1#=RayX2#
    RayY1#=RayY2#

  ; project the rebounded ray way off into the distance    
    RayX2#=cosnewvalue(RayX2#,ReflectAngle#,1000)
    RayY2#=sinnewvalue(RayY2#,ReflectAngle#,1000)

    ink rgb(255,255,0)

   
  endif
 inc MaxRebounds

 If MaxRebounds>10 then exit
 until Collision=0 or Rebounds  

unlockbuffer


EndPsub


kevin

#2
Ray Hit Sprite & Point In Sprite  Tech Demo

  This demo casts a ray from a random starting point (press left mouse to position it)  on the screen to the mouses current position.  This ray is then traced for intersections against the current set of sprites.  If an impact occurs, the ray is reflected and the process repeated until it leaves the scene or has been traced 25 times.  So it's simple 2d ray tracer.  



Demo Controls:

F1 Key = Toggle Sprites Debug mode (show collision region)
F2 Key = Toggle Sprites RenderMode (Transparent on/off)
Space Key = Randomly Reposition the boxes
Left Arrow = Slow Rotation Down
Right Arrow  = Speed Rotation up
Left Mouse Click = Reposition Ray Starting Point
Esc Key = Exit Demo



Download
  Ray Intersect Sprites Demo + Src (780k)   (login required)


   Note: Source Code requires at least PlayBASIC V1.084