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

#1 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 23 September 2015 - 10:31 PM

Learning C++ has been quite a journey, but I'm actually quite enjoying it.  Since I enjoyed discussing Zodiac here, I'll make this thread my go-do place for a dev log on the followup project.  (Never fear; Zodiac just requires tinkering on the weekends a little bit to finish the final release, and I'm waiting for MeleeWizard's Lets Play to finish before calling it done.)

 

First_Screenie.jpg

 

This is not a mockup; the game engine is very simple so far, but functional.  The little dude can go in or out of the tank and platform his heart away.  When you're in the tank, the camera zooms out to 2x this distance; tank moves faster and jumps higher, but can't fit in little spaces.  Sprites are animated for what they can do so far; jump, run, fire, etc.

 

No name yet, but I'm sure I'll think of something.  I've also roughed out the plot and mechanics, but of course they're subject to change.



#2 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members
  • Gender:Unspecified

Posted 23 September 2015 - 10:34 PM

So this is to Blaster Master what Zodiac is to Guardian Legend?



#3 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 23 September 2015 - 10:34 PM

You could certainly say that, and you wouldn't be totally wrong.  The difference here is that I LOATHED the top-down sections of Blaster Master, and I'm not sure I even want to try to fix those.  This might be platformer-only.  We'll see.



#4 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members
  • Gender:Unspecified

Posted 23 September 2015 - 10:39 PM

You could certainly say that, and you wouldn't be totally wrong.  The difference here is that I LOATHED the top-down sections of Blaster Master, and I'm not sure I even want to try to fix those.  This might be platformer-only.  We'll see.

My motto is, do what works, and fuck the arguments.  It may look bad on paper to emulate a franchise but skip a core part of it, but as long as it is made to work, I could care less.

 

Just have a save feature.  The one thing I hated about BM was reaching level 8, finding out the hard way it was 10x harder than what preceded it, then starting the whole game over because I wasn't ready for that.



#5 Dimentio

Dimentio

    Procrastinator at heart

  • Members
  • Real Name:Joshua
  • Gender:Male
  • Location:America's Hat.

Posted 24 September 2015 - 05:23 AM

Zodiac 2? A sequel already? Don't you think your're going a bit fast there, C-Dawg?



#6 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 24 September 2015 - 06:37 AM

Who said anything about a sequel? And fast, no, this'll take years to really have anything to show. It's just nice to have a little log of how it's going along the way.

 

EDIT: So, C++ folks out there, Ive run into a snag.

 

At the moment I only have a few classes; GameObject, Tank, Soldier, and Projectile.  I want to use a vector to store and manipulate an arbitrary number of projectiles.  This must be in main.cpp because only main.cpp can see the xOff and yOff being used to draw the map.  Main.cpp also is the place where the other vectors will eventually live (doodads, enemies, etc) and I need to have all the vectors in the same place so I can check for collisions.

 

But, I don't want the code that actually decides when to create and set up a bullet in main.cpp; I want that code to be a function within the Tank class since it's driven by input and timing that only those classes can see.  But, of course, the Tank class cannot actually see the Projectile vector because that's back up in main.   My initial thought was to have main.cpp call a function in Tank, "spawnProjectile()," that would create a Projectile object if the state of the Tank required it and return a pointer to the fully born object, which could then be pushed into the vector and manipulated by main.  But, I've been reading online that passing pointers like this is kind of a no-no because I'm violating the hierarchy of how objects work.  Plus, as I tinker with this, Visual C++ is tossing up various warnings I'm not sure I understand.

 

Anyone handle this sort of situation before?  What's the best design for something like this?

 

EDIT2: I ended up making a GameObjectManager that will own all the vectors of objects, and then got stuck until I realized something: you must have a vector of pointers if you are going to make a vector of base classes with virtual functions, but then call the functions of the derived classes.  Gah.

 

EDIT3: Huzzah!  Projectiles are working like a charm!  Vectors loading and drawing properly, offsetting where necessary, and all's well. And the best part is that all this object-oriented headaches I went through today should make making new projectiles super easy.  Yaaaay.

 

I think next I'll implement the Effects type of Game Object and get that working with the GameObjectManager, since that can be implemented without worrying about the screen too much; effects for bullet smoke and stuff get generated based on player input.  After that, I gotta figure out how Mappy uses layers to represent actual game objects so I can start writing Enemy objects, and then figure out a way to move between screens.  Then I think I gotta organize my code a bit, move some more functions out of main.cpp, and set things up for actual development to commence.  I'm almost positive I'll need to have someone look over my engine implementation for memory leaks and similar issues down the road, since I'm sure I'm missing em.

 

EDIT4: Effects handling now implemented.  Next step: look at enemies and learn how mappy can be used to set layers where enemies can spawn!


Edited by C-Dawg, 27 September 2015 - 09:04 AM.


#7 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 28 September 2015 - 10:10 AM

