• Advertisement
Sign in to follow this  
  • entries
    42
  • comments
    85
  • views
    46695

Entries in this blog




I've been trying to decide whether a light or dark negative space is more functional, and which looks better. I'm a fan of the silohuette style, but I think I'll go with a nightclub theme- mostly dark with bright colors in the foreground.

Thank you for testing, Staffan! I wish I had a vista or win7 computer to test on... I've added a line to the installer script that request's an admin's status to install the game. Its a weak attempt for compatibility, for now. I'm going to look for a better install system (than NSIS) that requires less esoteric one-time-use scripting knowledge.

There is no goal at the moment. The test level is where I'm puting all of the different creatures I'm making. I run performance tests, tweak Box2D, test AI behavior, tune gameplay controls, and fix bugs in the test level. Very soon I'll implement creature death, and have a enemy chase the player around. Expect future posts about waypoints and AI behaviors.

I'd have a demo, but I just started using a recent version of Box2d. I was using the code directly in my project from version 1.4.3 or something. Now I'll be linking to up-to-date static libs from the repository. I needed a joint that my creatures can use to bite and carry objects, and the old version didn't cut it. The new one has a b2WeldJoint, which should work nicely.

I added some music to the demo. My previous OpenAL/Ogg code was buggy, which didn't make sense because I started with demo code that worked fine! So I started over with the demo code and discovered that I was trying to open the Ogg stream using ov_open_callbacks() instead of ov_open(), which I found in the docs on the OpenAL site when I was trying to fix an (apparently) unrelated bug.

I've fixed it now and added a track I whipped up in Reason. I put it together in a couple hours using stock samples in Dr.Rex, and liberal use of faders and automation. Anyone that's used Reason knows that its a hack job, but I'm ok with that. I think a low-key Pink Floyd vibe would be suitable for the exploration parts of gameplay.... Maybe this lively tune could play when the creature is first introduced to the "outside world" (when leaving the introductory birth-caverns).

one lively song, one minute long

Fishy



Its been awhile, but progress is being made on my fishy prototype. I have a friend that's mentoring me to help me finish this project. He's a lead designer at a game company right here in town. I'm starting to use some techniques from agile development to make a schedule and track my progress. I have a tenative deadline at the end of June.

I've never written a design document before, but I'm struggling through my first draft for Aquarius. You can see my incomplete design doc here. I think the idea of the doc is to establish every feature the game will have ideally, and the finished schedule will show what I can have done in any given amount of time. *schedule not included

My latest build is just a level where I test anything new and lay out all the creatures so far. I've lined up each type of creature in child/parent sizes, and shown a few in groups. I haven't made half the creatures I want yet.

Demo (windows).

Controls.txt

Mouse to aim.
Use E and D to move forward and backward.
LMB to move forward.
RMB to bite.
Mouse Wheel to zoom
1-6 zoom level (6 is the highest real-game zoom)
~ is autozoom, on by default


Hold R to grow. Caution: growing is fast!
Hold T to shrink. Caution: shrinking too small will crash the program!

Q AI waypoints
G grid
W wireframe
C collision shapes
V extended vision type (off, normal, small circle). Currently quite crappy.
M "map" just shows the background gradient. and your position in the world as a red dot. I know its misleading but its not a high priority and wont be available in the game.
U toggle culling. Note: you can see if culling is enabled by looking for the waypoints of creatures that are not on screen, there's no real indicator.
I toggle the culling radii


Esc pause / menu
F2 toggle fullscreen. Note: some textures may disappear. you have to restart to get them back.
F5 screenshot
F6 experimental, crappy "motion blur" screenshot.
SPACE toggle an in-progress control panel for the world. In-progress and not functional!!






Oh yeah, I've moved my site to www.soulcraftgames.com and Soulcraft Games will be the name of my futuristic indie company.
Wow, its been another month already. I'm been making progress and killing bugs but I haven't finished a journal entry because I always feel like I'm explaining things in a way that isn't understandable or interesting. Anyway, I'll have gameplay-relevant entries soon. This one's about organization and deployment! Fun!

Project Organization

I finally organized my project folder to be much more simple. At the top level are the executable, DLLs, config file, and two folders: the "data" directory where all the game data is stored, and a "project" directory that stores everything related to the project. In the "project" folder I keep the source code/VC++ project, the game design folder where I plan the project and work on art assets and audio, the documentation folder (Doxygen), and the deployment folder.

This setup makes it easy to exclude everything but the relevant files when I deploy the game.

Deployment

I finally have my deployment process streamlined. All I do is run a batch file and it takes care of everything before building the installer with NSIS. So far, it creates an filename list for the uninstaller, moves any screenshots out of the data directory (so the user doesn't install my screenshots, and I don't need to manually move them each time), and builds the installer. The uninstaller list is just a list of all the files in the program hierarchy that the uninstaller uses to cleanup. Any other files are left over after the uninstall, such as the log file and screenshots.

In the NSIS build script, I exclude anything named "project" or any file with a .pdb or .ilk extension. The script automatically runs the VC++ redistributable and the OpenAL redistributable with the no-prompt option. Below, you'll my deployment folder. It has the script itself, the icons, the images used in the installer, the redistributables, the license agreement used in the setup, the filename list for the uninstaller (which is created with the installer in the same script), and the batch file that brings it all together in one command.


This is the batch file:

unList.exe /INSTDIR=C:\My_Stuff\PROJECTS\Aquarius
move /y "C:\My_Stuff\PROJECTS\Aquarius\data\screenshots\*.*" "C:\My_Stuff\PROJECTS\Aquarius\project\design\screenshots\"
"C:\Program Files\NSIS\makensis.exe" "C:\My_Stuff\PROJECTS\Aquarius\project\deployment\Aquarius.nsi"



I use absolute paths to be clear, and the directory structure won't change anyway. It runs an app (you can find at the NSIS wiki) that makes a list of filenames for the uninstaller, then moves the screenshots into my project/design/screenshots folder, then builds the installer by calling makensis.exe with the script as an argument.

Here's the NSIS script I use. If you want to start using NSIS, you could do worse than to start with this script and customize it to your project.

Documentation

I'm in the process of documenting my code with Doxygen. The config file for doxygen is loaded with comments that make it huge, and just repeat what the documentation says anyway. What I do is use the Doxywizard to create an initial config file (the last tab) and then manually copy+paste the abbreviated version into a text file. Its just much nicer to use the short version to make changes. I don't think the Doxywizard gives all the options it should (the "Advanced" tab is empty?), so this is what I do.

I think documenting the code will help my understanding of what I've written, and make it possible to share the code or point to it as a reference. I plan to release the code for Aquarius once its sufficiently documented. I'm not going to try to make it "impressive", either. A lot of the code is being written to fulfill a single purpose, so I don't waste time writing generic code. It will all be in the docs.

The Life Aquatic


Here's the player's character at (almost) full size.

The control scheme is like Asteroids with a cursor. The direction you move the cursor is the direction your character faces. The cursor's distance from the player determines the character's speed, and where you looking. You could previously zoom with the mouse wheel, but now the cursor distance controls that, too. The camera will zoom out when you move the cursor away, and will slowly zoom back in when the cursor is close to the character.

I'm going to include two sensory systems to help avoid detection, and find prey. The first is already in the demo: its the series of dark blobs around the edge of the screen. I call them "vision blobs" or "extended vision". They let you "see" what's off-screen in the form of dark blobs. The size and opacity of the blob indicate the size of the object and distance from you. The second sensory device in still in the works, I call it "particle smell". The particles are mostly white, but if you're observant you'll see that some of them have a different color. This color could represent a kind of "visual smell" and tell you what's nearby. You could smell food, predators, friends... I wanted this to be a subtle clue that only the keen would notice, but I can't keep secrets from my journal :) Your character's sense of smell could become more sensitive as you grow, too.

I've almost fixed the bonitis problem, but it can still happen if a creature's tail whips around too hard and the collision shapes tunnel. This happens because a half-grown fish's tail spasms like a freak when it moves. It's just a matter of tuning to make everything copasetic. I could remove the joint motors at the end of the tail to calm down the tail swing.

I don't have Vista to test things out, but in the VC++ Linker/Manifest File options I disabled the UAC and bypassed the UI protection. So hopefully, you won't have to run it as an administrator.

Those brown things aren't poops, they're seeds! If you grab one and let it touch a rock, it instantly sprouts a single giant leaf. Rocks are the only static objects I have at the moment, so that's why plants can grow out of them. All the bodies and joints necessary for leaves are very expensive and bring the game to a crawl in any large amount. I'm trying to find a way to do inexpensive plants...

Aquarius update



Demo Download(win32)



