Simple Shoot-em-up Development


This time around I've added a user-controllable player who can shoot, I fixed a few bugs, and created proper classes for the "RocketMan" and rocket. It's starting to look like a real game. There's no collision detection or enemy AI yet, so you can't really do much. Even so, we're getting close to having something playable up and running.

Here's what I ended up with:

tutorial6a.jpg


Here's my attempt at a top down view of the player:

player-4x.jpg


With a few tweaks to the TexturedObject class from the last installment, it's fairly easy to get the player, the bullets he fires, the enemy character, and the rocket into simple classes.

The Input class was expanded quite a bit to allow some input. I'm an old-school Quake player, so I wanted to be able to strafe and shoot easily. I figure that the Wiz the shoulder buttons can be used to rotate the player, while on the Pandora the second analog stick can be used to rotate. For now I'm using the mouse to rotate, and the WASD keys to run and sidestep.

For now the player runs backward more slowly than he runs forward, and running sideways is somewhere in between. This seems more realistic, and may end up enabling some interesting game mechanics.

I struggled quite a bit to get reliable mouse and keyboard input working under Windows. I didn't want to spend a huge amount of time on it, but ended up sinking a good night or two trying to work the kinks out. It turns out I had a message loop problem in my last several installments which was causing some of the problems.

I finally found a good article on the web talking about capturing mouse input. The article is over 11 years old, but the code still worked great. There are probably more modern ways of reading the input, but it solves the immediate problem.

I had to brush up on my fixed point math skills. In BlastRiot I'd implemented all the math as fixed point, but there wasn't much math involved overall. Plus, that was over a year ago. Since this game needs sine and cosine functions I had to relearn a bit as I went along. Here's a good article talking about trigonometry function implementation using fixed point. I struggled along, my current solution is probably not optimal, but it works.

I added my cosine/sine functions to a new class named FixedTrig. It's a singleton, and the first time it's referenced it builds a look up table used by the sine and cosine functions. It stores 1024 values over 90 degrees in a 0.10 fixed format. Note that it takes degrees instead of radians for it's argument, OpenGL uses degrees, so this saves a conversion.

CODE

class FixedTrig
{
public:
// Get singleton instance
static FixedTrig *GetInstance(void);

~FixedTrig(void);

// Returns the cosine of the passed in angle. Angle is in degrees.
S32BIT Cosx(S32BIT angle);

// Returns the sine of the passed in angle. Angle is in degrees.
S32BIT Sinx(S32BIT angle);

};



The trigonometry functions are used to move an object along a path. This is needed when the player shoots his gun, or the rocketman fires a rocket. In both cases the projectile inherits the angle from the shooter, then moves along that angle at a certain speed. The CalcOffset method in the TexturedObject does the work. It's a bit nasty due to the fixed point math.

CODE

// Uses object's angle and passed in x and y values to calculate offset
void TexturedObject::CalcOffset(GLfixed xDist, GLfixed yDist, GLfixed &lx, GLfixed &ly) {

lx += (((xDist >> 8) * FixedTrig::GetInstance()->Cosx(angle)) >> 8) -
(((yDist >> 8) * FixedTrig::GetInstance()->Sinx(angle)) >> 8);

ly += (((xDist >> 8) * FixedTrig::GetInstance()->Sinx(angle)) >> 8) +
(((yDist >> 8) * FixedTrig::GetInstance()->Cosx(angle)) >> 8);

}



For the RocketMan class, I made a straight-forward update method that just moves him in a circle firing rockets as fast as he can. All the classes have simple bounds checking to make sure they don't move out of the arena, but there's no real collision detection yet.

After getting things up and running I quickly found that the control scheme was a bit hard to use. In a first person shooter the world rotates around you as you turn. Here, the world was standing still and just the player was rotating.

After much trial and error, I got the playfield to rotate around the player. This makes things a lot easier (at least for me), and makes me hanker for some deathmatch. Even though it took me a while to figure out the required translation and rotation order, it only took 3 or 4 lines of code to get this to work.

tutorial6b.jpg


The first half of the video below is recorded using the original control scheme, about halfway through it switches to the other mode.

http://www.youtube.com/watch?v=XVVtrfm3b1Q

Next time around I'm hoping to address collision detection and some simple AI for the bad guy.

The sourecode for this version can be found here.
 
Last edited by a moderator:
I reccomend make to bullet's trails more longer. 10 times or so :)
 
