Nearly pixel perfect sprite collision detection by haggisman11th Oct 2003 7:23
|
---|
Summary It works for any sprite, no matter what the rotation or scaling of the sprites it will still retain the near pixel perfect collision. Description Everything needed can be found in the zip, both some simple code showing the collision detection routine and also the code for creating the collision template for the sprites. Code ` This code was downloaded from The Game Creators ` It is reproduced here with full permission ` http://www.thegamecreators.com Rem This is just sample source, it will most likely NOT work. For the actual source Rem download the attached zip file! Rem ***** Main Source File ***** rem Standard Setup Code sync on : sync rate 0 : color backdrop rgb(0,0,0) : hide mouse set text font "arial" : set text size 24 : set text transparent : set text to bold rem Variables global Uvector=1 global Vvector=2 global Wvector=3 global Normal_length# Sprite_number=2 control=2 Highest_possible=1000 Normal_length#=1.0 rem Types Type Sprite_data line_number as integer X as integer Y as integer Orig_Radius as float Radius as float Mass as integer endtype Type normal_data X as float Y as float endtype Type line_data X1 as float Y1 as float X2 as float Y2 as float endtype rem Arrays global Dim User_Sprite(Sprite_number) as Sprite_data global Dim lines(Sprite_number, Highest_possible) as line_data global Dim T_lines(Sprite_number, Highest_possible) as line_data global Dim normals(Sprite_number, Highest_possible) as normal_data rem Vectors rf=make vector2(Uvector) rf=make vector2(Vvector) rf=make vector2(Wvector) rem Firstly load the sprites in Load_Sprite("ShapeA", ".bmp", 1) Load_Sprite("ShapeB", ".bmp", 2) rem Set some nice sprite positions User_sprite(1).X=512 : User_sprite(1).Y=384 User_sprite(2).X=600 : User_sprite(2).Y=350 Transform_collision_coords(1) Transform_collision_coords(2) rem Main loop Do `control the strange shape User_sprite(control).X=mousex() User_sprite(control).Y=mousey() if mouseclick()=1 then rotate sprite control, (sprite angle(control) + 2) if mouseclick()=2 then rotate sprite control, (sprite angle(control) - 2) if upkey()=1 then stretch sprite control, sprite scale x(control), sprite scale y(control)+5 if downkey()=1 and sprite scale y(control)>10 then stretch sprite control, sprite scale x(control), sprite scale y(control)-5 if leftkey()=1 and sprite scale x(control)>10 then stretch sprite control, sprite scale x(control)-5, sprite scale y(control) if rightkey()=1 then stretch sprite control, sprite scale x(control)+5, sprite scale y(control) Transform_collision_coords(control) `check for collision for x=1 to 2 collision_return=0 `need distance check with bounding spheres. if x<>control collision_return=Sprite_Collision_Check(x, control) endif if collision_return>0 then collision_return=x : exit next x `Paste the sprites to screen for x=1 to Sprite_number if x<>control paste sprite x, User_sprite(x).X, User_sprite(x).Y endif next x paste sprite control, User_sprite(control).X, User_sprite(control).Y `draw all the lines for puropses of debugging `for x=1 to sprite_number `draw_lines_on(x) `next x center Text 512, 0, "Mouse moves the red object; Mouse buttons rotate it; Arrow keys change scale" center Text 512, 24, "COLLISION RESULT :- " + str$(collision_return) Text 0, 0, "FPS: " + str$(screen fps()) Sync Loop `******************************************************************************************* `******************************************************************************************* rem Finally the boring bit of checking lots of bloody line intersections function Sprite_Collision_Check(SA, SB) `setup variables SMALL_NUM#=0.00000001 D as float DU as float DV as float SI as float TI as float `default negative result collision_return=0 `firstly check if within collision radius distance_between_pivots#=SQRT((User_sprite(SA).X-User_sprite(SB).X)^2 + (User_sprite(SA).Y-User_sprite(SB).Y)^2) if distance_between_pivots#<User_sprite(SA).radius+User_sprite(SB).radius `hmm this bit could be slow For a=1 to User_sprite(SA).line_number For b=1 to User_sprite(SB).line_number set vector2 Uvector, T_lines(SA,a).X2-T_lines(SA,a).X1, T_lines(SA,a).Y2-T_lines(SA,a).Y1 set vector2 Vvector, T_lines(SB,b).X2-T_lines(SB,b).X1, T_lines(SB,b).Y2-T_lines(SB,b).Y1 set vector2 Wvector, T_lines(SA,a).X1-T_lines(SB,b).X1, T_lines(SA,a).Y1-T_lines(SB,b).Y1 D=perp(Uvector, Vvector) `test if parallel lines if abs(D)>SMALL_NUM# SI=perp(Vvector, Wvector)/D If SI>0 and SI<1 TI=perp(Uvector, Wvector)/D If TI>0 and TI<1 collision_return=1 endif endif endif if collision_return=1 then exit Next b if collision_return=1 then exit Next a endif endfunction collision_return rem Calculate the perp product function perp(VectorA, VectorB) D as float D=((x vector2(VectorA) * y vector2(VectorB)) - (y vector2(VectorA) * x vector2(VectorB))) endfunction D `******************************************************************************************* function Transform_collision_coords(number) cosine_multiple#=cos(-1*sprite angle(number)) sine_multiple#=sin(-1*sprite angle(number)) scale_X#=(sprite scale x(number)/100.0) scale_Y#=(sprite scale y(number)/100.0) for l=1 to User_sprite(number).line_number T_lines(number, l).X1=((lines(number, l).X1*scale_X#)*cosine_multiple#) + ((lines(number, l).Y1*scale_Y#)*sine_multiple#)+User_Sprite(number).X T_lines(number, l).Y1=(-(lines(number, l).X1*scale_X#)*sine_multiple#) + ((lines(number, l).Y1*scale_Y#)*cosine_multiple#)+User_Sprite(number).Y T_lines(number, l).X2=((lines(number, l).X2*scale_X#)*cosine_multiple#) + ((lines(number, l).Y2*scale_Y#)*sine_multiple#)+User_Sprite(number).X T_lines(number, l).Y2=(-(lines(number, l).X2*scale_X#)*sine_multiple#) + ((lines(number, l).Y2*scale_Y#)*cosine_multiple#)+User_Sprite(number).Y next l `set the new range check as well if scale_X#>scale_Y# max_scale#=scale_X# else max_scale#=scale_Y# endif User_Sprite(number).Radius=User_Sprite(number).Orig_Radius*max_scale# endfunction `******************************************************************************************* rem Load Sprite Function function Load_Sprite(Name$, FileType$, number) `Simple loading and creating sprite load image "Input/"+Name$+FileType$, number Sprite number, 0, 0, number `Open the sprites col file to extract important data open to read 1, "Output/"+Name$+".col" read file 1, line_number read file 1, offset_X read file 1, offset_Y read float 1, User_Sprite(number).Orig_Radius read file 1, User_Sprite(number).Mass `Read out all the polar coords into the global polar array For l=1 to line_number read float 1, lines(number,l).X1 read float 1, lines(number,l).X2 read float 1, lines(number,l).Y1 read float 1, lines(number,l).Y2 next l `Read out all the normals For l=1 to line_number write float 1, normals(number,l).X write float 1, normals(number,l).Y next l `close file close file 1 `misc clean up User_sprite(number).line_number=line_number offset sprite number, offset_X, offset_Y hide sprite number endfunction `******************************************************************************************* function draw_lines_on(number) for l=1 to User_sprite(number).line_number line T_lines(number,l).X1, T_lines(number,l).Y1, T_lines(number,l).X2, T_lines(number,l).Y2 next l endfunction `******************************************************************************************* |