Lately, I've been working on my top-down, sea-creature game. The basic idea is that you explore, find prey to eat, and avoid predators. Its really a labor of love. I've made a lot of progress since the last update but I'll post smaller updates instead of one giant entry.

A typical play-through is planned to go like this:
You are born.
You use your senses to avoid predators.
You're not fast enough to catch prey, so you eat plants.
As you eat, you grow and become faster.
You hunt down prey and keep growing.
...And that's all I'm realistically planning for now.


The actual experience so far:
You spawn at the origin.
You see rocks, plants growing on them, and prey going by.
You also see my test creature, the "Freakshow".
You can't actually eat things yet, but you can bite off pieces. (its far from finished)
There are no predators yet.

I'll go into more detail later about everything.
Also, know that if you hit 'R' to grow, the creature may suffer from what looks like Bonitis. Just quit and restart if any weirdness occurs.



Aquarius Demo (with Ninja Demo)


Here's my water game prototype so far. There isn't anything to do except bother the snakes. Today, I did some profiling with the Shiny profiler, made the level update loop more efficient, and suddenly my app runs faster with vertical-sync on than without. What the hell? I don't know why yet, but I must be doing something very wrong with it disabled. So if you try the demo, run Aquarius with v-sync on. The ninja app has a slight delay in response time with v-sync enabled. They both use the same config file, so you have to change it when you switch, sorry. I didn't want to create a separate installer for the ninja test because its so small. Hopefully it installs and runs ok. Let me know if it doesn't?

I've been playing a lot with the particle system in Aquarius (still working title). The particles are now little tiny circles, and theres a few different sizes stored in display lists. I've added culling, the ability to change the video settings from the menu, and I changed the snakes' behavior a bit.

Oops, I forgot to included a list of the controls again.

Aim with the mouse
E, LMB - move forward
D - move backward
roll the mouse wheel - zoom in/out
R - grow a little bit and get faster ( but not much )
W - toggle wireframe (weirdness with the collision shapes atm)
C - toggle collision render
P - toggle particle update
Esc - back to menu, quit
F2 - toggle window mode
Pause - pauses just for you

Video Settings


The video settings can now be changed from the main menu. They're stored in the config file (which is now XML). I'll have to write a proper GUI_Page class to handle menu pages so I can put it on an Options page. When a setting is changed in the menu, a simple VideoSettings struct is updated, and the 'Apply Settings' button resets the video mode using SetVideoMode() (same as the fullscreen toggle). When I create that GUI_Page class, I'll have to make sure the app takes you back to the correct menu page.

There is a bug that I can't duplicate: One time, when going from fullscreen back to windowed mode, the viewport stayed at the upper-left of the monitor- within the window. So I dragged the window to the upper left and back, and it was back to normal. Bizarre.
Another annoyance is that going fullscreen moves Windows' folders around. I have no idea how to fix it.



Culling


I'm using a simple culling technique based on bounding circles. It takes the distance from an object to the screen center, and subtracts the bounding radius of the object from the bounding radius of the screen. I could test the object's radius against a rectangle for the screen, but it might actually be a little slower since the cost of this (extremely simple) technique is in the squareroot operation already needed to get the distance. There is a bit of wasted space around the screen (shown in the image). I haven't compared the operations for an AABB technique to this method at a low level, but I don't think there would be much to gain from using AABBs instead.

Each object's bounding radius is calculated by finding the furthest vertex, or circle + radius, from the origin. This is done once, when the object's Collision shape is created. The objects are culled by placing only visible entities into a vector of Entity pointers each update. I loop through every object and call it's UpdateCulling() method, which I pass the camera's position and current radius. This method returns true if the object is within the radius, and is added to the vector of objects to render.
I've been learning CSS and thought it would be fun to make my journal match my site. You can get to my site by clicking on the flag at the top. There's hardly anything there yet, and I'll probably repost some significant posts from the last year. I have plans to post my custom model format spec with Maxscript exporter and loading/OpenGL render code; for anyone interested in writing their own format for learning purposes. I'll have to right a comprehensive post explaining the process, and caveats I found. I have a bunch of screenshots from the time, so it'll be a nice trip down memory lane for me. Also, I'll share my 3dsMax sprite render script for anyone interested.


I've been experimenting with the gameplay feel of a ninja character. My inspiration came from the game "N".[1] I thought it was neat how the ninja's orientation would rotate as he slips over the edges. I figured it must be a simple circle shape to accomplish this, and went to work trying to duplicate this ability with box2d. I needed a cheap placeholder for the ninja sprite and took the Ninja Gaiden ninja. I had to add a few frames because the original sheet didn't have a sliding frame, etc.. but most of them were ready to use. It looks like this so far:

I'll post demo as soon as I fix a silly issue with the config file: I'm using a plain-text file, which makes it error-prone when trying to overwrite the video resolution (when changed from the menu) if it happens to be one-character shorter or longer. So I plan to use an XML file instead. I have yet to fix this.


[1]
"N" is an award-winning flash game released in 2004 by Metanet Software. It's name means "way of the ninja", and features a ninja that must avoid deadly robots and reach a door at the end of each level. If you're not familiar with (or don't remember) the game, give it a try. The game is an action-based survival challenge with many levels and succeeds in being infinitely replayable.

Its about time.

For the first time, I've separated my engine code into its own project and built it as a static library. It was laughably easy. Not arrogant laughing, but relieved laughing. I've never had the need to build a library, or enough common usable code to warrant doing so. I have a GUI editor that inherits from the same framework class as my game class. I was manually calling (from the game class) all of the editor's methods that inherited from the framework so I could run the GUI editor from the main menu of the game. It was ugly and ridiculous, and the only reason I did that was because I thought learning how to build a library would be time-consuming (and I didn't want to copy the code into another project). So now, all within the same solution, I have my engine project that builds a static library, the GUI editor that links to that library, and the game that links to it as well.

The game and editor projects still had to link to all the libraries that the engine does. I'm not sure this is avoidable. I got a bunch of linker warnings saying the 'PDB' program database files for one of the projects couldn't be used. I figured out it was because all three projects were compiling into the same intermediate directory. Everything seemed fine except the "vc90.pbd" must have been overwritten by the previously-built project. Anyway, I had to make sure the intermediate directories had project-specific names and not just 'Debug' and 'Release'.

Entity Files

I've finally done away with the sprite data files and put the data directly in to the entity-XML file. Now the object type, name, collision model, image filenames and type info (diffuse, normal, etc), all the sprite animation data, and actions (sprite linkage) are all in one file for each entity. The original plan was to have separate collision, sprite, and entity data files in case objects needed to share resources. It was an attempt to be efficient and flexible (during my failed 3d project), but ultimately naive because I had no clue what the real needs would be. As it turns out, I need all the data for an entity to be in one file to keep things clean... my projects aren't huge.

I used to have the filename of the sprite-text file in the entity-XML, and would load it separately. The text file looked like this:


SEQUENCES 9
idle
FRAMES 2
timestep 400
PIVOTS 0
[(15 17) 0 0 32 32 ]
[(15 17) 32 0 32 32 ]
run
FRAMES 3
timestep 100
PIVOTS 0
[(15 17) 64 0 32 32 ]
[(15 17) 96 0 32 32 ]
[(15 17) 128 0 32 32 ]
duck
FRAMES 2
timestep 400
PIVOTS 0
[(15 17) 192 0 32 32 ]
[(15 17) 224 0 32 32 ]
... you get the idea




Now there's a data node in the XML file with child nodes for each sequence. I couldn't bear to put each little bit of data in it's own XML node, so I'm keeping the raw data in the same form as the text file. It looks like this:


"1.0" ?>
"ninja" type="4">

"ninjaBody">
"0.000" y="0.0" angle="0.000" />
static="0" sleeps="1" fixedRotation="0" mass="0.000" />
"ninjaCircle" type="0">
"0" density="0.700" friction="0.500" restitution="0.100" collisionProfile="2" />
"0.5" x="0.000" y="0.000" />


>

"ninja.png" type="0" />
"32" >
"idle" frames="2" timestep="400" pivots="0" >
[(15 17) 0 0 32 32 ]
[(15 17) 32 0 32 32 ]

"run" frames="3" timestep="100" pivots="0" >
[(15 17) 64 0 32 32 ]
[(15 17) 96 0 32 32 ]
[(15 17) 128 0 32 32 ]

"duck" frames="2" timestep="400" pivots="0" >
[(15 17) 192 0 32 32 ]
[(15 17) 224 0 32 32 ]

"slide" frames="1" timestep="0" pivots="0" >
[(15 17) 160 0 32 32 ]

"sword" frames="3" timestep="200" pivots="0" >
[(15 17) 0 32 32 32 ]
[(15 17) 32 32 64 32 ]
[(15 17) 96 32 64 32 ]

