I worked on your code some more. Here are the changes I made. I'm writing this while reading the code from beginning to end, so the order may seem strange.
`========================================================
`====================Simple FPS==========================
`========================================================
`=======by culmor30======================================
sync on
sync rate 60
color backdrop black
hide mouse
autocam off
global NextIDNumber = 0
`=====Create player object=====
PlayerObject = NextIDNumber()
make object cube PlayerObject,2
position object PlayerObject,10,10,0
sc_setupobject PlayerObject,0,2
`=====Create player object=====
`=====Add Level Light 1=====
make light 1
set spot light 1,100,200
position light 1,200,350,100
point light 1,200,0,350
set light range 1,600
color light 1,rgb(255,255,255)
`=====Add Level Light 1=====
color light 0,255,255,255
`=====Add Level Light 2=====
make light 2
set spot light 2,100,200
position light 2,100,350,200
point light 2,350,0,200
set light range 2,600
color light 2,rgb(255,255,255)
`=====Add Level Light 2=====
set normalization on
`=====Level Fog=====
`-(Only works if GFX card supports it)
fog on
fog color rgb(000,040,000)
fog distance 350
set ambient light 2.0
color ambient light rgb(000,040,000)
`=====Level Fog=====
`=====Load Level=====
LevelObject = NextIDNumber()
load object "level.x", LevelObject
position object LevelObject ,0,0,0
scale object LevelObject,400,400,400
set object collision to polygons LevelObject
SC_setupTerrainCollision LevelObject,0,999
`=====Load Level=====
`=====Load and position crosshair=====
screen_height=screen height()
screen_width=screen width()
screen_center_x=screen_width / 2
screen_center_y=screen_height / 2
CrossHairImage = NextIDNumber()
load image "crosshair.bmp",CrossHairImage,1
CrossHairSprite = NextIDNumber
sprite CrossHairSprite,screen_center_x - 50,screen_center_y - 50,CrossHairImage
`=====Load and position crosshair=====
type BulletType
ObjectNumber as integer
Distance as float
endtype
dim Bullets(10) as BulletType
for b=0 to 10
NewBullet = NextIDNumber()
make object sphere NewBullet, 1
` This is the object number.
Bullets(b).ObjectNumber = NewBullet
` This will keep track of the distance of flight of the bullet (for misses). It will also be used to determine
` which bullets are in flight. A value of -1.0 will be used for bullets not in flight. None are at this time.
Bullets(b).Distance = -1.0
hide object NewBullet
next b
BulletsInFlight = 0
BulletRange# = 90.0 ` In units of measurement.
BulletVelocity# = 30.0 ` In units of measurement per second.
MovementSpeed# = 20.0 ` In units of measurement per second.
` Make a bullet hole.
BulletHoleImage = NextIDNumber()
load image "BulletHole.bmp", BulletHoleImage, 0
OriginalBulletHole = NextIDNumber()
make object plain OriginalBulletHole, 1.5, 1.5
texture object OriginalBulletHole, BulletHoleImage
set object transparency OriginalBulletHole, 5
hide object OriginalBulletHole
`Begin main loop:
do
PreviousCycleTime = CycleTime
CycleTime = timer()
ElapsedTime = CycleTime - PreviousCycleTime
CyclesPerSecond# = 1000.0 / ElapsedTime
oldx#=object position x(PlayerObject)
oldy#=object position y(PlayerObject)
oldz#=object position z(PlayerObject)
`=====WASD Controls=====
if keystate(17)=1 then move object PlayerObject, MovementSpeed# / CyclesPerSecond#
if keystate(30)=1 then move object left PlayerObject, MovementSpeed# / CyclesPerSecond#
if keystate(31)=1 then move object PlayerObject, 0.0 - (MovementSpeed# / CyclesPerSecond#)
if keystate(32)=1 then move object right PlayerObject, MovementSpeed# / CyclesPerSecond#
`=====WASD Controls=====
x#=object position x(PlayerObject)
y#=object position y(PlayerObject)
z#=object position z(PlayerObject)
`=====Camera/Player Obj Lock=====
position camera object position x(PlayerObject),object position y(PlayerObject),object position z(PlayerObject)
rotate camera camera angle x(),object angle y(PlayerObject),camera angle z()
`=====Camera/Player Obj Lock=====
`=====Camera Controls=====
speed#=0.5
damper#=10.0
camy#=wrapvalue(camy#+mousemovex()*speed#):camx#=wrapvalue(camx#+mousemovey()*speed#)
if camx#<=290 and camx#>180 then camx#=290
if camx#>=70 and camx#<180 then camx#=70
tx#=curvevalue(-camx#,tx#,damper#)
ty#=curvevalue(-camy#,ty#,damper#)
rotate camera camx#,object angle y(PlayerObject),0
yrotate object 1,camy#
`=====Camera Controls=====
slidingcollision(oldx#,oldy#,oldz#,x#,y#,z#,3,PlayerObject,LevelObject)
` If the left mouse button is pressed and it has been at least a fifth of a second since the
` last bullet was fired, fire a bullet. This can be used to regulate the rate of fire.
if mouseclick() = 1 and FireTime < timer() - 200
gosub FireBullet
FireTime = timer()
endif
` Process the bullets that are in flight.
if BulletsInFlight > 0 then gosub bullets
` The following code will show you the bullet array. It will help you understand what's happening.
` For each bullet object, it shows the object number and how far it's flown.
LineY = 10
for b = 0 to 10
inc LineY, 20
text 10, LineY, str$(bullets(b).ObjectNumber) + " / " + str$(bullets(b).Distance)
next b
inc LineY, 20
text 10, LineY, str$(BulletsInFlight)
sync
loop
`End main loop
` --------------------------------------------------------------------------------------------------
`========<=-=Bullets=-=>========
`---------->-=-Are-=-<----------
`========<=-=Annoying-=>========
FireBullet:
` Find the first unused bullet.
for b = 0 to 10
` If the bullet isn't in flight, position it at the point of origin.
if Bullets(b).Distance = -1.0
BulletObject = Bullets(b).ObjectNumber
show object BulletObject
position object BulletObject, camera position x(), camera position y(), camera position z()
rotate object BulletObject, camera angle x(), camera angle y(), camera angle z()
` Annotate this bullet as being in flight.
Bullets(b).Distance = 0.0
inc BulletsInFlight
` We have our bullet, so exit.
exit
endif
next b
return
` --------------------------------------------------------------------------------------------------
bullets:
for b = 0 to 10
` If the bullet is in flight, see if it's going to hit something this program cycle.
if Bullets(b).Distance > -1.0
BulletObject = Bullets(b).ObjectNumber
` Note the bullets position.
PositionX# = object position x(BulletObject)
PositionY# = object position y(BulletObject)
PositionZ# = object position z(BulletObject)
` Move the bullet to where it's going to be if it doesn't hit anything.
move object BulletObject, BulletVelocity# / CyclesPerSecond#
` Check for collision between the two points.
ImpactObject = SC_RayCast(0, PositionX#, PositionY#, PositionZ#, object position x(BulletObject), object position y(BulletObject), object position z(BulletObject), 0)
` An impact has occured.
if ImpactObject <> 0
newx# = SC_getStaticCollisionX()
newy# = SC_getStaticCollisionY()
newz# = SC_getStaticCollisionZ()
normx# = SC_getCollisionNormalX()
normy# = SC_getCollisionNormalY()
normz# = SC_getCollisionNormalZ()
NewBulletHole = NextIDNumber()
instance object NewBulletHole, OriginalBulletHole
position object NewBulletHole, newx# + normx# / 10.0, newy# + normy# / 10.0, newz# + normz# / 10.0
point object NewBulletHole, newx# + normx#, newy# + normy#, newz# + normz#
` Reset the distance of flight for the next use of this bullet.
Bullets(b).Distance = -1.0
dec BulletsInFlight
hide object BulletObject
` An impact has not occured - the bullet will keep flying.
else
DistanceOfFlight# = Bullets(b).Distance + ThreeDimensionDistance#(PositionX#, PositionY#, PositionZ#, object position x(BulletObject), object position y(BulletObject), object position z(BulletObject))
` This round's flown too far, it's a miss.
` Note: This is kind of a bad example, since you're in such a confined space. Go to a corner
` and fire at the opposite corner and you'll see that the bullet disapears before it gets there.
if DistanceOfFlight# >= BulletRange#
` Reset the distance of flight for the next use of this bullet.
Bullets(b).Distance = -1.0
dec BulletsInFlight
hide object BulletObject
` The bullet's still flying, increase the distance of flight for next time.
else
Bullets(b).Distance = DistanceOfFlight#
endif
endif
endif
next b
return
` --------------------------------------------------------------------------------------------------
`Sparky's Function
function slidingcollision(x1#,y1#,z1#,x2#,y2#,z2#,Radius#,Dyn,Obj)
C = sc_SphereSlide(Obj,x1#,y1#,z1#,x2#,y2#,z2#,Radius#,0)
if C > 0
cx# = sc_getCollisionSlideX()
cy# = sc_getCollisionSlideY()
cz# = sc_getCollisionSlideZ()
position object Dyn, cx#, cy#, cz#
endif
endfunction
delete memblock 1
` --------------------------------------------------------------------------------------------------
function ThreeDimensionDistance#(FromX#, FromY#, FromZ#, ToX#, ToY#, ToZ#)
` This function calculates the distance between two points in three dimensions.
TempX# = abs(FromX# - ToX#)
TempY# = abs(FromY# - ToY#)
TempZ# = abs(FromZ# - ToZ#)
ReturnValue# = sqrt((TempX# * TempX#) + (TempY# * TempY#) + (TempZ# * TempZ#))
endfunction ReturnValue#
` --------------------------------------------------------------------------------------------------
function NextIDNumber()
` This function determines the next program ID number for objects, images, sounds, etc.
inc NextIDNumber
endfunction NextIDNumber
1. Added a system for assigning numbers for objects, images, sprites, etc. That way you don't have to keep track of those numbers and your code will be a lot easier to read. MOVE OBJECT EnemyObject, 12.0 is going to be a lot easier to understand than MOVE OBJECT 346, 12.0. Note that you can't use this with everything. Things like lights and file numbers have to be within a certain number range. Object limbs have to be added in order: 1, 2, 3, etc. But for the bulk of your media, this is the way to go.
2. Introduced a user-defined type (UDT). If you know what that means, skip this section. When you make an array with a DIM command, all of the elements of the array are of the same data type. But what if you need an array with different data types? That's what UDTs are for. You use a TYPE/ENDTYPE command to define the different data types that you want in your array. Since you have a full example to look at, I'm not going to go into great detail. Just notice the way the bullet array looks and is used. If you have any questions about it, just let me know. By the way, you can e-mail me if you want. We don't have to go through the forums all the time, but we can if you want. It's up to you.
3. Added the bullet holes. The graphic that I made is attached. It isn't any big deal. Note, however, that the black in the center of the picture isn't completely black. The black around the edge is. That's the reason the black around the edge doesn't show, but the black in the middle does. I'm partial to PNG files, but I find that when I have to differentiate between real black and faux-black, I need to go with a 24 bit BMP image.
4. Added the cycle timer and applied it to the bullet flight (more on that later) and the player movement speed. Now speeds should be consistent on different machines or if your program speed fluctuates (which it‘s more likely to do the bigger your program becomes).
5. Added a variable to keep track of the number of bullets in flight. That way, if there aren't any, the bullet procedure won't be called. I also added this number to the on-screen info. It's the number under the bullet array data.
6. Converted the raycast to the Sparkey's command. Everything that Sparkey's should be used for is now using it.
7. Changed the bullet burnout from being number-of-cycles-based to distance-flown-based, as discussed above.
I didn’t have your ammo code, so it’s not in there. I’m sure you’ll be able to integrate it.
Well, that's about it. Chew on this for a while and if you have any questions or problems, let me know.
- Jane