Jump to content

  • Log In with Google      Sign In   
  • Create Account

We need your feedback on a survey! Each completed response supports our community and gives you a chance to win a $25 Amazon gift card!


Roots

Member Since 21 Aug 2004
Offline Last Active Today, 09:25 PM

Topics I've Started

Using a global declarations header file: good idea or bad idea?

14 January 2013 - 07:23 PM

A practice that my project has been doing for a long time is to maintain a header file that lists declarations of nearly every single class in their respective namespaces. We did this because back when our code was much more volatile, we'd end up with numerous class declarations at the start of header files, some of which were later renamed or were no longer used/needed. Thus the code became a bit of a mess, and someone reading the code would get mistaken assumptions when reading the list of class declarations. We also had some problems with recursive file inclusion before this solution was put in place.

 

So instead, now nearly every header file in our source tree includes this one, so all class and other necessary declarations are made available. The primary disadvantage to this is that whenever you make any changes to this file, nearly the entire project has to be re-compiled and linked, which can take a long time for a large project like ours (over 100K lines of code). However, our code base is mature enough now that changes to this file are infrequent so it's not a huge issue.

 

What do you think of this practice? Is this something that you do in your own projects, or do you have an alternative? One guy who forked our game and created his own was insistent about removing this file because he didn't like the long compile times when he made changes to it (and AFAIK, that was his only reason). So I wanted to see what others thought.

 

Below is the file in question, for your leisure.

 

///////////////////////////////////////////////////////////////////////////////

//            Copyright © 2004-2013 by The Allacrost Project

//                         All Rights Reserved

//

// This code is licensed under the GNU GPL version 2. It is free software

// and you may modify it and/or redistribute it under the terms of this license.

// See http://www.gnu.org/copyleft/gpl.html for details.

///////////////////////////////////////////////////////////////////////////////


/** ***************************************************************************

*** \file    defs.h

*** \author  Tyler Olsen, roots@allacrost.org

*** \brief   Header file for forward declarations of classes and debug variables.

***

*** This file serves two purposes. The first purpose of this file is to forward

*** declare classes and shared variables in order to avoid problems with

*** recursive inclusion. The second purpose of this file is to declare

*** the functions that contains all of the Lua binding code. This makes the C++

*** C++ code available for use in Lua scripts.

***

*** \note Pretty much every header file in the source tree will need to include

*** this file, with a few exceptions (utils.h is one). The only source file

*** that should need to include this file is defs.cpp

***

*** \note The commenting for all namespaces, variables, and classes declared in

*** this file can be found in the respective header files for where these

*** structures reside in. There are no doxygen comments for the classes and

*** namespaces found here.

***

*** \note You should not need to use the hoa_defs namespace unless you are

*** making the call to bind the engine to Lua.

*** **************************************************************************/


#ifndef __DEFS_HEADER__

#define __DEFS_HEADER__


////////////////////////////////////////////////////////////////////////////////

// Game Engine Declarations

////////////////////////////////////////////////////////////////////////////////


// Audio declarations, see src/engine/audio/

namespace hoa_audio {

    extern bool AUDIO_DEBUG;

    class AudioEngine;


    class AudioDescriptor;

    class MusicDescriptor;

    class SoundDescriptor;


    namespace private_audio {

        class AudioCacheElement;


        class AudioBuffer;

        class AudioSource;

        class AudioStream;


        class AudioInput;

        class WavFile;

        class OggFile;

        class AudioMemory;


        class AudioEffect;

        class FadeInEffect;

        class FadeOutEffect;

    }

}


// Video declarations, see src/engine/video/

namespace hoa_video {

    extern bool VIDEO_DEBUG;

    class VideoEngine;


    class Color;

    class CoordSys;

    class ScreenRect;


    class FixedImageNode;

    class VariableImageNode;


    class ImageDescriptor;

    class StillImage;

    class AnimatedImage;

    class CompositeImage;


    class TextureController;


    class TextSupervisor;

    class FontGlyph;

    class FontProperties;

    class TextImage;


    class Interpolator;


    class ParticleEffect;

    class ParticleEffectDef;

    class ParticleEmitter;

    class EffectParameters;


    namespace private_video {

        class Context;


        class TexSheet;

        class FixedTexSheet;

        class VariableTexSheet;

        class FixedTexNode;

        class VariableTexNode;


        class ImageMemory;


        class BaseTexture;

        class ImageTexture;

        class TextTexture;

        class TextElement;

        class AnimationFrame;