"throw" frames="2" timestep="200" pivots="0" >
[(15 17) 0 32 32 32 ]
[(15 17) 160 32 32 32 ]

"jump_up" frames="4" timestep="60" pivots="0" >
[(15 17) 0 64 32 32 ]
[(15 17) 32 64 32 32 ]
[(15 17) 64 64 32 32 ]
[(15 17) 96 64 32 32 ]

"jump_down" frames="2" timestep="200" pivots="0" >
[(15 17) 128 64 32 32 ]
[(15 17) 160 64 32 32 ]

"wall" frames="1" timestep="0" pivots="0" >
[(15 17) 224 64 32 32 ]









What's missing from the above are Action nodes that define how sequences link together in a complicated sprite. The Saga City robot had to link it's arms and torso to the legs sequence each time the action changed (idle to running, for instance).

The ninja described in the file above is the entity I'm using to experiment with gameplay feel. More on that soon.

Demo

Ok, I finally uploaded the demo! I also have a new name that's much more fitting for me than this 'robot' business. Thank you Drew!

Demo (win32)

If you want to fly, just hop on one of the green guys and start shooting them. Stickybombs ('n' key) are the best for keeping them away from you. There's an elusive bug involving the stickybomb, so be warned. I've been experimenting with a slow-mode, just hold down the spacebar! You can jump really high while in slow-mode, but it works fairly well despite some inconsistencies.

I have everything load from the resource files now, not just images and sounds. Just try and steal them now! :) I'm not actually worried about having my mediocre assets stolen, but I'm glad I know how to pack things into a resource file now. I've learned some important lessons about using iostreams and stringstreams instead of the stdio methods. It took a few heap corruptions before I really dug in and fixed my old ways.

I'm aware of the goofy animation that happens when you run and dash at the same time. I haven't touched the player control code in a long time. After I finalize the basic character movement (with the physics), the animations will be tight, and blend together nicely. I'm going to change the look of the character, and everything else for that matter. A concept silohuette is on the main menu. The menu background color will randomize every execution (seeded with a value in stat.xml based on the number of executions).

I haven't fixed a few issues with the tools, and they don't use the resource files, so they might blow up on you. Its best to avoid them for now.

Demo

Ok, I finally uploaded the demo! I also have a new name that's much more fitting for me. Thank you Drew!

Demo (win32)

EDIT:
Demo 2

If you want to fly, just hop on one of the green guys and start shooting them. Stickybombs ('n' key) are the best for keeping them away from you. There's an elusive bug involving the stickybomb, so be warned. I've been experimenting with a slow-mode, just hold down the spacebar! You can jump really high while in slow-mode, but it works fairly well despite some inconsistencies.

I have everything load from the resource files now, not just images and sounds. Just try and steal them now! :) I'm not actually worried about having my mediocre assets stolen, but I'm glad I know how to pack things into a resource file now. I've learned some important lessons about using iostreams and stringstreams instead of the stdio methods. It took a few heap corruptions before I really dug in and fixed my old ways.

I'm aware of the goofy animation that happens when you run and dash at the same time. I haven't touched the player control code in a long time. After I finalize the basic character movement (with the physics), the animations will be tight, and blend together nicely. I'm going to change the look of the character, and everything else for that matter. A concept silohuette is on the main menu. The menu background color will randomize every execution (seeded with a value in stat.xml based on the number of executions).

I haven't fixed a few issues with the tools, and they don't use the resource files, so they might blow up on you. Its best to avoid them for now.



My self-imposed deadline is this weekend, so I'm almost out of time. I've learned a lot and managed to make a significant amount of progress on my project. My "engine" isn't complete or even ready to make a respectable game, but it should work just fine for the prototypes I'll be working on. I'm going to continue developing the engine as I experiment with gameplay using Box2d. I'm not giving up on Saga City, I just want to experiment with the physics and find something fun. Controlling the character so far has been no fun. I've been reading every list of game design tips and commandments that I can find. I've been reading the old "How to Prototype" article on Gamasutra and I want to start prototyping in quick intervals.

I've implemented my resource loader and I have my Ogg Vorbis music streamer sort of working. I know I said I'd have explosion shots, but I've done a bunch of other things instead. I'm going to stop declaring what I'll have done because I never do what I'm supposed to anyway. I'm still trying to figure out how to render the explosions.. Its more complicated than a single sprite animation for sure.

I can nudge objects in the editor to line them up by using the arrow keys, like in photoshop. I still need to make objects snap to the same resolution when dragged, like 1/100th of a unit or something. Actually, matching the snap resolution to the pixel density of the layer seems like an ideal solution.

The button "Create from Data" in the Sprite editor actually works now. It takes the text data file that my sprite renderer generates and creates the XML entity file. By default, it creates an 'action' from each sequence in the sprite data file. Hand-editing is still necessary for anything more complex than a single sequence.

Hitting 'r' and 't' cycle through the actions of the selected entity. I can now put a bunch of background images in a sprite sheet and cycle though the images (as actions) in a single entity while in the editor. I already have Ctrl-drag clone entities, so creating tiled backgrounds with variations is quick.

