This example uses the world and ray to world intersection features
in PB1.08 to help position sprites on sloped ground with rough
alignment to the terrain.
There's a few bugs,like really movement and aligment should be handed
together. but ya get that :)
[pbcode]
Constant ShowVectors=True
; create a Blue Block to represent a character
Constant Height=64
Cls 255
Getimage 1,0,0,32,Height
preparefximage 1
; create the players sprite
createsprite 1
spriteimage 1,1
spritedrawmode 1,2
centerspritehandle 1
; build a world with
MyWOrld=BuildWorld()
; create the camera
CreateCamera 1
; start of Main DO/Loop
Do
; Set PB to Capture all drawing operation to the scene buffer
Capturetoscene
clsscene
; Let the user Control the Sprite left/right
speed=5
mx=0
if LeftKey() then mx=-speed
if RightKey() then mx=speed
movesprite 1,mx,0
PositionSpriteOnGround(1,myWorld,4)
AlignSpriteToGround(1,myWorld)
; position camera at the sprite position
positioncamera 1,GetSpriteX(1)-GetScreenwidth()/2,GetSpriteY(1)-GetScreenHeight()/2
; draw the world/scene
Cameragrabworld 1,myworld
drawallsprites
DRawcamera 1
SYnc
loop
Function PositionSpriteOnGround(ThisSprite,ThisWorld,Speed)
; get the sprites Position
x=getspritex(ThisSprite)
y=getspritey(ThisSprite)+speed
newy=y
For Xoffset=-8 to 8 step 8
; cast a ray from the center of sprite downwards
Flag=Rayintersectworld(ThisWorld,x+Xoffset,y-(height/2),x+Xoffset,y+(height*2))
line x+Xoffset,y-(height/2),x+Xoffset,y+(height*2)
; check if the ray hit the world(ground in this example)
if Flag
;get the height of the ground at this point
groundY=GetIntersecty#(0)
; reposition the sprite if it's Y was lower than the ground
if (newy+(Height/2))=>GroundY then newy=groundY-((height/2)-1)
endif
next
; position the sprite after collision
positionsprite ThisSprite,x,newy
EndFunction
; =============================================================================
; This function calc's a rough approximation of this sprite to the ground.
; =============================================================================
Function AlignSpriteToGround(ThisSprite,ThisWorld)
Static OldAngle#
; get the sprites Position
x=getspritex(ThisSprite)
y=getspritey(ThisSprite)
CurrentAngle#=GetSpriteAngle(ThisSprite)
; CurrentAngle#=0
GroundAngle#=0
; Project line from /through sprites base
;Calc points for LEFT Ray
Left_rayx1#,Left_rayy1#=Rotate_Vertex(CurrentAngle#,-15,(height/2)*-1)
Left_rayx2#,Left_rayy2#=Rotate_Vertex(CurrentAngle#,-15,(height*1.0))
Left_rayx1#=Left_rayx1#+x
Left_rayy1#=Left_rayy1#+y
Left_rayx2#=Left_rayx2#+x
Left_rayy2#=Left_rayy2#+y
#if ShowVectors=true
line Left_rayx1#,Left_rayy1#,Left_rayx2#,Left_rayy2#
#endif
; cast a ray from the center of sprite downwards
LeftFlag=Rayintersectworld(ThisWorld,Left_rayx1#,Left_rayy1#,Left_rayx2#,Left_rayy2#)
; check if the ray hit the world(ground in this example)
if LeftFlag
;get point where the ray impact the ground (on the left side)
LeftGroundX#=GetIntersectX#(0)
LeftGroundY#=GetIntersectY#(0)
LeftGroundNX#=GetnormalX#(0)
LeftGroundNY#=GetnormalY#(0)
; LeftDist#=getdistance2d(left_rayx1#,Left_rayy1#,LeftGroundX#,LeftGroundY#)
#if ShowVectors=true
x2#=LeftGroundX#+(LeftGroundNX#*50)
y2#=LeftGroundY#+(LeftGroundNY#*50)
line LeftGroundX#,LeftGroundY#,x2#,y2#
#endif
endif
;Calc points for LEFT Ray
right_rayx1#,Right_rayy1#=Rotate_Vertex(CurrentAngle#,13,(height/2)*-1)
Right_rayx2#,Right_rayy2#=Rotate_Vertex(CurrentAngle#,13,(height*1.0))
right_rayx1#=right_rayx1#+x
right_rayy1#=right_rayy1#+y
right_rayx2#=right_rayx2#+x
right_rayy2#=right_rayy2#+y
#if ShowVectors=true
line right_rayx1#,right_rayy1#,right_rayx2#,right_rayy2#
#endif
; cast a ray from the center of sprite downwards
RightFlag=Rayintersectworld(ThisWorld,right_rayx1#,Right_rayy1#,right_rayx2#,Right_rayy2#)
; check if the ray hit the world(ground in this example)
if RightFlag
;get point where the ray impact the ground (on the left side)
RightGroundX#=GetIntersectX#(0)
RightGroundY#=GetIntersectY#(0)
RightGroundNX#=GetnormalX#(0)
RightGroundNY#=GetnormalY#(0)
; RightDist#=getdistance2d(right_rayx1#,Right_rayy1#,Rightgroundx#,Rightgroundy#)
#if ShowVectors=true
x2#=RightGroundX#+(RightGroundNX#*50)
y2#=RightGroundY#+(RightGroundNY#*50)
line RightGroundX#,RightGroundY#,x2#,y2#
#endif
endif
; If both rays hit the ground.
if RightFlag=true and LeftFlag=true
; Calc the average of the two grond normals
AverageNx#=(RightGroundNX#+LeftGroundNX#)/2
AverageNy#=(RightGroundNy#+LeftGroundNy#)/2
; get the angle of the averaged normal
GroundAngle#=atanfull(AverageNy#,AverageNx#)
; project a ray to show the direction
#if ShowVectors=true
x2#=X+cos(GroundAngle#)*250
y2#=Y+sin(GroundAngle#)*250
line X,Y,x2#,y2#
#endif
else
currentangle#=270
groundangle#=270
endif
Currentangle#=curveangle(groundangle#,OldAngle#,10)
RotateSprite Thissprite,CurrentAngle#+90
Oldangle#=currentangle#
EndFunction
Function Rotate_Vertex(Angle#,X#,y#)
newx#=((cos(Angle#)*x#)-(sin(Angle#)*y#))
newy#=((cos(Angle#)*y#)+(sin(Angle#)*x#))
Endfunction newx#,newy#
Function BuildWorld()
MyWOrld=GetFreeWorld()
CReateWOrld MyWorld
Capturetoworld Myworld
Xpos=-500
ypos=0
sh=getscreenheight()/2
repeat
xpos2=xpos+rndrange(25,100)
ypos2=sh+sinradius(xpos,70+rnd(10))
line xpos2,ypos2,xpos,ypos
xpos=xpos2
ypos=ypos2
until xpos>10000
; Partition The world up into 100*100 pixel regions
PartitionWorld MyWorld,48
; restore drawing to normal mode
drawgfximmediate
EndFunction MyWorld
[/pbcode]
Very nice, thanks alot