Breaking your program ... on purpose
DanielH

So, everything is running smoothly and I decided to change something up river. Part of the framework. I wasn't happy with my object handler code. It is a basic wrapper for a std::unordered_map of objects. The problem was that the object being stored was a 'has'. I changed it to an 'is'. Then I had to rework everything down stream. Finally after a couple of hours it's back to running smoothly again.

Niunio

That's nothing.

My game engine has 4 alpha versions right now. Each one written from scratch because I didn't like how it looked after using them. Next one will be alpha.5, and again written from scratch 3 times. Yep, I've started from scratch alpha.5 3 times for different reasons.

Beat it. 8-)

Erin Maus

I recently added multithreading to my game (splitting logic and rendering into two separate threads). Broke so much stuff in the process. Some stuff is still broken a over month later.

I also moved large parts of the renderer to C++, which created rendering glitches. I think those are all fixed but there's still more rendering code that needs to be migrated...

I'm going to be adding support for multiplayer so massive breaking change #3 incoming.

Polybios

In programming, the more you love it, the more you have to break it. 8-)

DanielH

I reworked the object system, then had to rework everything else.

Instead of storing the type in the object handler, I had to store the type in the object.

That meant, I couldn't just add a ALLEGRO_BITMAP to my handler.

So, I made a base object class with a single variable (int type).
And a derived wrapper sub class for Allegro objects.
Any custom objects are also derived from the main object class.

I also modified the manifest file. Display is still required, but the rest (timer, queue) I add in the background.

It's reworked and running great.

//Everying is loaded and/or created in the manifest parser
if (Parser::parseManifest(manifest_file) < 0)
{
  return -1;
}

// draw code
bool Game::OnRender(Allegro::Display& display)
{
  al_clear_to_color(al_map_rgb(0, 0, 255));

  Allegro::Font* font = static_cast<Allegro::Font*>(Object::getRegistry()->at("@font/main"));
  if (font)
  {
    al_draw_text(font->get(), al_map_rgb(255, 255, 255), 40, 40, 0, "Hello World!");
  }

  return false;
}

result
{"name":"613227","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/1\/916606dd990143214738360e83366eb9.png","w":1041,"h":818,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/1\/916606dd990143214738360e83366eb9"}613227

Edgar Reynaldo
DanielH said:

Allegro::Font* font = static_cast<Allegro::Font*>(Object::getRegistry()->at("@font/main"));

That's terrifying.

Compare it to this :

...
   win->DrawText(font_registry->GetFont("font/main") , "Hello World" , 10 , 10 , EagleColor(255,255,255) , ALIGN_LEFT , ALIGN_TOP);

Anyway, if your font derives from an object, you need dynamic_cast, not static_cast.

Niunio

"C++ has become much better in the last ten years", they said... ::)

DanielH
Quote:

font_registry->GetFont("font/main")

That would require a registry for every object type.

Anyway, if your font derives from an object, you need dynamic_cast, not static_cast

Good to know. I'll fix them. static_cast and dynamic_cast weren't a thing when I learned C++.

Edgar Reynaldo

No, but maybe a function. Just an example.

inline Font* Registry::GetFont(Object* o) {
   return dynamic_cast<Font*>(o);
}
//... This is literally what I have in Eagle
win->DrawText(win->GetFont("Verdana.ttf") , "Hello Verdana" , 10 , 10 , EagleColor(255,255,255) , ALIGN_LEFT , ALIGN_TOP );

DanielH

Cast before or after. Still needs casting. Looks nicer, but accomplishes the same thing.

My get function needs the cast before because the compiler cannot differentiate functions based on the return type alone.

I could do what you say and write a get function for each type. The library does have known types, but the type system is extendable. The program can/will add types to it.

Peter Hull

You could also use simple templates

class ObjectRegistry {
...
 template <typename T>
 T at(const char* key) {
  return static_cast<T>(__at(key));
 }
};

where __at is the function that accesses the registry.
Use like

auto font = Object::getRegistry()->at<Allegro::Font*>("@font/main");

If there's only one registry that's global I suppose you could alternatively

template <typename T>
T get(const char* key) {
 return static_cast<T>(Object::getRegistry()->at(key));
}
...
auto font = get<Allegro::Font*>("@font/main");

DanielH

I originally had a templeted get function, then I realize I was casting twice.

oncein the get function

 template <typename T>
 T at(const char* key) {
  return static_cast<T>(__at(key));
 }

2nd at the get call

auto font = Object::getRegistry()->at<Allegro::Font*>("@font/main");

When I was doing the rewrite, I left out the template and left the getter return the base Object*.

Mark Oates

{"name":"613227","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/1\/916606dd990143214738360e83366eb9.png","w":1041,"h":818,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/1\/916606dd990143214738360e83366eb9"}613227

^^ What's the name of this fancy font you're using here? I feel like I need to embrace more fantasy fonts in my designs. 🤔

DanielH

I've had it for years. Can't remember where I got it. It's called ds_mysticora.

I just grabbed it for testing the font loading code.

Thread #618702. Printed from Allegro.cc