Jump to content

Photo

No Name Yet -- CD'awgs Non-ZC Temporary Dev Log

C++

  • Please log in to reply
101 replies to this topic

#46 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members

Posted 12 October 2015 - 10:59 PM

Ah, so you're saying instead of making a new bitmap pointer for every game object -- every enemy and item grabs a .png from memory when it loads up -- just do what ZeldaClassic does and have a single spritesheet where EVERYTHING goes draw a small section of it to the screen when it needs to, huh?  That does sound faster, but it also sounds tricky; every object in the game will need access to that single bitmap object!  I dunno how to accomplish that.

 

It's no more tricky than calling your variables.  All canned software that I know of uses the trick, so if you want to know how it's done, you can just take a look at it.



#47 Saffith

Saffith

    IPv7 user

  • Members

Posted 12 October 2015 - 11:01 PM

I think, initially, I won't make spritesheets as a single file because I like the freedom of making each enemy / item / whatever it's own .png for animations.  But I could make an object that holds and deploys all sprites rather than making new bmp objects in every GameObject that gets born, so that should still work out okay.

I think that's what he meant. Copying everything into one big sheet wouldn't be worth the trouble.
Even if you don't feel like implementing a bitmap manager just yet, keep in mind that you can make things easier on yourself later on by creating and using the interface upfront.
 
BitmapWrapper* BitmapManager::getBitmap(const std::string& filename)
{
    // TODO
    return new BitmapWrapper(al_load_bitmap(filename.c_str()));
}
A basic implementation's pretty easy, though.

#48 Gleeok

Gleeok

    It's dangerous to dough alone, bake this.

  • Members
  • Real Name:Pillsbury
  • Location:Magical Land of Dough

Posted 12 October 2015 - 11:34 PM

Yeah, I don't mean one big mega-texture, but just group things together; even if it's just something like doodads.png or character_with_all_animations.png. If all your bitmaps are known at compile-time you can even go the super simple and highly efficient route:
#define MAX_BITMAPS 64 //set this

const char const* BitmapNameTable[MAX_BITMAPS] = {
  "null",
  "bitmap1", //id = 1
  "bitmap2", //id = 2
  "bitmap3", //id = 3
  ...
};

int BitmapReferenceCount[MAX_BITMAPS] = {}; //note that "= {}" will zero initialize. No need for c++ RAII bullshit
ALLEGRO_BITMAP* BitmapInstance[MAX_BITMAPS] = {};

// Loads an ALLEGRO_BITMAP from file or simply returns a previous bitmap pointer if it was already loaded.
// 
ALLEGRO_BITMAP* LoadBitmap(int id)
{
  assert(id < MAX_BITMAPS);
  ALLEGRO_BITMAP* bitmap = NULL;

  if(BitmapInstance[id] != NULL)
  {
    BitmapReferenceCount[id]++;
    bitmap = BitmapInstance[id];
  }
  else
  {
    bitmap = al_load_bitmap(BitmapNameTable[id]);
    if(bitmap)
    {
      BitmapReferenceCount[id]++;
      BitmapInstance[id] = bitmap;
    }
  }

  return bitmap;
}

void UnloadBitmap(int id)
{
  BitmapReferenceCount[id]--;
  if(BitmapReferenceCount[id] == 0)
  {
    al_unload_bitmap(BitmapInstance[id]);
    BitmapInstance[id] = NULL;
  }
}


#49 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members

Posted 13 October 2015 - 01:21 AM

Yeah but you may want to make it a horizontal only type thing.  Even if it's really long because of that.  The thing about animating on both an x and y axis is that it's a royal pain in the ass.  You can do it, but simultaneously worrying about precisely positioning both the height and width of each frame makes it exponentially worse.  Whereas if you just have to worry about width, it's not so bad.

 

It's kind of hard to put it into words, but believe me, you do NOT want more than one row in your condensed png's.



#50 Gleeok