I now have my own custom resource files. I used this and this article to learn how. I altered the pak file creation code to use the stdio library instead of the (I'm assuming C) _open, _seek functions that use file descriptors. The C code to load the resources from the file caused heap corruptions, but the standard library worked like a charm.

There's an article at DevMaster on how to stream Ogg files using OpenAL. I followed the article and the follow-up corrections in the forum, but there's still some skipping and looping issues to deal with. I can use Ogg and Wavs now, and retrieve them from the resource files. Loading Ogg files from memory is explained in this article, also at DevMaster.

- figured out why v-sync made my sprite animations choppy: I still had the accumulator cutting updates into discrete timesteps. Doh! Mouse movement is still choppy with v-sync on. I don't know why yet.

There's now a turret enemy that tracks the player's movement within a radius and shoots constantly. The turret is two parts: the base and the cannon. The base is a static body, and the cannon is dynamic and connected with a revolute joint. I use the revolute joint's motor to close the gap between the joint's current angle and the target angle. Doing this meant taking the vector from the turret's position to the player, and converting it to an angle for use with Box2d. My weapon system takes a vector for aiming, but I can't use the target vector, I have to take the joint's current angle and convert it back to a vector to get the correct firing vector.

Here's the turret's update code:

void turret::onUpdate( ulong dT )
{
for( int i=0; i < goodGuys->size(); ++i )
{
aimVec = vec2((*goodGuys)->getPosition()) - current_state.pos;
if( aimVec.magnitude() < 30.0f )
{
// the vector in the dot operation must align w/ the "zero" position of the sprite
aimVec.normalize();
targetAngle = acosf( aimVec.dot( vec2(1,0) ) );
targetAngle = ( aimVec.y <= 0 )? targetAngle : -targetAngle;

pivotAngle = gunJoint->GetJointAngle();
float dif = targetAngle - pivotAngle;
/*if( dif < -PI ) // I'm not sure if this is necessary, or if box2d automatically adjust the joint angle
dif += 2.0f*PI;
else
if( dif > PI )
dif -= 2.0f*PI;*/


gunJoint->SetMotorSpeed( dif * 5.0f ); // speed up the turret a bit

if( shotTime <= 0 )
{
shotTime = 800;
// convert the joint's actual angle into a vector for the weapon system
vec2 bodyVec( sinf(pivotAngle + (PI/2.0f)), cosf(pivotAngle + (PI/2.0f)) );
vec2 origin = GetPivotPosition( "gunPivot" ) + bodyVec * 1.75f;
weaponSystem->Fire( world, WEAPON_BLASTER, origin, bodyVec * 2.0f, 0, CP_HOSTILE );
}
else
shotTime -= dT;

break;
}
}

Sprite::onUpdate( dT );
}



The way the turret receives the array of possible targets is through a static vector given from the level class. It's ugly, and temporary, but it will have to do until I can figure out a better way.


I just need to make TinyXml work with loading resources from memory so my level, entity, and gui data files can be parsed. Once that's done, I'll post a demo. Its still not a game, but its becoming more playable. Now that I have a framework to use, I want to start making rapid prototypes with Box2d (time-permitting). I also have plans to use Doxygen and write a proper explanation for each part of the engine. Doing this would probably be more beneficial for me than anyone, helping me understand where I can improve things, and documenting my progress.

Oh, I turn 23 tomorrow! Its been a full year since I began this project... I haven't made the progress I would have liked, so I need to hit the gas and start producing playable demos. Its going to be tough to more productive while its glorious and sunny outside!

GameJolt has a contest going on with the theme, "shocking". Entries are due Friday before midnight. I'm going to try to whip up something to put my tools/skills to the test. It will force me to stop procrastinating with some things that I must do, such as using custom resource files. I'm going to create assets that I can use in Saga City, too. So it will be a robot-themed mini-game. I would like to use shaders for this, but there's no time.

I've made a few minor improvements:

I fixed the 'fly by hitting jump button rapidly' bug.
I removed the camera jerk that happens when you change the direction you're facing. In the same block of code I find the angle from the player's arm pivot (shoulder) to the reticle, and the camera's offset from the player's position (for looking around). The problem was that I used the arm pivot instead of the player's origin for the camera's offset origin. So the camera 'snaps' when you turn around because there's no smooth transition of the arm's position. If I add a turn-around animation, I could use the arm's position again. When the camera is based on the arm, the shoulder's animation position is translated to the camera, which gives it a kind of 'bounce' when running. I'm not sure if its a neat little detail, or just annoying.


Sound:

I've started the sound system, and I'm using OpenAL. I don't have time to design something better, so all sound capabilities are in a namespace. I have yet to have it check a list of loaded buffers so that nothing is loaded twice. OpenAL is designed to be like OpenGL, so I store the unsigned integer handles it generates in my object classes. It gives me a handle for each source and each buffer. When I want to play a sound, I take both the source ID and buffer ID that the object has, and make a call like: audio::Play( sourceID, bufferID ). Very simple. I'll need to update the source positions and the Listener position on each update. Each object with a source will update the position automatically in the top-level Object class (which is really only responsible for updating it's position anyway). Sound is equally as important as visual rendering so I don;t feel weird puting sound code in my basic Object class. The more sounds, the better! My namespace is really just a wrapper around OpenAL so far.
Here is the source: Audio.h Audio.cpp
If you decide to use them, download the OpenAL libraries here and be sure to get the documentation. The docs are absolutely great at explaining the elements of the library. Once you understand the elements: devices, contexts, listeners, sources, and buffers, you should see the code is straightforward.

I'm working on support for Ogg/Vorbis files using this article as a start. Its old but still seems halfway accurate. The Ogg format will be important to use for music files because they can get pretty big.

Let me say that it is a PAIN to find decent sounds to use.


Explosions:

I've implemented a simple-but-effective way to do explosions. My first was to create a circle shape, and upon any collisions with the shape, apply an outward force to the colliders. That didn't work for anyshapes already inside the circle when it's created. My next try was the most common. I would query the Box2d world for any shapes with a bounding box around the explosion point. I'd loop through those shapes and apply an outward force on each body. This works ok, but because you don't know where on the colliding body to apply the force, you must use the body's center of gravity. It works, but no offending bodies will have any spin as they fly away, which looks a little too unrealistic.

I searched on the Box2d forums to see what others where doing. One user is implementing an algorithm that uses a series of raycasts pointed outward in a radial pattern. For each cast that hits another body, you have the body and collision point to apply the force. It also gives you occlusion so explosions don't go through walls, and the basis for using particles during render. This seems impressive and perfect for my use, but he won't give away the source. So I was left to implement this technique myself or keep looking...

One of the replies to that user's technique suggested an easy and simple explosion method: simply create a bunch of circle shapes and send them outwards in every direction and destroying them after the explosion interval. It gives me the best approximation of an explosion, and lets the physics code "push" any offending objects away. Of course, it increases the time needed to compute the reactions, so a careful balance must be found in the settings to avoid a drop in frame rate when more than a couple explosions go off. Also, there is a limited number of 'contacts' allowed in Box2d, so I'll need to find a way to strictly enforce this limit.

Explosion shots and demo should be in the next post.

Weapons Demo

Ok, hopefully this one works for everyone. I've completely done away with my awful filesystem and replaced it with something very simple. I've tested the app on an old laptop without MSVC++ installed, and it worked fine.

Weapons Demo (.zip) Win32

I'd be interested to know if/how it runs on your system.

IMPORTANT: The first line in "config.cfg" needs to be the path of the folder. If it doesn't work, please let me know. Also, a value of '1' for VSYNC doesn't really work yet.

Controls:
E,S,D,F = movement (this is so your pinky can use 'A')
A = dash (too powerful, and not working correctly)
1-5 = cycle camera size
Z,X,C,V,B,N = the different weapons
LMB = fire weapon
mouse wheel up/down, and button = changes the camera between 2-4 (for ease)
Esc = quits
F5 = take screenshot

Weapons




Windows Demo (.zip) (untested for Vista/7, should work fine on XP) 8.5MB
I'd be interested to know if/how it runs on your system. Any comments welcome.

IMPORTANT: The first line in "config.cfg" needs to be the path of the folder. If it doesn't work, please let me know. Also, a value of '1' for VSYNC doesn't really work yet.

Controls:
E,S,D,F = movement (this is so your pinky can use 'A')
A = dash (too powerful, and not working correctly)
1-5 = cycle camera size
Z,X,C,V,B,N = the different weapons
LMB = fire weapon
mouse wheel up/down, and button = changes the camera between 2-4 (for ease)
Esc = quits
F5 = take screenshot


I've figured out why I'm so slow to implement some things. I tend to write my abstract classes first, and gradually define the more specific classes to fit my class hierarchy. This takes forever because I get really picky if something doesn't fit perfectly with what's established, and I waste a lot of time trying to make everything perfect. My new method (common sense) is to write the classes that actually DO SOMETHING first, so I have new features implemented even if the code design isn't pretty. Then I can consolidate the common functionality afterward.

My goals for this month are to get a weapon/projectiles system going, get sound working, add some content, and if time allows, experiment with gameplay. Gameplay is my highest priority as a designer, but I need to focus on other important things for now.

I've started the weapons system. The system will manage all projectiles within the level, fired from any source. At first I thought it would make sense for each armed character to "own" it's own projectile system, but then enforcing a memory limit would be difficult. So instead the level "owns" the projectile manager and gives the pointer to a static member of the character base class.


// .h

typedef enum
{
WEAPON_NULL,
WEAPON_BLASTER

} weaponType;

class WeaponSystem
{
public:
WeaponSystem();
~WeaponSystem();

void Fire( b2World* world, weaponType type, const vec2& origin, const vec2& trajectory, int weaponMode );

void Update(ulong dT);
void Render();

private:
static const int blasterNum = 100;
std::vector< BlasterRound* > blasterRounds;
std::vector< BlasterRound* >::iterator blasterRoundsIt;

BlasterRound* blasterMother;
};

// .cpp
WeaponSystem::WeaponSystem()
{
blasterMother = new BlasterRound;
blasterMother->LoadXml( "blaster.xml" );
blasterRounds.reserve( blasterNum );
for( int i=0; i < blasterNum; i++ )
{
blasterRounds.push_back( new BlasterRound( *blasterMother ) );
}
blasterRoundsIt = blasterRounds.begin();

//delete blasterMother;
//blasterMother = NULL;
}


WeaponSystem::~WeaponSystem()
{
for( int i=0; i < blasterNum; i++ )
delete blasterRounds;

blasterRounds.clear();

////////////////////////////////////////////////////////////////////////////
// no heap corruption when this is released after the blasterRounds!
delete blasterMother;
////////////////////////////////////////////////////////////////////////////
}


void WeaponSystem::Fire( b2World* world, weaponType type, const vec2& origin, const vec2& trajectory, int weaponMode )
{
switch( type )
{
case WEAPON_BLASTER:
for( int i = 0; i < blasterNum; i++, blasterRoundsIt++ )
{
if( blasterRoundsIt == blasterRounds.end() )
blasterRoundsIt = blasterRounds.begin();
if( (*blasterRoundsIt)->IsActive() == false )
{
(*blasterRoundsIt)->Fire( world, origin, trajectory, weaponMode );
break;
}
}
break;
default:
break;
}
}


void WeaponSystem::Update(ulong dT)
{
for( int i=0; i < blasterNum; i++ )
blasterRounds->Update( dT );
}


void WeaponSystem::Render()
{
for( int i=0; i < blasterNum; i++ )
blasterRounds->Render();
}








So here's the weapon system class. It just creates a round, called blasterMother, and copies the instance so the XML file is only loaded once. The number of active rounds is limited to 100 at the moment. I was thinking of borrowing an idea from Halo and making some weapons overheat if you shoot them for too long. That would give a reason for why you can't shoot an unlimited number of rounds (other than ammo), and force the player to break for cover once in awhile.

If I delete the blasterMother pointer in the constructor, it causes a heap corruption. If I delete it in the weaponSystem destructor its fine, but I don't want to have unused instances laying around because I can't figure it out. I think my Entity/Sprite/BlasterRound copy contructors are good. Nothing else causes the heap corruption...



// .h
#include "Sprite.h"

// temporary!
enum
{
MODE_NORMAL = 0,
MODE_BOUNCY,
MODE_FLAME,
MODE_HEAVY,
MODE_HIGHCALIBER,
MODE_STICKY
};


class BlasterRound : public Sprite
{
public:
BlasterRound();
BlasterRound( const BlasterRound& );
virtual ~BlasterRound();

bool IsActive(){ return active; }
void Fire( b2World* world, const vec2& origin, const vec2& trajectory, int weaponMode );

virtual void onLoad();
virtual void onUpdate( ulong dT );
virtual void onRender( float blend );
virtual void onCollision(const contactPoint& point);

protected:
int damage;

bool active;
bool render;
bool exploded;

int hitCount;
int timeLeft;
int explodeTime;

b2Vec2 initialPos;
b2Vec2 collidePosition;

// temporary!!!
int mode;

bool stickyFlag;
b2Joint* stickyJoint;
b2Body* stickToBody;

//b2CircleDef expDef;
//b2Shape* expShape;
};

// .cpp
BlasterRound::BlasterRound():
damage( 1 ),
active( false ),
render( false ),
exploded( false ),
hitCount( 0 ),
timeLeft( 1000 ),
explodeTime( 0 )

//expShape( NULL )
{

mode = MODE_NORMAL;
stickyFlag = false;
stickyJoint = NULL;
stickToBody = NULL;
}

BlasterRound::BlasterRound( const BlasterRound& rhs ):
Sprite( rhs ),
damage( rhs.damage ),
active( rhs.active ),
render( rhs.render ),
exploded( rhs.exploded ),
hitCount( rhs.hitCount ),
timeLeft( rhs.timeLeft ),
explodeTime( rhs.explodeTime )

//expShape( NULL )
{
mode = MODE_NORMAL;
stickyFlag = false;
stickyJoint = NULL;
stickToBody = NULL;
exploded = false;
}

BlasterRound::~BlasterRound()
{

}

void BlasterRound::Fire( b2World* world, const vec2& origin, const vec2& trajectory, int weaponMode )
{
active = true;
hitCount = 0;
explodeTime = 200;
exploded = false;
render = true;

//////////////
//bodies[0]->pointer->SetBullet(true); // this didn't work
bodies[0]->isBullet = true;
//bodies[0]->shapes[0]->SetCollisionProfile( CB_FRIENDLY );
//bodies[0]->shapes[0]->SetCollisionGroup( 2 );
////////////

vec2 variance;
variance.x = (random_f()-0.5f) * 0.04f; // accuracy (between .5 and .01)
variance.y = (random_f()-0.5f) * 0.04f;
float multiplier = 20.0f;
mode = weaponMode;
switch( mode )
{
case MODE_FLAME:
SetCurrentSequence("explode");
multiplier = 20.0f;
timeLeft = 300;
break;

case MODE_HIGHCALIBER:
SetCurrentSequence("idle");
multiplier = 80.0f;
timeLeft = 500;
variance.x = (random_f()-0.5f) * 0.01f; // accuracy (between .5 and .01)
variance.y = (random_f()-0.5f) * 0.01f;
break;

case MODE_HEAVY:
SetCurrentSequence("idle");
multiplier = 20.0f;
timeLeft = 5000;
break;

case MODE_BOUNCY:
SetCurrentSequence("idle");
multiplier = 30.0f;
timeLeft = 300;
break;

default:
SetCurrentSequence("idle");
multiplier = 40.0f;
timeLeft = 1000;
break;
}

setPosition( origin );
Create( world );
initialPos = b2Vec2( origin.x, origin.y );
variance += trajectory;
b2Vec2 velocity( variance.x, variance.y );
velocity *= multiplier;
bodies[0]->pointer->SetLinearVelocity( velocity );

}


void BlasterRound::onLoad()
{
timeLeft = 0;
explodeTime = 0;
}

void BlasterRound::onUpdate( ulong dT )
{
if( !active )
return;

if( exploded )
{
if( explodeTime <= 0 )
{
/*switch( mode ) // trying to release the joint apparently deletes twice. Need to find out why.
{
case MODE_STICKY:
if( stickyJoint )
{
world->DestroyJoint( stickyJoint );
stickyJoint = NULL;
}
break;
default: break;
}*/


active = false;
render = false;
exploded = false;
DestroyCollisionModel();
}else
explodeTime -= dT;
}
else
{
// the round needs to start the explode/death sequence
if( timeLeft <= 0 )
{
exploded = true;
SetCurrentSequence("explode");

switch( mode )
{
case MODE_BOUNCY:
DestroyCollisionModel();
break;

case MODE_STICKY:

break;
default:
setPosition( vec2(collidePosition.x, collidePosition.y) );
break;
}
}
else // the round is still active, update timer
{
timeLeft -= dT;

switch( mode )
{
case MODE_FLAME:
bodies[0]->pointer->ApplyForce( b2Vec2(0,(float)dT * 0.05f), bodies[0]->pointer->GetWorldPoint(b2Vec2(0,0)) );
break;

case MODE_STICKY:
{
// stuck to something
if( stickyFlag )
{
setPosition( vec2(collidePosition.x, collidePosition.y) );
bodies[0]->pointer->SetLinearVelocity( b2Vec2(0.0f,0.0f) );

if( bodies[0]->pointer && stickToBody )
{
b2DistanceJointDef stickyDef;
stickyDef.Initialize( bodies[0]->pointer, stickToBody,
bodies[0]->pointer->GetWorldPoint( b2Vec2(0,0) ),
collidePosition);
//stickyDef.body1 = bodies[0]->pointer;
//stickyDef.body2 = stickToBody;
//stickyDef.localAnchor1 = bodies[0]->pointer->GetLocalPoint( b2Vec2(0,0) );
//stickyDef.localAnchor2 = stickToBody->GetLocalPoint( collidePosition );
//b2Vec2 d = stickyDef.localAnchor1
//stickyDef.length = 0.0f;
stickyJoint = world->CreateJoint( &stickyDef );
}
stickyFlag = false;
}
}
break;
//case MODE_HIGHCALIBER:
//break;
default:
break;
}
}
}
if( render )
Sprite::onUpdate( dT );
}


void BlasterRound::onRender( float blend )
{
if( !render )
return;

SetColor( WHITE );
if( exploded && explodeTime > 0 )
{
if( mode == MODE_HEAVY )
{
glPushMatrix();
glScalef( 6.0f, 6.0f, 1.0f );
Sprite::onRender( blend );
glPopMatrix();
}
else
Sprite::onRender( blend );
}else
{
if( bodies[0]->pointer )
{

vec2 velocity( bodies[0]->pointer->GetLinearVelocity().x, bodies[0]->pointer->GetLinearVelocity().y);
b2Vec2 shotDistance = bodies[0]->pointer->GetPosition() - initialPos;
float mag = min( velocity.magnitude() / 10.0f, shotDistance.Length() );
velocity.normalize();
float aim_angle = acosf( velocity.dot(vec2(0,1)) );
aim_angle = ( velocity.x <= 0 )? aim_angle : -aim_angle;

float roundScale = 1.0f;
if( mode == MODE_HEAVY )
roundScale = 3.0f;

glPushMatrix();
glRotatef( RAD_DEG( -render_state.angle + aim_angle ), 0, 0, 1 );
glScalef( roundScale, ( roundScale + mag ), 1.0f );
Sprite::onRender( blend );
glPopMatrix();
}
}
}

void BlasterRound::onCollision(const contactPoint& point)
{
if( point.obShape->IsSensor() )
return;

/*std::string shapeName = (char*)point.obShape->GetUserData();
if( shapeName == "blasterShape" )
return;*/


if( ++hitCount == 1 )
{
//m_body->SetBullet(false);
collidePosition = point.position;

switch( mode )
{
case MODE_BOUNCY:
break;

case MODE_STICKY:
if( stickyFlag == false )
{
stickyFlag = true;
stickToBody = point.obBody;
}
break;

default:
FlagForDestruction();
timeLeft = 0;
break;
}
}
}








Here's the BlasterRound class in it's entirety. I wanted to post it before I break it into separate classes. I added a temporary parameter to the Fire method, "weaponMode". This is to quickly test different projectile behaviors without writing more classes.

The Fire() method creates the collision model and gives it an initial velocity. The timeLeft var puts a timer on the round in case it doesn't hit anything. The current animation sequence is chosen here, too. There are only two sequences for my tests, "idle" and "explode". I realize now that the finished weapon classes won't load from an XML file, they'll just create their collision definitions when constructed.

onUpdate() checks whether the round has exploded and needs to destroy it's collision model. If it doesn't, it updates the timer variable 'timeLeft'. So far, only the flame-thrower (and stickybomb) mode needs to affect the body during update. I'm experimenting with the stickybomb and its not working correctly just yet. It stretches upward after its attached, its weird.

All the weapon "modes" have the same firing interval at the moment, I'll fix that soon. I left it at 30ms so the flame-thrower mode looks okay. All the weapons shoot fast, which sometimes isn't appropriate.

If you playtest in the level editor, it will probably crash when you exit. There's an unsolved bug involving the weapon system. Also, be aware that 'c' toggles collision rendering AND the flame-thrower, 'b' toggles the background/sniper gun. That just means you have to press it twice, I'm not going to change the bindings. I'll probably have the mouse wheel cycle the weapons soon.

Well, there's a lot to improve, but its a start. Next step is audio!

Untitled

Sadly, I haven't done much for the project in the last few weeks. My only excuse at the moment is that I've just built my new computer, and I'm in the process of moving everything over. Reinstalling everything will take a day or two. Quick specs:

CPU: AMD Phenom X4 940 3.0Ghz
Mobo: Gigabit GAMA790-FX
GPU: ATI Radeon 4870 1GB
RAM: 2x Mushkin 2x2GB Redline (5-5-5-12) 8GB total
Case: Antec Sonata Designer 500 (very quiet!)
PSU: Earthwatts 500w (supposed to be very efficient)

With a better cooling system, I should be able to overclock above 5Ghz but I've never tried overclocking and I know it voids the warranties, so I'm going to wait a while and do some research before I try.

I haven't bought a new OS yet. I'm bound to windows for now because of my software. I'm deciding between getting Vista Home premium 64-bit or using the Windows 7 RC 64-bit until it hits RTM.

I was sick of having to exit my app to switch to fullscreen, and finally implemented a fullscreen toggle method. I thought someone getting started with SDL and OpenGL could benefit from knowing how I do it, so here's a mini-article:

There isn't an easy way to do a fullscreen-switch with SDL and OpenGL. Without GL, a fullscreen switch is as easy as making another call to SDL_SetVideoMode() with SDL_FULLSCREEN as a flag. When you call SDL_SetVideoMode() with a SDL_OPENGL flag, SDL creates the OpenGL context for you. Any successive calls to set the video mode cause the OpenGL context to be lost. This means all the texture data, shaders, display list, vertex buffers, GL states, and anything controlled by GL are invalidated or deleted (see link at the bottom). I don't know if the all the memory associated with the GL state is freed when this happens, but I'll assume not until I know for sure.

So when your app needs to toggle the window mode, all the textures and shaders and etc.. need to be freed, then the video mode set, and then everything must be reloaded. This is obviously a pain, especially if your program's GL-using classes are not easily accessed from a single place in the code.

I have a framework class that handles setting the video mode, gathering user input, keeping time, and updating the app. My game class subclasses the framework and overrides the virtual methods for updating, event handling, initialization and cleanup, etc... Here's a stripped-down header for the framework:


class SDL_Framework
{
public:
void Execute();

protected:
virtual int PreExecute(){ return 0; };
virtual int PostExecute(){ return 0; };
virtual int Update( ulong dT ){ return 0; };
virtual void mouseEvent( const MouseEvent& evt ){};
virtual void keyEvent( const KeyEvent& evt ){};

virtual void PreVideoMode(){}
virtual void PostVideoMode(){}

bool SetVideoMode();
bool toggleWindowMode();

private:
SDL_Surface *v_screen;
const SDL_VideoInfo *v_info;
// etc...
};



For the window mode switch, I provide two virtual methods that allow the app to free the resources before the video mode change, and reload them afterward. They're called PreVideoMode() and PostVideoMode(), and they're called just before, and right after the call to SDL_SetVideoMode(). I use a namespace for common render calls, so the fullscreen flag is retrieved with render::getFullscreen(). At the end is a way to center the window on the screen in Windows.


bool SDL_Framework::SetVideoMode()
{
// The app can release all textures, shaders, display lists, and vertex buffers with this call.
PreVideoMode();

//SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
//SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
//SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
//SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
//SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 1 );
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, vertical_sync ); // Enable vertical-sync
SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ); // Enable hardware acceleration

if( anti_aliasing )
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // AA
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); // AA
}

