Jul 13, 2015

Posted by in Game Development | 2 Comments

Market Forces

Central to the idea of a “space trading game” is the presence of something to trade. The most basic idea is that you as a player must find the lowest price on a specific item, buy as much of that as you can afford/hold, and then fly it to another location where you sell it for more — hopefully much more — than you paid for it. In a simulation, it can’t be the case where you bounce between two nearby stations ferrying goods back and forth until you’ve amassed a fortune, so the system needs to implement a kind of rough supply-and-demand system so that stations with lower inventory will buy for more cash, while stations with higher inventories will offer less cash. Behind the scenes, processes run to simulate other traders, moving goods around to shift buy/sell conditions at all stations.

I’ve gone over this system about 100 times at this point, but I still haven’t quite mastered the art of market simulation. Ideally, I should be creating dummy data and then simulating it with a spreadsheet or some quick scripting tests. I am cursed with being a visual developer; I need to see something in front of me in some semblance of how I picture it in my mind, and that usually leads me to taking a detour into the world of UI design.

The “new” Unity UI is better than the old system at least because it’s visual. I can drag elements onto the screen and position them, wiring up actions to event handlers to make stuff happen. Unfortunately, the new system is sometimes pretty esoteric if you’re not internalizing it’s quirks. Scale and position have all thrown me for a loop recently, and I’m always just one slip of the mouse away from getting myself hopelessly tweaked in a way that I struggle to recover from, because now a panel is too big or the font is too jagged. I learned today that using childTransform.SetParent(parentTransform, false) is better than the standard transform.parent = ? when dealing with the UI because the former method respects scale and position, whereas the later does not. Thankfully, I learned that quickly. Other questions haven’t been as forthcoming with satisfactory answers.

Like other iterations I’ve worked on in the past, this market panel takes the inventory of a specific station’s commodity (trading goods) market and lists them. Unlike previous attempts, this is an integrated list. Previous attempts had been working under the assumption that I needed to have two panels: one for the shop inventory, and one for the player inventory. But that was unwieldy and required me to duplicate code, once for the player, once for the shop. And then they had to talk to one another to keep each other updated. Yeesh.

My decision to use a central data clearinghouse is paying off by helping to fix this issue. Now I’m taking more of an Elite: Dangerous method as opposed to the traditional RPG shop method. The list of commodities at any shop shows one row for each item. Each row contains the name of the commodity, it’s calculated price, the quantity in the shop, and a quantity that the player is hauling. The SHOP and HOLD columns will have buttons pointing at one another (SHOP > and < HOLD). Those buttons equate to “transfer one unit of this item in the direction of the arrow when I click that arrow”.

CommodityMarket2015

Testing the new commodity market layout (WIP).

What’s happening under the hood (eventually) is this:

  1. Clicking the arrow (not shown in the image above) updates either a SHOP_CART or PLAYER_CART collection with the quantity. The SHOP_CART is used when the player is selling, and the PLAYER_CART is used when the player is buying.
  2. The quantity of the item in the SHOP is calculated based on the quantity of the shop, and plus or minus the values in the CART collections. When a player is buying from the shop, the shop quantity should be diminished. But the carts are there to hold items until the transaction is complete; therefor, we need to take the shop quantity and subtract the PLAYER_CART amount from that value. We’re essentially putting that in escrow until the player decides to check out, or abandon the cart.
  3. At the same time, the value in the HOLD is the current count of that item in the player inventory, plus the amount in PLAYER_CART. So to the player, it looks like she’s bought — but not finalized — a quantity from the shop (seen the number go down) and transferred it to her ship (seen the quantity go up).
  4. All of this takes place simply by updating various data collections, and the display of the labels on each row are updated in the instance’s UPDATE statement. Polling the data collection runs pretty fast. In previous attempts I tried to have GameObjects communicate changes to one another, and that was a pain in the ass. This method updates data and lets the instanced shop item row handle the display. It’s much easier.
  5. When the player is done, she can click CHECKOUT. At that point, the quantity will be formally deducted from the shop using the SHOP_CART, and the the quantity in the hold will be incremented using the PLAYER_CART. Also, cash will be debited/credited accordingly. The carts will then be cleared.

One thing I’ve always wanted to do was to add an extra layer not usually found in trading sims, and that’s history.  I know that EVE Online has a kind of trading history, so players can see what the historical high and low prices were for specific items. In a single player game like mine, though, I think that data would be for edification, maybe for light analysis. Obviously you can see the difference in price between toilet paper and palladium, but what’s the profit margin? Is it better to haul toilet paper in one sector, even if palladium is available? This is why I need to work weight or mass into each item, and to create different classes of cargo holds, so you might be able to jam in more soft rolls of TP than you can carry in palladium bars.

First things first: I want to make the player inventory, a cargo hold view, and then get the buying and selling working.

Leave a Reply

  1. If you’re going to implement actual NPC traders, you’ll going to need the price history anyway to see whether they work properly. You’ll also need some rudimentary AI for the station merchants so that the prices change according to the actions of the players and the traders.

    One way to do this would be to specify that a station needs X amount of Y good per unit of time. Likewise, an another station might produce Z amount of that good per unit of time. Each side would also have a buffer of that good. If Z > X, then the buffer for the producer would start getting full and they would decrease prices to get rid of it. Likewise, the consumer would either not pay as much or stop buying altogether when their buffer would start getting full. And when Z < X, the buffers would empty and the prices would rise. This would give both the NPC traders and the player valuable input to base their trades on. NPC traders could also have different profiles: Some would accept only high profits, some could trade more per unit of time and some would travel further than others when evaluating prices. You could also add random events that would throw things out of equilibrium and see how the traders adapt.

    • Scopique says:

      I do have ideas for an expanded market system, but I need to get this transfer system working first because I can leverage it for later AI transactions

What do you think?