        class ImageElement;


        class ParticleManager;

        class ParticleSystem;

        class ParticleSystemDef;

        class Particle;

        class ParticleVertex;

        class ParticleTexCoord;

        class ParticleKeyframe;


        class ScreenFader;

        class ShakeForce;

    }

}


// Script declarations, see src/engine/script/

namespace hoa_script {

    extern bool SCRIPT_DEBUG;

    class ScriptEngine;


    class ScriptDescriptor;

    class ReadScriptDescriptor;

    class WriteScriptDescriptor;

    class ModifyScriptDescriptor;

}


// Mode manager declarations, see src/engine/

namespace hoa_mode_manager {

    extern bool MODE_MANAGER_DEBUG;

    class ModeEngine;


    class GameMode;

}


// Input declarations, see src/engine/

namespace hoa_input {

    extern bool INPUT_DEBUG;

    class InputEngine;

}


// Settings declarations, see src/engine/

namespace hoa_system {

    extern bool SYSTEM_DEBUG;

    class SystemEngine;

    class Timer;

}


////////////////////////////////////////////////////////////////////////////////

// Common Code Declarations

////////////////////////////////////////////////////////////////////////////////


// Common declarations, see src/common

namespace hoa_common {

    extern bool COMMON_DEBUG;

    class CommonDialogue;

    class CommonDialogueOptions;

    class CommonDialogueWindow;

    class CommonDialogueSupervisor;

}


// Global declarations, see src/common/global/

namespace hoa_global {

    extern bool GLOBAL_DEBUG;

    class GameGlobal;

    class GlobalEventGroup;


    class GlobalObject;

    class GlobalItem;

    class GlobalWeapon;

    class GlobalArmor;

    class GlobalShard;

    class GlobalKeyItem;


    class GlobalStatusEffect;

    class GlobalElementalEffect;

    class GlobalSkill;


    class GlobalAttackPoint;

    class GlobalActor;

    class GlobalCharacter;

    class GlobalEnemy;

    class GlobalParty;

}


// GUI declarations, see src/common/gui

namespace hoa_gui {

    class GUISystem;

    class MenuWindow;

    class TextBox;

    class OptionBox;


    namespace private_gui {

        class GUIElement;

        class GUIControl;

        class MenuSkin;


        class Option;

        class OptionElement;

        class OptionCellBounds;

    }

}


////////////////////////////////////////////////////////////////////////////////

// Game Mode Declarations

////////////////////////////////////////////////////////////////////////////////


// Battle mode declarations, see src/modes/battle/

namespace hoa_battle {

    extern bool BATTLE_DEBUG;

    class BattleMode;


    namespace private_battle {

        class BattleMedia;


        class SequenceSupervisor;


        class BattleActor;

        class BattleCharacter;

        class BattleEnemy;


        class BattleAction;

        class SkillAction;

        class ItemAction;


        class BattleTimer;

        class BattleTarget;

        class BattleItem;


        class BattleSpeaker;

        class BattleDialogue;

        class DialogueSupervisor;


        class BattleStatusEffect;

        class EffectsSupervisor;


        class IndicatorElement;

        class IndicatorText;

        class IndicatorImage;

        class IndicatorSupervisor;


        class ItemCommand;

        class SkillCommand;

        class CharacterCommand;

        class CommandSupervisor;


        class CharacterGrowth;

        class FinishDefeatAssistant;

        class FinishVictoryAssistant;

        class FinishSupervisor;

    }

}


// Boot mode declarations, see src/modes/boot/

namespace hoa_boot {

    extern bool BOOT_DEBUG;

    class BootMode;


    namespace private_boot {

        class BootMenu;

        class CreditsWindow;

        class WelcomeWindow;

    }

}


// Map mode declarations, see src/modes/map/

namespace hoa_map {

    extern bool MAP_DEBUG;

    class MapMode;


    namespace private_map {

        class TileSupervisor;

        class MapTile;


        class MapRectangle;

        class MapFrame;

        class PathNode;


        class ObjectSupervisor;

        class MapObject;

        class PhysicalObject;

        class TreasureObject;


        class VirtualSprite;

        class MapSprite;

        class EnemySprite;


        class DialogueSupervisor;

        class SpriteDialogue;

        class MapDialogueOptions;


        class EventSupervisor;

        class MapEvent;

        class DialogueEvent;

        class ScriptedEvent;

        class ShopEvent;

        class SoundEvent;

        class MapTransitionEvent;

        class JoinPartyEvent;

