Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Servant of the Lord

Member Since 24 Sep 2005
Online Last Active Today, 08:29 PM

#5223815 Best CHEAP/FREE 2D Game Engine?

Posted by Servant of the Lord on 16 April 2015 - 06:37 PM

I guess by 'engine' you mean you want not just the game engine, but also a pre-built set of tools/editors that work with that engine?

 

GameMaker is one (don't bash it as just some "kiddy" tool).

Construct 2 is another.

 

If you're making an RPG specifically, you can also try RPG Maker VX Ace.




#5223573 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 15 April 2015 - 07:23 PM

Though for something like this, would there be any danger of major slowdown etc.if you had a vector with many thousands of items? It's just that with my game idea being based largely on trading items, there's a very real possibility that someone might want to e.g. sell 1000 assault rifles, or even worse something like 100,000 rounds of ammunition type X. With the previous system it was no problem to just change the quantity from 1 to any arbitrary value that fit in an int, but it seems like a red flag for me when I think of making 100,000 copies of what are probably going to be the same item.


Different implementations are good for different game designs. I was thinking of your design differently (thinking of it more like a traditional JRPG), and so was suggesting something that fits that better.

If you are selling 100,000 bullets or 100,000 assault rifles, you'll want to use a different system.

Maybe I'm still thinking of your design wrong, but in this sense, it seems like 'conditions' is less like armor durability (which is how I was thinking of it), and seems more like different items entirely. "Rusty sword" vs "Polished sword", "Tainted potion" vs "Fresh potion", {"New","Like-new","Great","Good","Poor"}.

Does it make sense in your design to actually have different quality items be actual different items?

 

If so, player's inventory could be: std::unsigned_map<ItemTypeID, Count>.




#5223541 RPG Mechanics

Posted by Servant of the Lord on 15 April 2015 - 04:39 PM

When did I ever say that I am going to do nothing more than what I find in other games?


All sorts of people are making games and posting design questions here, with a wide range of skills and experience, so I have to try to figure out what they mean and where they're at from a few sets of paragraphs and, based off of that estimation, whether any of my limited knowledge would be useful to them. If I accidentally mis-interpreted your mindset or goals, I definitely meant no offense and was not trying to belittle you. sad.png 

In particular, I wasn't accusing you of making a clone, or of lacking imagination, I was just warning of two potential pitfalls that it looked like you might be walking into:

Potential Pitfall A: If I set out to make a game in a specific genre, I don't want to accidentally box myself into the genre so tightly that I can't innovate within it or cross-pollinate from other genres - I don't want to accidentally give myself genre tunnel-vision.

Potential Pitfall B: If I want to make a game, and I see other games doing X and Y, I need to be aware that what worked for one game given the entirety of that game's designs and features may not work as well for my game unless I'm also thinking about how it works with the rest of my game's design. That is to say, features don't exist in a vacuum independent of each other.

If you already know that, great! I'd rather have shared it with you already knowing it, then for me not to share it when you weren't aware of it (and hey, maybe someone else will read this thread and benefit from it). Plus, I need to remind myself of this pretty frequently even when I already 'know it'. laugh.png 

I probably fixated too much on the graph and the question "Does that sum up RPG mechanics I should add to my game?".
My answer to that one question is 'no', in the sense that it doesn't 'sum up RPG mechanics', being very un-comprehensive (in that I mean it's not, "complete; including all or nearly all elements or aspects of something."), and also 'no' in the sense that (someone, anyone) shouldn't "add to [their] game" purely because it's an RPG, which is what I thought you were asking (possibly incorrectly).

My point about 'turn based' vs 'real-time' was just an example of the chart's incompleteness; not a suggestion for your game. Same with what I meant about the different forms of skill leveling in games - not intended as a suggestion for your design, but intended as commentary on the chart itself.
 

Then I started thinking about RPG mechanics, what sorts of things other games have done, and what I can do differently. How can I answer the latter without being aware of the former?


Certainly, and that definitely makes sense! I just completely misinterpreted your question, thinking you were asking what we thought you should add, mechanic-wise, to your game. Asking for details about what other games have done makes perfect sense, and is a completely different question entirely!

Thankfully, in my previous post I did provide some details about what other games do. Maybe it'll be useful to you, maybe not.
 

If there is a game like this already (verbatim), then I will cease and desist.

I wasn't I trying to discourage you from making a game; merely give advice in how to approach the design.
 

It's not like you're playing an RPG where you're a male warrior who has to save a princess [and the world] for the hundredth time. That would a clone of a lot of things already out there, not to mention cliche.

I wasn't even thinking of story/plot when talking about the game design. In my personal (and novicely!) view of game design, I view story, artwork, level design, music, etc... as game content and, while influencing each other, less integrated with the gameplay features - which, based on your questions, I thought was what you meant by "mechanics". While content and mechanics definitely interact, I find it beneficial to remember both that they need to cohesively fit together as a whole but also that they are separate and disconnected components. I probably lean too far to the second half of that myself. wink.png 

I didn't bother with much more than a glance at the rest of your design (which I didn't responding to), partly because other people were already responding to it, partly because I was only interested in responding to a particular part of your post, but mostly because I agree with Orymus that "You're jumping to the specifics much too quickly.". Either you're focusing too much on details that don't matter at this step of the design process (in my opinion) or, if you're beyond that step of the design process, you're posting too much content-related details (also in my opinion) that aren't relevant to the game-mechanic question I thought you were asking.