Gleeok

    It's dangerous to dough alone, bake this.

  • Members
  • Real Name:Pillsbury
  • Location:Magical Land of Dough

Posted 13 October 2015 - 03:05 AM

&nbsp;

Yeah but you may want to make it a horizontal only type thing.&nbsp; Even if it's really long because of that.&nbsp; The thing about animating on both an x and y axis is that it's a royal pain in the ass.&nbsp; You can do it, but simultaneously worrying about precisely positioning both the height and width of each frame makes it exponentially worse.&nbsp; Whereas if you just have to worry about width, it's not so bad.
&nbsp;
It's kind of hard to put it into words, but believe me, you do NOT want more than one row in your condensed png's.


No way! It's actually really easy.

Rect GetAnimationFrameRect(
	int currentFrame,
	const Rect& sourceRect,
	int bitmapWidth,
	int bitmapHeight
){
	int x = sourceRect.x + (sourceRect.width * currentFrame);
	int y = sourceRect.y;
	int yOffset = x / bitmapWidth;

	if(yOffset > 0)
	{
		x %= bitmapWidth;
		y += sourceRect.height * yOffset;

		//you can also wrap y
	}

	Rect frameRect = { x, y, sourceRect.width, sourceRect.height };
	return frameRect;
}


#51 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members

Posted 13 October 2015 - 03:36 AM

&nbsp;
No way! It's actually really easy.

 

 

I meant animation wise, not code wise, LOL

Slapping together 36 pixel high, 36 pixel wide sprites on a 1440 x 36 png is MUCH easier than doing the same on a 288 x 180 one.



#52 C-Dawg

C-Dawg

    Magus

  • Members

Posted 13 October 2015 - 07:55 AM

He's right, and that's exactly how my sprite sheers at currently organized; horizontal strips.

Thank you for the ideas; I'll tinker wit them and see what I come up with. On a related note, do you know of ways to streamline the loading of mappy maps as the player moves from one to another? Right now there is a brief load time whenever my plate goes to a new room as the room data is loaded from the hd.

#53 Gleeok

Gleeok

    It's dangerous to dough alone, bake this.

  • Members
  • Real Name:Pillsbury
  • Location:Magical Land of Dough

Posted 13 October 2015 - 08:28 AM

He's right, and that's exactly how my sprite sheers at currently organized; horizontal strips.

Thank you for the ideas; I'll tinker wit them and see what I come up with. On a related note, do you know of ways to streamline the loading of mappy maps as the player moves from one to another? Right now there is a brief load time whenever my plate goes to a new room as the room data is loaded from the hd.

No idea. This is why I stopped using other peoples libraries: I just assume they are all shit and do it myself. (..which I also presume to be better.) :P (There are exceptions, obviously)

This may be highly unhelpful, but I suspect that attempting to fix it involves rewriting the allegro mappy loading stuff, or at the least going through it all and profiling sections and understanding what it's doing. It's just the price you pay to get maps up and running quickly, so I wouldn't worry about it much. You can always try and improve it later.

Of course I have no idea how big the maps are, but I'm assuming--since there is noticable load time--they are many megabytes large or the maps have more than 1,000,000 tiles and multiple layers, or something like that, so it may be difficult to make it seamless without baking all the maps into a packfile.
  • C-Dawg likes this

#54 Saffith

Saffith

    IPv7 user

  • Members

Posted 13 October 2015 - 09:23 AM

I don't know much about Mappy's file format, but I'd bet it's not all that fast. You could try converting it to a more suitable format.
If you can predict which map will be next, you could preload it in the background. That would mean getting into the happy fun time of multithreading, but should be about as easy as that gets.

#55 C-Dawg

C-Dawg

    Magus

  • Members

Posted 13 October 2015 - 10:10 AM

Mappy packages the data you've loaded about each tile, the tile's placement on the map, and the single .png file holding all of the map data into it's own format.  It's not terribly huge, I don't think, but it isn't compressed.  And it's like a 0.5 second delay when my player reaches a door before the next room pops into existence.  

 