quasist said:
I reccomend make to bullet's trails more longer. 10 times or so :)

Right now the bullets are just drawn to be long like that, they don't really have trails. Or are you talking about the rocket smoke trails? I think it'd be pretty cool to have the arena eventually fill up with smoke during a good firefight.

Either way, I think at some point the harsh reality of having too many objects on the screen will cause speed issues on the Wiz. Can't wait to find out.
 
Last edited by a moderator:
You can draw bullets and some effects like lighting using GL_LINES primitive... if OpenGl ES still supports it ...
There some proc called glSetLineWidth(...) or something alike
 
I haven't had the drive to do much coding on the project lately, but I did mess around with some of the graphics a bit.

One thing I'd noticed early on is that the simple graphics I'd draw on a black background didn't look as great on a lighter background. Here's the rocket on a black background:

rocket-black.jpg


When drawing the rocket, I'd anti-aliased the fins and nose cone without thinking about it. If this rocket was displayed on a light grey background, it'd look like this:

rocket-grey.jpg


Since I'd automatically blended things to black, you could see a fringe of black when displayed on a lighter background.

It didn't look too bad, but I figured if I used alpha blending instead on the partially lit pixels, it'd look a bit better. Since this game will eventually run on the Wiz's 320x240 screen, it'd be nice to make each pixel look as nice as possible. So I redrew the rocket, and also drew an alpha map for it. This is what they look like:

rocket-alpha.jpg


The darker grey the pixel is on the alpha map, the more transparent the pixel would be on the texture. There are probably paint programs out there that do this for you automatically, but doing it by hand isn't too bad, especially on such small images.

The next thing I wondered about was what this thing would actually look like on a 320x240 screen. I'd been running it under much higher resolutions on my desktop, and letting OpenGL magnify the image appropriately. The problem with this is that as the scaled up textures are drawn, the larger "pixels" also rotate, which isn't going to happen at 320x240. The pixels end up no longer being square, but look more diamond like.

boss-pixels.jpg


I was also curious about how the GL_NEAREST and GL_LINEAR scaling methods would look at 320x240. In order to see what things really would look like at 320x240, I changed the screen width and height down to 320x240, reran the game with the new and old graphics, and toggled between GL_NEAREST and GL_LINEAR. I then enlarged the screen shots so I could get a better view of what was going on.

compare.jpg


From what I can tell, the alpha enabled rocket looks a little better than the non-alpha rocket. I also think the GL_LINEAR looks better than the GL_NEAREST, especially for the boss character. One interesting thing to note on the "Original Rocket / GL_LINEAR" frame is that the tips of the rocket fins bled over to the front of the rocket. Since the scaling algorithm wraps it's coordinates to find averages, it added 3 small dots to the front of the rocket.

So, I'll probably leave the scaling rules as GL_LINEAR, and add alpha maps to the appropriate textures. It's nice to have busy work like this when you don't feel like coding.
 
