Jump to content
  • Advertisement
Sign in to follow this  
Rifle_001

on creating enemies in a 2D side-scrolling shooter

This topic is 4204 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hullo, I have a book (AI Game Engine Programming) and in one of his examples for creating game objects (this has nothing to do with AI just something I noticed and I thought it could help me) he uses an enumeration for types of objects that looks kind of like this: enum//collision flags/object types { OBJ_NONE = 0x00000001, OBJ_ASTEROID = 0x00000002, OBJ_SHIP = 0x00000004, OBJ_BULLET = 0x00000008, OBJ_EXP = 0x00000010, OBJ_POWERUP = 0x00000020, OBJ_TARGET = 0x00000040, OBJ_SAUCER = 0x00000080 }; The author said that those magic numbers on the right were bitwise numbers (I think) and that they were for collision flags. The game he described in his examples is a game called AIsteroids (pretty much the same thing as Asteroids). I'm not familiar with bitwise anything so please explain what they mean and how they would work with two game objects colliding (and in doing so calling a doCollision() function and an explode() function). Also I need to know how to place my enemies within my level without them being on the screen yet. I'm using DirectX now but I might use OpenGL instead because Dev- C++ works better with it.

Share this post


Link to post
Share on other sites
Advertisement
The 0x prefix means the given numbers are in hexadecimal notation. 0x1 is 1 in binary, 0x2 is 10 in binary, 0x3 is 11, 0x4 is 100, etc. It's usefull to get familiar with these notations and conversions because they pop up now and then.

Anyway, I assume this enumeration is used to do quick collision test culling. For example, a bullet doesn't need to do a collision check against another bullet - it's not worth the time checking for it, because in most games, you don't want your bullets to stop each other, right? OBJ_BULLET and OBJ_SAUCER both have the 4th bit from the right set to 1, so the collision check probably checks if both objects have a 1-bit in common, and if so, it performs a collision check. Otherwise, it ignores the test and returns false.
In the end, it's an optimization. I wouldn't really go for a bitwise flag system, unless it turns out to be a bottleneck, because it's not really straight-forward what's actually going on. If the collision system takes a lot of time however, then such methods may help speed it up. It's one of those situations where you want to profile your code first, and only optimize what actually takes a lot of time.


As for placing your enemies in your levels, that's a very broad question. I'm afraid I can't give you much help without further information.

Share this post


Link to post
Share on other sites
That explained hexadecimal notation, but not bitwise operations. Before going into bitwise operators let me recap the logical operators because they are somewhat related.

Let's say you have two expressions, Alice_Money < Bob_Money as well as Bob_Money < Cecilia_Money, then you can check if they are both true by using the && operator like so:

if(Alice_Money < Bob_Money && Bob_Money < Cecilia_Money) { /*do stuff*/}


If alice has $20, bob has $30, and Cecilia has $40, then the expression alice_money < Bob_money is true and bob_money < cecilia_money is also true. The above if statement can be seen as:

if(true && true)


The result of the above conditional, true && true is also true. If it was true && false the result would be false. Okay, recap over. Bitwise operators do the same thing, but one bit of a number at a time for All the bits of a number. So if you had the binary number A b0011 0101 and another number B b1111 0011 then what would happen if you split all of the individual bits up and compared them like above? You'd have this:

A & B == C
-------
0 && 1 == 0
0 && 1 == 0
1 && 1 == 1
1 && 1 == 1
0 && 0 == 0
1 && 0 == 0
0 && 1 == 0
1 && 1 == 1

Another bitwise operator includes | which is like the || operator and will yield a one if at least one corresponding bit in A and B are one. Another is ~ which is like the ! operator which can only work on one number and it flips all of the bits to opposite. There are also operators that can shift the bits in numbers to the left(<<) or right(>>) and another(^) which yields one if(and only if) a corresponding bit is one between A and B. Some good info is found here on using the operators.

You may have seen code that may have looked like this:

SetProgramState(CNST_FULLSCREEN | CNST_NO_MOUSE | CNST_SOME_OTHER_SETTING);

That is a pretty common use of bitwise operators, but I'd stay away from them unless you have a reason. Hope my rambling post makes some sense.

Share this post


Link to post
Share on other sites
What he does is pack 32 booleans in an integer. Each bit represents whether something is true or false.

Some examples (using only a few bits to keep things simple):

FLAG_PLAYER = 0x01
FLAG_ENEMY = 0x02
FLAG_BULLET = 0x04
FLAG_ACTIVE = 0x08
(note the powers of two, so that each number represents a single bit)

Object0.flags = FLAG_ACTIVE | FLAG_PLAYER; // the player
Object1.flags = FLAG_ACTIVE | FLAG_PLAYER | FLAG_BULLET; // friendly fire
Object2.flags = FLAG_ACTIVE | FLAG_ENEMY | FLAG_BULLET; // not so friendly fire
Object3.flags = FLAG_ACTIVE | FLAG_ENEMY; // an enemy
Object4.flags = FLAG_ENEMY; // a sleeping enemy (inactive)

if (AnyObject.flags & FLAG_BULLET)
{
// a bullet
}

if (AnyObject.flags & FLAG_ENEMY)
{
// if we hit this, we die
}

if (AnyObject.flags & FLAG_PLAYER)
{
// this is ours
}

// --- let's go a bit deeper

if ((AnyObject.flags & (FLAG_BULLET | FLAG_ACTIVE)) == FLAG_BULLET)
{
// inactive bullets
}
else if ((AnyObject.flags & (FLAG_BULLET | FLAG_ACTIVE)) == FLAG_ACTIVE)
{
// active objects that are not bullets
}
else if ((AnyObject.flags & (FLAG_BULLET | FLAG_ACTIVE)) == 0)
{
// inactive objects that are not bullets
}
else
{
// active bullets
}

...and finally:

AnyObject.flags ^= FLAG_ACTIVE; // active objects become inactive and vice versa
AnyObject.flags &= ~FLAG_ACTIVE; // objects will be inactive
AnyObject.flags |= FLAG_ACTIVE; // object will be active

Summary:

Use AND (y & x) to test flags x in y / reset all flags in y, but x
Use OR (y | x) to set flags x / combine flags of y and x
Use XOR (y ^ x) to invert flags x in y
Use AND with INVERSE (y & ~x) to reset flags x in y.


Bonus quiz:

(FLAG_ACTIVE | FLAG_BULLET) & FLAG_BULLET == ???
(FLAG_ACTIVE | FLAG_BULLET) & ~FLAG_BULLET == ???
(FLAG_PLAYER | FLAG_BULLET) ^ FLAG_ACTIVE == ???

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!