int width = 0;
int height = 0;

if( render::isFullscreen() )
{
v_flags = SDL_OPENGL | SDL_FULLSCREEN;
width = full_width;
height = full_height;
render::setAspectRatio( xy_aspectRatio );
}
else
{
v_flags = SDL_OPENGL;
width = win_width;
height = win_height;
render::setAspectRatio( (float)width / (float)height );
}
render::setWidth( width );
render::setHeight( height );

if( SDL_VideoModeOK( width, height, v_bpp, v_flags ) != 0 )
{
if( v_screen )
SDL_FreeSurface( v_screen );

v_screen = SDL_SetVideoMode( width, height, v_bpp, v_flags );

if( v_screen->flags & SDL_FULLSCREEN )
log_write("+ Going fullscreen...");
else
log_write("+ Going to window mode...");

if( v_screen == NULL )
{
log_write("!!! VIDEO FAILED: (%dx%dx%d): %s" , width, height, v_bpp, SDL_GetError() );
return false;
}
else
log_write("+ Video: (%dx%dx%d)", width, height, v_bpp );
}
else
{
log_write("!!! Video mode not available: (%d)x(%d)x(%d)", width, height, v_bpp );
return false;
}

// Initialize GL: viewport, state, read shaders
render::InitRenderer();

SDL_SysWMinfo info;
SDL_VERSION( &info.version ); // this version number is needed to get the window info.
if( !SDL_GetWMInfo( &info ) )
{
log_write("!!! Window info cannot be obtained!");
return false;
}