Michoko said:
A lot of great informations here. It should be stickied IMHO.
Rotating sprites for a month is such a depressive scene :(

Trenki's renderer was sticked. Do you see any 3D games using it?
 
Last edited by a moderator:
quasist said:
Michoko said:
A lot of great informations here. It should be stickied IMHO.
Rotating sprites for a month is such a depressive scene :(

Trenki's renderer was sticked. Do you see any 3D games using it?


Well, as a beginner in OpenGL, I found satacoy's approach really interesting. It allows to figure out the possible learning curve I may experience myself.

I just hope your comment won't discourage satacoy to post further tutorials, some people really appreciate them ;)
 
Last edited by a moderator:
Michoko said:
I just hope your comment won't discourage satacoy to post further tutorials, some people really appreciate them ;)
It won't discourage me. Quasist is a bit crazy, and I'm not doing this with the specific goal of keeping him entertained. I'm finding the process of trying to explain what I'm doing interesting in it's own right, regardless of what the response is.
 
Last edited by a moderator:
Hi , as an open gl beginner I find this thread very useful too,
and I follow it.
this is homebrew, let's take it easy ;)
this is for fun after all.
 
trabitboy said:
this is for fun after all.
Let's then stick every thread in this forum section for fun :)
Sorry if I sounded bad to this project. My opinion was abount stickin topic :D
 
Last edited by a moderator:
Could a Mod move this to the "Developers' Corner [Wiz]" forum? Thanks!
 
Life as been keeping me pretty busy, I haven't been able to spend as much time on this project as I'd like. Regardless, I've been playing around with it here and there, and have enough small random additions to warrant an update.

I read up a bit on texture mapping, and found that it's easy to clamp the textures so that using linear mapping doesn't borrow pixels from the opposite side of a texture map along the edges. I'd mentioned this happening on some of the rocket texture mapping experiments a few posts back. To fix this, I used the GL_CLAMP_TO_EDGE texture parameter:

CODE

glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);



I reorganized a few sections of the code. I found that I was passing the various object managers around quite a bit as arguments. The use of singletons was bothering me too, as it seems like every time I convince myself that I'll ever only need one copy of a class, inevitably I find a reason that I need multiple instantiations of that class. To address this, I created a "GameContext" class that contains all the classes a typical game object may need access to. Right now this includes the input handler, the object and special effect managers, and a texture manager. I'm sure this class will continue to evolve, it's a bit rough right now.

CODE

//Contains all the relevant info that a GameObject may need access to.
class GameContext
{
public:
GameContext(TextureManager *tMgr, ObjectManager *oMgr, ObjectManager *fMgr, Input *in);
~GameContext(void);

TextureManager *texMgr;
ObjectManager *objMgr;
ObjectManager *fxMgr;

Input *input;
};



I started playing around with explosion effects. I'm finding that they're a lot harder to get right than smoke trails. So far I'm using the same bitmap as I did for the smoke particles, but have changed their color and behavior. They currently don't look nearly as good as I'd like them to.

tutorial7-explosion.jpg


I also made an initial pass at collision detection. To keep things simple and fast, I decided to go with a bounding circle instead of a bounding box technique. Bounding boxes work great when your objects don't rotate, but it becomes more expensive to calculate once the objects start rotating.

I added some optional code that draws the bounding circle around each object. This helped me get an idea of how rough the collision detection would be for each object, and also helped a lot as I was debugging the code. As you can see below, the player and the boss character both fill the bounding circle fairly well, but the rocket and the bullets only take up a small portion of their bounding circles.

tutorial7-circles.jpg


If the collision detection for rockets and bullets appear too rough, I could add further collision tests based off a bounding box if the circle test found an apparent collision. However, so far things look OK to my eye. The bullets and rockets travel fast enough that it's not obvious that the collision detection is rough.

To implement the collision detection, I added a "hitRadius" attribute to each game object. This specifies in pixels the radius of a circle roughly surrounding the object. Each time an object moves, I check to see if it's bumped into anything by calculating the distance between it and each of the other objects in the game. If the distance is less than the sum of both objects hitRadius, a collision has occurred.

Here's some video showing the collision detection. It starts out with the bounding circles being drawn, then later they are turned off.

http://www.youtube.com/watch?v=-CAPb2UoLHM

In the next go around I'll try adding some simple boss AI and game mechanics.

Source code can be found here: http://www.blastriot.com/tutorials/tutorial7.zip
 
Last edited by a moderator:
Very interesting series Satacoy! Hope you keep them coming.

Here's a thought about collision detecting with the bullets & rockets ...
Make the radius equal to the width of the object as they are travelling linearly and quickly, the front-back dimension doesn't matter nearly as much as the bore (width)
 
Hi there everyone!

This is my first post. I have never developed something for open source handhelds, never even heard of one. But since a few months I have completely fallen in love with the Wiz and the Pandora, maybe I even gonna get them both.

Okay back 2 topic: Your tutorial is great! Although I did already know most of the OpenGL stuff, the part about setting up OpenGL ES has been very useful to me, thanks!
 
gp32rich said:
Very interesting series Satacoy! Hope you keep them coming.

Here's a thought about collision detecting with the bullets & rockets ...
Make the radius equal to the width of the object as they are travelling linearly and quickly, the front-back dimension doesn't matter nearly as much as the bore (width)
I like your suggestion, it makes a lot of sense. I'll try it out in the next iteration.

The holidays have slowed my work on this, but I'm still planning on getting one or two more postings out before I move on to something else. Once the Wiz comes out, I'll add at least one more entry detailing the work required to get it running on the device proper.

QUOTE

Okay back 2 topic: Your tutorial is great! Although I did already know most of the OpenGL stuff, the part about setting up OpenGL ES has been very useful to me, thanks!



Glad to hear this is helping people out.
 
Last edited by a moderator:
As the Wiz and Pandora creep ever closer to seeing the light of day, I've started poking around at this project again. I've managed to add improved explosions, simple enemy AI, and even simpler game mechanics.

Tutorial8.jpg


Video:
Youtube Video

After tearing my hair out for a while trying to make the explosions look better, I eventually arrived at something I'm semi-satisfied with. I drew a much larger texture to represent the explosion. I also added a bit more "texture" to the image. This allowed the explosions to be larger than what I was trying before, and the added texture made them look a little more interesting. They're still not nearly as cool as I hoped, but they're good enough for now.

cloud.jpg


For the AI I experimented around with various state machine ideas. I knew I wanted a few basic "modes" for the enemy, but deciding how to implement them took longer than I expected. I eventually settled on a very simple mechanic, my original attempts were too complex.

The enemy can be in one of three states:

Idle: The player isn't visible.
Randomly look around the arena, pause, then look around a bit more.
If shot, turn toward whatever collided with you by entering the FaceObject state.
If the player is visible, enter the Attack state.

Attack: We spotted the player, attack!
If player is no longer visible, enter idle mode.
If player is directly in front of you, fire a rocket at them.
Otherwise Turn toward the player.
Optionally move toward the player.

FaceObject: Used to turn toward a non-visible object.
Turn toward your goal.
If player is visible, enter Attack mode.
If destination reached, and player isn't visible, enter Idle state.

This result in OK behavior by the enemy character. Since the arena is so small they can typically see the player, so the Idle state and FaceObject state aren't very obvious.

For the play mechanics, I added health to the enemy and player classes. It takes 10 hits to kill an enemy, at which point the enemy blows up, and two more enemy randomly spawn in the arena. I limited the number of enemies to 5, more than that and things get very chaotic in such a small area.

The player can take 3 direct hits by the rocket, after which point the game ends. Every shot that you fire that hits an enemy gives you a point, the goal being to score as many points as possible before dying.

I also realized that OpenGL ES doesn't natively have any functions to display text on the screen. I pulled over some old code from BlastRiot that draws characters using line primitives. It's not pretty, but at least it gets text on the screen.

There are a number of issues that I could pursue. Sometimes the player doesn't get hit with a rocket when it looks like he should. I believe this is due to the bullets from the player hitting the rocket first. This would require some tuning to get it to feel right.

There's also issues with rocket smoke trails showing on top of explosions, which is counter intuitive. I'd have to sort the effects somehow to fix this. I'm not going to worry about for now.

I'm not going include source this time around. There's some non-fixed point math in there that I need to clean up, and some of the text routines need further work before being ready for public consumption. I may wait until I get a Wiz version running to release a final source revision.
 
Last edited by a moderator:
satacoy posted on Oct 22 2008 at 04:21 AM) [...] Some graphics formats (such as TGA and PNG said:
support storing the alpha data directly in the file. Instead of figuring out how to read a more complicated file format in, I'll use the BMP file loading we got working last time, and use it to add alpha values to the textures.
[...]
TGA is actually a very simple format. Like BMP it's also "raw" which makes reading/writing it pretty straightforward.

And PNG... well... it's great for the web, but not all that useful when it comes to games. It utilizes the Deflate compression scheme just like Zip, GZip, or SWF. Compression and decompression is very fast, but usually you'll use something like Deflate or something better anyways (e.g. some "pak" file or an installer with LZMA compression).

Great stuff btw. The GLES pointers were really useful. :)

Edit:

You can use this texture if you like:
http://kaioa.com/k/bloodsplatter2.png (lhfire+imagemagick)

It's probably a "bit" excessive. ;)
 
Last edited by a moderator:
After some frustration fighting with OpenGL on the Wiz, I finally got Tutorial 8 running on the actual Wiz hardware:

.

Pickle's OpenGL/SDL archive topic finally got me compiling properly, from that point it was fairly trivial to get things running properly.

OpenGL doesn't seem to be blindingly fast on the Wiz, there's obvious slowdown when more than a few rockets are fired. There also seems to be some blending differences between the emulator on the PC and the actual hardware. You can see all kinds of strange transparency artifacts on the Wiz.

I've still got a little code cleanup to do, I'll post it here once it all looks good.

Thanks again Pickle!
 
Last edited by a moderator:
Back
Top