simple 3D shooter

Started by RemiD, October 21, 2018, 11:08:03

Previous topic - Next topic

RemiD

Hello,

I initially started to code this by showing Phodis how to detect collisions / reposition turning moving entities using linepicks and pickables, see : https://www.syntaxbomb.com/index.php/topic,4937.msg20244.html#15

and then i added some things / improvements here and there, and now i plan to (try to) finish a simple 3d shooter.

here is where i am at :

;see last post of this thread

Pakz

Brilliant!!

Wish there was example code like this back when b3d came out :)

phodiS

I can follow bits and pieces on your code RemiD... this is shaping up to be something really good... I'm envisioning that game Ravenfield and how I imagine
it would have started out in it's early stages. Freaking awesome :)

peteswansen


3DzForMe

Nice work Remid, very clear code  :)
BLitz3D, IDEal, AGK Studio, BMax, Java Code, Cerberus
Recent Hardware: Dell Laptop
Oldest Hardware: Commodore Amiga 1200 with 1084S Monitor & Blitz Basic 2.1

RemiD

#5
a few updates :
->i have put the player and the bots in one list "humanoids"
->i have added grenades (so now there are bullets, grenades, mines)
->humanoids, when damaged, lose particles of blood (red)
->each weapon produce a different amount of damage and consequently different amount of blood particles

the game is all made of primitives at the moment...
edit : fixed a bug

;simple-shooter-3D-201810242122
Graphics3D(1000,624,32,2)

HidePointer()

SeedRnd(MilliSecs())

Global ColorR%
Global ColorG%
Global ColorB%

;----------premade shapes----------
Global XRock = CreateRock(8,0.4)
ScaleMesh(XRock,2.0/2,1.5/2,2.0/2)
PositionMesh(XRock,0,1.5/2-0.5,0)
EntityColor(XRock,125,125,125)
HideEntity(XRock)

Global XTree = CreateTree()
EntityColor(XTree,100,050,000)
HideEntity(XTree)

Global XHumanoid = CreateCylinder(16)
ScaleMesh(XHumanoid,0.5/2,1.75/2,0.5/2)
PositionMesh(XHumanoid,0,0.875,0)
EntityColor(XHumanoid,125,125,255)
HideEntity(XHumanoid)

Global XBullet = CreateSphere(2)
ScaleMesh(XBullet,0.06/2,0.06/2,0.06/2)
EntityColor(XBullet,190,190,190)
HideEntity(XBullet)

Global XGrenade = CreateMesh()
TPart = CreateSphere(8)
ScaleMesh(TPart,0.3/2,0.3/2,0.3/2)
AddMesh(TPart,XGrenade) : FreeEntity(TPart)
TPart = CreateCylinder(8)
ScaleMesh(TPart,0.1/2,0.2/2,0.1/2)
PositionMesh(TPart,0,0.3/2,0)
AddMesh(TPart,XGrenade) : FreeEntity(TPart)
EntityColor(XGrenade,065,130,065)
HideEntity(XGrenade)

Global XMine = CreateCylinder(16)
ScaleMesh(XMine,0.3/2,0.06/2,0.3/2)
PositionMesh(XMine,0,0,0)
EntityColor(XMine,060,060,060)
HideEntity(XMine)

Global XPack = CreateCube()
ScaleMesh(XPack,0.1/2,0.1/2,0.1/2)
PositionMesh(XPack,0,0.1/2,0)
EntityColor(XPack,255,255,255)
HideEntity(XPack)

Global XTriParticle = CreateSphere(2)
ScaleMesh(XTriParticle,0.06/2,0.06/2,0.06/2)
EntityColor(XTriParticle,125,125,125)
HideEntity(XTriParticle)

Global XCubeParticle = CreateCube()
ScaleMesh(XCubeParticle,0.03/2,0.03/2,0.03/2)
EntityColor(XCubeParticle,125,125,125)
HideEntity(XCubeParticle)

Global XLineParticle = CreateCube()
ScaleMesh(XLineParticle,0.01/2,0.01/2,0.6/2)
EntityColor(XLineParticle,125,125,125)
HideEntity(XLineParticle)

Global XOmniExplosion = CreateSphere(16)
ScaleMesh(XOmniExplosion,1.0/2,1.0/2,1.0/2)
EntityColor(XOmniExplosion,255,125,000)
EntityFX(XOmniExplosion,1+16)
HideEntity(XOmniExplosion)

Global XDirExplosion = CreateCylinder(16)
ScaleMesh(XDirExplosion,1.0/2,1.0/2,1.0/2)
PositionMesh(XDirExplosion,0,1.0/2,0)
EntityColor(XDirExplosion,255,125,000)
EntityFX(XDirExplosion,1+16)
HideEntity(XDirExplosion)

Global XTrail = CreateMesh()
Surface = CreateSurface(XTrail) ;vertices 0 and 3 will be the start of the trail, vertices 1,2 and 4,5 will be the end of the trail
VI% = AddVertex(Surface,-0.06,0.0,0.0) : VertexColor(Surface,VI,255,255,255,0.0)
VI% = AddVertex(Surface,+0.06,0.0,0.0) : VertexColor(Surface,VI,255,255,255,0.0)
VI% = AddVertex(Surface,0.0,0.0,+1.0) : VertexColor(Surface,VI,255,255,255,0.1)
VI% = AddVertex(Surface,0.0,+0.06,0.0) : VertexColor(Surface,VI,255,255,255,0.0)
VI% = AddVertex(Surface,0.0,-0.06,0.0) : VertexColor(Surface,VI,255,255,255,0.0)
VI% = AddVertex(Surface,0.0,0.0,+1.0) : VertexColor(Surface,VI,255,255,255,0.1)
AddTriangle(Surface,0,1,2)
AddTriangle(Surface,3,4,5)
UpdateNormals(XTrail)
EntityFX(XTrail,1+2+16+32)

;-----------------------------------

;camera
Global Camera = CreateCamera()
CameraRange(Camera,1,1000)
CameraClsColor(Camera,001,001,001)

;input
Global MXDiff%
Global MYDiff%

;origine
Origine = CreateCube()
ScaleMesh(Origine,0.03/2,0.03/2,0/03.2)
EntityColor(Origine,255,000,255)
EntityFX(Origine,1)

Global BulletsCount% = 0 ;to track how many bullets are active in the scene
Global GrenadesCount% = 0 ;to track how many grenades are active in the scene
Global MinesCount% = 0 ;to track how many mines are active in the scene
Global ParticlesCount% = 0 ;to track how many particles are active in the scene
Global ExplosionsCount% = 0 ;to track how many explosions are active in the scene
Global TrailsCount% = 0 ;to track how many trails are active in the scene

;ground
Global GroundShape

AddGround()

;rocks
Type Rock
Field Shape
End Type

AddRocks()

;trees
Type Tree
Field Shape
End Type

AddTrees()

;player
Global PlayerYaw#
Global PlayerH%

;humanoids
Type Humanoid
Field Eyes
Field Ears
Field ColorR%, ColorG%, ColorB%
Field Shape
Field VX#
Field VY#
Field VZ#
Field PrevMS%
Field LifeMS%
Field SpeedMS%
Field ShieldMS%
Field PowerMS%
Field BulletsCount%
Field GrenadesCount%
Field MinesCount%
Field Life%
End Type

AddHumanoids()

;bullets
Type Bullet
Field Shape
Field Velocity#
Field VX#
Field VY#
Field VZ#
Field TrailH%
End Type

;grenades
Type Grenade
Field Shape
Field Velocity#
Field Gravity#
Field VX#
Field VY#
Field VZ#
End Type

;mines
Type Mine
Field Shape
End Type

AddMines()

;particles
Type Particle
Field Shape
Field Velocity#
Field Life#
End Type