/// Center the window
#ifdef __WIN32__

if( !render::isFullscreen() )
{
int windowX = ( v_desktopW / 2 ) - ( (int)render::getWidth() / 2 );
int windowY = ( v_desktopH / 2 ) - ( (int)render::getHeight() / 2 );
SetWindowPos(info.window, HWND_TOP, windowX, windowY, render::getWidth(), render::getHeight(), SWP_NOSIZE);
}
#endif

// The app will reload everything needed when this is called.
PostVideoMode();

return true;
}



Now, all I need to have a single-function call that does a fullscreen toggle is wrap this function in a toggleWindowMode() function. This toggles the fullscreen flag and calls SetVideoMode().


bool SDL_Framework::toggleWindowMode()
{
if( render::isFullscreen() )
render::setFullscreen( false );
else
render::setFullscreen( true );

// SDL_WM_ToggleFullScreen( v_screen ); // only works with the x11 video driver
if( SetVideoMode() )
log_write("+ Window mode toggle successful");
else
{
log_write("!!! Window mode toggle FAILED.");
return false;
}
return true;
}



I think its more useful to see the context in which toggleWindowMode is called, so here's a (stripped) version of my Execute function for reference. It has some tips for working with SDL and OpenGL, too.


void SDL_Framework::Execute()
{
// config and intialize everything here

// Get information about the current video settings.
// Call SDL_GetVideoInfo() before SDL_SetVideoMode() for the desktop resolution.
v_info = SDL_GetVideoInfo();
int v_desktopW = v_info->current_w;
int v_desktopH = v_info->current_h;
// Divide the width by the height for the x-to-y screen ratio of the desktop.
// Use this ratio in glOrtho(), or gluPerspective() when in fullscreen mode.
// Windowed mode should use the ratio of the video resolution for 1:1
float xy_ratio = (float)v_desktopW / (float)v_desktopH;

// Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) > 0 )
log_write( "!!! SDL_Init failed" );

// You must set the video mode in SDL before you can access GL functions!
if( !SetVideoMode() )
{
PostExecute(); // Quit
return;
}

// load the menu, cursors, whatever
PreExecute();

// main loop
while( executing )
{
// time task here

// update
Update(dT);
// swap buffers
SDL_GL_SwapBuffers();

// This is so the CPU gets a break when v-sync is disabled, otherwise, cpu usage is around 100%!!!
// This should only be enabled in windowed mode, or for saving the battery on laptops
SDL_Delay( 1 );

// input task
SDL_PumpEvents();
SDL_Event event;
while( SDL_PollEvent(&event) )
{
switch( event.type )
{
case SDL_KEYDOWN: //SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_KEYUP, SDL_QUIT
{
if( event.key.keysym.sym == SDLK_F2 )
{
// this calls SetVideoMode
toggleWindowMode();
}
}
}
}
}

PostExecute(); // Quit
}



I'd recommend only allowing window-mode changes in the options menu, or require a restart of the program. The reason is that relatively fewer resources are needed for the menus as apposed to within a level, and the switch will be much faster.

I hope this is useful to someone out there!

Link: "OpenGL and SDL" This page is the best resource I've found for uncovering the caveats involved with using SDL and OpenGL.