Apparently I'm completely off-base, but hopefully you can eek some value out of my posts anyway! 
Best of luck on your project; sorry I couldn't provide the help you were looking for. smile.png




#5223477 RPG Mechanics

Posted by Servant of the Lord on 15 April 2015 - 11:42 AM

At the moment, I feel like I've been dropped in the middle of a vast desert without a map. That's essentially the experience of trying to make a game for a particular genre without prior experience in that area, and without guidance. The reason why games, music, movies, art, etc. have been classified with different genres is because they share many features. They're different, of course, but they do have similar attributes. Romanic comedies tend to have romance and comedy. Heavy metal music usually includes guitars with distortion. I was only looking for a bit of guidance finding the general features that compose an RPG.

 

Genres are ways for consumers to classify media, so they can more easily find similar media they might like ("You liked X? You might also like Y."). They aren't blueprints for designers to create the media. No new genres could ever be created if games are created from genres instead of vice-versa, and even more games would be identical clones of each other with just different artwork, if designers treated genres as blueprints instead of categories.

 

The earlier stages of designing a game are difficult, at least for me. I have loads of ideas, but then getting those ideas filtered down, discarding the ideas that don't fit, and figuring out what gaps exist in the design that need to be filled can be difficult.

 

You shouldn't limit yourself to "what is an RPG", especially since RPGs are all over the map with a huge amount of variation.

Take for example "turn based" vs "real time" - it's not one or the other, it's a spectrum with many games in between:

855c4a66df.png

 

Or take something as simple as leveling up. There are probably a dozen different ways to handle it. Experience is a common one, but some games have multiple forms of experience. Fable for example, has four types - three categorical experiences and one general experience, and you spend the experience like currency on leveling up individual skills. Paper Mario has it that every time you level up, you choose one of three upgrades (health, mana, or equipment slots). Quest 64 lets you level up normally, and each level up gives you a skill point but you can also find instant skill points hidden across the world - and Quest 64 stat points improve only through usage of that stat (i.e. you get more health the more you get beaten up). King's Field skills can only be found by finding hidden skill points in the world.

 

It's great to look at other games for ideas, but less beneficial to look at other games as the "mould" your game needs to fit into.




#5223330 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 14 April 2015 - 10:54 PM

A map is excellent for referring to unique items, like your "types" of items.
 