;explosions
Type Explosion
Field Shape
Field Size#
Field MaxSize#
Field Growth#
End Type

;trails (for bullets)
Type Trail
Field Shape
Field BulletH%
End Type

;packs
Type Pack
Field Kind% ;lifepack or speedpack or shieldpack or powerpack or bulletspack or grenadespack or minespack
Field Shape
End Type

;pack kinds
Const CLife% = 1
Const CSpeed% = 2
Const CShield% = 3
Const CPower% = 4
Const CBullets% = 5
Const CGrenades% = 6
Const CMines% = 7

;lifepack = life+1 during xms
;speedpack = speed*2 during xms
;shieldpack = damagereceived/2 during xms
;powerpack = damageemitted*2 during xms
;bulletspack = bullets+30
;grenadespack = grenades+3
;minespack = mines+3

AddPacks()

EntityPickMode(GroundShape,2) : NameEntity(GroundShape,"GRO"+Str(1))
For r.Rock = Each Rock
EntityPickMode(r\Shape,2) : NameEntity(r\Shape,"ROC"+Str(Handle(r)))
Next
For t.Tree = Each Tree
EntityPickMode(t\Shape,2) : NameEntity(t\Shape,"TRE"+Str(Handle(t)))
Next
For h.Humanoid = Each Humanoid
EntityPickMode(h\Shape,2) : NameEntity(h\Shape,"HUM"+Str(Handle(h)))
Next

Global PickPoint = CreateCube()
ScaleMesh(PickPoint,0.03/2,0.03/2,0.03/2)
EntityColor(PickPoint,255,000,255)
EntityFX(PickPoint,1)

Global PickNormal = CreateCube()
ScaleMesh(PickNormal,0.01/2,0.01/2,0.3/2)
PositionMesh(PickNormal,0,0,0.3/2)
EntityColor(PickNormal,125,000,125)
EntityFX(PickNormal,1)

DLight = CreateLight(1)
LightColor(DLight,255,255,255)
PositionEntity(DLight,50,1000,-1000)
RotateEntity(DLight,45,0,0)

AmbientLight(064,064,064)

PlayerH% = GetHumanoidH(Rand(1,10))
hu.Humanoid = Object.Humanoid(PlayerH)
PositionEntity(Camera,EntityX(hu\Shape,True),EntityY(hu\Shape,True),EntityZ(hu\Shape,True))
MoveEntity(Camera,0,1.65+1.5,-3.0)
TurnEntity(Camera,22.5,0,0)
EntityParent(Camera,hu\Shape)

;PositionEntity(Camera,50,50,-22.5)
;RotateEntity(Camera,45,0,0)

Global MainLoopTimer = CreateTimer(30)

;mainloop
Main()

End()

Function Main()

Repeat

  MainLoopMilliStart% = MilliSecs()

  MXDiff = MouseXSpeed()
  MYDiff = MouseYSpeed()

  ;update humanoids
  UpdateHumanoids()

  ;update bullets
  UpdateBullets()

  ;update grenades
  UpdateGrenades()

  ;update mines
  UpdateMines()

  ;update particles
  UpdateParticles()

  ;update explosions
  UpdateExplosions()

  ;update packs
  UpdatePacks()

  ;update effects (on player / bots)
  UpdateEffects()

  ;update trails
  UpdateTrails()

  ;wireframe mode off/on
  WireFrame(False)
  If( KeyDown(2)=True )
   WireFrame(True)
  EndIf

  ;render
  RenderWorld()
 
  Color(255,255,255)
  If( KeyDown(3)=1 )
   Text(500,0,"Tris = "+TrisRendered())
   Text(500,16,"FPS = "+FPS)
   Text(0,0,"BulletsCount = "+BulletsCount)
   Text(0,16,"GrenadesCount = "+GrenadesCount)
   Text(0,32,"MinesCount = "+MinesCount)
   Text(0,48,"ParticlesCount = "+ParticlesCount)
   Text(0,64,"ExplosionsCount = "+ExplosionsCount)
   Text(0,80,"TrailsCount = "+TrailsCount)
  EndIf

  ;display life points on top of player/bots
  For hu.Humanoid = Each Humanoid
   CameraProject(Camera,EntityX(hu\Shape,True),EntityY(hu\Shape,True)+1.75+0.1,EntityZ(hu\Shape,True))
   LineStr$ = Str(hu\Life) : PX% = ProjectedX()-StringWidth(LineStr)/2 : PY% = ProjectedY()-16
   Color(hu\ColorR*0.9,hu\ColorG*0.9,hu\ColorB*0.9) : Text(PX,PY,LineStr)
  Next

  ;display the result on the screen
  ;Flip(1)
  WaitTimer(MainLoopTimer)
  VWait():Flip(False)

  MainLoopMilliTime = MilliSecs() - MainLoopMilliStart
  If( MainLoopMilliTime < 1 )
   MainLoopMilliTime = 1
  EndIf

  FPS% = 1000.0/MainLoopMilliTime

Until( KeyDown(1)=1 )

End Function

;vertices+triangles (with normals, with colors, with alphas, with uvs)
Function AddSurfaceToOtherSurface(Surface,Mesh,OSurface,OMesh)

SurfaceVerticesCount% = CountVertices(Surface)
;DebugLog("SurfaceVerticesCount = "+SurfaceVerticesCount)
OSurfaceVerticesCount% = CountVertices(OSurface)
;DebugLog("OSurfaceVerticesCount = "+OSurfaceVerticesCount)
For VI% = 0 To CountVertices(Surface)-1 Step 1
  ;DebugLog("VI = "+VI)
  VLX# = VertexX(Surface,VI)
  VLY# = VertexY(Surface,VI)
  VLZ# = VertexZ(Surface,VI)
  TFormPoint(VLX,VLY,VLZ,Mesh,0)
  VGX# = TFormedX()
  VGY# = TFormedY()
  VGZ# = TFormedZ()
  VNX# = VertexNX(Surface,VI)
  VNY# = VertexNY(Surface,VI)
  VNZ# = VertexNZ(Surface,VI)
  VR% = VertexRed(Surface,VI)
  VG% = VertexGreen(Surface,VI)
  VB% = VertexBlue(Surface,VI)
  VA# = VertexAlpha(Surface,VI)
  VU# = VertexU(Surface,VI,0)
  VV# = VertexV(Surface,VI,0)
  If( OSurfaceVerticesCount = 0 )
   NVI = VI
  Else If( OSurfaceVerticesCount > 0 )
   NVI% = OSurfaceVerticesCount+VI
  EndIf
  ;DebugLog("NVI = "+NVI)
  AddVertex(OSurface,VGX,VGY,VGZ)
  VertexNormal(OSurface,NVI,VNX,VNY,VNZ)
  VertexColor(OSurface,NVI,VR,VG,VB,VA)
  VertexTexCoords(OSurface,NVI,VU,VB)
  ;WaitKey()
Next
SurfaceTrianglesCount% = CountTriangles(Surface)
;DebugLog("SurfaceTrianglesCount = "+SurfaceTrianglesCount)
OSurfaceTrianglesCount% = CountTriangles(OSurface)
;DebugLog("OSurfaceTrianglesCount = "+OSurfaceTrianglesCount)
For TI% = 0 To CountTriangles(Surface)-1 Step 1
  V0I% = TriangleVertex(Surface,TI,0) ;vertex0
  V1I% = TriangleVertex(Surface,TI,1) ;vertex1
  V2I% = TriangleVertex(Surface,TI,2) ;vertex2
  ;DebugLog("oldtriangle"+TI+" "+V0I+","+V1I+","+V2I)
  If( OSurfaceVerticesCount = 0 )
   NV0I% = V0I
   NV1I% = V1I
   NV2I% = V2I
  Else If( OSurfaceVerticesCount > 0 )
   NV0I% = OSurfaceVerticesCount+V0I
   NV1I% = OSurfaceVerticesCount+V1I
   NV2I% = OSurfaceVerticesCount+V2I
  EndIf
  ;DebugLog("newtriangle"+TI+" "+NV0I+","+NV1I+","+NV2I)
  AddTriangle(OSurface,NV0I,NV1I,NV2I)
