5
\$\begingroup\$

Current Git (Needs more documentation)

Current working prototype to play with (Git code is after a BIG refactor)

Background: I'm making a javascript text city/nation builder along the lines of A Dark Room or Candy Box. This is going to be the player managing a city but be able to vassalise other cities (Ala Europa Universalis), giving you a tribute of their income but no specific control over it like your own one.

Each city has a tree of things in it, including buildings, resources, tools/machines and intermediate crafting items. These types each have their own object constructors and can easily have a complex object of about 5-50 keys depending on the item just from a few lines of code. Each tree starts at the top, a category for sorting on the UI/namespace, and then inside that is the actual object itself. So whenever referencing an item in a crafting recipe or production chain there's a "resource.material.wood" or "buildingHouse.tent.small" or such.

The player or "empire" can own multiple cities, but only directly control one in the city view screen (You can tell your city exactly how to be managed, but all other cities you've taken over live their own life, but you can send them requests and investments to boost specific things). Because the item trees are so expansive (170 items in the prototype on my website) I need an easy way to hide things away that aren't unlocked yet. Decided to go with the Civ 5 tech tree route.

Current problem: In the prototype I had the tech tree and items bound to the window instead of to the city. This meant there was only ever a single instance of everything and to unlock something in the UI I could just go (simplified) foreach (unlockedItem) {item.unlocked = true}. I can't do this as easily in the multiple city model because the tech system is player specific, not city specific, and so if you take over a new city they should retroactively build the city's tech level from that player's tech level. I'm not sure how I want to handle inheriting resources/buildings from a more advanced civ yet either.

Relevant code pulled from the Git as an example: pastebin.com/DbbUXbaL

As far as I can tell, there's a not so easy way I can work around this.

Flip the way I unlock things. The item is then bound to a tech that unlocks it instead of a tech being bound to multiple items. In my head I prefer the latter way because it means I can group like items together (The resource with the building that produces it) and it's easier to list the items that the tech unlocks when you're in the research menu. It's also much easier in the code to see what a tech unlocks at a glance, instead of going from class to class. The problem with the latter way though is that it's hard to retroactively unlock things in a newly unlocked city.

The question to Gamedev: Those of you with more experience than I, how would you go about designing a technology system for an entity heavy game like the Anno series or Civ if each tech unlocked 5+ things? Do I have the right idea binding the item to the tech or is there a much simpler way of doing it I'm just not seeing?

\$\endgroup\$
  • 1
    \$\begingroup\$ Hi, and welcome to the site. Your question is quite detailed and includes a working prototype and a clear problem description. That's awesome. Welcome! (+1) \$\endgroup\$ – ashes999 Aug 6 '14 at 9:56
3
\$\begingroup\$

Here is my suggestions

Dealing with Trees You can do any tree by using tables. It can serve as dependency counter for what ever tree you are doing. Already tested by me some time ago were skill tree, knowledge tree and my favorite, item tree.

For this example we are going to use "Item" tree.

Each item will be a record for the table name ItemTree. They will be composed of the following fields:

id
itemName
Status
itemCaller
itemDependencyCounter
itemDependencyTotal
etc...

Status field indicates if item is locked or unlocked. It can have 0 or 1 value. 0 for locked and 1 for unlocked.

itemCaller are string typed field consisting of other item "id"s with separator (a comma) in which the content can be like so...

id, id, id, id...

itemDependencyCounter indicates how much times a dependency of that item has been unlocked.

itemDependencyTotal indicates the total dependency of that item before that item is unlocked.

How to use: Whenever an item is unlocked your program should read itemCaller and update the rest of the items indicated on it to increment their itemDependencyCounter. Then another loop on the table should check if there are new items where itemDependencyCounter is equal to their itemDependencyTotal. if there is, it will unlock that item and do the loop again until there are no more items needed to be unlocked.

Note that the number of items are dependent on certain amount of item plus numbers of scenarios/events (which again can be tabled in the same way).

Example item1 has 5 itemDependencyTotal but there are only 2 item calling(unlocking) it. This is possible because certain scenarios/events might hold the other 3 triggers missing in order to unlock that item.

All together it create this kind of logic example:

item=pike
dependencies=array(item=wood,item=Ore,knowledge=bronze,time>2000BC,etc...)
unlocks=array(unit=phalanx,item=spear,etc...)

You see the benefit here is prominent because you do NOT have to declare the actual dependencies. Only the unlocks are stated on the table. No Redundancy.

Again as I've mentioned scenarios/events even skills, knowledge and other game parameters for your cities or your character can be tabularized the same way.

This behaves like a tree but is much simplified in some way.

2 Dimensional Array You can also use 2 dimensional array that acts the same logic as table above. Problem here is you have to memorize the sequence which parameter gives status, itemDependencyCount and itemDependencyTotal. Another problem might be memory size but everything can be managed upto a certain degree.

Dealing with Multiple Cities. Using the solution above all you need is another field named "City". You can add a whole batch of item specific for that city that is currently locked and few unlocked items to begin.

Next you need to create an AI that randomly unlocks per item or per scenario/events. Then when your program does the checking for unlock, it should be included since they are one table.

Random Events and/or AI Randomly choosing things to do can have parameters that increase over time.

Example: Initially the AI (because of limited resources,items,knowledge,etc) can only do 5 things at one time but eventually increases as more parameters are unlocked. Therefore you can assign it like so...

 AITodo = Random(n) 

where n is the number of things the AI can do.

How many tables should I put?. It depends on your games. Essentially if the table listed applies to your game tree, you can put it.

1.)Item  runned
2.)Skills
3.)Knowledge(like in Civ) 
4.)Milestone/prizes 
5.)Map Areas 
6.)Resources 
7.)Enemies