What may ultimately be cool is having some kind of screen transition effect that masks the load time, but as you say, I suspect that involves learning multithreading.  I'll get to that... but not any time soon.

 

@Gleeok: So, if I follow the logic of that code you posted,it -- whatever "it" is -- holds an index of filenames.  Then, when I want to to draw a sprite to the screen, I call it by the filename.  "It" then looks to see if that name is already loaded, and if it is, just returns it.  If not, it loads it and stores it forever and then returns it.  So, the first time you encounter, say, a kind of enemy, it will load from the HD, but thereafter it'll be already existing in RAM and ready to go.  Since I doubt I'll have more than a few hundred sprites loading even throughout the whole game, that should be managable.

 

Now, as to the "it."  My rudimentary understanding of C++ is that you can have your main.cpp and you can put global functions and variables there after your void main() function.  But, I thought everything was really supposed to be a class.  What is your code snippet?  Is it a class, a global function, or...?

 

Is this similar to what allegro and mappy provide?  That is, I have functions in both of those libraries I can call wherever, without regard to what the object knows.


Edited by C-Dawg, 13 October 2015 - 10:15 AM.


#56 Saffith

Saffith

    IPv7 user

  • Members

Posted 13 October 2015 - 10:42 AM

@Gleeok: So, if I follow the logic of that code you posted,it -- whatever "it" is -- holds an index of filenames.  Then, when I want to to draw a sprite to the screen, I call it by the filename.  "It" then looks to see if that name is already loaded, and if it is, just returns it.  If not, it loads it and stores it forever and then returns it.  So, the first time you encounter, say, a kind of enemy, it will load from the HD, but thereafter it'll be already existing in RAM and ready to go.  Since I doubt I'll have more than a few hundred sprites loading even throughout the whole game, that should be managable.

Not exactly. You'd use it similarly to what you've already got. You'd use LoadBitmap() to get a bitmap pointer to give to the doodad to hold onto. In its destructor, or wherever you clean up, you call UnloadBitmap(). The bitmaps don't stay loaded in memory forever; once the last thing using a bitmap releases it, the bitmap is unloaded.
 

Now, as to the "it."  My rudimentary understanding of C++ is that you can have your main.cpp and you can put global functions and variables there after your void main() function.  But, I thought everything was really supposed to be a class.  What is your code snippet?  Is it a class, a global function, or...?

Global functions and variables. You certainly can design things such that everything is a class, and there are those who insist on it, but it's not good to be dogmatic in software design. This is a relatively simple, small project; using some global stuff is perfectly reasonable and probably easier.

#57 C-Dawg

C-Dawg

    Magus

  • Members

Posted 04 February 2016 - 06:25 PM

Man, this is difficult.  

 

The most powerful impediment I'm running into is just map design.  Mappy makes it pretty simple to set up tiles as a simple 2-D array, but when it comes to things like tile layers, event layers, item layers, etc, the program is just totally opaque.  Basically, I want to be able to draw my tiles, then go to a different layer and place things like enemies, warps, items, doodads, and so on, and then have my game be able to read them.  But I don't understand how to do that.  I can place them all on the SAME layer, but that means I have lots of indistinguishable black tiles.  Not the kind of thing I can hand off to someone else to create rooms and maps for me.

 

There's gotta be a better guide out there to using Mappy, but I can't find it.  

 

If only I could get over this hurdle, working on C++ would now be about the same as working in Zelda Classic.  Well, the way I use Zelda Classic, anyway.


Edited by C-Dawg, 04 February 2016 - 06:27 PM.


#58 Gleeok

Gleeok

    It's dangerous to dough alone, bake this.

  • Members
  • Real Name:Pillsbury
  • Location:Magical Land of Dough

Posted 05 February 2016 - 02:58 AM

Sounds like we are in the same boat, you and me. Tooling is a bit of a pain in the ass. It's times like this you wish you had a studio and a team and could just say "hey, someone who's not me throw together a map editor that supports objects and whatever! chop chop." I've just been too preoccupied to work on my editor, so I probably can't help you there.