Next
;WaitKey()

End Function

Function ColorWithBrush(Surface,R%,G%,B%,A#=1.0,Fx%=0,BlendMode%=1)

Brush = CreateBrush()
BrushColor(Brush,R,G,B)
BrushAlpha(Brush,A)
BrushFX(Brush,Fx)
BrushBlend(Brush,BlendMode)
PaintSurface(Surface,Brush)
FreeBrush(Brush)

End Function

Function CreateRock(Details%=8,MaxIrregularity#=0.3)

SMesh = CreateSphere(Details)
SSurface = GetSurface(SMesh,1)

DMesh = CreateMesh()
DSurface = CreateSurface(DMesh)
DVerticesCount% = 0

;for each triangle of the source surface
For STI% = 0 To CountTriangles(SSurface)-1 Step 1

  ;for vertex0 of this triangle
  SV0I% = TriangleVertex(SSurface,STI,0)
  ;get this vertex0 position
  X# = VertexX(SSurface,SV0I) : Y# = VertexY(SSurface,SV0I) : Z# = VertexZ(SSurface,SV0I)
  ;check if there is already a vertex existing at this position in the destination surface (with a tolerance of 0.01unit)
  TVI% = -1
  For DVI% = 0 To CountVertices(DSurface)-1 Step 1
   If( VertexX(DSurface,DVI) >= X-0.01 And VertexX(DSurface,DVI) <= X+0.01 And VertexY(DSurface,DVI) >= Y-0.01 And VertexY(DSurface,DVI) <= Y+0.01 And VertexZ(DSurface,DVI) >= Z-0.01 And VertexZ(DSurface,DVI) <= Z+0.01 )
    TVI = DVI
    Exit
   EndIf
  Next
  ;if yes
  If( TVI <> - 1 )
   ;use this vertex
   DV0I% = TVI
  ;if no
  Else If( TVI% = - 1 )
   ;create a new vertex in the destination surface
   DVerticesCount = DVerticesCount + 1
   DV0I% = DVerticesCount - 1
   AddVertex(DSurface,X,Y,Z)
  EndIf

  ;for vertex1 of this triangle
  SV1I% = TriangleVertex(SSurface,STI,1)
  ;get this vertex1 position
  X# = VertexX(SSurface,SV1I) : Y# = VertexY(SSurface,SV1I) : Z# = VertexZ(SSurface,SV1I)
  ;check if there is already a vertex existing at this position in the destination surface (with a tolerance of 0.01unit)
  TVI% = -1
  For DVI% = 0 To CountVertices(DSurface)-1 Step 1
   If( VertexX(DSurface,DVI) >= X-0.01 And VertexX(DSurface,DVI) <= X+0.01 And VertexY(DSurface,DVI) >= Y-0.01 And VertexY(DSurface,DVI) <= Y+0.01 And VertexZ(DSurface,DVI) >= Z-0.01 And VertexZ(DSurface,DVI) <= Z+0.01 )
    TVI = DVI
    Exit
   EndIf
  Next
  ;if yes
  If( TVI <> - 1 )
   ;use this vertex
   DV1I% = TVI
  ;if no
  Else If( TVI% = - 1 )
   ;create a new vertex in the destination surface
   DVerticesCount = DVerticesCount + 1
   DV1I% = DVerticesCount - 1
   AddVertex(DSurface,X,Y,Z)
  EndIf

  ;for vertex2 of this triangle
  SV2I% = TriangleVertex(SSurface,STI,2)
  ;get this vertex0 position
  X# = VertexX(SSurface,SV2I) : Y# = VertexY(SSurface,SV2I) : Z# = VertexZ(SSurface,SV2I)
  ;check if there is already a vertex existing at this position in the destination surface (with a tolerance of 0.01unit)
  TVI% = -1
  For DVI% = 0 To CountVertices(DSurface)-1 Step 1
   If( VertexX(DSurface,DVI) >= X-0.01 And VertexX(DSurface,DVI) <= X+0.01 And VertexY(DSurface,DVI) >= Y-0.01 And VertexY(DSurface,DVI) <= Y+0.01 And VertexZ(DSurface,DVI) >= Z-0.01 And VertexZ(DSurface,DVI) <= Z+0.01 )
    TVI = DVI
    Exit
   EndIf
  Next
  ;if yes
  If( TVI <> - 1 )
   ;use this vertex
   DV2I% = TVI
  ;if no
  Else If( TVI% = - 1 )
   ;create a new vertex in the destination surface
   DVerticesCount = DVerticesCount + 1
   DV2I% = DVerticesCount - 1
   AddVertex(DSurface,X,Y,Z)
  EndIf

  ;create a new triangle in the destination surface
  AddTriangle(DSurface,DV0I,DV1I,DV2I)
 
Next

UpdateNormals(DMesh)

;add some irregularities to the surface
For DVI% = 0 To CountVertices(DSurface)-1 Step 1
  X# = VertexX(DSurface,DVI) : Y# = VertexY(DSurface,DVI) : Z# = VertexZ(DSurface,DVI)
  NX# = VertexNX(DSurface,DVI) : NY# = VertexNY(DSurface,DVI) : NZ# = VertexNZ(DSurface,DVI)
  NewX# = X + NX*Rnd(0.1,MaxIrregularity) : NewY# = Y + NY*Rnd(0.1,MaxIrregularity) : NewZ# = Z + NZ*Rnd(0.1,MaxIrregularity)
  VertexCoords(DSurface,DVI,NewX,NewY,NewZ)
Next

DebugLog(CountVertices(SSurface)+" "+CountTriangles(SSurface))
DebugLog(CountVertices(DSurface)+" "+CountTriangles(DSurface))

FreeEntity(SMesh)

UpdateNormals(DMesh)

Return DMesh

End Function

Function CreateTree()

DMesh = CreateMesh()

TPart = CreateCone(8)
ScaleMesh(TPart,0.3/2,3.0/2,0.3/2)
PositionMesh(TPart,0,3.0/2,0)
AddMesh(TPart,DMesh) : FreeEntity(TPart)

Return DMesh

End Function

Function Distance2D#(PAX#,PAZ#,PBX#,PBZ#)

Distance2D# = Sqr( ( ( PBX - PAX ) * ( PBX - PAX ) ) + ( ( PBZ - PAZ ) * ( PBZ - PAZ ) ) )
Return Distance2D

End Function

Function Distance3D#(PAX#,PAY#,PAZ#,PBX#,PBY#,PBZ#)

Distance3D# = Sqr( ( ( PBX - PAX ) * ( PBX - PAX ) ) + ( ( PBY - PAY ) * ( PBY - PAY ) ) + ( ( PBZ - PAZ ) * ( PBZ - PAZ ) ) )
Return Distance3D

End Function

Function AddGround()

GroundShape = CreateCube()
ScaleMesh(GroundShape,100.0/2,1.0/2,100.0/2)
PositionMesh(GroundShape,100.0/2,-1.0/2,100.0/2)
EntityColor(GroundShape,050,150,050)

End Function

Function AddRocks()

For n% = 1 To 15 Step 1
  ;choose a position
  .LineChooseRockPosition
  X# = Rnd(0+1.0,100-1.0) : Z# = Rnd(0+1.0,100-1.0)
  ;check if this position is far enough from others existing rocks
  For rr.Rock = Each Rock
   D# = Distance2D(X,Z,EntityX(rr\Shape,True),EntityZ(rr\Shape,True))
   If( D < 1.0+1.0+1.0 )
    Goto LineChooseRockPosition ;i have not added a check to exit the loop in case there are no more empty space, so don't add too many rocks !!!
   EndIf
  Next
  r.Rock = New Rock
  r\Shape = CopyEntity(XRock)
  Size# = Rnd(0.5,2.0)
  ScaleEntity(r\Shape,Size,Size,Size)
  PositionEntity(r\Shape,X,0,Z)
Next

End Function

Function AddTrees()

For n% = 1 To 60 Step 1
  ;choose a position
  .LineChooseTreePosition
  X# = Rnd(0+1.5,100-1.5) : Z# = Rnd(0+1.5,100-1.5)
  ;check if this position is far enough from others existing rocks
  For rr.Rock = Each Rock
   D# = Distance2D(X,Z,EntityX(rr\Shape,True),EntityZ(rr\Shape,True))
   If( D < 1.0+1.5+1.0 )
    Goto LineChooseTreePosition ;i have not added a check to exit the loop in case there are no more empty space, so don't add too many trees !!!
   EndIf
  Next
  ;check if this position is far enough from others existing trees
  For tt.Tree = Each Tree
   D# = Distance2D(X,Z,EntityX(tt\Shape,True),EntityZ(tt\Shape,True))
   If( D < 1.5+1.5+1.0 )
    Goto LineChooseTreePosition ;i have not added a check to exit the loop in case there are no more empty space, so don't add too many trees !!!
   EndIf
  Next
  t.Tree = New Tree
  t\Shape = CopyEntity(XTree)
  Size# = Rnd(1.0,3.0)
  ScaleEntity(t\Shape,Size,Size,Size)
  PositionEntity(t\Shape,X,0,Z)
Next

End Function

Function AddHumanoids()

For n% = 1 To 10 Step 1
  ;choose a position
  .LineChooseHumanoidPosition
  X# = Rnd(0+0.25,100-0.25) : Z# = Rnd(0+0.25,100-0.25)
  ;check if this position is far enough from others existing rocks
  For rr.Rock = Each Rock
   D# = Distance2D(X,Z,EntityX(rr\Shape,True),EntityZ(rr\Shape,True))
   If( D < 2.0+0.25+1.0 )
    Goto LineChooseHumanoidPosition ;i have not added a check to exit the loop in case there are no more empty space, so don't add too many humanoids !!!
   EndIf
  Next
  ;check if this position is far enough from others existing trees
  For tt.Tree = Each Tree
   D# = Distance2D(X,Z,EntityX(tt\Shape,True),EntityZ(tt\Shape,True))
   If( D < 1.5+0.25+1.0 )
    Goto LineChooseHumanoidPosition ;i have not added a check to exit the loop in case there are no more empty space, so don't add too many humanoids !!!
   EndIf
  Next
  ;check if this position is far enough from others existing humanoids
  For hh.Humanoid = Each Humanoid
   D# = Distance2D(X,Z,EntityX(hh\Shape,True),EntityZ(hh\Shape,True))
   If( D < 0.25+0.25+1.0 )
    Goto LineChooseHumanoidPosition ;i have not added a check to exit the loop in case there are no more empty space, so don't add too many humanoids !!!
   EndIf
  Next
  h.Humanoid = New Humanoid
  h\ColorR = Rand(025,255) : h\ColorG = Rand(025,255) : h\ColorB = Rand(025,255)
  h\Shape = CopyEntity(XHumanoid)
  EntityColor(h\Shape,h\ColorR,h\ColorG,h\ColorB)
  PositionEntity(h\Shape,X,0,Z)
  h\PrevMS = MilliSecs()+Rand(1,1000)
  h\LifeMS = MilliSecs()-100000
  h\SpeedMS = MilliSecs()-100000
  h\ShieldMS = MilliSecs()-100000
  h\PowerMS = MilliSecs()-100000
  h\Life = 100
Next

End Function

Function AddMines()

For n% = 1 To 50 Step 1
  .LineChooseMinePosition
  X# = Rnd(0+0.3,100-0.3) : Z# = Rnd(0+0.3,100-0.3) : Y# = 0
  MinesCount = MinesCount + 1
  m.Mine = New Mine
  m\Shape = CopyEntity(XMine)
  PositionEntity(m\Shape,X,Y,Z)
Next

End Function

Function AddPacks()

For n% = 1 To 10 Step 1
  TKind% = Rand(1,1) ;Rand(1,7) ;1->LifePack 2->SpeedPack 3->ShieldPack 4->PowerPack 5->BulletsPack 6->GrenadesPack 7->MinesPack
  .LineChoosePackPosition
  X# = Rnd(0+0.05,100.0-0.05) : Z# = Rnd(0+0.05,100.0-0.05)
  p.Pack = New Pack
  p\Kind = TKind
  p\Shape = CopyEntity(XPack)
  GetPackColor(TKind)
  EntityColor(p\Shape,ColorR,ColorG,ColorB)
  PositionEntity(p\Shape,X,0.05,Z)
Next

End Function

Function GetPackColor(TKind%)

If( TKind = CLife ) ;lifepack
  ColorR = 065 : ColorG = 255 : ColorB = 255
Else If( TKind = CSpeed ) ;speedpack
  ColorR = 255 : ColorG = 255 : ColorB = 065
Else If( TKind = CShield ) ;shieldpack
  ColorR = 065 : ColorG = 255 : ColorB = 065
Else If( TKind = CPower ) ;powerpack
  ColorR = 255 : ColorG = 065 : ColorB = 065
Else If( TKind = CBullets ) ;bulletspack
  ColorR = 125 : ColorG = 095 : ColorB = 095
Else If( TKind = CGrenades ) ;grenadespack
  ColorR = 095 : ColorG = 125 : ColorB = 095
Else If( TKind = CMines ) ;minespack
  ColorR = 095 : ColorG = 095 : ColorB = 125
EndIf

End Function

Function GetHumanoidH%(I%)

TI% = 0
For h.Humanoid = Each Humanoid
  TI = TI + 1
  If( I = TI )
   Return Handle(h)
  EndIf
Next

End Function

Function UpdateHumanoids()

;update player depending on controls
pl.Humanoid = Object.Humanoid(PlayerH)
If( pl\Life <= 0 )
  ;destroy player
  FreeEntity(pl\Shape) : Delete(pl)
Else If( pl\Life > 0 )
  ;update player
  ;turn left/right
  MoveMouse(GraphicsWidth()/2,GraphicsHeight()/2)
  PlayerYaw = PlayerYaw - Float(MXDiff)/10
  RotateEntity(pl\Shape,0,PlayerYaw,0,False)
  ;move forward/backward/left/right
  Velocity# = 6.666/30.0
  If( KeyDown(17)=0 And KeyDown(31)=0 And KeyDown(30)=0 And KeyDown(32)=0 )
   TFormVector(0,0,0,pl\Shape,0)
  Else If( KeyDown(17)=1 )
   TFormVector(0,0,+Velocity,pl\Shape,0)
  Else If( KeyDown(31)=1 )
   TFormVector(0,0,-Velocity,pl\Shape,0)
  Else If( KeyDown(30)=1 ) 
   TFormVector(-Velocity,0,0,pl\Shape,0)
  Else If( KeyDown(32)=1 )
   TFormVector(+Velocity,0,0,pl\Shape,0)
  EndIf
  ;calculates the movement vector
  pl\VX = TFormedX() : pl\VY = TFormedY() : pl\VZ = TFormedZ()
  ;before moving humanoid, check if it will collide with an obstacle entity (ground or rock or tree or humanoid)
  TFormPoint(0,0.25,0,pl\Shape,0) ;root of humanoid shape +0.25 (on the Y axis)
  LinePick(TFormedX(),TFormedY(),TFormedZ(),pl\VX,pl\VY,pl\VZ,0.25-0.01) ;humanoid radius is 0.25 ;throws a linepick from the position of humanoid +0.25 to direction of the movement vector
  EntRef% = PickedEntity()
  ;if yes
  If( EntRef <> 0 )
   PositionEntity(PickPoint,PickedX(),PickedY(),PickedZ())
   PositionEntity(PickNormal,PickedX(),PickedY(),PickedZ()) : AlignToVector(PickNormal,PickedNX(),PickedNY(),PickedNZ(),3,1.0)
   ;recalculate the appropriate position
   PlayerX# = EntityX(pl\Shape,True) : PlayerY# = EntityY(pl\Shape,True) : PlayerZ# = EntityZ(pl\Shape,True)
   PickX# = PickedX() : PickY# = PickedZ() : PickZ# = PickedZ()
   D# = Distance2D(PlayerX,PlayerZ,PickX,PickZ)
   TCoeff# = (D-0.25)/(Velocity)
   pl\VX = pl\VX*TCoeff : pl\VZ = pl\VZ*TCoeff
   ;move player
   TranslateEntity(pl\Shape,pl\VX,pl\VY,pl\VZ)
  ;if no
  Else If( EntRef = 0 )
   ;move player
   TranslateEntity(pl\Shape,pl\VX,pl\VY,pl\VZ)
  EndIf

  If( MouseDown(1)=1 )
   ;shoot a bullet
   NowMS% = MilliSecs()
   If( NowMS - pl\PrevMS > 100 )
    ;create a new bullet
    BulletsCount = BulletsCount + 1
    bu.Bullet = New Bullet
    bu\Shape = CopyEntity(XBullet)
    PositionEntity(bu\Shape,EntityX(pl\Shape,True),EntityY(pl\Shape,True)+0.875,EntityZ(pl\Shape,True))
    RotateEntity(bu\Shape,EntityPitch(pl\Shape,True),EntityYaw(pl\Shape,True),EntityRoll(pl\Shape,True))
    TurnEntity(bu\Shape,Rnd(-1,+1),Rnd(-1,+1),0)
    ;bu\Velocity = 35.208/30.0*Rnd(0.9,1.1)
    bu\Velocity = 125.0/30.0*Rnd(0.9,1.1)
    ;get bullet position / orientation
    TX# = EntityX(bu\Shape,True) : TY# = EntityY(bu\Shape,True) : TZ# = EntityZ(bu\Shape,True)
    TPitch# = EntityPitch(bu\Shape,True) : TYaw# = EntityYaw(bu\Shape,True) : TRoll# = EntityRoll(bu\Shape,True)
    ;create a new trail
    TrailsCount = TrailsCount + 1
    tr.Trail = New Trail
    tr\Shape = CopyEntity(XTrail)
    PositionEntity(tr\Shape,TX,TY,TZ,True)
    RotateEntity(tr\Shape,TPitch,TYaw,TRoll,True)
    ScaleEntity(tr\Shape,1.0,1.0,0.001)
    ;associate bullet and trail
    bu\TrailH% = Handle(tr)
    ;associate trail and bullet
    tr\BulletH% = Handle(bu)
    ;store new milli value
    pl\PrevMS = NowMS
   EndIf

  Else If( MouseHit(2)=1 )
   ;throw a grenade
   NowMS% = MilliSecs()
   If( NowMS - pl\PrevMS > 250 )
    ;create a new grenade
    GrenadesCount = GrenadesCount + 1
    gr.Grenade = New Grenade
    gr\Shape = CopyEntity(XGrenade)
    PositionEntity(gr\Shape,EntityX(pl\Shape,True),EntityY(pl\Shape,True)+0.875,EntityZ(pl\Shape,True))
    RotateEntity(gr\Shape,EntityPitch(pl\Shape,True),EntityYaw(pl\Shape,True),EntityRoll(pl\Shape,True))
    TurnEntity(gr\Shape,-45,Rnd(-1,+1),0)
    gr\Velocity = 35.208/3.0/30.0*Rnd(0.9,1.1)
    gr\Gravity = 0.0
    ;store new milli value
    pl\PrevMS = NowMS
   EndIf   

  Else If( MouseHit(3)=1 )
   ;drop a mine
 
  EndIf

EndIf

;update bots depending on AI
For bo.Humanoid = Each Humanoid
  If( Handle(bo) <> PlayerH )
   If( bo\Life <= 0 )
    ;destroy bot
    FreeEntity(bo\Shape) : Delete(bo)
   Else If( bo\Life > 0 )
    ;update bot
    ;simple AI :
    ;check if player is near enough
    D# = Distance2D(EntityX(bo\Shape,True),EntityZ(bo\Shape,True),EntityX(pl\Shape,True),EntityZ(pl\Shape,True))
    If( D < 30 )
     PointEntity(bo\Shape,pl\Shape,0)
     ;shoot a bullet
     NowMS% = MilliSecs()
     If( NowMS - bo\PrevMS > Rand(200,400) )
      ;create a new bullet
      BulletsCount = BulletsCount + 1
      bu.Bullet = New Bullet
      bu\Shape = CopyEntity(XBullet)
      PositionEntity(bu\Shape,EntityX(bo\Shape,True),EntityY(bo\Shape,True)+0.875,EntityZ(bo\Shape,True))
      RotateEntity(bu\Shape,EntityPitch(bo\Shape,True),EntityYaw(bo\Shape,True),EntityRoll(bo\Shape,True))
      TurnEntity(bu\Shape,Rnd(-1,+1),Rnd(-1,+1),0)
      bu\Velocity = 125.0/30.0*Rnd(0.9,1.1)
      ;get bullet position / orientation
      TX# = EntityX(bu\Shape,True) : TY# = EntityY(bu\Shape,True) : TZ# = EntityZ(bu\Shape,True)
      TPitch# = EntityPitch(bu\Shape,True) : TYaw# = EntityYaw(bu\Shape,True) : TRoll# = EntityRoll(bu\Shape,True)
      ;create a new trail
      TrailsCount = TrailsCount + 1
      tr.Trail = New Trail
      tr\Shape = CopyEntity(XTrail)
      PositionEntity(tr\Shape,TX,TY,TZ,True)
      RotateEntity(tr\Shape,TPitch,TYaw,TRoll,True)
      ScaleEntity(tr\Shape,1.0,1.0,0.001)
      ;associate bullet and trail
      bu\TrailH% = Handle(tr)
      ;associate trail and bullet
      tr\BulletH% = Handle(bu)
      ;store new milli value
      bo\PrevMS = NowMS
     EndIf
     ;throw a grenade
     ;
     ;drop a mine
    EndIf
   EndIf
  EndIf
Next

End Function

Function UpdateBullets()

For bu.Bullet = Each Bullet

  ;calculates the movement vector
  TFormVector(0,0,+bu\Velocity,bu\Shape,0)
  ;calculates the movement vector
  bu\VX = TFormedX() : bu\VY = TFormedY() : bu\VZ = TFormedZ()
  ;before moving the Bullet, check if it will collide with an obstacle entity (ground or rock or tree or humanoid)
  TFormPoint(0,0,0,bu\Shape,0) ;root of Bullet shape
  LinePick(TFormedX(),TFormedY(),TFormedZ(),bu\VX,bu\VY,bu\VZ,0.03) ;bullet radius is 0.03 ;throws a linepick from the position of Bullet +0 to direction of the movement vector 
  EntRef% = PickedEntity()

  ;if yes
  If( EntRef <> 0 )
   ;recalculate the appropriate position
   BulletX# = EntityX(bu\Shape,True) : BulletY# = EntityY(bu\Shape,True) : BulletZ# = EntityZ(bu\Shape,True)
   PickX# = PickedX() : PickY# = PickedY() : PickZ# = PickedZ()
   PickNX# = PickedNX() : PickNY# = PickedNY() : PickNZ# = PickedNZ()
   D# = Distance2D(BulletX,BulletZ,PickX,PickZ)
   TCoeff# = (D-0.03)/(bu\Velocity)
   bu\VX = bu\VX*TCoeff : bu\VY = bu\VY*TCoeff : bu\VZ = bu\VZ*TCoeff
   ;move Bullet
   TranslateEntity(bu\Shape,bu\VX,bu\VY,bu\VZ)

   ;get the name, kind, handle of the entity hit (ground or rock or tree or bot or player)
   EntName$ = EntityName(EntRef) : EntKind$ = Left(EntName,3) : EntH% = Right(EntName,Len(EntName)-3)

   ;depending on the kind, get the color of the material hit
   MaterialR% = 000 : MaterialG% = 000 : MaterialB% = 000
   If( EntKind = "GRO" ) ;050,150,050
    MaterialR% = 050*0.9 : MaterialG% = 150*0.9 : MaterialB% = 050*0.9
   Else If( EntKind = "ROC" ) ;125,125,125
    MaterialR% = 125*0.9 : MaterialG% = 125*0.9 : MaterialB% = 125*0.9
   Else If( EntKind = "TRE" ) ;100,050,000 (trunc)
    MaterialR% = 100*0.9 : MaterialG% = 050*0.9 : MaterialB% = 000*0.9
   Else If( EntKind = "HUM" ) ;125,125,255
    MaterialR% = 225*0.9 : MaterialG% = 000*0.9 : MaterialB% = 000*0.9
   EndIf

   ;destroy the associated trail
   trH% = bu\TrailH
   tr.Trail = Object.Trail(trH)
   FreeEntity(tr\Shape) : Delete(tr)
   TrailsCount = TrailsCount - 1

   ;destroy the Bullet
   FreeEntity(bu\Shape) : Delete(bu)
   BulletsCount = BulletsCount - 1

   ;create particles of impact/damage
   For n% = 1 To 8 Step 1
    pa.Particle = New Particle : ParticlesCount = ParticlesCount + 1
    pa\Shape = CopyEntity(XTriParticle)
    EntityColor(pa\Shape,MaterialR,MaterialG,MaterialB)
    PositionEntity(pa\Shape,PickX,PickY,PickZ)
    AlignToVector(pa\Shape,PickNX,PickNY,PickNZ,3,1.0) : TurnEntity(pa\Shape,Rand(-45,+45),Rand(-45,+45),0)
    pa\Velocity = 0.03
    pa\Life = 1.0
   Next

   ;remove life from collided entity (if humanoid)
   If( EntKind = "HUM" )
    hu.Humanoid = Object.Humanoid(EntH)
    hu\Life = hu\Life - 2
   EndIf

  ;if no
  Else If( EntRef = 0 )
   ;move the Bullet
   TranslateEntity(bu\Shape,bu\VX,bu\VY,bu\VZ)
  EndIf

  If( bu <> Null )

   ;check if Bullet is near enough or too far the center of the map
   D#=Distance3D(50,0.875,50,EntityX(bu\Shape,True),EntityY(bu\Shape,True),EntityZ(bu\Shape,True))

   ;if too far
   If( D > 100.0 )

    ;destroy the associated trail
    trH% = bu\TrailH
    tr.Trail = Object.Trail(trH)
    FreeEntity(tr\Shape) : Delete(tr)
    TrailsCount = TrailsCount - 1

    ;destroy the Bullet
    FreeEntity(bu\Shape) : Delete(bu)
    BulletsCount = BulletsCount - 1

   EndIf

  EndIf

Next

End Function

Function UpdateGrenades()

For gr.Grenade = Each Grenade

  ;increase gravity force
  gr\Gravity = gr\Gravity + 9.780/30.0/10

  ;calculates the movement vector
  TFormVector(0,-gr\Gravity,+gr\Velocity,gr\Shape,0)
  gr\VX = TFormedX() : gr\VY = TFormedY() : gr\VZ = TFormedZ()
  ;before moving the Grenade, check if it will collide with an obstacle entity (ground or rock or tree or humanoid)
  TFormPoint(0,0,0,gr\Shape,0) ;root of grenade shape
  LinePick(TFormedX(),TFormedY(),TFormedZ(),gr\VX,gr\VY,gr\VZ,0.3) ;grenade radius is 0.3 ;throws a linepick from the position of grenade +0 to direction of the movement vector 
  EntRef% = PickedEntity()

  ;if yes
  If( EntRef <> 0 )
   ;recalculate the appropriate position
   GrenadeX# = EntityX(gr\Shape,True) : GrenadeY# = EntityY(gr\Shape,True) : GrenadeZ# = EntityZ(gr\Shape,True)
   PickX# = PickedX() : PickY# = PickedY() : PickZ# = PickedZ()
   PickNX# = PickedNX() : PickNY# = PickedNY() : PickNZ# = PickedNZ()
   D# = Distance3D(GrenadeX,GrenadeY,GrenadeZ,PickX,PickY,PickZ)
   TCoeff# = (D-0.3)/(gr\Velocity)
   gr\VX = gr\VX*TCoeff : gr\VY = gr\VY*TCoeff : gr\VZ = gr\VZ*TCoeff

   ;move grenade
   TranslateEntity(gr\Shape,gr\VX,gr\VY,gr\VZ)

   ;get the name, kind, handle of the entity hit (ground or rock or tree or bot or player)
   EntName$ = EntityName(EntRef) : EntKind$ = Left(EntName,3) : EntH% = Right(EntName,Len(EntName)-3)

   ;store grenade properties
   GrenadeX# = EntityX(gr\Shape,True) : GrenadeY# = EntityY(gr\Shape,True) : GrenadeZ# = EntityZ(gr\Shape,True)

   ;destroy grenade
   FreeEntity(gr\Shape) : Delete(gr)
   GrenadesCount = GrenadesCount - 1

   ;create explosion effect
   e.Explosion = New Explosion : ExplosionsCount = ExplosionsCount + 1
   e\Shape = CopyEntity(XOmniExplosion)
   e\Size = 0.3
   e\MaxSize = 3.0
   e\Growth = 0.2
   A# = 1.0-(e\Size/e\MaxSize)
   EntityAlpha(e\Shape,A)
   PositionEntity(e\Shape,GrenadeX,GrenadeY,GrenadeZ)

   ;create particles of spread (from Grenade)
   MaterialR% = 065 : MaterialG% = 130 : MaterialB% = 065
   For n% = 1 To 32 Step 1
    pa.Particle = New Particle : ParticlesCount = ParticlesCount + 1
    pa\Shape = CopyEntity(XCubeParticle)
    EntityColor(pa\Shape,MaterialR,MaterialG,MaterialB)
    PositionEntity(pa\Shape,GrenadeX,GrenadeY,GrenadeZ)
    RotateEntity(pa\Shape,-90,0,0) : TurnEntity(pa\Shape,Rand(-180,+180),Rand(-180,+180),0)
    pa\Velocity = 0.09
    pa\Life# = 1.0
   Next

   ;create particles of damage (on ground or rock or tree or humanoid)
   MaterialR% = 000 : MaterialG% = 000 : MaterialB% = 000
   If( EntKind = "GRO" ) ;050,150,050
    MaterialR% = 050*0.9 : MaterialG% = 150*0.9 : MaterialB% = 050*0.9
   Else If( EntKind = "ROC" ) ;125,125,125
    MaterialR% = 125*0.9 : MaterialG% = 125*0.9 : MaterialB% = 125*0.9
   Else If( EntKind = "TRE" ) ;100,050,000 (trunc)
    MaterialR% = 100*0.9 : MaterialG% = 050*0.9 : MaterialB% = 000*0.9
   Else If( EntKind = "HUM" ) ;125,125,255
    MaterialR% = 225*0.9 : MaterialG% = 000*0.9 : MaterialB% = 000*0.9
   EndIf
   For n% = 1 To 120 Step 1
    pa.Particle = New Particle : ParticlesCount = ParticlesCount + 1
    pa\Shape = CopyEntity(XTriParticle)
    EntityColor(pa\Shape,MaterialR,MaterialG,MaterialB)
    PositionEntity(pa\Shape,PickX,PickY,PickZ)
    AlignToVector(pa\Shape,PickNX,PickNY,PickNZ,3,1.0) : TurnEntity(pa\Shape,Rand(-45,+45),Rand(-45,+45),0)
    pa\Velocity = 0.09
    pa\Life = 1.0
   Next

   ;remove life from collided entity (if humanoid)
   If( EntKind = "HUM" )
    hu.Humanoid = Object.Humanoid(EntH)
    hu\Life = hu\Life - 12
   EndIf

  ;if no
  Else If( EntRef = 0 )

   ;move the grenade
   TranslateEntity(gr\Shape,gr\VX,gr\VY,gr\VZ)

  EndIf

  If( gr <> Null )
   
   ;check if grenade is above the ground level

   If( EntityY(gr\Shape,True) < 0 )

    ;destroy the grenade
    FreeEntity(gr\Shape) : Delete(gr)
    GrenadesCount = GrenadesCount - 1

   EndIf

  EndIf

Next

End Function

Function UpdateMines()

For m.Mine = Each Mine

  ;check if an entity triggers it (player or bot)
  IsTriggered% = False
  EntName$ = "" : EntKind$ = "" : EntH% = 0
  ;is player or a bot near enough to trigger it ?
  For hu.Humanoid = Each Humanoid
   D# = Distance2D(EntityX(m\Shape,True),EntityZ(m\Shape,True),EntityX(hu\Shape,True),EntityZ(hu\Shape,True))
   If( D < 0.15+0.25 )
    IsTriggered = True
    EntName$ = EntityName(hu\Shape) : EntKind$ = Left(EntName,3) : EntH% = Right(EntName,Len(EntName)-3)
    Goto LineEndCheckIfTriggered
   EndIf
  Next
  .LineEndCheckIfTriggered
  If( IsTriggered = True )
   ;store mine properties
   MineX# = EntityX(m\Shape,True) : MineY# = EntityY(m\Shape,True) : MineZ# = EntityZ(m\Shape,True)
   ;destroy mine
   FreeEntity(m\Shape) : Delete(m)
   MinesCount = MinesCount - 1

   ;create explosion effect
   e.Explosion = New Explosion : ExplosionsCount = ExplosionsCount + 1
   e\Shape = CopyEntity(XDirExplosion)
   e\Size = 0.01
   e\MaxSize = 3.0
   e\Growth = 0.2
   A# = 1.0-(e\Size/e\MaxSize)
   EntityAlpha(e\Shape,A)
   PositionEntity(e\Shape,MineX,MineY,MineZ)

   ;create particles of spread (from mine)
   MaterialR% = 060 : MaterialG% = 060 : MaterialB% = 060
   For n% = 1 To 16 Step 1
    pa.Particle = New Particle : ParticlesCount = ParticlesCount + 1
    pa\Shape = CopyEntity(XCubeParticle)
    EntityColor(pa\Shape,MaterialR,MaterialG,MaterialB)
    PositionEntity(pa\Shape,MineX,MineY,MineZ)
    RotateEntity(pa\Shape,-90,0,0) : TurnEntity(pa\Shape,Rand(-22.5,+22.5),Rand(-22.5,+22.5),0)
    pa\Velocity = 0.09
    pa\Life# = 1.0
   Next

   ;create particles of damage (on player or on bot)
   If( EntKind = "HUM" )
    MaterialR% = 225 : MaterialG% = 000 : MaterialB% = 000
   EndIf
   For n% = 1 To 200 Step 1
    pa.Particle = New Particle : ParticlesCount = ParticlesCount + 1
    pa\Shape = CopyEntity(XTriParticle)
    EntityColor(pa\Shape,MaterialR,MaterialG,MaterialB)
    PositionEntity(pa\Shape,MineX,MineY,MineZ)
    RotateEntity(pa\Shape,-90,0,0) : TurnEntity(pa\Shape,Rand(-45,+45),Rand(-45,+45),0)
    pa\Velocity = 0.09
    pa\Life# = 1.0
   Next

   ;remove life from collided entity (player or bot)
   If( EntKind = "HUM" )
    hu.Humanoid = Object.Humanoid(EntH)
    hu\Life = hu\Life - 24
   EndIf

  EndIf
Next

End Function

Function UpdateParticles()

For pa.Particle = Each Particle
  MoveEntity(pa\Shape,0,0,pa\Velocity)
  pa\Life = pa\Life - 0.03
  EntityAlpha(pa\Shape,pa\Life)
  If( pa\Life <= 0 )
   FreeEntity(pa\Shape) : Delete(pa)
   ParticlesCount = ParticlesCount - 1
  EndIf
Next

End Function


Function UpdateExplosions()

For e.Explosion = Each Explosion
  e\Size = e\Size + e\Growth
  ScaleEntity(e\Shape,e\Size,e\Size,e\Size)
  A# = 1.0-(e\Size/e\MaxSize)
  EntityAlpha(e\Shape,A)
  If( e\Size => e\MaxSize )
   FreeEntity(e\Shape) : Delete(e)
   ExplosionsCount = ExplosionsCount - 1
  EndIf
Next

End Function

Function UpdatePacks()

  For p.Pack = Each Pack

  ;check if an entity takes it (player or bot)
  IsTaken% = False
  EntName$ = "" : EntKind$ = "" : EntH% = 0
  ;is player or a bot near enough to take it ?
  For hu.Humanoid = Each Humanoid
   D# = Distance2D(EntityX(p\Shape,True),EntityZ(p\Shape,True),EntityX(hu\Shape,True),EntityZ(hu\Shape,True))
   If( D < 0.05+0.25 )
    IsTaken = True
    EntName$ = EntityName(hu\Shape) : EntKind$ = Left(EntName,3) : EntH% = Right(EntName,Len(EntName)-3)
    Goto LineEndCheckIfTaken
   EndIf
  Next
  .LineEndCheckIfTaken
  If( IsTaken = True )
   ;store pack properties
   PackX# = EntityX(p\Shape,True) : PackY# = EntityY(p\Shape,True) : PackZ# = EntityZ(p\Shape,True)
   PackKind% = p\Kind
   ;destroy pack
   FreeEntity(p\Shape) : Delete(p)
   
   ;create particles of effect
   ;

   ;add effect to entity (if player or if bot)
   If( EntKind = "HUM" )
    hu.Humanoid = Object.Humanoid(EntH)
    If( PackKind = CLife )
     hu\LifeMS = MilliSecs()
    Else If( PackKind = CSpeed )
     hu\SpeedMS = MilliSecs()
    Else If( PackKind = CShield )
     hu\ShieldMS = MilliSecs()
    Else If( PackKind = CPower )
     hu\PowerMS = MilliSecs()
    Else If( PackKind = CBullets )
     hu\BulletsCount = hu\BulletsCount+30
    Else If( PackKind = CGrenades )
     hu\GrenadesCount = hu\GrenadesCount+3
    Else If( PackKind = CMines )
     hu\MinesCount = hu\MinesCount+3
    EndIf
   EndIf

  EndIf

Next

End Function

Function UpdateEffects()

NowMS% = MilliSecs()
For hu.Humanoid = Each Humanoid
  ;LifePack effect
  If( NowMS - hu\LifeMS < 10000 )
   hu\Life = hu\Life + 1
   If( hu\Life > 100 )
    hu\Life = 100
   EndIf
  EndIf
  ;SpeedPack effect
  ;
  ;ShieldPack effect
  ;
  ;PowerPack effect
  ;
Next

End Function

Function UpdateTrails()

For tr.Trail = Each Trail
  buH% = tr\BulletH
  bu.Bullet = Object.Bullet(buH)
  D# = Distance3D(EntityX(tr\Shape,True),EntityY(tr\Shape,True),EntityZ(tr\Shape,True),EntityX(bu\Shape,True),EntityY(bu\Shape,True),EntityZ(bu\Shape,True))
  ScaleEntity(tr\Shape,1,1,D)
  ;PositionEntity(tr\Shape,EntityX(bu\Shape,True),EntityY(bu\Shape,True),EntityZ(bu\Shape,True))
  ;RotateEntity(tr\Shape,EntityPitch(bu\Shape,True),EntityYaw(bu\Shape,True),EntityRoll(bu\Shape,True))
  ;ScaleEntity(tr\Shape,1.0,1.0,+bu\Velocity)
Next

End Function


executable (Windows) : http://rd-stuff.fr/simple-shooter-3D-201810242122-EXE.zip

(the "mav" when player has no more life points is normal, i have not finished to code this part)

controls :
mouse horizontal axis to turn left/right
WASD (or ZQSD) to move forward/backward/left/right
mouse left to shoot bullets
mouse right to throw a grenade

i plan to had a way to throw a grenade at different ranges by holding the mouse button for some time then releasing it.

the big step is still to code a system where humanoids can turn move jump fall, and detect collisions to be stopped by obstacles.

then this would also allow to add forces which make the humanoids move in the direction of explosions (of a grenade or mine)

Steve Elliott

Sounds cool.  Hopefully an exe too at the end (for those without Blitz3D).
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

3DzForMe

Blitz 3D is free to download these days, I recommend using it with the IDEal UI, So much coding fun within B3D. And... It'd give you a chance to modify Remid s code, the best way to learn IMO.

Blitz 3D lives on ;)
BLitz3D, IDEal, AGK Studio, BMax, Java Code, Cerberus
Recent Hardware: Dell Laptop
Oldest Hardware: Commodore Amiga 1200 with 1084S Monitor & Blitz Basic 2.1

RemiD

#8
What is funny is that when i was a noob (i started to code 9 years ago, but not continuously) i use to be afraid to post my codes on forums, because i thought that somebody would steal them and make a similar game.

Now i know that for a good enough gameplay, the code has some complex stuff here and there, and keeping a understandable, well organized, error-free, code is not easy, and only a few coders will understand it and be able to use it, so i don't care to post it ;)
(and i don't plan to earn money by selling games anymore, i am more interested in designing/building/selling physical things, like homemade devices which are useful in the real world -> this requires some programming too !)

But making games is a cool hobby in the winter season ! 8)

Xerra

Quote from: RemiD on October 24, 2018, 17:42:00
What is funny is that when i was a noob (i started to code 9 years ago, but not continuously) i use to be afraid to post my codes on forums, because i thought that somebody would steal them and make a similar game.

Now i know that for a good enough gameplay, the code has some complex stuff here and there, and keeping a understandable, well organized, error-free, code is not easy, and only a few coders will understand it and be able to use it, so i don't care to post it ;)
(and i don't plan to earn money by selling games anymore, i am more interested in designing/building/selling physical things, like homemade devices which are useful in the real world -> this requires some programming too !)

But making games is a cool hobby in the winter season ! 8)

This is exactly how I look at it. I made a little money coding some Amiga stuff back in the nineties but I'm stone-cold realistic enough to know that it's a hard thing to make money from either games or application programming now. I always consider game coding a hobby now and do it just to keep my mind sharp and that invariably helps me with my day job anyway, so it's all win.
M2 Pro Mac mini - 16GB 512 SSD
ACER Nitro 5 15.6" Gaming Laptop - Intel® Core™ i7, RTX 3050, 1 TB SSD
Vic 20 - 3.5k 1mhz 6502

Latest game - https://xerra.itch.io/Gridrunner
Blog: http://xerra.co.uk
Itch.IO: https://xerra.itch.io/

3DzForMe

#10
I first coded 35 years ago, a little AI stuff in ZXBasic. Probably explains my coding fatigue of late  ;D

35 z a big number in the years stakes - thanks to Qube and his coding compo s, my mojo has been reinvigorated invigorated... If only a little, cheers Qube.

@xerra, I got a demo of a blitzbasic app (they were called programs back then), on an Amiga Format cover disk, I can't recall if it was diskette or CD, happy days.
BLitz3D, IDEal, AGK Studio, BMax, Java Code, Cerberus
Recent Hardware: Dell Laptop
Oldest Hardware: Commodore Amiga 1200 with 1084S Monitor & Blitz Basic 2.1

Xerra

Quote from: 3DzForMe on October 24, 2018, 23:49:40
I first coded 35 years ago, a little AI stuff in ZXBasic. Probably explains my coding fatigue of late  ;D

35 z a big number in the years stakes - thanks to Qube and his coding compo s, my mojo has been reinvigorated invigorated... If only a little, cheers Qube.

@xerra, I got a demo of a blitzbasic app (they were called programs back then), on an Amiga Format cover disk, I can't recall if it was diskette or CD, happy days.

I remember the same magazine and even buying it from W.H.Smiths in Liverpool Street station as I was catching a train to work from there that afternoon. Reason I remember all that is because I'd been an Amos guy prior to that and a buddy and I were looking forward to getting the demo so we could collaborate on a game for the competition they were running with the demo.

Think it was another year or so before I actually wrote something worthwhile with it, however. Never did do that collaboration :-(

As for years coding, I've been at it since I first read a book on Basic programs and typed in a few listings on my Vic 20 back in 1981 or so. Got a few years where I didn't code much between then and now, however, even though I've always had a computer of some sort since then.
M2 Pro Mac mini - 16GB 512 SSD
ACER Nitro 5 15.6" Gaming Laptop - Intel® Core™ i7, RTX 3050, 1 TB SSD
Vic 20 - 3.5k 1mhz 6502

Latest game - https://xerra.itch.io/Gridrunner
Blog: http://xerra.co.uk
Itch.IO: https://xerra.itch.io/

RemiD

#12
I wonder what hijacking means ? (related to posting on forums) :P

( in a way i hijacked my own thread by talking about my coding history, ;D )

Xerra

Quote from: RemiD on October 25, 2018, 17:28:30
I wonder what hijacking means ? (related to posting on forums) :P

( in a way i hijacked my own thread by talking about my coding history, ;D )

Yeah, kinda went on a tangent there. My bad. Sorry, RemiD. I'll save my waffle for another post where I can brag about what an old fart I am :)
M2 Pro Mac mini - 16GB 512 SSD
ACER Nitro 5 15.6" Gaming Laptop - Intel® Core™ i7, RTX 3050, 1 TB SSD
Vic 20 - 3.5k 1mhz 6502

Latest game - https://xerra.itch.io/Gridrunner
Blog: http://xerra.co.uk
Itch.IO: https://xerra.itch.io/

RemiD

no progress for today because i want to add a rebounding effect for grenades (before they explode) but i have difficulties with some maths formulas to add reflections (of vectors) by considering the movement speed, the gravity speed, the air friction, the impact slowdown... and for now it is a buggy mess  ;D