        class BattleEncounterEvent;

        class SpriteEvent;

        class ScriptedSpriteEvent;

        class ChangeDirectionSpriteEvent;

        class PathMoveSpriteEvent;

        class RandomMoveSpriteEvent;

        class AnimateSpriteEvent;


        class TreasureSupervisor;

        class MapTreasure;


        class ZoneSection;

        class MapZone;

        class ResidentZone;

        class EnemyZone;

        class ContextZone;

    }

}


// Menu mode declarations, see src/modes/menu/

namespace hoa_menu {

    extern bool MENU_DEBUG;

    class MenuMode;

}


// Pause mode declarations, see src/modes/

namespace hoa_pause {

    extern bool PAUSE_DEBUG;

    class PauseMode;

}


// Scene mode declarations, see src/modes/

namespace hoa_scene {

    extern bool SCENE_DEBUG;

    class SceneMode;

}


// Shop mode declarations, see src/modes/shop/

namespace hoa_shop {

    extern bool SHOP_DEBUG;

    class ShopMode;


    namespace private_shop {

        class ShopMedia;

        class ShopInterface;

        class ShopObject;

        class ShopObjectViewer;

        class ObjectListDisplay;


        class RootInterface;

        class CategoryDrawData;


        class BuyInterface;

        class BuyListDisplay;


        class SellInterface;

        class SellListDisplay;


        class TradeInterface;


        class ConfirmInterface;


        class LeaveInterface;

    }

}


// Test mode declarations, see src/modes/

namespace hoa_test {

    extern bool TEST_DEBUG;

    class TestMode;

}


////////////////////////////////////////////////////////////////////////////////

// Miscellaneous Declarations

////////////////////////////////////////////////////////////////////////////////


// Utils declarations, see src/utils.h

namespace hoa_utils {

    extern bool UTILS_DEBUG;

    class ustring;

    class Exception;

    extern float RandomFloat();

}


////////////////////////////////////////////////////////////////////////////////

// Binding Declarations

////////////////////////////////////////////////////////////////////////////////


//! \brief Namespace which contains all binding functions

namespace hoa_defs {


/** \brief Contains the binding code which makes the C++ engine available to Lua

*** This method should <b>only be called once</b>. It must be called after the

*** ScriptEngine is initialized, otherwise the application will crash.

**/

void BindEngineCode();

void BindCommonCode();

void BindModeCode();


} // namespace hoa_defs


#endif // __DEFS_HEADER__



Hero of Allacrost (RPG) - Development Gameplay Video

07 January 2013 - 03:25 AM

This has been a long time project of mine, and I've been posting about it here on GameDev ever since it started way back in 2004. After the project laid dormant for nearly 18 months, we've picked it up again, dusted it off, and have resumed active development. A few hours ago I uploaded a video that demonstrates the current state of the game along with audio commentary discussing various aspects of the game's design. I wanted to share it and get some feedback, as well as maybe find some interested people who would like to help out. Enjoy!

 

 

Also, here are some old screenshots.

 

 

About Hero of Allacrost

 

Hero of Allacrost is a single player 2D role-playing game inspired by classic console RPGs. In Hero of Allacrost, the player will explore rich environments, solve challenging dungeon puzzles, and fight strategic battles in an active-time based system. The game is free open-source software and is available across several platforms including Windows, OS X, Linux, and FreeBSD.

 

Links


What techniques do you use to balance your game?

08 November 2012 - 03:08 PM

I'm working on a couple different sister projects (Hero of Allacrost and Valyria Tear, both Japanese-style RPGs) and the latter has a release coming up soon which still needs a fair amount of balancing. I've done balancing of releases in the past, but I've always done it in a sloppy, ad-hoc manner as we were trying to rush a release out the door. I want to invest some time and effort now to do balancing right (or at least better) for this upcoming release, and I was hoping that others here could share the techniques and tools that they employed to balance their games.

I want to make it clear that I'm not looking for mathematical formulas or anything technical like that. I'm more interested in the balancing of stats and numbers, such as experience awarded by defeating enemies or attack rating. The main balance issue that I'm trying to address is with regard to experience level gains with the playable characters (we want them to feel stronger to the player with each level, but not become overwhelmingly powerful).



With that in mind, here are some ideas that I have thought of thus far.

1) Produce data spreadsheets

This would entail something like putting all of the character data for each experience level into a spreadsheet application along with a sample of enemies, use some simplified equations to calculate average DPT (damage-per-turn) and how much damage we can expect a character party to take, determining how "hard" a battle is based on the amount of hit points likely to be lost before the battle is over.

