James Bond the Dinosaur

Blitz3D Forums/Blitz3D Beginners Area/James Bond the Dinosaur

wizzlefish(Posted 2004) [#1]
nevermind the title. I need some help making a first person shooter. I made my level, just a wall, floor and ceiling, and I know some Blitz3D programming, I just have NO idea how to put together an FPS. Thanks, O Reliable Blitz Forums.


WolRon(Posted 2004) [#2]
Really basic example:

Not finished...

Start with setting up 3D graphics
Graphics3D 800, 600
SetBuffer BackBuffer()

Set up your types
Type bullettype
  Field entityhandle
End Type
Type badguytype
  Field entityhandle
  Field state
End Type

Load in your 3d objects
light = CreateLight()
player = CreatePivot()
camera = CreateCamera(player)
level = LoadMesh("level.b3d")
weapon1 = LoadMesh("pistol.b3d", camera)
bulletmesh = LoadMesh("bullet.b3d")
badguymesh = LoadMesh("badguy.b3d")
HideEntity bulletmesh
HideEntity badguymesh
etc...

Create your beginning objects
For iter = 1 to 10
  badguy.badguytype = New badguytype
  badguy\entityhandle = CopyEntity(badguymesh)
  badguy\state = Rnd(1, 2) ;1=Guard 2=Search 3=Evade 4=Fire 5=Dead
  EntityType badguy\entityhandle, 3
  EntityRadius badguy\entityhandle, .7, 2
Next

Arrange your objects
MoveEntity camera, 0, .8, 0
MoveEntity weapon1, .1, -.15, .1
MoveEntity player, 20, 1, -20
For bgiter.badguytype = Each badguytype
  PositionEntity iter\entityhandle, Rnd(100)-50, 1, Rnd(100)-50
Next
etc...

Set up collisions between all of the objects. EntityTypes and radiuses for badguys and bullets are set upon their creation.
EntityType player, 1
EntityRadius player, .7, 2
EntityType level, 2
Collisions 1, 2, 2, 2 ;player to level
Collisions 3, 2, 2, 2 ;badguy to level
Collisions 4, 2, 2, 1 ;bullet to level
Collisions 4, 3, 2, 1 ;bullet to badguy

Then add a loop that updates the screen every frame.
While Not Keyhit(1)
  
  ;insert additional code here

  UpdateWorld

  RenderWorld
  Flip
Wend

Inside of your loop (before UpdateWorld) add lines that handle how to move the player (camera)
If Keydown(17) then MoveEntity player, 0, 0, .1
If Keydown(31) then MoveEntity player, 0, 0, -.1
If Keydown(30) then MoveEntity player, -.1, 0, 0
If Keydown(32) then MoveEntity player, .1, 0, 0

Next add lines that handle how to allow the player (camera) to look around
TurnEntity player, 0, -MouseXSpeed()/5.0, 0
TurnEntity camera, MouseYSpeed()/5.0, 0, 0
If EntityPitch(camera) < -45
  RotateEntity camera, -45, EntityYaw(camera), EntityRoll(camera)
EndIf
If EntityPitch(camera) > 45
  RotateEntity camera, 45, EntityYaw(camera), EntityRoll(camera)
EndIf
MoveMouse GraphicsWidth()/2, GraphicsHeight()/2

Add code to allow the player to shoot
If MouseHit(1)
  bullet.bullettype = New bullettype
  bullet\entityhandle = CopyEntity(bulletmesh)
  PositionEntity bullet\entityhandle, EntityX(weapon1, 1), EntityY(weapon1, 1), EntityZ(weapon1, 1)
  RotateEntity bullet\entityhandle, EntityPitch(weapon1, 1), EntityYaw(weapon1, 1), EntityRoll(weapon1, 1)
  EntityType bullet\entityhandle, 4
  EntityRadius bullet\entityhandle, .01
EndIf

Add code to move bullets every frame
For biter.bullettype = Each bullettype
  MoveEntity biter\entityhandle, 0, 0, 2
  If Abs(EntityX(biter\entityhandle, 1)) > 10000
    FreeEntity biter\entityhandle
    Delete biter
  ElseIf Abs(EntityY(biter\entityhandle, 1)) > 10000
    FreeEntity biter\entityhandle
    Delete biter
  ElseIf Abs(EntityZ(biter\entityhandle, 1)) > 10000
    FreeEntity biter\entityhandle
    Delete biter
  EndIf
Next

Add code between UpdateWorld and RenderWorld to check if any collisions occured between the bullets and anything else. Kill a badguy if the bullet hit one.
For biter.bullettype = Each bullettype
  If CountCollisions(biter\entityhandle) > 0
    badguyhit = EntityCollided(biter\entityhandle, 3)
    For badguysearch.badguytype = Each badguytype
      If badguyhit = badguysearch\entityhandle
        If badguysearch\state <> 5
          badguysearch\state = 5 ;dead
          RotateEntity badguysearch\entityhandle, 0, 0, 90
          TranslateEntity badguysearch\entityhandle, 0, -1, 0
          Exit
        EndIf
      EndIf
    Next    
    FreeEntity biter\entityhandle
    Delete biter
  EndIf
Next



Perturbatio(Posted 2004) [#3]
The code archives are your friend, there is at least one FPS framework in there already.


wizzlefish(Posted 2004) [#4]
Thanks....


WolRon(Posted 2004) [#5]
Updated the code I wrote above (removed a TON of errors) and improved it some. You can now shoot the bad guys.

Here is the sample code in full: (with some temp objects for bullets and badguys)
Graphics3D 800, 600
SetBuffer BackBuffer()

Type bullettype
  Field entityhandle
End Type
Type badguytype
  Field entityhandle
  Field state
End Type

light = CreateLight()
player = CreatePivot()
camera = CreateCamera(player)
CameraRange camera, .01, 250
level = LoadMesh("level.b3d")
weapon1 = LoadMesh("pistol.b3d", camera)
;bulletmesh = LoadMesh("bullet.b3d")
;badguymesh = LoadMesh("badguy.b3d")
bulletmesh = CreateCone():RotateMesh bulletmesh, 90, 0, 0:ScaleEntity bulletmesh, .1, .1, .1
badguymesh = CreateCylinder():ScaleEntity badguymesh, .4, 2, .25
HideEntity bulletmesh
HideEntity badguymesh

For iter = 1 To 10
  badguy.badguytype = New badguytype
  badguy\entityhandle = CopyEntity(badguymesh)
  badguy\state = Rnd(1, 2) ;1=Guard 2=Search 3=Evade 4=Fire 5=Dead
  EntityType badguy\entityhandle, 3
  EntityRadius badguy\entityhandle, .7, 2
Next


MoveEntity camera, 0, .8, 0
MoveEntity weapon1, .1, -.15, .1
MoveEntity player, 20, 1, -20
For bgiter.badguytype = Each badguytype
  PositionEntity bgiter\entityhandle, Rnd(100)-50, 1, Rnd(100)-50
Next

EntityType player, 1
EntityRadius player, .7, 2
EntityType level, 2
Collisions 1, 2, 2, 2 ;player to level
Collisions 3, 2, 2, 2 ;badguy to level
Collisions 4, 2, 2, 1 ;bullet to level
Collisions 4, 3, 2, 1 ;bullet to badguy


While Not KeyHit(1)
  
  If KeyDown(17) Then MoveEntity player, 0, 0, .1
  If KeyDown(31) Then MoveEntity player, 0, 0, -.1
  If KeyDown(30) Then MoveEntity player, -.1, 0, 0
  If KeyDown(32) Then MoveEntity player, .1, 0, 0

  TurnEntity player, 0, -MouseXSpeed()/5.0, 0
  TurnEntity camera, MouseYSpeed()/5.0, 0, 0
  If EntityPitch(camera) < -45
    RotateEntity camera, -45, EntityYaw(camera), EntityRoll(camera)
  EndIf
  If EntityPitch(camera) > 45
    RotateEntity camera, 45, EntityYaw(camera), EntityRoll(camera)
  EndIf
  MoveMouse GraphicsWidth()/2, GraphicsHeight()/2

  If MouseHit(1)
    bullet.bullettype = New bullettype
    bullet\entityhandle = CopyEntity(bulletmesh)
    PositionEntity bullet\entityhandle, EntityX(weapon1, 1), EntityY(weapon1, 1), EntityZ(weapon1, 1)
    RotateEntity bullet\entityhandle, EntityPitch(weapon1, 1), EntityYaw(weapon1, 1), EntityRoll(weapon1, 1)
    EntityType bullet\entityhandle, 4
    EntityRadius bullet\entityhandle, .01
  EndIf

  For biter.bullettype = Each bullettype
    MoveEntity biter\entityhandle, 0, 0, 2
    If Abs(EntityX(biter\entityhandle, 1)) > 10000
      FreeEntity biter\entityhandle
      Delete biter
    ElseIf Abs(EntityY(biter\entityhandle, 1)) > 10000
      FreeEntity biter\entityhandle
      Delete biter
    ElseIf Abs(EntityZ(biter\entityhandle, 1)) > 10000
      FreeEntity biter\entityhandle
      Delete biter
    EndIf
  Next
	 

  UpdateWorld


  For biter.bullettype = Each bullettype
    If CountCollisions(biter\entityhandle) > 0
      badguyhit = EntityCollided(biter\entityhandle, 3)
      For badguysearch.badguytype = Each badguytype
        If badguyhit = badguysearch\entityhandle
          If badguysearch\state <> 5
            badguysearch\state = 5 ;dead
            RotateEntity badguysearch\entityhandle, 0, 0, 90
            TranslateEntity badguysearch\entityhandle, 0, -1, 0
            Exit
          EndIf
        EndIf
      Next
      FreeEntity biter\entityhandle
      Delete biter
    EndIf
  Next

  RenderWorld

  Flip

Wend



wizzlefish(Posted 2004) [#6]
That's it??!?! That's pretty short code for a FPS....

One other thing--how would I check to see if the "badguy" is not placed inside a wall of the level? Would I do this? :

Before the main loop:

If EntityCollide(badguy,level) ;I'm not really sure if those are the correct perimeters
   Goto setupbadguy ;Where setupbadguy is the "For...Next" loop in which the badguys are placed.
EndIf


Would this be correct, or does the code above already do that?

Thanks for everything, though :)


WolRon(Posted 2004) [#7]
That's it??!?! That's pretty short code for a FPS....
Well, there isn't any code for enemy AI yet, but you could call it a First Person Shooter at this point I guess (although there's absolutely no bells & whistles).

how would I check to see if the "badguy" is not placed inside a wall of the level?
Well, there is no easy solution. The one you suggested would work per say, but wouldn't be very efficient (it may have to try 1268 times before it gets it right...). Also it wouldn't be very efficient because you are starting over from the beginning each time. A better solution would be to create a REPEAT-UNTIL loop that keeps trying until the current guy is placed.

[pseudocode]
Repeat
MoveEntity badguy, Rnd(100), Rnd(100), Rnd(100)
Until EntityCollided(badguy, level) = False
[/pseudocode]

Also, what if a badguy ends up on the OUTSIDE of a level? How does your code tell the INSIDE from the OUTSIDE?
Or what about this scenario:
B=badguy P=player

     outside
 +------------------+
 |  B      B        |
 |     P            |
 |          inside  |
 |   +----+         |
 |   | out|         |  outside
 |   |side|         |
 |   |  B |    B    |
 |   +----+         |
 | B                |
 +------------------|
           outside
The badguy is inside the boundary of the game, but not in the playing area.


One possible solution could be to start at a known good location (or several good locations) inside of the level and then randomly move the badguys around for a while with Collisions enabled. That way, they can't end up on the outside or within a wall.

or you could just hard code in starting positions for the badguys,

or you could create starting "zones" within your level by inserting huge hidden cubes in your level where the zones are. If the badguy isn't touching a zone (one of the hidden cubes) then try moving him somewhere else.

I guess it's up to you.


wizzlefish(Posted 2004) [#8]
My map looks more like this:
B = Badguy
P = Player
+---------------------+
|           B         |
|-------------------  |
|B -------------------|
|------------------- B|
|------+    B         |
|  P                  |
+---------------------+


But I'll figure out the AI....I have an AI structure in a Space Invaders clone that I can work from....Thanks anyway, though :)

And I think I will hardcode them - it will just be so much less complicated! :)


wizzlefish(Posted 2004) [#9]
the program didn't work...have you tested it yet?


WolRon(Posted 2004) [#10]
What program? Are you referring to the code I wrote above. If so, yes, I tested it, and it works perfectly fine on my machine.

You would of course have to supply your own meshes for the level and weapon.

And some of the numbers (like the MoveEntity commands) would have to be tweaked to fit your situation.


jfk EO-11110(Posted 2004) [#11]
a true fps game engine is a huge job that cannot be explained in a couple of lines of text. My own FPS engine has currently reached line 5908, include files not counted.
And there is still no multiplayer inside.

basicly you need an object structure for all meshes in your world. the object structure should contains a describtion string that will help you to handle special object jobs. So if your player steps close to a mesh that is described as "ammo", you can free the mesh, print "picked up some ammo" and add a number to the player_ammo variable.

The easiest way to achieve this is to write a little world editor that will let you load a building mesh plus additional meshes as well as 3d-sounds. The editor will let you position, scale, rotate things, as well as to set all possible parameters (fx, alpha, pickable etc.) including said description string. It will then save a file that contains all the parameters of each mesh (and/or 3dsound etc.) including file-paths in a way that will allow your game engine to LOAD all the meshes and all parameters correctly. If you once have the Saving code, you can make a level-loader out of it relatively easy. The engine will then handle the description strings by seeking special triggering words, eg. "ammo", "medicine", "door" etc.
It is recommended to parse the decription-string only once while loading the level and store the required information in arrays (eg. door()), together with individual counters for special arrays etc.

Of course you can also use types instead of arrays, so you wont need counters, but it may complicate things as soon as you need to connect unrelated types by indexes.

Enemies are a further chapter, true AI is pretty hard, but there are some collision avoidance examples around, with source.
An alternative to AI is Waypoints. For this you only need to walk around in your level while recording your position frequently, then store this list of positions, just to apply it to an enemy in the engine. So the enemy will then walk along the points you have recorded, and only attack the player when he's visible to the enemy. This way your enemies even don't need collision since they follow the waypoints anyway.

Multiplayer is yet a further job that will make things much more complicated. If you want multiplayer, you should implement it from beginning on to prevent dead ends.

SaveGame is probably the trickiest thing, if you want SaveGame and LoadGame to work correctly (save any game State and restore it by the user) then you best implement this from beginning on as well, because it will become almost impossible if you didn't think of it from beginning on.

And keep it up, Unreal wasn't made by a single person on a rainy afternoon.


wizzlefish(Posted 2004) [#12]
I only have two problems with the code above: one, the gun mesh I made is not in the lower-right hand corner, but in the middle of the right hand side. Another is that all collisions work, except for me and the walls....but...wait a minute! I just had an idea!

Goooo me!


WolRon(Posted 2004) [#13]
the gun mesh I made is not in the lower-right hand corner

Then modify this line to put it where you want it.


Arrange your objects.
MoveEntity weapon1, .1, -.15, .1