So my adventures in Mappy continue.  Since I did not see any useful guides online really detailing the process of making a game in this way, I figured I would make a post kind of detailing how you do that.  For those who are interested, Mappy is a map-creation utility that allows you to make maps in a way that is similar to Zelda Classic that you can import into Allegro 5 games.  I want to say "almost as easy," but it's really not.  

 

For starters, of course, you have to have set up C++ code in Allegro to do something with the map file -- get input, move things around, whatever.  Luckily, doing that just takes a few weeks' of learning.  I recommend getting Visual Studio 2010 (plays well with Allegro 5), which is free from Microsoft, and the Allegro 5 binaries.  Once you have that, I'd recommend following along with this EXCELLENT tutorial series:  https://www.youtube....277DEF3A4AEE4A0

 

If anyone wants to do this, and has questions about strange things not working, I encountered a ton of non-obvious rules and issues as I mucked around through the process.  Happy to try to help and make a thread that better explains the process.

 

Okay, so assuming you've got a beginners understanding of C++, now you download Mappy AND the .png support package AND the header and C files (.h and .c) that will give your code access to the Mappy commands.  The thing none of the tutorials tell you about Mappy is how you need to set up your tiles.  Unlike ZClassic, where you set up "combos" by going to a specific combo and then loading it with a specific 16x16 tile, Mappy will grab all of your tiles at once from a single .png file.  And, at least initially, how it chooses to do this was a mystery.  You present it with, say, an organized 16x16 tilesheet and it loads up however it damn well pleases, putting things out of order and generally making a mess.

 

What I found worked well was to create your tilesheet according to very specific rules so you know exactly how it will load into Mappy.  I used Aseprite and set up each of my tiles on "frames" that are 5x5 tiles large.  (My tiles are each 32/32 but they could be any size; you specify this in Mappy).  Then, leave the very first tile in the top left corner of the first frame blank, because Mappy reserves that tile for the "zero" or "blank" tile. Next, I made sure that the color "black" in my Aseprite palette is not QUITE true black, because Mappy is going to assume pure black (RGB color 255,255,255) is transparent as a default.  Finally, I exported my tiles as a (1) vertical strip and (2) .png file type out of Aseprite.  The result is a .png file that will load up and look well-organized in Mappy as long as you make sure you're viewing the tiles in a tile browser window of 5 tiles wide.  (Unlike ZClassic, you can change the size of the window holding the "combos" in Mappy.)

 

So now that you've got the tiles organized, you need to set up their properties.  You know how ZClassic gives you lots of options about combos?  Some are solid, some are water, some are damage, etc?  Well, you can do the same thing with Mappy, but instead of getting pre-made options you just get user fields for each tile (BlockStructures, to be precise).  In theory you get four "collision bits" (tl, tr, bl, br) which don't do anything out of the box but are designed to allow your engine to check for solidity.  I chose to use "tl" as collision for solid tiles, and "tr" for collision with platforms you can jump up into, but not fall through.  What you use them for is up to you; Mappy.c gives you functions your Allegro program can call to examine the variables you've set in a given tile and then you do whatever you want with that information.

 

For backgrounds, Mappy does support multiple layers and parallax scrolling, but I don't understand it yet.  What does seem to work well at the moment is just telling your code to draw a background picture to the screen before telling Mappy to draw.  Remember how the black was different from transparent?  This ensures that background only shows where you left the blocks transparent.  Looks nice.

 

