Oh I see what you mean. Yes, it's the smartbomb explosion causing the slowdown. Will take a look at optimizing that.
Ah, the launch position on level 11 is indeed a bit mean. I'll fix that. What I actually meant was that if you wait too long on level 11, all the turrets gather around and start doing damage before you're even launched which is just not fair.
I did initially write the collision system to use sqr(x*x+y*y) for distance thinking that it would be faster than entitydistance() because I'm only using 2 axis but was surprised to find the latter was so much faster. Much later I realised that you didn't have to even get the square root so with renewed enthusiam I went about reverting to calculating my own distance again only to find out that it was still much slower than entitydistance(). Still, I'm sure it can be sped up further without having to revert to C.
Here's my collision module...
Save this as Collisions2D.bb
; ---------------------------------------------------------------
; Collisions2D.bb
; (Very) Simple sphere to sphere collision detection module
;
; Look at example code for an idea of how to use it.
; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
; Collision types
; Dictates which EntityType combinations will be checked as per the
; collisions table Blitz3D manages itself.
; ---------------------------------------------------------------------------
Dim Collisions2Dsrctgt(64,64)
Dim Collisions2Dsrc(64)
; ---------------------------------------------------------------------------
; Collision instance
; One of these must exist for each entity that needs to be checked for collisions.
; Note that if you delete your entity and want to stop collision checks
; happening for it you *must* also delete the corresponding collision type instance.
; The example shows you a good way of doing this.
; ---------------------------------------------------------------------------
Type Collision
; collision entity information
Field srcEntity ; the entity to check collisions for
Field srcRadius# ; the radius - equiv of EntityRadius
Field sType ; the entity type - equiv of EntityType
; collision result information
Field hasCollided ; boolean indicates whether a collision has taken place or not for the entity
Field cEntity ; collided with entity
Field cNx#,cNy#,cNz# ; collision Normals
End Type
; ------------------------------------------------------
; Enable a valid entity type combo
; -------------------------------------------------------
Function setCollisionTypes(srcType,tgtType)
Collisions2Dsrctgt(srcType,tgtType) = True
Collisions2Dsrc(srcType) = True
;DebugLog "collision type added between types " + srcType + " and " + tgtType
End Function
; -----------------------------------------------------------------------
; Add a entity to the collision system
; Collision detection information is passed back via the Type instance.
; -----------------------------------------------------------------------
Function addCollisionEntity.Collision(entity,radius#)
c.Collision = New Collision
c\srcEntity = entity
c\srcRadius = radius
c\sType = GetEntityType(entity)
c\hasCollided = False
;DebugLog "collision instance added for entity " + c\srcEntity + " type " + c\sType
Return c
End Function
; -------------------------------------------------------------
; Perform collision detection between valid type combinations
; This method should be called once per updateWorld.
; -------------------------------------------------------------
Function updateCollisions()
;count = 0
For s.Collision = Each Collision
s\hasCollided = False
If Collisions2Dsrc(s\sType)
For t.Collision = Each Collision
If Collisions2Dsrctgt(s\sType,t\sType)
If s\srcEntity <> t\srcEntity
;count = count + 1
;dx# = (EntityX(s\srcEntity,True) - EntityX(t\srcEntity,True))
;dz# = (EntityZ(s\srcEntity,True) - EntityZ(t\srcEntity,True))
;dsq# = dx*dx + dz*dz
d# = EntityDistance(s\srcEntity,t\srcEntity) ; if an error occurs here it's because you haven't deleted
; the collision instance associated with one of these entities !
If d# - s\srcRadius - t\srcRadius < 0
; If dsq < (s\srcRadius*s\srcRadius+t\srcRadius*t\srcRadius)
; collision has occurred !
s\hasCollided = True
s\cEntity = t\srcEntity
; d# = Sqr(dsq)
If d# = 0 d# = .00001 ; prevent division by zero
; normalize collision vector
; s\cNx = dx / d#
; s\cNz = dz / d#
s\cNx = (EntityX(s\srcEntity,True) - EntityX(t\srcEntity,True)) / d#
s\cNz = (EntityZ(s\srcEntity,True) - EntityZ(t\srcEntity,True)) / d#
;DebugLog "collision between type " + s\sType + " " + s\srcEntity + " and " + t\sType + " " + s\cEntity
End If
End If
End If
Next
End If
Next
;DebugLog count +" collision checks performed"
End Function
; ====================================================================================================================================
And a example program using it :
; -------------------------------
; collision library example usage
; -------------------------------
Include "Collisions2D.bb"
.define
Graphics3D 800,600
Global collisionResponseMode = 1
Global thingCount
; collision types
Const TYPE_THING = 1
Type Thing
Field entity
Field xspeed#,yspeed#
Field hp
Field collisionInfo.Collision
End Type
.setup
; -----------------------------------------------------------
; Enable collisions between entity types.
; Same as using the Blitz3D Collisions <type>,<type> command
; but no collision type or response needed as we handle that
; ourselves.
; -----------------------------------------------------------
setCollisionTypes(TYPE_THING,TYPE_THING)
SetBuffer BackBuffer()
Global world = CreatePivot()
Global camera_target = CreatePivot(world)
Global camera = CreateCamera(world)
cameray# = -16
createThings(333)
.mainloop
While Not KeyHit(1)
updateThings()
If thingCount < 64 createThings(200)
;TurnEntity blurclear,1,0,0
; ----------------------
; Perform collision checks
; ----------------------
time = MilliSecs()
updateCollisions()
time = MilliSecs()-time
PositionEntity camera,0,cameray,0
PointEntity camera,camera_target
UpdateWorld()
RenderWorld()
Color 255,255,0
modeStr$ = ""
Select collisionResponseMode
Case 0 modeStr = "none"
Case 1 modeStr = "soft"
Case 2 modeStr = "rigid"
End Select
Text 0,0,thingCount+" things processed in "+time+"ms"
Text 0,16,"Press [SPACE] to cycle Collision Response Mode : " + modeStr
Flip
If KeyHit(57) ; space
collisionResponseMode = (collisionResponseMode + 1) Mod 3
End If
Wend
End
; ------------------------------------------------------------------------------------------------------------------------------------
Function createThings(amount=64)
For i = 1 To amount
x# = Rand(-16,16)
y# = Rand(-12,12)
xspeed# = Rnd(-.08,.08)
yspeed# = Rnd(-.08,.08)
size# = Rnd(.1,.5)
createThing(x,y,xspeed,yspeed,size)
Next
End Function
; ------------------------------------------------------------------------------------------------------------------------------------
Function createThing(x#,y#,xspeed#,yspeed#,radius#)
a.Thing = New Thing
a\entity = CreateSphere(6)
EntityColor a\entity,255,255,0
EntityBlend a\entity,3
EntityAlpha a\entity,.7
PositionEntity a\entity,x,0,y
ScaleEntity a\entity,radius,radius,radius
EntityType a\entity,TYPE_THING ; make sure type is setup *beforehand*
; --------------------------------------------------------
; Include the entity in collision checking.
; The Collision Type instance gets updated by updateCollisions
; if any collisions with this entity occur
; --------------------------------------------------------
a\collisionInfo = addCollisionEntity(a\entity,radius)
a\xspeed# = xspeed#
a\yspeed# = yspeed#
a\hp = 512
NameEntity a\entity,Handle(a) ; setup Type instance <-> entity association
End Function
; ------------------------------------------------------------------------------------------------------------------------------------
Function updateThings()
; iterate through things
thingCount = 0
For a.Thing = Each Thing
; -------------------------------------------------------------
; Check the Collision instance to see if a collision has been
; flagged or not and handle the collision accordingly
; Collision normals are accessible via the cNx & cNz fields.
; -------------------------------------------------------------
If a\collisionInfo\hasCollided
EntityColor a\entity,0,512,512
hitThing(a\entity)
Else
EntityColor a\entity,255,a\hp,0
End If
If a <> Null ; only update if entity hasn't already been deleted
; keep thing within boundary
If EntityX(a\entity,True) < -16 Or EntityX(a\entity,True) > 16
a\xspeed = - a\xspeed
End If
If EntityZ(a\entity,True) < -12 Or EntityZ(a\entity,True) > 12
a\yspeed = - a\yspeed
End If
If Abs(a\xspeed) > .1 a\xspeed = a\xspeed * .99 ; max speed dampner
If Abs(a\yspeed) > .1 a\yspeed = a\yspeed * .99
; move the thing
TranslateEntity a\entity,a\xspeed,0,a\yspeed
thingCount = thingCount + 1
End If
Next
End Function
; -------------------
; handle a collision
; -------------------
Function hitThing(entity)
; get the Type instance associated with the entity
a.Thing = Object.Thing(EntityName(entity))
currentSpeed# = Sqr((a\xspeed * a\xspeed) + (a\yspeed * a\yspeed))
; decide how to handle the collision
Select collisionResponseMode
Case 1
a\xspeed = a\xspeed + ((a\collisionInfo\cNx * currentSpeed#) ) * .1
a\yspeed = a\yspeed + ((a\collisionInfo\cNz * currentSpeed#) ) * .1
Case 2
a\xspeed = a\collisionInfo\cNx * currentSpeed#
a\yspeed = a\collisionInfo\cNz * currentSpeed#
End Select
a\hp = a\hp - 1
If a\hp <= 0
; remove entity making sure to delete the related collision instance !
Delete a\collisionInfo
FreeEntity a\entity
Delete a
End If
End Function
; ====================================================================================================================================
Note that I'm using the x,z axis instead of x,y. Just a legacy thing because of the way the camera pointed when I started out ;)