Level Editor

I figured out what was wrong with my system, and I can hardly believe the truth. I had given up, formatted, and reinstalled windows. I was installing the latest graphics drivers when I decided to turn off my firewall (and unplug the cat-5) because it kept giving me Allow/Block options and slowing the install process. To see if the new drivers solved my freezing issue, I launch VC++ and run my app- it works! It seemed the drivers fixed the problem, but left me wondering if my hardware was bad because these were the same drivers I had tried before. So I re-enable my firewall, check email, and when I run my app the next time, it freezes again!! I found my problem: the firewall. More specifically, I'm using the PC Tools Firewall and it has a "Enable Enhanced Security Verification" setting that was causing all my problems! (and its enabled by default) I never thought a firewall could cause my system to freeze like that. I feel kinda dumb for not finding it sooner, but I won't be bitten by experimental firewall settings ever again! Onward!



The level editor is coming along nicely. It has the drag-and-drop feature I mentioned before for placing objects. I load and save levels with an EditText box, and my crappy resource manager finds the file for me. I haven't written a filebrowser like I planned because there's no time. I'm sure theres a cross-platform filebrowser I can use somewhere, but it'll have to wait. I forgot to mention this last post, but I've abandoned the idea of merging the level and sprite editors this time around because of the work involved, considering its unneccesary anyway.

Now I don't want anyone to think I copying Aardvajk, but my editor has a 'Simulation' mode that updates the Box2d world so that objects can come to a rest before you export the level. I've had this option for a while, so its kinda funny we came up with the same solution right around the same time. It seems to be a neccessity when using Box2d to "bake" your objects into their resting positions.

Theres a 'Launch' button that starts the playtest mode. This will start the player at a spawn point when I implement them, but for now you start at the origin. Also, objects don't move back to their initial positions after playtesting, but I think this will be easy to correct by storing the objects' state when positioned/rotated.

I've implemented rotational snapping for objects, expressed as a division of PI. This is neccesary for consistency with how my entities orient themselves. Without snapping, its difficult to return objects to their previous rotation because the rotation value accumulates a little extra each time. This way, all rotations will be in consistent division of PI, and not rigidly bound to the mouse-drag vector. It doesn't drag as smoothly as I'd like, but it works damnit, it works. The snap interval is hard-coded as ( PI / 16.0f ) for the moment, which is around 12 degrees:

if( dragging )
{
vec2 drag = worldPos - lastDragPos;
lastDragPos = worldPos;

if( selectedEntity )
{
if( evt.button == M_LEFT )
selectedEntity->setPosition( worldPos + dragOffset );
else
if( evt.button == M_RIGHT )
{
float interval = ( PI / 16.0f );
float angle = selectedEntity->getRotation();
if( drag.x != 0 )
{
if( abs(drag.x) < interval )
angle += (drag.x > 0)? interval : -interval;
float snapped = interval * float((int)( angle / interval ));
if( abs( snapped - angle ) < interval * 0.4f )
angle = snapped;

}
selectedEntity->setRotation( angle );
}
}
}




The background image is easily changed with the given text box. Sprites will be supported soon.

There are five hardcoded layers in the levels/editor at the moment. I can select the active layer in the editor with the given spinner, and isolate it with the checkbox (square next to it). It would be nice to be able to add/remove and edit layers and their properties directly in the editor, but I'm not sure it would be worth the time. Because I'm not using a scripting language, unique levels will need to subclass the basic level class anyway, and changing the layer params directly in the class won't be too limiting.

Below the main panel is the sprite panel. I haven't put arrows on the spinners or added any proper UI textures yet.

The "Layer" spinner changes the selected object's layer freely, but any object with a collision model should remain on Layer 0 because it will scroll at a different speed than it's collision shapes, making them invisible. I could put in a restriction for this later. The "Render" spinner changes (what I call) the object's "render layer", which is really just a value that the sort algorithm for the layer uses to determine render order. The player's layer and render layer are always 0. The spinner labeled "pixel density" effectively changes the size of the selected sprite. I'm using this spinner to determine what pixel densities I'll use for each layer, and then I'll make pixel density a property of a layer instead of each sprite.

Below the pixel density spinner you'll see a droplist that holds all the available actions for the selected sprite. This is useful for scenery that needs to have variation. It gives me an easy way to change what the sprite looks like without creating a new sprite for each look. For instance if a tree sprite has many tree variations in a single image file, each variation would be a separate "action", and I can pick which one I like from this droplist.
I have yet to automate the creation of a sprite's action list; I'll set up a button in the sprite editor to do this automatically. In this image, the same hallway sprite can be used for many different hallway variations.



The possible number of variations for a sprite will multiply if I set up the sprite with a bunch of pivots, and attach separate parts of the sprite's image to those pivots. For example, the hallway could have pivots on the ceiling and walls, and any number of doodads in the image file. I can then generate all the possible "actions" based on the number of pivots * doodads and have them ready to use in the editor! I'll try to have a working example of this by next week. There's so much to do!

I'm starting to experiment with the gameplay and controls, and I think its going to take me a few weeks to find something acceptable. This process will be much more productive than when I started because of the GUI and editors I've built. If you look in the images for a spinner labeled "Run:", you'll see the beginning of a GUI panel that will let me change all of the player's parameters (once I have it set up) such as run speed, jump height, wheel speed, mass, etc. (more on that later)

As of this weekend I have 9 weeks remaining until my self-imposed deadline on June 30th. It looks like I'll have a playable prototype, but not much more by that time. I'm definitely going to keep working on it after that, who knows for how long? I'm wondering how complete the demo needs to be before I can submit it to the GD Showcase.



This screen is of the level being played directly without the editor. Those crappy photoshop clouds in the background scroll sideways for unparalleled realism!

Playtest Mode

I've managed to make a weeks' worth of progress in the last month.
I've recovered the same playable functionality that I had months ago, but it now uses a better system.


I've also improved the level editor slightly. I'll post more soon. Oh, I'm using a shader that reduces the contrast of the background layers so it has an atmospheric effect.



Someone said in the forums that they wished people wouldn't bind the aspect ratio to the resolution, or at least leave an option to change the aspect ratio. I didn't realize they could be different, but I found out it's really easy to keep them separate (in the world). The GUI would be difficult to scale, I think, but the game world space is defined with glOrtho so I just have a setting in the config file like this: "4:3". The x-to-y ratio is calculated and passed along to glOrtho and now it can be played on any screen ratio.

After doing some renders of a model based on the concepts my friend did, I realized that the scale and detail of his drawings really don't show when the sprite ends up being 100 pixels tall. I'd post the renders to show what I mean if I had them. Anyway, we're going to find a quicker way to get some finished assets done. I'm thinking of concept silohuettes done at the final resolution (about 100x100 pixels for the main character) so they're designed at the correct scale. We can both make the relatively-tiny models needed. He could then do quick concepts of action poses, and I'd use those action poses to animate the sprite. That's what I have in mind, and we'll see how that works out.

