March 20, 2019, 04:00:15 AM

Author Topic: simple 3D shooter  (Read 893 times)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 801
simple 3D shooter
« on: October 21, 2018, 11:08:03 AM »
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 :
Code: [Select]
;see last post of this thread
DualCore AMD E-450, 1646 MHz - 6 Go DDR3 1333 SDRAM - AMD Radeon HD 6320 Graphics (384 Mo) - Windows 7 Home Premium - DirectX 11.0

Offline Pakz

  • Full Member
  • ***
  • Posts: 131
    • My homepage
Re: simple 3D shooter
« Reply #1 on: October 21, 2018, 11:22:32 AM »
Brilliant!!

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

Offline phodiS

  • Jr. Member
  • **
  • Posts: 40
Re: simple 3D shooter
« Reply #2 on: October 21, 2018, 08:37:35 PM »
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 :)

Offline peteswansen

  • Jr. Member
  • **
  • Posts: 48
Re: simple 3D shooter
« Reply #3 on: October 21, 2018, 08:49:51 PM »
good work Remi!

Offline 3DzForMe

  • Sr. Member
  • ****
  • Posts: 430
Re: simple 3D shooter
« Reply #4 on: October 22, 2018, 02:52:15 PM »
Nice work Remid, very clear code  :)
happy coding ;)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 801
Re: simple 3D shooter
« Reply #5 on: October 23, 2018, 10:05:47 PM »
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
Code: [Select]
;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)
DualCore AMD E-450, 1646 MHz - 6 Go DDR3 1333 SDRAM - AMD Radeon HD 6320 Graphics (384 Mo) - Windows 7 Home Premium - DirectX 11.0

Offline Steve Elliott

  • Hero Member
  • *****
  • Posts: 1533
Re: simple 3D shooter
« Reply #6 on: October 23, 2018, 10:07:54 PM »
Sounds cool.  Hopefully an exe too at the end (for those without Blitz3D).
Windows 10, 64-bit, 16Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb)

MacOS Mojave, 64-bit, 8Gb RAM, CPU Intel i5, 2.3 Ghz, Intel Iris Plus Graphics 640 1536 MB.

Offline 3DzForMe

  • Sr. Member
  • ****
  • Posts: 430
Re: simple 3D shooter
« Reply #7 on: October 24, 2018, 04:49:22 PM »
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 ;)
happy coding ;)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 801
Re: simple 3D shooter
« Reply #8 on: October 24, 2018, 05:42:00 PM »
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)
DualCore AMD E-450, 1646 MHz - 6 Go DDR3 1333 SDRAM - AMD Radeon HD 6320 Graphics (384 Mo) - Windows 7 Home Premium - DirectX 11.0

Offline Xerra

  • Sr. Member
  • ****
  • Posts: 468
    • Retro Evolved
Re: simple 3D shooter
« Reply #9 on: October 24, 2018, 11:16:44 PM »
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.

Offline 3DzForMe

  • Sr. Member
  • ****
  • Posts: 430
Re: simple 3D shooter
« Reply #10 on: October 24, 2018, 11:49:40 PM »
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.
happy coding ;)

Offline Xerra

  • Sr. Member
  • ****
  • Posts: 468
    • Retro Evolved
Re: simple 3D shooter
« Reply #11 on: October 25, 2018, 05:26:40 PM »
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.

Offline RemiD

  • Hero Member
  • *****
  • Posts: 801
Re: simple 3D shooter
« Reply #12 on: October 25, 2018, 05:28:30 PM »
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 )
DualCore AMD E-450, 1646 MHz - 6 Go DDR3 1333 SDRAM - AMD Radeon HD 6320 Graphics (384 Mo) - Windows 7 Home Premium - DirectX 11.0

Offline Xerra

  • Sr. Member
  • ****
  • Posts: 468
    • Retro Evolved
Re: simple 3D shooter
« Reply #13 on: October 25, 2018, 05:44:24 PM »
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 :)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 801
Re: simple 3D shooter
« Reply #14 on: October 25, 2018, 09:39:44 PM »
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

DualCore AMD E-450, 1646 MHz - 6 Go DDR3 1333 SDRAM - AMD Radeon HD 6320 Graphics (384 Mo) - Windows 7 Home Premium - DirectX 11.0