Okay, so I'm trying to think of things that I should consider for enemy attributes. When I say attributes, I mean all of the information that the enemy will need. What kinds of things do you guys store data-wise? Do you have bytes set aside to define the top, bottom, left, and right of their hit detection, or do you do a routine that draws their hitbox when they first appear on screen? Do you have a byte set up for which direction they are facing, like a direction state? A byte for what they are doing at that time, like moving, standing still, be destroyed, etc.?
I'd really like to know how everyone else handles this. I'd like to come up with a couple of routines that can handle all the enemies, but I don't know if that will be possible or not.
In my game, each enemy is assigned 16 variables and there can be 16 enemies/objects total on-screen, basically taking up a full 256 chunk. I use $0300-$03FF for enemy stuff.
Anyway, the variables I use are as follows:
0 - Type
1 - State (reads from each individual enemy's table of stuff and has them behave accordingly). State 0 initializes the enemy and sets the various other variables.
2 - Hit box left
3 - Hit box right
4 - Hit box top
5 - Hit box bottom
6 - Health (can be used for other things if I need another var and health is a non-issue)
7 - Sprite X (sprites can be drawn in a different spot relative to the hitbox)
8 - Sprite Y
9 - Sprite Attribute
A - Tile. This mainly functions as an index as things can be animated. For bullets I just use it to be the actual tile in memory, however.
B - State after init. Some enemies might start out doing an assortment of things, so this will tell it where to go from there. The ball enemies, for example, can start out by moving in one of 4 directions as well as a certain speed. This would tell which of those I would want it to go to.
C, E, D, and F: Extra variables. Can be used for whatever.
For my game, all of the objects in the room are given a variable chunk of RAM. I use SRAM, so I have more RAM to work with than normal. I assign 2k of RAM to be distributed among all the enemies in the room. Some are more complex than others and need more RAM to work with, so this is why I decided to allow enemies to have variable sized RAM given to them. But in general, here's how my enemy's chunks of RAM will look:
00 - Address of AI code Low
01 - Address of AI code High
02 - Size of RAM dedicated to enemy
03 - X Coordinate (precision)
04 - X Coordinate Low
05 - X Coordinate High
06 - Y Coordinate (precision)
07 - Y Coordinate Low
08 - Y Coordinate High
09 - Health Low
0A - Health High
0B - Mana (maybe, I haven't decided on having this yet)
0C - Current Graphic
0D - Direction Facing
;A bunch of other counting variables are used too.
What's great is that I handle all of my enemies with their own AI code. So any stats like strength, magic power, etc. are all hard coded into the AI code. But the thing about this is that once a room is entered, objects can neither be created nor destroyed. Since this is the case, if a skeleton wants to throw a bone at you, it has to use its own RAM to keep track of the bone's coordinates, and to check if the bone hit the player the skeleton has to do that in its AI code. So a skeleton may reserve 32 bytes of RAM or so for itself, because it has to save room for the bone it will throw.
And I don't need to keep track of "states", because I can change the "address" bytes to point to a different section of code depending on what the enemy is doing.
Anyways, that's the story about RAM usage. There are attributes to an enemy which I may not store in RAM, but generally they still exist:
Max Health (8 or 16 bits)
Max MP (8 or 16 bits, maybe I'll use it, maybe I won't)
Strength
Magic Power
Defense
Elemental Weakness
Items to drop
Address of graphics data
Money to drop
But again, there are really no strict guidelines to the way I have things set up. I could make an enemy that has 64 bits worth of HP or 128 bits worth of MP, though it would be ridiculous. Since things like candles (Castlevania candles) are considered objects, they have their own AI code too, but they only need like 6-8 bytes to keep all their information, and I won't need to waste time/space defining HP or MP of a candle. Unfortunately, I will still need to have 16-bit coordinates for them because the rooms are multiple screens in size. For them I will probably have:
00 - Size of chunk
01 - Address Low
02 - Address High
03 - X Coordinate Low
04 - X Coordinate High
05 - Y Coordinate Low
06 - Y Coordinate High
And even though they don't move, I still need to keep to reserve space for the coordinates also because they drop items, and those coordinates can be replaced with those of the items they drop.
Well, I handle this so that each enemy has in ROM some data for it :
- Sprite Animations
- Color used (for palette swapping)
- AI start adress
- Width and height of collision detection
- Score points rewarded
- Vunlerability against various weapons
In RAM I handle :
- X, Y position
- Software stack containing AI adress (automatically changes every frame with some stack tweaking, as discussed
here)
- Stack poitger
- What animation frame is currently used
- Which direction the ennemy is facing
- Health
- Some more general-purpose variables
- Topleft, topright, bottomleft and bottomright coordinates (I've added them later so that ennemies can change their own shape if they want). Are normally initialized once and never touched again, but I touch them for bosses
I set the coordinate in RAM zero page variable each frame, they're not part of the enemy's stat.
Thanks guys, this will be great food for thought : )
Bregalad, when you say width and height of the collision detection, does this mean you use the center of the character as a reference point?
I would guess the top left corner is a reference point, and "height" actually extends downward, since we're working with the (whatever the hell it's called) coordinate system where X increases left to right, and Y increases top to bottom.
But I forgot to list that in the things I keep track of. Each object pretty much has it's own bounding box with a width and height. I usually use the top left corner as a reference point for this, where the enemy's right border edge would be something like "XCoordinate + 24".
Quote:
Bregalad, when you say width and height of the collision detection, does this mean you use the center of the character as a reference point?
Well, by default when a new enemy appear on screen my "NewEnemy" routine makas the top = YPos-Height, Bottom = YPos+8, Left = XPos-Width, Right = XPos+Width.
So my reference is the center horizontally, and 8 pixels above the bottom vertically. This is because I use top-down view, and that 8 pixel is about the height of stuff, when colliding with the background the top is ignored and YPos is used directly instad, so that the head of player/ennemies can go into obscacle, but it will stop where the feets are.
If I were to do a plaftormer I would probably also make the center as a reference vertically to simplify things up.