Example of Game Logic:

SetInitialScenario >> UserInteraction >> CoreLogic >> TerminatorChecks >> 
Render >> BackToUserInteraction

Inside Core Logic:

AIInput >> UserAIValidation >> TableProcess >> OtherLogicYouLike >>
EnemyAIInput >> TableProcess >> OtherLogicYouLike >> ExitCoreLogic

where TableProcess is the "How to Use" as indicated above.

Task/Timer Organization You can put a single time-counter that checks the time based tasked. Again every time a task is expected to happen (after user interaction), tasked should be inserted to the table. The records of this task are index in time the task is suppose to finish.

Next is on your program logic you can add a TaskMonitor function that whenever a task is expired (current time >= timeToExpire) it will be deleted on the table and the desired changes are applied to the game. This function can be run Asynchronously or dependent on User activity.

Data Structures I could explain this to you or I can do this instead.

City1
City2
|_____Resources
|        |______Wood
|        |______Gold
|        |______etc...
|
|_____Production(Rates)
|        |______Wood
|        |______Gold
|        |______etc
|
|_____Building
|        |______Factories
|        |         |_______Smerlters
|        |         |_______ etc...
|        |______Homes
|        |______etc
|
|_____Tools
|_____Machines
|_____Item
|_____Research
City3
etc...

Do not confuse your data structures with game logic and functions. You need a way to associate the dependencies of your structure as tree... that is different. You need a function that monitors task... again that is different. You need an AI for the other Cities management... again different. You need an Enemy-AI that will randomly attack or give a challenge to your game... again it is a different function.

Try separating the logic for your user interaction versus the logic that happens behind the scene with or without user interaction.

Will it create an Overload the beauty of databases/tables is you do not need to store them on memory therefore your game will not be a resource hog. Overload may also be prevented by choosing a proper PL.

Programming Language Although it can be done in JavaScript there are better PLs out there that gives best results. Some favorites are C++, Java, even C#.net can be used to make games for XBOX. Note Rendering and actual game logic programming may use different applications.

Finally Do not overshoot your design. Make one and move on. Research some stuff then apply it to your next project.

\$\endgroup\$
  • \$\begingroup\$ I'm not sure I follow. Are you saying to set up the unlocked status to watch each requirement that can unlock it (in my case, researching a technology or a random event) and have it cycle through those requirements each time something changes? Wouldn't that create a lot of overhead? Sorry for not understanding, JS was the first language I learnt and it's only been about 8-12 months of tinkering with it since I started. Usually I can BS my way through figuring out the intention of something but most of that flew over my head. \$\endgroup\$ – LastElf Aug 6 '14 at 13:32
  • \$\begingroup\$ I'ĺl try to be more specific and will provide more example. I'm currently editing and adding stuff since you got lots of item up there. \$\endgroup\$ – Ace Caserya Aug 6 '14 at 13:35
  • \$\begingroup\$ Ok done. Thanks for waiting. The key is there are always structures and functionality behind the scene. How a good game is appreciated is actually designing these key aspects cleverly and deploying them in-game for players to worry upon. \$\endgroup\$ – Ace Caserya Aug 7 '14 at 0:42
  • \$\begingroup\$ Thanks Alvin. Sorry for taking so long to reply, saw all of that and went "This is going to take a while to digest." I do very much appreciate the detailed post you made, and if I were to do it again from scratch it makes sense to do it that way, but my reasons for making it in JS is to be platform independent and this style of game suits browsers better (Tribal Wars, Candy Box, Cookie Clicker to an extent). It's basically a "Facebook game" without the friends or the 8+ hour time constraints and a lot more combat depth. \$\endgroup\$ – LastElf Aug 11 '14 at 2:10
  • \$\begingroup\$ I understand this makes it harder on myself, but JS is the language I'm wanting to learn (For other business reasons as well) so I'll stick with it. I did start to understand the post a lot better when it was finished though, and I'll probably be applying some of the things in there to it. As far as my question goes, you've given me an alternate way of doing it if I were to rewrite the architecture from scratch (a third time), but I'm still interested in finding a way around the problem without setting up a server-side DB for data lookups. \$\endgroup\$ – LastElf Aug 11 '14 at 2:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.