Unlike ZClassic, you can also use Mappy to place enemies, objects, items, etc on the screen as simple tiles as well.  That's the stage I'm at in my engine.  In addition to the four "collision bits," that are either true or false, you also get these User fields (user1, 2 3, and 4) that supposedly can hold whatever you want.  Well, the first two are long ints and the second are chars or something, whatever.  The point is you can use the first one to indicate what kind of tile it is (I'm using "1" for "enemy placement") and the second one for what kind of thing to spawn (so like "1" in user2 would be the simplest enemy on the map).  I'm having trouble getting my code to read the user1 and user2 variables at the moment, but I'll update once I get this working.

 

More to come!

 

EDIT: 

 

Alright, so the Mappy spawning function is now working.  Here's what I did.

 

I have an Object in my game called the GameObjectManager.  Each frame, I have that object scan the tiles visible on the screen.  If it finds one of the "spawn tiles," that I've set up in Mappy, it then reads the user1 data to decide what to do with it and user2 to decide what to create.  Then, it overwrites the tile with a blank one so that it only fires once.  So, it's sort of like the enemy flags in ZClassic.  

 

On top of that, the GameObjectManager is stashing things in vectors.  A "vector" in C++ is a fun little data structure that is basically an array that grows or shrinks depending on how much you need to shove into it.  So it's ideal for things that can spawn in variable amounts.  Each time the GameObjectManager is told to spawn a projectile, an effect, an enemy or (soon to come) items or doodads, it will create the appropriate object and then stick it into the appropriate vector.  Then, each frame, it goes through it's vectors and updates each element.

 

One thing that stymied me for awhile was the algorithm for checking for the spawn tiles.  When I'm checking what tile is at a particular X / Y location on a Mappy map, it will always be measuring from the top left corner, regardless of where the player has moved along to.  So, you need to start checking your X and Y not at 0,0, but at xOff, yOff (being the offsets from 0,0 where the top of the visible screen starts.)  Whoops!

 

Coming next: collision detection between objects!  Each vector cares about collisions with only some other kinds of objects.  Enemys care about collisions with player projectiles.  Players care about collisions with enemies, enemy projectiles, doodads, or items.  And so on.  


Edited by C-Dawg, 29 September 2015 - 11:35 AM.


#8 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 30 September 2015 - 12:00 AM

Second_Screenie.jpg

 

So we've got collision checking (other than walls, which have been implemented for awhile already)!  The GameObjectManager now checks for collisions between the solider and enemies, and the enemies and player projectiles.  If it finds a collision, it relays that information to the relevant objects; projectiles die, enemies and player trigger a damage function.  The solider and enemies have a damage sprite and then an invulnerability period.  Tank doesn't really do anything yet.

 

I think next up will be a basic HUD to display hit points, making damage matter.  Then maybe a better test map as an obstacle course and a few extra enemies.  I think then I handle the item system OR I figure out how to move from one map to another through a door or something.


Edited by C-Dawg, 30 September 2015 - 12:03 AM.


#9 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members
  • Gender:Unspecified

Posted 30 September 2015 - 12:08 AM

Will the tank drive up walls and across ceilings late in the game :D



#10 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 30 September 2015 - 09:43 AM

Tell ya what; if someone can think of a control scheme for that capability that is not garbage, I'll consider it. From Blaster Master to Castlvana 3 to Little Sampson, I've never seen it done really well.

Edited by C-Dawg, 30 September 2015 - 09:46 AM.


#11 Anarchy_Balsac

Anarchy_Balsac

    Quest Builder

  • Members
  • Gender:Unspecified

Posted 30 September 2015 - 10:00 AM

Tell ya what; if someone can think of a control scheme for that capability that is not garbage, I'll consider it. From Blaster Master to Castlvana 3 to Little Sampson, I've never seen it done really well.

 

Why not just implement a Super Metroid style upgrade disabling system?  That way, it can be turned on when needed, and turned off when it becomes an annoyance.  Simplicity is always better than a splitting headache.  I'm not saying don't implement such a control scheme if you can, but I am saying the occasional, pragmatic approach can work almost as well if the more straightforward method is proving too troublesome.

 

That said, learning to adjust to that control STILL wasn't the hardest part of level 8, it was defeating phase 1 of the Plutonium Boss.  That thing is way harder than it looks.


Edited by Anarchy_Balsac, 30 September 2015 - 10:31 AM.


#12 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 03 October 2015 - 12:33 AM

Finally made some progress.  I moved a lot of functions out of Main.cpp into a new object call the "WorldManager."  And, once made, I implemented a way to put player landing tiles (like the blue squares in Zelda Classic) when they arrive on a screen.  Next step: transitions between different rooms.  Whooohooo.



#13 Gleeok

Gleeok

    It's dangerous to dough alone, bake this.

  • ZC Developers
  • Real Name:Pillsbury
  • Gender:Male
  • Location:Magical Land of Dough

Posted 04 October 2015 - 10:11 PM

Love the sprite work. You planning on adding some RPG elements, item upgrades, etc.?

#14 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 05 October 2015 - 07:07 AM

Metroidvania elements, yes, but no RPG style griding or leveling.

I got room transitions working. Hardest pay was keeping track of where the tank is when you leave a room without it. Also implemented a player lifebar. In doing this, I learned that allegro load bitmap functions are quite slow and you should not call them every frame!

Next up, implement enemy hp and death, then the item system. After that, gonna stop to better organize the project before adding new stuff. When I do that, Gleeok, you willing to take a peek and tell me if the are organizational things or coding issues I should address before the game gets too big? I only learned allegro and object-oriented design a month ago, so I might be missing efficencies.

#15 C-Dawg

C-Dawg

    Magus

  • Members
  • Gender:Unspecified

Posted 06 October 2015 - 10:50 PM

Alright, so the following now works:

 

1. Moving between different rooms (but it needs tweaking, as it's currently clunky and slllooooowwww to load the next room off the HD);

2. Player lifebars and damage from enemies (tank is roughly 10x as strong as soldier)

3. Items implemented, right now just health drops

4. Sound effects added

5. Damaging-on-contact spikes added.  And... they work way better than in Zelda Classic. (Shhhhh 2.5.1, your offset damage tiles in side-view are not missed!)

 

Third_Screenie.jpg

 

One big type of game object remains to be outlined; Doodads!  These are meant to organize non-player, non-enemy, non-item things like moving platforms, etc.  One I get those loaded into the GameObject manager, I think the skeleton of the engine is there.  I'll try to organize, look for memory leaks, and then run it past Gleeok or someone else who knows what they are doing before beginning to flesh out the features so it's ready to design a full game with. Wheeeee


Edited by C-Dawg, 06 October 2015 - 10:57 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