Its become apparent that this project will not be the megaman remake/ fan game I wanted to do initially, mostly because I don't have enough time or a fully-functional engine. So rather than try to make a half-assed tribute game, I'm trying to make the best original demo I can with the time I have. Sure, it'll have robots and whatnot, but I'm not going to try to recreate the super-tight gameplay that the (SNES) MMX series had because its near-impossible to do with a physics engine. Instead, I'm going to explore the idea of climbing- the way Wolverine uses his claws to climb the back of a sentinel. The game could have sloping walls at any angle, and trying to implement wall-jumping/sliding would be difficult. I'll be experimenting with the gameplay and controls and posting more on that soon (I don't mean "soon like in a month").

Non-project rant:
Life is kinda dragging me along right now. I promised myself to avoid making this dev journal into a blog about my life, so I'll just say I'm depressed for no good reason and can't get out of bed, I have no health insurance, just paid a thousand bucks for an ER visit (I thought I had an eye infection, but it was just a migraine), and my computer doesn't want to work.

A week ago, out of nowhere I get a BSOD followed by my system freezing fairly often. It looked like my RAM or my disk was bad (just a guess) because of the way 3d models in a game I was playing had "spikes" in the models. So I test the RAM using memtest86, and nothing. I had no viruses or spyware, I bought Registry Mechanic (by PC Tools) and still nothing. I reinstall and update everything, including drivers for all my hardware. It still froze on me, so I figure its the hard disk or God doesn't want me to have a computer that works. I took it in for repair months ago for the same problem and they told me its probably the hard disk. So I bought a disk and before I even put it in, the symptoms were gone! I've had the disk laying around since and I guess its time to actually use it before I decide to throw money at the repair guys. I've just gotten everything installed and updated, and it seems to work fine. Great! By now I'm ready to start making some progress on Saggy City again, so I fire up VC++, hit debug.... frozen. Everything works great except when I try to debug my own app. I've reinstalled VC++, updated, repaired the registry, run my malware scans, and I'm about to pray. This stuff drives me nuts, but I keep my acoustic close by for when I need to mellow out.
The Entity Editor is now the Sprite Editor and works exclusively with the Sprite class. I'm going to make Entity into a subclass of Sprite ( and call it CollisionObject ) because there will be much fewer entities without a sprite to render (like triggers) than sprites that don't have collision models. The Level Editor will need to create these triggers, so that's a big reason to merge the Level and Sprite editors, which will be a tedious process. The level editor now supports scrolling layers, and changing the "render layer" of any sprite so that I can change the rendering order of sprites on the same scrolling layer.

I'm now at point where I'll start prototyping gameplay. Now that I can create collision models and put levels together, I'll be able to try different physics contraptions, tune the controls, and create game situations much easier than before.
I've set a timeframe of 3 months to have a "finished" demo. Whatever I have in that time will be my demo.

I met with a friend that does concept drawings and we discussed the possibilities of the system I have in place, and what the demo would be like. I'm going to supply him with rough drawings or models, and he'll make awesome concept art which I'll use to create models and animations. We're going to pass the art back and forth and get a collaborative thing going.

Here are a couple of his drawings:
I really want to have something to show for all my effort this year. I always underestimate how long it will take me do anything, so I'm going to say it will take me until June. I mean really, I just want to finish a SINGLE level prototype so I have something to show, but I approached this project with an attitude to learn as much as I can. Because of that, I do many things the hard way but I gain so much from the experience, it's worthwhile.

Since the last post, I've gotten sprite 'actions' working and I'm able to view them in the editor. I can cycle through the actions, play, pause, stop, and scroll through the frames. There's no way to edit them yet because when I started to gather how that would work, I realized the Sprite/Sequence classes are long overdue to be rewritten. I didn't want to do this right away because I wouldn't have all the fun of editing entities if I can't put them into a level. So I began writing the Level Editor and made it's first feature: the Entity Catalog (Library).



The catalog is really just a GUI panel with a scrollbar that lets you browse the available entities for placement in the level. I'll need it in the Entity Editor too, but I'm debating whether or not to make them the same editor. I'll need to write more GUI classes like tabbed panels, or popout panels or something before I can have an interface that isn't too crowded.

Each entity in the catalog is displayed with a thumbnail render. At first it was just going to be an image, but I don't want to render, crop, and maintain a library of thumbnails. So each entity itself is loaded and rendered. This has the added benefit of me being able to copy the entity directly when you place it into the level. All you do is drag and drop from the catalog into the level. This will be in the next video. I only have two entities so far, and the catalog isn't visually appealing enough for a pic.

I'm at the point where I need to revamp the Sprite structure before I can continue. The current structure between Entities, Sprites, Sequences, Pivots, and Actions is fragile and likes to explode once in a while when I add something. Finding the bugs when this happens has gotten too time-consuming.

Here's an idea of my progress:

Framework: (5/5) or at least good enough.
Resource Manager: (1/5) NEEDS REWRITE, needs a rewrite using boost::filesystem during development, and a custom resource format for final distribution).
GUI Editor: (4/5) MOSTLY DONE, made in parallel with the GUI classes, it will be done when they are.
Entity Editor: (3/5) HALF DONE, Needs sprite-editing options, which I can only add after the Sprite class rewrite.
Level Editor: (0/5) JUST STARTED, Has Entity catalog, but lacks everything else. In the interest of finishing my prototype, the editor will probably not have more than basic-features.

Game classes: (0/5) I'll start writing unique classes when experimenting with gameplay (within a month).
Level classes: (2/5) The base Level class is mostly done, but new classes will be needed.
Sprite class, and helpers: (2/5) HALF DONE?, I'm in the process of rewriting.
GUI classes: (4/5) MOSTLY DONE, there are a few more classes to write, but I have to call it quits sometime.

Overall Code progress: (2/5)
I'm hoping to not take more than a few more months on this project. I need to set a deadline to push myself to finish and have something to show.

Entity Editor

The revolute and prismatic joints now have an interface for adjusting their joint limits, and the limits are drawn correctly on the joints. Joints can be selected and repositioned, too. Bodies and shapes can now be copied by Crtl-dragging them. I spent a good amount of time trying to make it possible to cycle through the bodies under the cursor- no matter how many bodies there are- and failed miserably. It may be because I was trying to work while tired/hungry and couldn't think straight. I'll leave the code that works with a couple bodies because that'll be better than nothing until I try rewriting it.

I'm about done with the collision-model creation aspect of the entity editor (for now), and soon I'll move on to the sprite-editing features. I'll need to heavily modify my sprite base class to support what I will call "actions". An action is just the structure of pivots and their attached sequences. so, for instance, a character might have a 'run' action. For this, sprite would set the current sequence to whatever the run base sequence is (lets say the legs). The legs-sequence has the pivot data for the torso for the run sequence. The sprite would automatically attach the torso-run sequence to the correct pivot in the legs-run sequence. So the sprite class manages which sequences are attached to which pivots based on which action is the current action. These actions would be defined in the XML file for the entity, under the sprite node along with any sprite-specific data. The ability to attach sequences to pivots, create actions, and adjust them will be the main features of the sprite-editing interface to come. Another possibility is tying together the behavior (forces on the bodies, and joint motor speeds) of the collision model with the action. I'm not sure if the that will have to be done in the classes directly, though. I won't know until I try it I guess!

Entity Editor update

I've had some good progress on the Entity Editor. I have my first joint working, only a revolute (rotator) so far. Each joint requires that two bodies be selected, but since I don't have the ability to select multiple bodies yet, I just had it keep track if any extra body that's below the selected when clicked. Then, when the joint is created it uses both. Joints are positioned in world position, and they aren't attached to a body yet, so they don't move with the body when its translated in the editor. On top of that, I haven't implemented joint selection with the cursor. The main problem is that Joints have a position, but they don't really have dimensions, so trying to select them is going to be weird. I could have an option to cycle through the joints of a selected body, which seems easier to code and use (no clicky guesswork). So anyway, I have a gui panel that shows most of the properties of the selected body/shape and lets you edit them. The new properties are: if its a static body, if the shape is a sensor (collision detection, but no response), if the body has a fixed rotation (good for characters), and the basic properties such as mass, density, friction, restitution. The missing property is the collision category/group that I plan to implement using what I call 'collision profiles', which are just a pairing of the category and group. Possible profiles would be Neutral(collides with everything), Friendly(player, allies, and their weapons), Triggers, and maybe a few different enemy profiles.

I was excited to get the first revolute joints working and ended up staring at a windmill-type of collision model for about ten minutes just imagining the possibilities (and relaxing for a minute). It gave me an idea for a project I could do right after this one. I haven't even started this game yet, but its fun to dream. It would be a sidescroller too, but it would be completely digitally painted. I'm not a talented painter, but I needed to see if I was able to attach sprites to the collision bodies. So I painted a windmill and created the collision model for it. I had to write a new windmill class, and all the class does is attach ( single frame )sequences to the correct pivot points, and updates the rotation of the 'axle' pivot point on the windmill based on the body's rotation. Normally I would render a sprite and export the sprite data from Max, but since I painted the windmill, I had to create the data manually, which was tedious. I'll need the ability to edit sprite sheets later. So I painted the sheet, wrote the data, and attached the sequences to their pivots in the class. The axle pivot is attached to the building, and four blade pivots are attached to the axle. When I test this, I find that the windmill blades don't inherit their parent pivot's rotation, so they just stay in one place as the axle turns. I find out the only way to really fix this is to include the original sprite render structure I had before that pushes a matrix before rendering the child pivots. This wasn't a problem because it just meant uncommenting some code and setting a flag if the pivot was a 'child pivot', and if not the sprite class organizes the pivots based on their absolute layer. The result of all this is that I can attach multiple sprite sequences to a single collision body. I used four identical windmill blades in the sprite sheet, which goes against the spirit of efficiency, but its only because I don't have a way to store a sequence's initial orientation yet. So that means they're created with the orientation that they have on the sprite sheet.

Here's a vid of the new stuff

Tool video

Ok, here is a video of the GUI editor, and Entity editors. It starts with the GUI editor, and I admit that I didn't do a great job showing the features of it, but then it shows the entity editor, and the ability to create shapes, load sprites, move and rotate shapes and bodies, delete shapes, and use the test mode. Next I'll implement the joints. After that, I'll need to include an interface for selecting a different sprite sequence. Later on, having the sprites change their collision models on the fly for different "forms" is a likely possibility.
Sign in to follow this  
  • Advertisement