I am very recluctant to post this old clunky code (2003).
I am sure you can get leaner and more elegant solutions with vectors and face normals detection.
Nevertheless the underneath logic used is still valid IMHO.
Hope it helps.
Rem Project: bullets_hit
rem by Scorpyo
Rem Created: 08/12/03 14.14.03
Rem ***** Main Source File *****
rem ********** INITIALIZATION ****************
set display mode 1920,1080,32
rem hide mouse
set global collision off
autocam off
backdrop on
sync on
cls
landsize=20000
grid=40
mtxrandomize=3
gx#=10000.0
gy#=200
gz#=10500.0
bulletnumber=53
shootcount=3
gosub makematrix
gosub makeobjects
gosub Resetcam
gosub reset_shoot
position mouse 400,300
rem *********MAIN LOOP**********
do
gosub gunwalk
gosub movegun
gosub movetarget
gosub check_hitspot
if controlkey()=1 and shootcount<bulletnumber then gosub shoot
if shiftkey()=1 then gosub reset_shoot
gosub check_distance
gosub camera_controls
gosub update_camera
gosub printdata
sync
loop
shoot:
rem shoot routine
rem gosub check_hitspot
if hit#=0.0 then return
if hit#>0.0 then shootcount=shootcount+1
gosub position_bullet
gosub check_bullet_position
gosub bullet_ytilt
gosub bullet_xtilt
move object shootcount,-1
wait 100
return
check_hitspot:
rem check target hit spot distance from gun - blu sphere as marker (gun range: 3000)
ifarx#=newxvalue(gx#,gay#,3000)
ifarz#=newzvalue(gz#,gay#,3000)
ifary#=newyvalue(gy#,gax#,3000)
hit#=intersect object(2,gx#,gy#,gz#,ifarx#,ifary#,ifarz#)
rem find bullet coords on target surface
newbx#=newxvalue(gx#,gay#,hit#)
newbz#=newzvalue(gz#,gay#,hit#)
newby#=newyvalue(gy#,gax#,hit#)
position object 100,newbx#,newby#,newbz#
return
position_bullet:
if hit#=0 then return
rem adjust parallax error to make bullet plane center
rem to exactly hit the target surface (needed for correct tiltint)
hit2#=intersect object(2,newbx#,newby#,newbz#-100,newbx#,newby#,newbz#+100)
hit3#=intersect object(shootcount,newbx#,newby#,newbz#-100,newbx#,newby#,newbz#+100)
adjustz#=100-(hit2#-hit3#)
rem position bullet plane at world coord at correct hit spot
position object shootcount,newbx#,newby#,newbz#-adjustz#
return
bullet_ytilt:
if hit#=0 then return
rem y rotation
rem check bullet to target distance 5 units beside hit spot (x axis)
ydistbullet#=intersect object(2,newbx#-5,newby#,newbz#-100,newbx#-5,newby#,newbz#+100)
ydisttarget#=intersect object(shootcount,newbx#,newby#,newbz#-100,newbx#,newby#,newbz#+100)
deltay#=ydistbullet#-ydisttarget#
rem translate found value to y tilt angle for bullet plane
bay#=atan(deltay#/5)
yrotate object shootcount,bay#
return
bullet_xtilt:
if hit#=0 then return
rem find intersect direction for x rotation
rem the new intersect ray
rem MUST BE y angle ortogonal to bullet plane
rem put new "from" spot 100 units before hit point
newfrombix#=newxvalue(newbx#,bay#,-100)
newfrombiz#=newzvalue(newbz#,bay#,-100)
rem put new "to" coords 200 units beyond hit spot
newtobix#=newxvalue(newbx#,bay#,200)
newtobiz#=newzvalue(newbz#,bay#,200)
rem cast intersect line 5 units above hit spot (y axis)
rem and get bullet plane to target plane distance
xdistbullet#=intersect object(2,newfrombix#,newby#+5,newfrombiz#,newtobix#,newby#+5,newtobiz#)
xdisttarget#=intersect object(shootcount,newfrombix#,newby#,newfrombiz#,newtobix#,newby#,newtobiz#)
deltax#=xdistbullet#-xdisttarget#
rem translate found value to x tilt angle for bullet plane
bax#=atan(deltax#/5)
xrotate object shootcount,bax#
return
check_bullet_position:
newbx#=object position x(shootcount)
newby#=object position y(shootcount)
newbz#=object position z(shootcount)
return
reset_shoot:
gosub reset_bullets
rem reset shoot conditions
shootcount=3
deltay#=0
deltax#=0
bay#=0
bax#=0
return
reset_bullets:
for n=3 to bulletnumber
position object n,n*10,100,10
yrotate object n,0.0
xrotate object n,0.0
next n
return
movetarget:
if shootcount<bulletnumber and shootcount>3 then return
gosub reset_shoot
rem use arrow keys to rotate target cube
if inkey$()="e" then oaz#=wrapvalue(oaz#-1)
if inkey$()="d" then oaz#=wrapvalue(oaz#+1)
if inkey$()="w" then oax#=wrapvalue(oax#-1)
if inkey$()="q" then oax#=wrapvalue(oax#+1)
if inkey$()="s" then oay#=wrapvalue(oay#-1)
if inkey$()="a" then oay#=wrapvalue(oay#+1)
rotate limb 2,0,oax#,oay#,oaz#
return
movegun:
gay#=wrapvalue(mousex())
gax#=wrapvalue(mousey())
rotate object 1,gax#,gay#,0
return
gunwalk:
gx#=newxvalue(gx#,gay#,s#)
gz#=newzvalue(gz#,gay#,s#)
if upkey()=1 and s#<8 then s#=s#+0.5
if downkey()=1 and s#>-8 then s#=s#-0.5
if leftkey()=1 then ay#=wrapvalue(gay#-2)
if rightkey()=1 then ay#=wrapvalue(gay#+2)
if inkey$()="ù" then s#=0.0
position object 1,gx#,gy#,gz#
return
check_distance:
diffposx#=abs(object position x(1)-object position x(2))
diffposz#=abs(object position z(1)-object position z(2))
collsqrt#=sqrt((diffposx#*diffposx#)+(diffposz#*diffposz#))
if collsqrt#<300 then s#=-0.1
return
camera_controls:
if inkey$()="z" then camdist=camdist+5
if inkey$()="x" then camdist=camdist-5
if inkey$()="c" then camhgt=camhgt+2
if inkey$()="v" then camhgt=camhgt-2
if inkey$()="b" then camrot#=wrapvalue(camrot#+2)
if inkey$()="n" then camrot#=wrapvalue(camrot#-2)
if inkey$()=">" then gosub Resetcam
return
rem camera update
update_camera:
cx#=newxvalue(gx#,gay#,camdist)
cz#=newzvalue(gz#,gay#,camdist)
cy#=get ground height(1,x#,z#)
position camera cx#,cy#+camhgt,cz#
rem Point camera at object
rem point camera gx#,cy#+camhgt+camlen,gz#
yrotate camera gay#+camrot#
return
Resetcam:
set camera range 1,20000
camdist=-400
camhgt=300
camrot=20
camlen=0
cx#=9600
cz#=9700
return
printdata:
set cursor 0,0
set text opaque
rem debug check
print "polygons=",statistic(1)
print "Fps=",screen fps()
print " gun coords "
print "gx#=",gx#
print "gy#=",gy#
print "gz#=",gz#
print " bullet gross coords on target "
print "newbx#=",newbx#
print "newby#=",newby#
print "newbz#=",newbz#
print " correction for above "
print "adjustz#=",adjustz#
print " gun angles "
print "gax#=",gax#
print "gay#=",gay#
print "hit#=",hit#
print " bullet target displaced y values "
print "ydistbullet#=",ydistbullet#
print "ydisttarget#=",ydisttarget#
print " bullet - target displaced x values "
print "xdistbullet#=",xdistbullet#
print "xdisttarget#=",xdisttarget#
print " calculate difference of above "
print "deltay#=",deltay#
print "deltax#=",deltax#
print " bullet y and x angle3 "
print "bay#=",bay#
print "bax#=",bax#
print "shootcount=",shootcount
print "Ctrlkey = Shoot"
print "Shiftkey = Reset Shooting"
print " q w e a s d to rotate target cube"
print " z,x,c,v,b,n and < control camera"
print " mouse rotate gun "
return
rem ****** CREATE LEVEL ******
makematrix:
rem Load and create images
rem textures
rem create ground texture
cls rgb(0,100,20)
inkcolor#=rgb(255,255,255)
for n=1 to 50 step 10
line n,0,n,50
line 0,n,50,n
next n
get image 2,0,0,50,50
rem create bullet plane texture
cls rgb(0,100,100)
inkcolor#=rgb(255,255,255)
get image 1,0,0,50,50
rem create pointer texture
cls rgb(0,0,100)
inkcolor#=rgb(255,255,255)
get image 5,0,0,50,50
rem Make landscape
make matrix 1,landsize,landsize,grid,grid
rem set matrix 1,1,0,0,1,1,1,1
prepare matrix texture 1,2,1,1
randomize matrix 1,mtxrandomize
rem get ground done
update matrix 1
return
rem make gun,target,bullet
makeobjects:
rem make gun
make object cone 1,40
scale object 1,100,500,100
set object cull 1,0
position object 1,gx#,gy#,gz#
xrotate object 1,90
fix object pivot 1
rem make target
make object cube 2,300
position object 2,10000,200,11000
xrotate object 2,60
yrotate object 2,40
zrotate object 2,40
rem make bullets
rem load image "bullhole02.bmp",4
for n=3 to bulletnumber
make object plain n,80,80
yrotate object n,180
fix object pivot n
set object transparency n,1
rem use image 4 if using bullet hole bmp
texture object n,1
position object n,n*10,100,10
next n
rem make pointer
make object sphere 100,30
texture object 100,5
return
end