Have you thought about in-game editing support? Another similar idea would be an 'editing mode'. I actually have this in my game, although I only support editing tile-cell solidity for now. A third idea might be to just write an object-placement editor thingy then store it in whatever format you like alongside the .fmp files. Fun stuff.

#59 C-Dawg

C-Dawg

    Magus

  • Members

Posted 01 July 2016 - 12:35 AM

So, I finally sucked it up and did some of the housekeeping work I needed to do in order to proceed here.

 

1. Figured out how to fully implement layers in Mappy.  Now I can use it just like Zelda Classic.  FINALLY.  I will probably write a manual on this or something, since the documentation is atrocious and even figuring out incredibly basic things was just stupidly hard.  Now, I just need to agree with myself on some conventions on how I use Mappy fields and values and I'll be good to go, map-wise.

 

2. Replaced all bitmaps inside game objects with global functions pointing to a GraphicsHandler, per all of your suggestion.   When the game starts, some critical graphics will get loaded into a vector.  After that, anything in the game that wants to display something has to call the Handler, and only the Handler ever goes to the hard disk to load something. It keeps track of how many times a particular .png has been "reserved" and will release it once it's no longer needed.  Should minimize both RAM use and hard drive churning.

 

3. Organized the project into sub-folders so I can actually follow what is going on, and added resources directly to the project instead of putting them elsewhere on the disk.

 

With all that in mind, the next step is implementing the subscreen so you can swap active items, and then implementing a few other items and enemies.  Hopefully I can produce a tech demo of some sort for ya'll in a month or so.


  • Anarchy_Balsac likes this

#60 C-Dawg

C-Dawg

    Magus

  • Members

Posted 04 July 2016 - 12:02 PM

A nice long weekend gave me some time to work on this more.

 

1. Pause button functionality implemented.

 

2. Soldier subscreen and inventory system implemented, for the most part.  

 

3. First new Shot modification for the Soldier implemented.

 

4. Moving platforms now work beautifully.

 

Next thing I think I'll do is implement an Equipment and a Tool for the Solider, implement the ability to place Item objects using Mappy, and then do the same chunk of things for the Tank.

 

One problem I'm running into is that the inventories are specific to the Tank and Soldier objects.  They're not global.  (Why not?  Because in a million years I think it might be sweet to allow multiple players to speed race the game or have cooperative game modes.)  That means that, if the Tank picks up an item meant to be in the soldier's inventory, it can't just put it there automatically.  It will have to tell the Game Object Manager that it's got an item meant for the other player object and then the Game Object Manager can put it over there.  That's kind of an interesting pain in the butt from how I've been doing this, where everything is object-oriented and very little is global.

 

Oh, and I need to make a global vector and global functions to implement a Sound Manager as well.  Those who have done this before: if I plan on using, say, 50 different .wav files as short sound effects in the game, would it be a massive problem to just load them up all immediately from the hard disk at startup and store them in memory while the game runs?  Or should I have a smart loading and unloading function for sounds like I do for graphics? 

 

Sounds like we are in the same boat, you and me. Tooling is a bit of a pain in the ass. It's times like this you wish you had a studio and a team and could just say "hey, someone who's not me throw together a map editor that supports objects and whatever! chop chop." I've just been too preoccupied to work on my editor, so I probably can't help you there.
 

 

Well, luckily, my requirements are pretty minimal.  I just need to be able to place and read Mappy blocks.  From there, it's just setting variables on those blocks in Mappy.  The problem is that the documentation is utter trash and doesn't tell you simple things like what functions are used to tell Mappy what layer to read from.  I couldn't even figure it out from looking at the code.  Anyway, now that I've figure that out, Mappy does everything I need for my limited purposes.


Edited by C-Dawg, 04 July 2016 - 12:39 PM.




Also tagged with one or more of these keywords: C++

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users