Saturday, December 28, 2013

HBF, last 2013 update

Last update of the year, merry Xmas and happy new year!

Binaries and sources can be downloaded at the moment from SugarSync.

Latest changes:


  • Fixed a memory leak in TSpriteEngine.SpritesAt() when using spatial partitioning
  • New TGraphicDriver.Circle() primitive
  • Fixed a potential memory leak in TCollisionMatrix


  • Hover now shows a different animation when colliding
  • Hover was looking for collisions in wrong rectangle
  • Mummy now shows a different animation when jumping
  • Mummy speed is twice as fast
  • Titan now kills non mechanical enemies when rolling over them
  • Bat collision improved
  • Fixed a weird move in jellyfish 
  • Blob always jumps to exit from traps
  • Droid laser also kills enemies 
  • Eye laser also kills enemies 
  • Fish now inherits from TBoundingEnemy
  • Flame now behaves like the spike (hides and shows)
  • New enemy Hooper 
  • New door bitmaps
  • New enemy hooper
  • New map Colors 
  • Spike bitmap shrink a bit
  • Spikes can now be reversed (top to bottom)
  • Sounds emitted outside hero's range are discarded
  • Explosions and blood die animations last longer
  • CorrectGravityOrientation() now properly adjusts the angle to the distance of the target tile
  • Now hero is in front of the ladders in the darkness level
  • Hero dies in a different way (BTW still not sure)
  • Minor map changes
  • ApplyGravity property removed, added Gravity.gNone
  • Platforms now use the bouncing properties (I'd lost that change in the hard disc failure and hadn't notice it)

New level Colors

Entering a new level

Sunday, December 15, 2013

Avoiding too much memory consumption

I realize that HBF was consuming too much memory so I tried the following approaches:

  • Avoiding in main classes the creation of internal classes until they are needed (the so called lazy initialization), since in most cases it's not mandatory to use them at all, for example one can freely assign any kind of value to sprites via GetVar/SetVar, but this is only used in a few classes. Another example is the use of distortions, currently they are only used with the grass element, so any other class doesn't need these distortions.
  • Create something that loads the bitmaps on demand (before all bitmaps were loaded), therefore TAnimationOptimizer was created, no code has to be changed with this approach, just wrap the assignation of animation via this class
Binaries and sources can be downloaded at the moment from SugarSync.

So what's new?

Avoiding early creation of aditional classes when creating sprites (vars, triggers and distortions)
More lazy creation approach on TCollision and TComponentEx (avoiding creation of internal classes when not used)
FillSurface() and DoColorKey() in D3D optimized a bit
Die event can be also assigned via closures (very handy)
New random methods based on KISS RNG
Some TLayer scan functions optimized a bit
New TSpriteEngine CountClasses() method (avoids the creation of a list like in Find() )
Laser beam didn't have assigned the camera so it was not shown
Fixed some overflow sound volume and panning issues

Spike fixed (once for all?)
Avoiding early creation of lightmaps (darkness, etc)
New element princess (guess for what...)
There is a new animation optimizer so the system knows when to load animation bitmaps, just call TAnimationOptimizer.Instance.Get(), now the game does not load all graphics at the beginning
New element black hole (experimental)
Map folders renamed
New EnemyType property, removed IsMechanic and Indestructible properties (when Indestructible, hero's shield cannot kill the enemy)
Hero now has a limited amount of air under the water (in percentage), the water level has some escapes to get extra air
Memory leak in darkness fixed
Arrows now explode bubbles
Some entities no do longer generate shadows
Calls to Engine.Find() changed to Engine.SpritesAt() which uses the spational partitioning and therefore it is much faster
New map called "No name" based on bubbles
Enemies on top of Items won't try to move left and right all the time as if there was no tomorrow
New TGameSprite helper methods IsBall(item): bool and IsBubble(item): bool
New element door (it didn't need to be an item), Items should be very simple sprites that can interact with normal sprites
When Ball collides against a tile it stops (last level contains one)
New bubbles element
Keys, lives and princess created when needed
HandleSprings() refactored and renamed to GetJumpMultiplicator()
New class THud that does all the job related to displaying lives, key, etc
New enemy Tom
New images for Mummy
Bubbles were generating memory leak (what's wrong with me?!)
Bubbles now collide against solid tiles
Flame kills hero
Weird now tries to connect to the closer wall when instantiated
Trap door adds a delay for every instance, this way the doors are not synchronized therefore it looks nicer

Mummy and new bubbles

Air vents

Our new friend Tom, well I guess it should be bigger...

Friday, December 13, 2013

Observer and Observable

In BB framework what to do when there is a relationship between entities and one of them dies?

TDummySprite inherits from TComponentEx which implements the Observable/Observer pattern.

So for example bubbles are solid temporally so any enemy or hero itself can be on top of them, but since a  bubble can suddenly explode, the sprites needs to be informed in order to remove the reference, this is how I did it:

procedure TGameSprite.SetCarryTile(aTile: ISprite);
  if FCarryTile = aTile then


  if aTile <> nil then
    //So for instance if a sprite is on top of a bubble and this bubble explodes (it dies), sprite is informed and can react
    (aTile as IObservable).AddObserver(self);

    Y := GetContactPlatformY(Gravity, aTile);
    if Gravity = gDown then
      Y := Y - Height;

    if State = ssFalling then
      State := ssWalking;
  end else
    HorizontalSpeed := 0;
    VerticalSpeed := 0;


  FCarryTile := aTile;

And then override the method Update()
procedure TGameSprite.Update(aMessage: TMessage);

  if aMessage.Sender = CarryTile as TObject then
    CarryTile := nil;

And there you can update your pointer to nil.