But you must separate the idea of the item type (e.g. Long Sword), from the items you hold in your inventory (Long Sword with a condition of '2'), because you want the items you hold in your inventory to have different states (the items' conditions).

An easy way to do this is to hold a vector of item instances, and a map of item types. You need unique IDs for each type, so you can refer to them. You use these IDs instead of iterators or pointers. But you don't need a unique identifier for each item in a player's inventory, because each instance of the struct is the item.
 

struct ItemType //The item details that don't change.
{
      std::string displayName;
      TextureID appearance;
      int price;
      int attackPower;
      float whatever;
};
 
//Loaded from XML or whatever. This is a part of the game's "content". It's the same for any player who downloads the game.
//It comes with the game, just like sound effects or textures, and isn't changed when players play the game.
std::unsigned_map<ItemTypeID, ItemType> itemTypes;
 
struct Item //The item details that vary between each "instance" of the same type of item.
{
     ItemTypeID typeID; //What type of item is it? (instead of a pointer)
     int condition; //What condition is it in?
};

//Part of the game's "state". It is created during a playing session based on the game's logic and the player's actions.
//It varies from player to player what items they have in their inventory and what conditions those items are in.
//It is saved when a player saves his game.
std::vector<Item> itemsInInventory; //No unique IDs needed.

 
To give a player an item, just add it to his inventory:

itemsInInventory.push_back(Item(shortSwordID, condition)); //The player has one short sword.
itemsInInventory.push_back(Item(shortSwordID, sameCondition)); //Now he has two.
itemsInInventory.push_back(Item(shortSwordID, differentCondition)); //And now a third one.

If you need to count how many items of the same type the player has, just iterate over the vector and count them (wrap that into a convenience function or use a standard algorithm).

 

To remove an item, just erase it from the vector.




#5223232 How to protect the idea?

Posted by Servant of the Lord on 14 April 2015 - 03:03 PM

So, here's the deal, I've got an idea, and I want to protect it. By that, I am not talking about piracy protection, more like content protection.

 

'Content' is what is created from ideas. 'Content' is protected by copyrights.

 

 

 

Say there's a hypothetical scenario, a fiend hacks into my files and steals that which I plan to put into development, and that thing finds its way into big bucks publishing house and they end up hoarding million for something whose concept I conceived... how can I protect myself from such a scenario outside of making a patent, it being under lock and key?

 

You can't patent, trademark, or copyright ideas. Ideas can't be owned.

 

Only your specific implementation or design of that idea can be protected.

If your implementation or design gets stolen, and you can prove it through your documentation, then sue the crap out of that company. But if it's under lock and key, you won't be able to prove that your idea was created beforehand.

 

Apart from that, keep your idea to yourself, and if you must talk to someone else (say an investor), make them sign an NDA. If they violate the NDA, sue them.

 

Ofcourse, if your idea is generic enough, chances are other people also have the same idea, and someone might get around to making it before you. Or even after you. When this occurs, don't assume that they stole "your" idea. Many people come out of the woodwork and start suing big successes like Star Wars and Harry Potter and Twilight and Facebook and whatever else, claiming (and even proving) that they had the "idea" first, or even wrote and published a book or game that's similar. Doesn't matter. If one human can have an idea, hundreds of other humans might get the same idea independently. "Boy goes to magic school" (Harry Potter) isn't owned by anyone. "Boy is chosen one" (Harry Potter and Star Wars and a bajillion others) isn't owned by anyone. Only the execution/implementation of the idea is owned.

 

Same with names. If someone else happened to use the name "Harry Potter" in a book before JK Rowling did, that doesn't mean JK Rowling stole the name. Heck, there are more than one real life people with the name Harry Potter. That doesn't mean JK Rowling stole their birth name either.




#5223226 RPG Mechanics

Posted by Servant of the Lord on 14 April 2015 - 02:47 PM

Does that sum up RPG mechanics I should add to my game?

 

That (incomplete) chart sums up a few of the RPG mechanics some other RPGs added to their games because it fit well with their designs.

 

There's no checklist of mechanics that should be added to your game (sad.png) - you have to ask yourself and figure out whether X or Y mechanic enhances your game and goes well with all the other mechanics in your design.




#5223222 PerfectMMORPG

Posted by Servant of the Lord on 14 April 2015 - 02:39 PM

I designed this perfect MMORPG game.

 

There's no such thing as a "perfect" MMO, since different people have different tastes.

 

Also, all you posted is a bunch of numbers and ideas (I have folders of that), but disparate ideas aren't what make a design. Design means taking all the various ideas and making them work well together, as a seamless whole, not just duck-taped together.

 

Two different cool ideas might ruin each other if they are put together in the wrong way. Game design isn't about cramming as much "ideas" as possible into one game. That's not design, that's just a mess.

 

Think of it like an artist's painting. The artist had a cohesive, knowledge and experience, and great skill. Each brush stroke works with every other brush stroke. Every choice in color must work with every other color used. Choosing colors that don't go together just because they look cool individually, makes a very terrible painting. Mixing all the awesome colors together just makes a big grey brown smear of ugliness.

 

Good design means throwing out ideas that don't play well with the rest of the ideas. Good design sometimes means adding ideas that, on their own, aren't enjoyable, because when mixed with other ideas, make the overall result even better.

 

 

 

You can build your character as you want. You can be everything you want to be. You can be a turtle or ice elemental, it doesnt matter. Everything is limitless.

 

Your budget, your skills, and your time isn't limitless. And that very much does matter. That's the difference between a designer and wishful thinking.

A designer says, "These are the limited resources and skills I have... How can I make something great even with these limitations?"

 

Letting a player do anything he wants is an idea every single game designer has had, for the past 40 years. But nobody has the skill and resources to make that kind of game.

 

What skills do you have? (nobody will work for you for free) What resources do you have? (nobody will invest money if you don't have experience)

 

Within your limitations, can you create something awesome? Many game designers had nothing but pencils and papers. Working within those limitations, they made amazing board games. Other game designers taught themselves computer skills, to make enjoyable videogames.




#5222835 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 12 April 2015 - 07:15 PM

So then for example, if you had 10 textures they would have the IDs {0,1,2,3,4,5,6,7,8,9}, and if you deleted the last 5 it would look like: {0,1,2,3,4}, then if you added another texture... am I right that it would be assigned ID 10 and 5-9 would never be used again?

Sortof, yes. Since I check at load-time for the highest ID, it'd actually start counting from 5 again. But if you had {0,1,2,3,4,5,6,7,8,9}, and deleted all of them except '9', it'd continue counting at 10.

This isn't a big deal, because I'm using a map not an array, so the "wasted" IDs take up literally zero space. (If I was using a vector, then there would be wasted "empty" spots, but not with maps). And I don't care if I waste a couple ID numbers, because I use uint16_t's as my IDs (unsigned shorts - 2 bytes), giving me up to 65,535 IDs, which is plenty for my needs. If I needed more, I'd use uint32_t's (unsigned ints - 4 bytes), which would give me >4 billion IDs.

But if it became a big deal, it's equally easy to write code to have the editor find an available empty ID, reusing spots that have already been needed. It's just not necessary in my case.
 

If we take the xml example, I assume the original .xml data was created using the editor itself?

Yes, but they could be hand-created if desired. An editor isn't necessary.
 

So something like: Open editor, load texture, save as .xml with generated ID, then it saves the map in .dat form also?
So in this case, do the .xml files only exist as a second copy of the data, so as to be human-readable?

Yes, sortof. You don't actually need to save the .dat for smaller projects.

In my engine, when running the editor, the editor saves/writes the XML files. However, as an optimization, when the editor closes, it writes all the texture details into a single .dat file so the actual game doesn't have to go crawling through the directory looking for files, reading and parsing thousands of text human-readable files,

This is a premature optimization on my part, just to make the real game's start-up occur faster for end users. It's premature because it wasn't actually running slow, and I just was guessing by the time I get all my >10,000 different files added to the game, that it might run slow. This is why I say for smaller projects this probably isn't necessary. Or rather, for situations where the number of resources are fewer than a couple thousand.

In my case, the editor automatically scans the directory for textures, and also scans the directory for human-readable files (YAML, in my case).
If it finds textures but no matching YAML, then it auto-adds that texture to the list (but marks it as "New" so I can visually see it in the editor, so I can add any details I need to).
If it finds a YAML but no matching texture file, then it marks that texture's details as "Missing"

Here's my actual code, copy+pasted: (thankfully it's one of the better commented areas of my project)
 

//Crawls the editor resource directories looking for Yaml files describing what resources exist,
//as well as looking for new resources.
void Resources::CrawlDirectoryForEditorResources()
{
    ERROR_CONTEXT("When crawling the resource directories for YAML files...", "");

    //Load the tag redirects.
    this->Load_TagRedirectMap_ForEditor();
    this->Load_MaterialDetails_ForEditor();

    //==========================================================
    //Load the texture details and animation details.

    //---------------------------------------
    //Phase 1: Find all the image files.

    StringList missingTextures;
    StringList imageFilepaths = GetFilesInDirectory(this->Paths.Editor.TextureDirectory, SV_MatchesWildcard({"*.png", "*.jpg", "*.jpeg"}));

    //---------------------------------------
    //Phase 2: Load all the Yaml files.
    StringList yamlFilepaths = GetFilesInDirectory(this->Paths.Editor.TextureDirectory, SV_MatchesWildcard({"*.yaml"}));
    for(std::string &filepath : yamlFilepaths)
    {
        //Load the yaml filepath.
        this->priv_loadTextureAnimationDetailsFile(filepath);

        //Remove ".yaml" from the filepath, so we can compare the strings later.
        if(filepath.size() > 5)
        {
            //The image filepath is the same as the yaml filepath, except without ".yaml" as an extension.
            std::string imageFilepath = filepath.substr(0, (filepath.size() - 5));

            //Remove the image filepath from all the images we found when we crawled the directory.
            if(!RemoveAll(imageFilepaths, imageFilepath, PathsAreEquivilent))
            {
                //If we can't find this image filepath in the files we've just crawled, mark it as missing.
                missingTextures.push_back(imageFilepath);
            }
        }
    }

    //---------------------------------------
    //Phase 3: Process our missing and new textures.

    //Any remaining filepaths in 'imageFilepaths' were images we aren't yet aware of.
    StringList newTextures = imageFilepaths;

    //For every new texture, create a new TextureDetails.
    for(const std::string &filepath : newTextures)
    {
        this->CreateTextureAnimationDetailsFile(filepath);
    }

    //For every missing texture, modify the TextureDetails to mark it as missing.
    for(std::string &filepath : missingTextures)
    {
        Engine::TextureID textureID = MapGetKeyFromValue(this->Details.TextureDetails, Engine::TextureDetails(filepath), Engine::InvalidTextureID);
        if(this->Details.TextureDetails.count(textureID) > 0)
        {
            this->Details.TextureDetails[textureID].fileStatus = TextureDetails::FileStatus::Missing;
        }
    }

    //==========================================================
}

//Creates a new details for the image located at 'textureFilepath' (assumes there is no existing details for the image).
void Resources::CreateTextureAnimationDetailsFile(const std::string &textureFilepath)
{
    //Get an available ID.
    Engine::TextureID newTextureID = (this->Details.nextTextureID++);

    //Fill in the details.
    Engine::TextureDetails newTextureDetails;
    newTextureDetails.filepath = textureFilepath;
    newTextureDetails.tagSuggestions = this->GenerateTagsFromFilepath(textureFilepath);
    newTextureDetails.fileStatus = TextureDetails::FileStatus::New;

    //Add it to the details map.
    this->Details.TextureDetails[newTextureID] = newTextureDetails;

    //Save the details.
    this->Save_TextureDetail_ForEditor(newTextureID);
}

//Loads the details for the image located at 'textureFilepath', and returns the texture's ID.
Engine::TextureID Resources::priv_loadTextureAnimationDetailsFile(const std::string &yamlFilepath)
{
    ERROR_CONTEXT("When loading a TextureDetails/AnimationDetails editor-friendly file", yamlFilepath);

    //...yaml crap...
}

//============================================

typedef std::vector<std::string> StringList; //In some header somewhere

//============================================
//In some other file somewhere: (feel free to take!)

#include <boost/filesystem.hpp>

/*
	Returns a list of every file in the folder and (if desired) the files in each sub-folder.
	If 'timeThreshold' is specified, only files that have been written to *after* that threshold are returned.
	If 'fileFilterFunc' is specified, this filters out all file names (not the entire path) that don't pass the filter.
	If 'folderFilterFunc' is specified, entire subdirectories are filtered out.
	If 'pathPrefix' is specified, this determines what prefixes the returned paths.
	Suggestions for 'pathPrefix' are: Nothing ("FolderA"), "./" ("./FolderA") for relative paths, or passing in baseFolder for absolute paths.

	Example:
		"./File1.ext"
		"./File2.ext"
		"./FolderB/File3.ext"
		"./FolderB/File4.ext"
		"./FolderB/Folder2/File5.ext"
		"./File6.ext"
*/
StringList GetFilesInDirectory(const std::string &baseFolder, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with filters that accept everything.
	return GetFilesInDirectory(baseFolder, IsAnything, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with a directory filter that accepts everything.
	return GetFilesInDirectory(baseFolder, fileFilterFunc, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, StringValidatorFunc folderFilterFunc,
							   SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	StringList listOfFiles;
	if(!DirectoryExists(baseFolder))
		return listOfFiles;

	boost::filesystem::directory_iterator directoryIterator(baseFolder);
	boost::filesystem::directory_iterator endOfDirectory; //An unitialized iterator is the end iterator.

	//Loop through everything in this directory.
	for(; directoryIterator != endOfDirectory; directoryIterator++)
	{
		//Make sure the item found is a file and not a folder.
		if(boost::filesystem::is_regular_file(directoryIterator->path()))
		{
			//Get the name of the folder.
			std::string filename = GetFilenameFromPath(directoryIterator->path().generic_string());

			//Check if the filename passes the filter.
			if(fileFilterFunc(filename))
			{
				//Check if it was written to after 'timeThreshold'.
				if(timeThreshold == 0 || timeThreshold < boost::filesystem::last_write_time(directoryIterator->path()))
				{
					//Add it to our list.
					listOfFiles.push_back(ConvertWinPathToUnix(pathPrefix + '/' + filename));
				}
			}
		}
		else if(boost::filesystem::is_directory(directoryIterator->path()))
		{
			//Check to make sure we want to crawl subfolders.
			if(subFoldersEnum == IncludeSubFolders)
			{
				//Get the name of the folder.
				std::string directoryName = GetFinalDirectoryFromPath(directoryIterator->path().generic_string());

				//Check if the directory name passes the filter.
				if(folderFilterFunc(directoryName))
				{
					//Get all subfolders and add them to the list.
					listOfFiles += GetFilesInDirectory(baseFolder + "/" + directoryName, fileFilterFunc, folderFilterFunc, IncludeSubFolders, (pathPrefix + '/' + directoryName + '/'), timeThreshold);
				}
			}
		}
	}

	return listOfFiles;
}

 
In this case, I'm just showing what I'm doing, so you can get an idea and more food for thought, and am not necessarily advising you do the same. Since you're talking about items, not textures, you don't need to keep track of textures AND yaml files, you can just have your item XML files.

If you don't use an editor, but edit the files by hand, you can do something like: Create an XML file manually, but don't create an <ID> field. When the game starts up, if it finds an XML file without an ID field, it assigns the next available ID and re-saves the file, so the file now has a permanent unique ID. Any missing fields could be initialized to defaults and re-saved, with the 'default' ID being a unique one.
 

I also wonder about how to refer to the resources by ID. In the first example, if the IDs are assigned by the editor and saved to a .dat, how do I know the IDs of each Item so I can e.g. give an item to the player at some specific point in the story?


In my specific case with the textures, the IDs are displayed by the editor, so I can see that #5742 = blah. In the small ORPG I mentioned previously, we just had our scripts do: AddItemToInventory(playerID, itemID). And really, for the several hundred items we had, this worked fine, because we had our editor open while we edited scripts (a different editor, different project, written by different programmer). Yea, we had to do some scrolling through lists of items to find what the ID was, but that really wasn't a problem.

In my new editor, I wouldn't even have to scroll, since the new editor can search lists of [textures, in my case] using wildcards (e.g. "potion" displaying "Red potion","Potion of healing", "HiPotion", and so on), to filter the lists by tags and display names, and filters instantly while typing in the search box.

Though you could also have your scripts lookup an item by name if you want to, but again you might accidentally later rename the item, or more than one item with the same name or typos in the name (though you can typo numbers too!).
This might look something like this:

AddItemToInventory(LookupItemByName("Bob's Quest Item"))

(Where 'LookupItemByName' would emit a descriptive error if the item isn't found, and a different descriptive error if more than one item with the same name exists).
 

Or do we read them from inside the editor once the data has been loaded?

Ah yes, this one. smile.png

If you don't have a fancy editor, and don't want to waste the development time making one (smart choice!), you could do this very easy hack:

When your game loads up, it reads the directory looking for all the item XML files (and fills in any missing IDs), it could then immediately output (while the game is still running) a very simple, very basic, CSV (comma-seperated-value) text file that contains just the display name and the ID of every item.

1,Potion
2,Sword of Pwning
17,Fluffy Kitten
18,Midnight Armor
142,Bob's Quest Item

This file wouldn't be used by the game at all, just auto-generated by the game at startup for your own use during development.

What you do then is just open it up in Excel or Google Docs or whatever (which you can have open in another window/tab while you work) - both of which can read CSV files, and whenever you want to know the ID of an item for your scripts or events or whatever, you just do a Ctrl+F search for the display name of the item.

(CSV is a real simple format. Feel free to hack apart my CSV outputting function to get started. My function has a few weird dependencies on my own libraries, but you can cut those out easily enough, especially since you don't need all those features)




#5222655 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 11 April 2015 - 03:52 PM

 

What I do is I generate a unique ID when I create the resource, and then save the resource details and their IDs to the file.

 

Hmmm... don't think I'm following the exact process involved here...

 

How is the resource created?

 

In my own project, I create resources within an editor I made. 

 

Basically, to use images as an example, the process I use goes like this:

 - Editor loads "Textures.dat" which contains [ID, TextureDetails] (and TextureDetails contains, among other things, the filepath to the texture itself).

 - Editor puts it all in std::unsigned_map<TextureID, TextureDetails>

 - At load-time, Editor runs through the map and finds the largest ID and sets it to 'nextID'.

 - When I want to add a new texture to the editor, the editor assigns it an ID of "++nextID".

 - The editor re-saves the entire map to 'Textures.dat', ID and data together.

 

Another solution, which I also use, goes like this:

 - Editor reads Textures directory looking for every *.xml file (I'm using yaml, but the idea is the same) (file contains the texture details and the unique IDs).

 - The editor loads all those .xml files into the std::unsigned_map<TextureID, TextureDetails>

 - At load-time, Editor runs through the map and finds the largest ID and sets it to 'nextID'.

 - When I want to add a new texture to the editor, the editor assigns it an ID of "++nextID".

 - The editor re-saves the entire map to 'Textures.dat', ID and data together.

 

If you are creating resources outside of any editor instead of inside of it, you could use filename hashes or something - but one of the benefits of IDs is that it provides a level of indirection if you rename or move a file (e.g. fixing a typo). You could use creation-date instead, or manually enter the date/time as an ID (2015-04-11 4:51pm = 1504111651), but you risk messing up and accidentally assigning the same ID twice. Though your game could detect that at runtime, saving alot of debug hassle. Another option is writing a little command-line tool that runs through all the files, finds the largest ID, and gives you a new available ID to use. That might be over-complicating the process though.




#5222538 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 10 April 2015 - 07:19 PM

 

And yes, I'd occasionally want more than one item to share the same display name - I can think of at two unique situations where I'd want that, if the gameplay desired that feature.

 
Just the way I've been viewing it so far... is that if I ever had 2 types of item that theoretically could have the same display name... it seems like I'd be just as well to give them different names, even if it was something like "AK-47" vs "AK-47 (Gold)" or w/e.

 


I was thinking:
A) Quest related

If you have an item that you carry with you long-term through a quest sequence, and the item takes on new attributes as you progress through the quest, you might want to silently swap out the quest item for the next item in the sequence, but have them look identical and have the same name.

Example: You're required to get a "Official Pardon" signed by three judges. You have "Official Pardon" in your inventory, as given to you by the Judicial Administrator of Blahblah Sometown.

Item #221 = "Official Pardon". Description = "A bureaucratic form requesting pardon for Charlie the condemned blacksmith. It needs to be signed by three high-court judges."

Item #222 = "Official Pardon" (still the same display name). Description = "A bureaucratic form requesting pardon for Charlie the condemned blacksmith. It's been signed by The Honorable Justice McGuyver. It needs to be signed by two more judges."

...and so on. Yes, you could still give them different names (like "Official Pardon (1 signature)", but stylistically I'm not fond of that because, to me personally, it can be slightly immersion breaking.

B) Cursed items

Imagine a cursed helmet that disguises itself as a regular helmet of the same type, i.e. "Iron Helm"

In single-player games, I wouldn't mind the cursed item having a different name (like "Black Steel Bascinet"), which lures the player to try it on just by sounding cool. But in a more online-enabled game, news would spread much more quickly, and players would self-defeatingly avoid interesting experiences by knowing ahead of time that the item is cursed (my goal of the cursed item being to create interesting experiences and unique-ish personal stories - my goal is not to annoy or frustrate players).

Another example would be two mushroom items with the same name but slightly different appearances, one of which is edible and another poisonous.

C) Enchanted items

Imagine you got an item ("Short Sword"), and imagine you enchanted it so it had quicker attack speed ("Short Sword of Swiftinessitude"). But imagine that the strength of the enchantment was based on your current enchantment level ("Short Sword of Swiftinessitude +12"). But imagine you enchanted it in both attack power and attack speed ("+5 Damaging Short Sword of Swiftinessitude +12"?). Sometimes I want items to have dynamic attributes that can be altered by scripts ran in-game, and I'd rather the benefits be shown on the tooltip and not always in its display name.

So really, it comes down to gameplay needs. Your gameplay might not need it. But in general, given two different methods of equal code complexity, I prefer the one that doesn't constrain what the content creators can do with the engine.

I used to be a part of a small 2D online RPG (10-20 players online at once). The programmer and project leader made the smart decision to give the two mapmakers (me and another gent) access to the engine via a scripting interface. Boy, we put that thing through its paces! (I personally crashing the server probably forty times. He had to give me remote access to the server so I could restart it if he wasn't available tongue.png). Any and every feature he exposed to us through the scripting engine, we consumed and used in ways he hadn't ever thought about. It's a very basic 2D RPG, and I used the scripting engine to implement various minigames, and the other mapmaker added an auction house. The scripting engine we were using was a very very basic home-rolled thing the lead developer wrote - nothing fancy. And it exposed barely any functionality.

Anyway, I guess my point is that 'creativity reaches to and exceeds the constraints of the technology it is working with'. You go down an endless bunny trail if you start coding features you don't yet need, but at the same time, you hinder creativity if you unnecessarily exclude features you don't think you'll need.
 

What would you have in mind? Just read all item data from a file, then have the program automatically generate numerical item type IDs in sequence?


Nope, because if you remove an item later, then every item after the removed item gets accidentally reassigned a new ID.

What I do is I generate a unique ID when I create the resource, and then save the resource details and their IDs to the file.

I personally use a std::unordered_map<MyResourceID, MyResource> for that, and use a special serialization system to read/write the entire container to file.

But another thing I've done in the past in a simpler project was to use the unique ID as the filename itself, and store each resource in its own file (i.e. Item_22342.cfg), and then at loading just scan the entire "Item" directory and read the files and the filenames (though this is only good for smaller projects or for resources that you only have a few of - like music files). If you're talking about item templates, you can use this same method with std::string IDs.
 

So where I'm at right now regarding my inventory architecture is:
- My Inventory class contains a vector, the vector contains objects of the class InvEntry.
- InvEntry represents an inventory entry describing the item contained.
- InvEntry contains an Item object, and a quantity integer representing how many of that Item are stored.
- The Item class describes the item.


Sounds good.

Two thoughts:
- How are you handling 'condition' in this system?
- How do you prevent items of different conditions from stacking?

One possible way is to make "Short Sword" with condition 3, and "Short Sword" with condition 4 merge together and stack into a single "Short Sword" with 7 condition.
If acceptable gameplay-wise, basically each sword slash uses one "usage" of the sword. You could relabel "condition" in equipment and "item count" of potions to actually mean the same thing, relabelling them both as "uses left".

This means you'd have to give up your 1-5 'condition' range, and instead go to a >0 'usages', and if you pick up a sword, maybe it came with 5 usages, and when you pick up another sword of the same item, it comes with 5 more, giving you ten on that "stack".

This is the easiest way to go about doing it. In this design, you wouldn't need InvEntry, and you'd just have std::unordered_map<ItemID, Item> EveryItemInGame; or std::unordered_map<std::string, Item> EveryItemInGame; (or a std::vector).
And the player's inventory would just be a vector or map of struct { ItemID, numUsagesForThatItem }, or you could keep the usages in 'Item' itself, and just initialize every item's usages to 0.

If you do use a string for lookups, I suggest you either be super positive about normalizing your strings (i.e. converting them all the lowercase and stripping out whitespaces), or else you make your std::unordered_map or std::vector lookup functions be case-insensitive.

When I need to make a std::unordered_map case insensitive, I do so like this:

//Declared in a header someplace where it's easy to re-use.
//WARNING: Test before actually using, I can't copy+paste my real code because of dependencies.
class case_insensitive_equals
{
public:
   bool operator()(const std::string &strA, const std::string &strB) const
   {
      if(strA.size() != strB.size())
         return false;
      
      for(size_t i = 0; i < strA.size(); ++i)
      {
         if(std::tolower(strA[i]) != std::tolower(strB[i]))
            return false;
      }
      
      return true;
   }
};

typedef std::unordered_map<std::string, Item, std::hash<std::string>, case_insensitive_equals> ItemMap;

ItemMap EveryItemInGame;

You might need the hash itself to be case-insensitive too, I forget.




#5222333 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 09 April 2015 - 05:54 PM

 

Personally, I wouldn't use a string to identify them, but I'll do it that way below anyway.

 
Regarding this, why is that exactly BTW?

 


Because I'd want to load data from files, I'd want each item to have a unique ID, and unique integers are easier to generate than unique strings (just increment ), and unique gibberish strings serve no benefit. And yes, I'd occasionally want more than one item to share the same display name - I can think of at two unique situations where I'd want that, if the gameplay desired that feature.

Ideally*, the code wouldn't be hard-coding any item names or IDs anyway - but scripts or other data files might.

*Ideally. wink.png 
 

What I've actually been planning has been what is probably best described as the Flyweight pattern, which I've also used before.


Flyweight is excellent when trying to conserve memory, like for textures and song files and such. But each item is only a tiny piece of memory - even if you had 20,000 items, it still wouldn't be a problem. You'd be trading code complexity for memory conservation in an area where you don't need memory conservation.
 

What I was going to do exactly was mark the Inventory entry with the std::string to signify the type, and then I would have looked up a table of ItemType objects which described all of the characteristics common to that type.

Certainly, and that's still doable. Using the string as a lookup to a template item "type" is a reasonable thing to do. I just wouldn't use a string for each item instance, since you'll be creating additional item instances at runtime.
 

As it is now, since I'm replacing the map with a vector of Item objects, I'm going to just give the Item class a shared_ptr< ItemType > member that refers to the ItemType object found in a map of all ItemTypes keyed by an std::string.


That's also a reasonable solution. Although, at the risk of complicating things, I'd suggest a simple raw pointer instead of a smart pointer. Don't get me wrong, I like smart pointers! But if you are loading all your item types at startup, then you've probably guaranteed that all your item types will outlive your item instances. In which case, a raw pointer or reference is also perfectly acceptable.
 

Is that closer to what you were thinking about, or was it something completely different?

 

Something like that. My actual implementation would depend on my gameplay needs. There are a number of ways to do it, which are all fine.




#5222244 C++ indie games + pixel art

Posted by Servant of the Lord on 09 April 2015 - 09:11 AM

games made with C++ and OpenGL/Directx/SDL/SFML/Any library, that have pixel art graphics?

 

Pixel art is a graphical style. OpenGL, DirectX, SDL, and SFML all support drawing 2D graphics, and thus all "support" pixel art as a style. The "style" is handled by the textures being drawn by the artist, not by the language or library used to code the game.

 

I personally have used C++ and SDL, C++ and SFML, and (now) C++ and OpenGL. All of them are capable of pixel art graphics.




#5222114 Detecting if 2 Iterators point to the same thing?

Posted by Servant of the Lord on 08 April 2015 - 01:42 PM

I remembered later too that even resizing a container will invalidate an iterator

Sometimes. Not always. Each function for each container has different guarantees about whether it'll invalidate the iterators, and which iterators it'll invalidate.

A basic example is std::vector::pop_back(). That'll invalidate the last iterator (and the end() iterator). But it also guarantees it won't invalidate the other iterators.

See std::vector::pop_back(), and the section labeled "Iterator validity". Each function's page has the details for that function/container. You don't have to worry about memorizing that detail, only remembering to *check*, and overtime you'll remember the details for the ones you use most frequently.
 

so clearly iterators are very much linked to the state of their particular containers.

Yes. Iterators and pointers to the raw memory, depending on the container. 

The point of iterators and pointers pointing at elements is to hold onto them for a short time for the use of a single function or algorithm. For referring to objects long-term, you need a different method - that's not iterators' purpose (and dangerous for pointers to), because containers need to shuffle around their objects in memory.
 

Guess one way of getting around it is just by testing if we're dealing with the same container first, then continuing as appropriate.

I think you took the wrong off-ramp, and need to get back on the highway for another couple exits before making your turn.

What I mean is, take a step back and don't ask "how can I check if the iterators refer to the same object", and instead ask, "What is my actual goal again? How can I go about implementing that?"
 
 

- Have an inventory that stores how many of whatever items someone/something has.
- Item type is referred to using a string.
- Items have a condition value referring to their state of repair, from 1-5.
- The quantity of items stored is recorded using an int.


 
Personally, I wouldn't use a string to identify them, but I'll do it that way below anyway.
 
You have two conflicting 'requests' for this container. The quantity of items is stored (great! So all items of the same type are identical!), but differing durability/condition on each item (oh, so they're not identical?). Since they aren't actually identical (they have different conditions), each item (even of the same type) should be different elements. You don't need compression or need to micro-manage the memory here, items are very small, memory-wise.
 
An easy straightforward way to doing this is:

struct Item
{
     std::string name;
     Enum type;
     int condition = ...;
     Stats stats;
};
 
typedef std::vector<Item> Items;
typedef size_t ItemIndex;
typedef ItemIndex InvalidItemIndex = ItemIndex(-1);
 
//Convenience functions. Iterates over the container and looks up an index using the item name.
//If multiple items exist with the same name, returns the first one found. If no item in 'items' exists with that name, returns 'InvalidItemIndex'.
ItemIndex FindFirstIndexWithName(const Items &items, const std::string &name);
 
//If it exists, "erases" that index from 'items'. To prevent other indices from becoming invalid,
//that item's name is just set to "" (an empty string), so we know that spot is available for re-use.
void EraseItemByIndex(Items &items, ItemIndex indexToDelete);
 
//Adds an item to the container and returns its new index.
ItemIndex AddItem(Items &items, Item itemToAdd)
{
      //Check for the first available spot we can re-use, by looking for an item with an empty string name (which means we previously erased it).
      ItemIndex availableIndex = FindFirstIndexWithName(items, "");
 
      if(availableIndex != InvalidItemIndex)
      {
           items[availableIndex] = itemToAdd;
           return availableIndex;
      }
      
      //If the index returned is invalid, that means we need to create a new spot.
      //This potentially invalidates any *iterators*, but our indices are still fine.
      items.push_back(itemToAdd);
 
      //The new index is the final index in the container.
      return (items.size() - 1);
}
 
struct Player
{
     ItemIndex equippedHelm = InvalidItemIndex;
     ItemIndex equippedChestPiece = InvalidItemIndex;
     ItemIndex equippedWeapon = InvalidItemIndex;
    
     Items inventory;
};

 
I'd actually do it a bit more complicated than this, probably using std::unordered_maps, unique IDs, and more layers of redirection, but for a simple game, there's no point in overcomplicating it.
 
The key is, make it simple, and write convenience functions to do the heavy lifting for you.




#5221986 Programmatic Pixel Art

Posted by Servant of the Lord on 07 April 2015 - 09:05 PM

Hello. I was just wondering, has anyone ever tried making a game with programmatic pixel art? What I mean is, instead of using a spritesheet, this individual would have used an array (for example) to map out a sprite in the program and draw them with pixels using a graphics primitive function.

 

Sure. It's not very practical because it goes the exact object direction of separating assets from code, but yes, it's been done.

 

Advanced automated examples of this are systems like Visual Studio's and QtCreator's resource-packing wizards that load arbitrary files from disk and convert them to code so they can be baked into the resulting DLLs or EXEs.

 

There are even projects that have gone further, and use algorithmic rules to generate the assets procedurally.






PARTNERS