2) Write a stand-alone script that does number crunching on character/enemy stats

Similar to the first one, but instead of putting it into a spreadsheet (which can be time consuming to do), a script will process all of the data and spit out the same type of results. Probably easier, plus we can pass the script parameters (character and enemy party composition along with XP levels) and get an idea of how "hard" the battle will be.

3) Add an accelerated battle simulatior into the game

Same idea as #2, only this time the battle is actually simulated instead of only performing some simplified numerical calculations. Again we could input any party configurations we want to the simulator, then the AI would take over and run the battle to it's conclusion. This would be difficult to do because it requires us to develop AI to run the characters (we only have a very very basic AI for enemy characters at the moment). Probably too large of a task for us to work on right now (limited developer resources and higher priority tasks elsewhere).



Of course none of this is a subsitute for actually sitting down and playing through the game to see how it really feels. But playing through a game multiple times is a time intensive process, and we don't have any dedicated play testers (unless someone would like to volunteer?), so I'd like to minimize the number of times that we would need to do that by utilizing some of these other techniques.

So, what have you tried in your games? What worked for you, and what didn't? I'm eager to hear about other's experiences in this design problem.

(Note to moderator: this topic doesn't seem to fit into any of the other forums so I put it here. Feel free to move it elsewhere if needed).

The Power of Open Source Game Development

07 November 2012 - 06:14 PM

I had a personal experience with my project this week that I think is really cool and thought it was worth sharing.


I've been working on the role-playing game Hero of Allacrost since 2004 in my spare time. I've talked about it on this site many times in the past so some people here might remember it. Recent years have been rough for me and I haven't always been able to work on it. I recently came back from a 15 month break where I completely detached myself from the project. Sadly, no progress was made by anyone else during that period of time and the project has been effectively dead, so I gathered the wreckage and get it off the ground once again.

Then I learned that someone who was disappointed with the lack of progress decided to fork my project into their own, Valyria Tear, with a different story, new content, and a great number of new features that he added that were on our development task list. He's really made some awesome improvements to the game, which I am now able to backport and add into my own project. I've even decided to help him out with his project for the time being while I work on organizing my own, as working on his project is just as good for my project as working on my own directly, and he's in a better position to make some real progress right now.

I'm really happy about all this, and I feel like everyone wins. He gets a great starting point for his game with years of work already invested, I get a free "upgrade" to my project despite it being dormant for over a year, and the players get better, faster releases as a result. This is (just one reason) why I love open source software development. Posted Image It has always been a personal goal for me with this project for others to be able to use our code in their own projects, and after 8 years it has finally happened.


A video showcasing his game in play is below.

http://www.youtube.com/watch?v=bKo5wiqfc7A&feature=player_embedded

And for comparison, here's a video of my own project in development from about two years ago.

http://www.youtube.com/watch?v=Aok94zFs9Jc&feature=player_embedded

[C++] Need help optimizing performace of a small function

21 November 2011 - 10:42 AM

Hello. I have a relatively simple problem that I wrote a function to solve but I'm running into performance issues when the input size to this function gets exceptionally high. Basically, I'm trying to find the number of ways that I can build a wall of height "n" using a number of different arrangements of lines of blocks. Not all lines are allowed to be placed on top of one another. Each "BlockLine" object has a vector container called "compatible_lines" that contain the indeces of all lines that this line is compatible with.

So for example if line 0 was compatible with lines 1 and 2, line 1 was compatible with 0 and 3, line 2 was compatible with 0, and line 3 was compatible with line 1, then the number of ways I can build a wall of height "3" would be:

0-1-0
0-2-0
0-1-3
1-0-1
1-3-1
1-0-2
2-0-2
2-0-1
3-1-3
3-1-0

For a total of 10 ways. Make sense?


I already have written a function that calculates the correct result when given a wall height (between 1 and 10) and a set of BlockLine objects that already have their compatible_line data entered. The function works great for small to mid-size wall configurations (a wall of height 10 with 65 possible lines is computed in a fraction of a second). But when I change the number of lines to a larger number (3329 in the test that I'm using) the function is exceptionally slow for larger heights. (3329, 5) is still computed in under a second, but (3329, 10) takes much much too long (several minutes). So I'm trying to figure out how to optimize this code so that it performs well for the larger input sets. Here's the source:

/** \brief Determines the number of possible configurations that can build a block wall of a specific height
*** \param wall_height The height of the wall, as a number of wall lines
*** \param lines A reference to the container where all possible block line permutations are stored
*** \return The number of wall configurations
*** \note The BlockLine objects stored in the lines argument must have all their line compatibilities
*** set before this function is called.
***
*** This function works by starting with constructing the base of the wall with all possible lines. For each
*** line at the base, the compatible lines are placed on top, and those lines have their compatible lines placed
*** on top of them and so on until the wall has reached its maximum height.
**/
int64_t ComputeNumberWallConfigurations(int wall_height, vector<BlockLine>& lines) {
	// In the case that the height of the wall is one, the number of configurations is simply the number of line permutations
	if (wall_height == 1) {
		return lines.size();
	}

	// A counter that keeps track of the number of wall configurations
	int64_t num_configurations = 0;
	// A stack of all the lines that build the current configuration being examined
	vector<int> line_stack;
	// A companion stack that tracks the index of the next compatible line to examine for each line in the stack
	vector<int> next_stack;

	for (int i = 0; i < lines.size(); i++) {
		// Lines that are not compatible with any other line can not be used to form a wall that is two or more lines tall
		if (lines[i].compatible_lines.empty() == true) {
			continue;
		}

		line_stack.push_back(i);
		next_stack.push_back(0);

		int64_t temp = 0;
		printf("Constructing wall with base line: %d ... ", i);

		// With the base line established, now determine all possible configurations for the wall for the provided base line
		while (line_stack.empty() == false) {
			int this_line = line_stack.back();

			// (Case 1): If the next line pushed on the stack would be the top of the wall, add the number of compatible lines for this line and pop
			if (line_stack.size() == (wall_height - 1)) {
				temp += lines[this_line].compatible_lines.size();
				num_configurations += lines[this_line].compatible_lines.size();
				line_stack.pop_back();
				next_stack.pop_back();
			}
			// (Case 2): There are no more compatible lines to examine for this configuration on this level. Pop back to a lower level.
			else if (next_stack.back() >= lines[this_line].compatible_lines.size()) {
				line_stack.pop_back();
				next_stack.pop_back();
			}
			// (Case 3): Add another line to the top of the stack and increment the current line's "next" index
			else {
				int next_line = next_stack.back();
				next_stack.back() += 1;

				line_stack.push_back(lines[this_line].compatible_lines[next_line]);
				next_stack.push_back(0);
			}
		}

		printf("number configurations == %lld\n", static_cast<long long int>(temp));
	}

	return num_configurations;
}


Its a pretty simple algorithm as you can see. It used to be a recursive function, but I rewrote it to be an iterative version when I noticed how slow it ran. Basically I build the wall up from the bottom one line at a time until I'm at the second to last line from the top. Then I simply add to my accumulator variable (num_configurations) the amount of lines I can put at the top, then pop back down the stack.



I realize that this algorithm is a prime candidate for multithreading and that could improve performance (launch each while(line_stack.empty()) loop logic in its own thread) but I don't really want to make this code multithreaded if I don't have to. Plus, I'm kind of doubtful that it would give me the degree of performance that I'm seeking unless I'm launching these threads across 64 different processor cores or something. I've been staring at this function for an hour and I haven't though of any way to drastically increase the performance. Is there something that I'm missing?



One behavior that I did notice during my testing with these larger input sets is that the further along I get, the slower it seems to take for each base line. What I mean is, when this function starts running the first few hundred lines are printed out very quickly

(each line computed quickly, hundredths of a second)

Constructing wall with base line: 0 ... number configurations == 1
Constructing wall with base line: 1 ... number configurations == 252
Constructing wall with base line: 2 ... number configurations == 731808
Constructing wall with base line: 3 ... number configurations == 267227532
Constructing wall with base line: 4 ... number configurations == 13534077843
(each line computed slowly, several seconds each)
Constructing wall with base line: 468 ... number configurations == 1733285040
Constructing wall with base line: 469 ... number configurations == 2477179776
Constructing wall with base line: 470 ... number configurations == 2673027300
Constructing wall with base line: 471 ... number configurations == 2108819760
Constructing wall with base line: 472 ... number configurations == 808799196
Constructing wall with base line: 473 ... number configurations == 6573600

I examined my performance monitor and I didn't see anything wrong with the memory usage. The process remains static at 800KB of memory and 100% CPU, so I'm pretty certain that this is a computationally bound performance issue and has nothing to do with inefficient memory access.

PARTNERS