v1.10 patch notes

WARNING: CHANGE YOUR HOTKEYS TO DEFAULT BY GOING INTO THE MENU OPTIONS AND HITTING "RESTORE HOTKEY DEFAULTS." IF YOU DO NOT DO THIS, YOU ARE GOING TO HAVE A BAD TIME.

  • New build options: houses. Houses cost 100 gold and increase your population limit by 3. Upgrade to tier 2 and 3 (10 gold each) to increase your population limit by 4 and 5, respectively. 
  • New build option: mining camp. Mining camps cost 50 gold and generate income over time. Mines start out generating 7 gold per 5 seconds and this amount diminishes over time until the mine collapses. 
  • Castles now produce 2 gold per 5 seconds instead of 6 every 7 seconds. 
  • Castles now provide only 5 supply instead of 15.
  • The default / minimum population is now 15. i.e. if you have no houses and no castles, you will have 15 population. 
  • Start gold increased from 150 to 350.

Reason for houses and mining camps: To reduce the strategic important of castles. Currently, castles are the end-all be-all. The player with the most castles, wins, almost always. This is so because castles provide 1) income 2) supply (pop limit) 3) map control and 4) military strength. The goal in this patch is to relegate some of the strategic advantages of castles to other buildings (namely houses and mines relegating supply and income). That way, players must adopt more creative strategies -- besides simply capturing all the castles -- to win.

  • New build option: blacksmith, costs 225 gold.
  • New units: hand gunner (tier 2) and mounted hand gunner (tier 3), trained from the blacksmith. These units have their own sub-class (gunpowder) and are weak against missile / archer units (missile does double damage to gunpowder units), but strong against buildings (200% damage vs. buildings). Additionally, gunpowder units, as opposed to missile units, have bloom which causes them to fire at slightly randomized angles and miss occasionally. 

Reason for these new units: A dedicated anti-building unit is much-needed to prevent stalemates and tower spam.

  • You can now sell buildings (except castles and mines) if the building was not attacked recently using the delete key. Refunds are 50% the original purchase price of the building.
  • Barracks now costs 150 instead of 125.

Reason: To prevent polearm spam as a valid strategy and encourage unit diversity.

  • Cavalry now do half damage against pole arm

Reason: Although pole arm had massive DPS vs. cavalry (220% damage), it didn’t matter because low health coupled with cavalry high DPS causes the pole arm unit to die too quickly. This will make pole arm a hard counter to cavalry.​

Other changes:

  • Significantly improved performance for mid to late game, when there are a lot of units on the map. 
  • Upgrades are significantly cheaper (30% original price of building multiplied by the tier, instead of 50%). 
  • Castle unit spawn time reduced from 30 sec to 25.
  • Non-castle unit spawn time reduced from 20 to 15.
  • You are now forced to place castles in such a way that leaves walkable areas around the castle.
  • You now get a message warning and text flash if you reach your population limit.
  • In-game text for earning gold (e.g. when a castle earns gold) are now more legible with a black stroke.
  • Refunds for canceling a building or selling, now shows in plain text.
  • Longbow damage reduced from 26 to 22.
  • Set the minimum victory time to 50 seconds because a lower time was causing bugs in the map editor test mode.
  • Units now fade after 15 seconds instead of 60 (for better performance).
  • Fixed longbow arrows looking like the smoke from newly placed or destroyed buildings.
  • Added sounds for the house, blacksmith, tower and mining camp. 
  • Home screen music now plays every 5 hours instead of 24. 

Feudal Wars is back!

[x-posted from Kickstarter]

It has been almost 2 years since development of Feudal Wars went on hiatus. In that amount of time, I created two games: Strike Tactics and STBA.io. Several weeks ago, I made the decision to finish Feudal Wars as my next game!

Because I am utilizing the engine I built for Strike Tactics (instead of starting from the old Feudal Wars codebase), Feudal Wars is actually very far along. I am very close to a multiplayer pre-alpha and I intend to have a finished game by March (3 months from now) at the earliest, and April at the latest.

The game engine is fundamentally different from the one built for the demos currently accessible at feudalwars.net. The biggest change concerns performance. Environment (such as mountain and trees) won't be rendered as individual entities, allowing the game to run at a smooth 60FPS with 1,000 units on the map on good machines. Another major change relates to pathfinding. In summary, units will find the quickest path possible, regardless of what that does to change their formation. 

In addition, many things have changed concerning the original scope and vision of the project. I no longer wish to make a “full blown RTS” but instead, a form of gameplay which distills the fun things about RTS (unit control, base-building, etc) while shedding the (sometimes) boring and time-consuming aspects (eco-management, production, etc). My ultimate goal has always been to make a traditional “highly accessible RTS” that anyone can enjoy, including younger kids. I'm still doing that. The only part I'm changing is the "traditional" part. 

I recognize this is very different from my original vision - which was to make a purebred classic RTS. I feel I accomplished that goal with Strike Tactics and want to take Feudal Wars in a different direction. I want to make something more approachable but with the same level of depth.  

Because it is constantly changing, I have decided to not go into an in-depth explanation of what gameplay will be like in the new Feudal Wars, but I can say that I have elaborate plans. Here are some bullet points concerning gameplay:

  • You will be able to choose civilizations which have special units and bonuses. I intend to have at least 5 civilizations at launch (French, English and Teutonic Order are givens).
  • The standard game mode will be free-for-all, aligning with the theme of the middle ages which more or less, was a free-for-all (kingdoms divided into smaller parts or fiefs, constant warring between factions, etc). This tones down the competitive aspect because things won't be "head to head." However, there is nothing stopping me from releasing other more competitive game modes (such as 1v1 or 2v2) later on. 
  • Gameplay will focus on the military mechanics found in traditional RTS games. Unit control, map control and military strategy will determine your success in the game. Building and capturing castles will allow you to gain map control. There won’t be a long 10-15 minute slow period at the start of the game in which everyone is focusing on developing their economy. Instead, military conquest and map control will be the driving force behind the game mechanics (and by that I don’t mean control points). You will however, grow your kingdom and army as the game progresses. There will be huge incentives for attacking, which will make games short and fast-paced.
  • There will be 2 classes (infantry/cavalry) and 3 subclasses (polearm, missile and sword) making a total of 6 unit archetypes. Each archetype will have strengths and weaknesses. Buildings will be considered a pseudo-class. Each subclass will be accessible from all civilizations and will have 3 tiers (e.g. tier 1, tier 2 and tier 3 polearm). 

Great efforts will be made to make it easy to find games. Although there will be a somewhat hidden lobby system you can access, the default screen will funnel all players into a single queue for finding free-for-all games. We’ll start with that and expand as the game grows.

Who is working on the project? 

Currently, I am the only one working on the project. All of the original Feudal Wars team members are busy working on other projects. However, I would happily hire them back if they were interested. Realistically, this won’t happen till after Feudal Wars has launched and made some money. 

What about art? 

Before FW went on hiatus, Jorge (the lead artist) was kind enough to donate all of the assets he created for the Age of Chivalry AOE2 mod. These assets will essentially fill in the gaps for much of the unit art which is missing. Ground textures, trees, buildings and most environment art was complete before FW went on hiatus. Thus, I have everything I need in the art department to complete the game. 

Contour Chromatic (a collaboration between British composers Robert Sword and Giles Thomas) will be producing an original soundtrack, as originally planned. 

How much will the game cost? 

The game will be free, supported by ads, and accessible from any browser, but will work best in Chrome. If your computer can play stba.io, it won’t have any problem with Feudal Wars. Feudal Wars in fact, will have smaller hardware requirements than stba.io or Strike Tactics. 

How can I get involved? 

You can get involved by joining the Discord which is the best way to interact with me and also where I will make important announcements and field questions. I'm pretty much perpetually on Discord, so it's the best place to get in touch with me. 

Invite link: https://discord.gg/SQFMnMK

I hope to see some of you there. I am excited to finally complete this project as it has always been lurking in the back of my mind. I learned a lot about game development in the last two years (specifically browser game development), and I like to think I am much better equipped than when i started with Feudal Wars. 

I will do my best ... stay tuned for further updates! 

The next step: a mini-game

Now that a demo of the map editor is complete, I can start working on a playable version of the game. That’s really what people want. Making maps is fun but if you can’t do anything with the maps, what’s the point? It’s like making a car but not having any gas to power the car. There’s only so much enjoyment you can get out of staring at a car. What you really want to do is *drive* the car. 

I needed to build the map editor because it assists me greatly with the development process, but now that it’s done, I can start building the fun stuff. I’ve already completed most of the core game mechanics like pathfinding and basic unit attack AI. Although I’ve not showcased it anywhere, all of the units have attack and death animations. It needs major tweaking, but the foundation is there.

Instead of working towards the full completed version of the game, I’ve decided to aim for a smaller, easier and more realistic target first. My plan is to start working on a tower defense mini game, which I will release by mid-October. The mini-game serves a few purposes:

  • It will help to promote the game before the full version is released.
  • It greatly reduces the scope of creating a ‘playable’ version. The mini-game will not have multiplayer and all of the art assets used will be existing assets already implemented in the game. It also won’t have a lot of the components the full game needs to have, such as player coloring, tech trees, unit balancing and all the bells and whistles. Every component of the game, including core game mechanics, will be greatly simplified to reduce the scope. I want to get something playable out to you guys as soon as possible. 
  • It serves as an introduction to core game mechanics. Believe it or not, RTS is not considered a mainstream genre. Or, if it is, It’s considerably less popular than the Tower Defense genre. This is because RTS games have a huge learning curve. By making a Tower Defense mini-game with lots of RTS mechanics mixed in, it gives non-RTS players a watered-down version to serve as an introduction to the genre. It’s RTS-light. Players can familiarize themselves with the controls and core mechanics, and when the full version is released, they won’t be so overwhelmed. They will know how to move a group of units from one location to another. They will understand the basic concept of a player economy and how to use those resources for buildings and units. 

Here’s a basic outline of what the mini-game will be:

  • On the map, is a small town and on the opposite side of the map is a forest.
  • A 2-minute timer begins. You have some resources starting out and can use those resources to build walls, towers and units. 
  • The units are spawned from buildings surrounding your village. You can change the rally points for where the units will run to after spawning. 
  • Once the timer runs out, enemy units begin spawning out of the forest. I haven’t decided yet what these enemy units will be. Possibly goblins or zombies? I don’t know yet. But these enemy units will try to break down your walls and make their way to your villagers. It’s your job to kill as many of them as you can. 
  • The more enemies you kill, the more resources you gain and with those resources, you can build additional defensive structures and units to defend your town. 
  • The enemy units will come in progressive waves (sort of like nazi zombies) and once they kill all your villagers, the game is over. 

That’s the basic outline. I’ll likely run contests to see who can get the best time. 

So, those are my plans for the immediate future. A Tower Defense mini-game, then possibly a kickstarter, then the full version. I think it would be foolish to go straight for the full game as I am just one guy. Instead I’m breaking up the development process into tiny pieces (map editor, mini-game, beta, full release, etc) not only for my own sanity but so that I’ll have something to show for every step in the process.

If you have any questions/advice/feedback, I’m all-ears!

New animated isometric water tiles

I received tons of positive feedback from the map editor prototype video. A common theme was: "wow, looks incredible, but what's the deal with the water?" The water in that video was more of an experiment with Phaser filters. Using fractals ended up not working out because it put too much of a heavy load on the renderer (10-20% at times) and it could not be blended or masked to work with the ground textures.

This video demonstrates my second attempt at animated isometric water.

The animation is created from a single image file (below). 

It actually looks quite good with any ol' water texture, even ones that are non-isometric. This is ideal because I want players to be able to upload their own water textures in the map editor and multiple files would complicate that. 

To achieve the effect, I'm using two Phaser.Tilesprites on top of each other. Both scroll the same texture (water image above) in the opposite direction. The one on top has a reduced opacity (30%). It's that simple!

The hard part really was creating the beach texture which goes on top of each tile placement. The tiles themselves are masks of the scrolling tilesprite. It would be too much of a performance-suck on the webgl renderer to create individual scrolling tilesprites for each tile, so instead of creating many tiny tilesprites, I'm created one big one, with masks applied on the areas of the map a tile is placed.

When a tile is placed, a series of operations take place:

1. A grid is checked to determine if that area isn't already occupied by a water tile or game object.

2. A grid is checked for adjacent water tiles. A string with 4 digits is generated from the check to represent the kind of configuration the beach needs to have:

0-0-0-0: Represents 0 adjacent tiles

0-1-0-0: 1 adjacent tile to the right

0-0-1-0: 1 adjacent at the bottom

0-0-0-1: 1 adjacent at the left

1-1-1-1: adjacent on every side (i.e. no beach texture required)

etc ...

As you can see there are quite a lot of possible configurations.

Actually, there are 15 total, not including 0-0-0-0. There reference image above is inaccurate.

3. Once the configuration is determined, the appropriate beach texture is added on top of the mask. The 4-digit text string maps directly to filenames. So if the function receives a 0-1-0-0 string, it knows to use beach_0-1-0-0.png:

4. The operation is then repeated an all tiles adjacent to the newly placed tile. Adjacent tiles need to have their beaches updated as well because their configuration has changed when a new tile is placed next to them. 

It probably still needs work, but I think the new animated water is a vast improvement from the old.

Later I'll add functionality for adding various depths of water and I may just change the shape to be that of a rhombus instead of a square, which (I think) is a more appealing tile shape for isometric games.  

Saving and loading a large HTML5 canvas with Phaser

In addition to spending a lot of time on the server-side stuff last weekend, I was able to completely finish the save/load functionality. It's actually quite a bit different from what I originally intended - and different in a good way. For one saving/loading runs completely from the client-side, which is a contributing factor in how fast it is.  

When you want to save a map in the map editor, you simply click the "Save Map" button under the "Settings" tab. You'll then start to download a JSON file to your downloads folder. The JSON file is self-containing, without external references. There's two reasons why I made it self-containing:

  1. You can load it up offline and it will still work. 
  2. If there were external references to images in the map file and those images were moved or deleted, the map file wouldn't work. 

The biggest disadvantage of not using external references is file size. If I had used external references, map files would be mere kilobytes. But because I'm storing edited areas of the canvas with the base64 encoding scheme, the files have the potential to be 10-15MB+. File size will vary greatly, in fact, and I'll explain why below. For every 1000 x 1000 square-pixel area of the map you edit with the brush tool, an additional 300KB is added to the file size. 

Because of this, I'll likely add an option to save a light-weight version of the map file, with external references to images stored on Amazon's S3. 

How it works - you can stop reading now if you have no interest in programming

In my game, there are two aspects of the HTML5 Canvas that need to be saved: game objects and the texture layer. The game objects consist of everything you can interact with in the game: units, buildings, trees, etc. In my game, those game objects are Phaser.Images and Phaser.Sprites. Saving those is easy and I won't go into detail on that here. The basic idea is that you loop through all of your game objects, store their x/y coordinates, image keys and any relevant data into the object that will go into the file the client will download.

The texture layer is the hard part. In Feudal wars, the 'texture layer' is the landscape created by the map editor's brush tool which blends textures on top of an orthogonally-tiled base texture (grass is the default). Although the tiles in the texture layer are images and bitmap data objects themselves, they differ from regular game objects because their pixels are altered by the brush tool. This is why I need to 'take a picture' of them. I can't regenerate them from their base textures because their pixels are altered from their original state.

Normally, with these kinds of games, saving and loading doesn't need to be all that sophisticated. But in my particular game, saving and loading is complicated by two factors:

  1. Browsers aren't designed to save/load content from a user's local machine. They're designed to upload/download content from a web server.
  2. My texture-placement system is completely unorthodox. In typical 2d map editors, textures are placed using a grid-based system. My texture placement system isn't constrained to a grid. The reason why they are typically constrained to a grid is because of one simple fact: if the placement of textures can be recorded with simple x/y coordinates, you don't need to save the textures in the map file. You only need to save the x/y coordinates of the textures that are placed and then you can regenerate the map procedurally from within the game. 

Problem #1 was solved easily thanks to the File API which works surprisingly well in all modern browsers. Problem #2 required a bit of thinking. It's one thing to save the visible portion of the canvas as a dataURL and write it to a file - any chump can do that. But to save the entire canvas in a manageable file size, including the invisible parts not being rendered, when it's 15,000 pixels in width/height and in webgl mode**, now that's tricky. If you were to save a 15,000-square-pixel map as a PNG for example, your file size would be in the gigabites. And that isn't even an option because, with memory constraints, browsers aren't capable of processing that much data anyway. 

My original plan was to rely on server-side processing. If I could send the canvas data piece meal to the server, I could have the server process it, compress it and send it back as a single file in a manageable format, such as a zip.

So I set about slicing up the data into small bits that could be sent and processed by the server. What I ended up figuring out was that I could slice everything in such a way that I didn't even need server-processing. Instead of taking a picture of the entire canvas and putting it into string format, I took pictures of only the parts of the canvas I couldn't procedurally regenerate. The only parts of the canvas I couldn't procedurally regenerate from the base tiles were the parts affected by the brush tool. So it was only a matter of identifying those affected parts and extracting their base64s. Here's what I did to accomplish that. 

1. Create a grid representing the entire game world. The node sizes in the grid are 1000 x 1000 pixels. Inside each node, place a Phaser.Rectangle at the appropriate coordinates. You can use a nested for loop to determine the coordinates:

function createCustomizedTilesGrid() {
    customizedTilesGrid = {
    };
    
    customizedTilesGridNodeSize = 1000;
    
    customizedTilesGrid.width = fnRound(game.world.width / customizedTilesGridNodeSize) + 1;
    customizedTilesGrid.height = fnRound(game.world.height / customizedTilesGridNodeSize) + 1;
    
    for(var i = 0; i < customizedTilesGrid.height; i++) {
        customizedTilesGrid[i] = [];
        for(var q = 0; q < customizedTilesGrid.width; q++) {
            
            var topX = (q * customizedTilesGridNodeSize);
            var topY = (i * customizedTilesGridNodeSize);
            var rect = new Phaser.Rectangle(topX, topY, customizedTilesGridNodeSize, customizedTilesGridNodeSize);
            customizedTilesGrid[i][q] = {
                'customized' : false,
                'rect' : rect,
                'debugColor' : 'blue'
            };
            
        }
        
    }
    
}

2. Whenever an area of the canvas is altered, mark it in your grid. To determine which areas are marked, I’m checking for intersections with the brush tool and the Phaser.Rectangle in my grid, then setting a property called "customized". I'm debugging by coloring in the grid nodes as red or blue, customized and not customized, respectively.

function markCustomizedNode(brushCircle) {
	
	var brushBounds = brushCircle.getBounds();
	
	if(customizedTilesGrid != undefined) {
		
		for(var i = 0; i < customizedTilesGrid.height; i++) {
			
			for(var q = 0; q < customizedTilesGrid.width; q++) {
				
				var rect = customizedTilesGrid[i][q].rect;
				
				if(Phaser.Rectangle.intersects(brushBounds, rect)) {
					customizedTilesGrid[i][q].customized = true;
					customizedTilesGrid[i][q].debugColor = 'red';
					
				}
				
			}
			
		}
		
	}
	
}

function debugMarkedNodes() {

if (customizedTilesGrid != undefined) {

            for (var i = 0; i < customizedTilesGrid.height; i++) {

                for (var q = 0; q < customizedTilesGrid.width; q++) {

                    game.debug.geom(customizedTilesGrid[i][q].rect, customizedTilesGrid[i][q].debugColor, false);
                }

            }

        }

}

3. When a user clicks "save map," extract the base 64s from the marked nodes and their x/y coordinates. To accomplish this, I’m drawing the entire texture layer into a bitmap data object using drawGroup. Then I copy the area of my texture layer (topLayerBMD) which corresponds with a marked node and extract the base64 from its canvas property:

function getCustomizedBase64s() {
    var customizedTiles = {
    };
    var topLayerBMD = game.make.bitmapData(game.world.width, game.world.height);
    
    topLayerBMD.drawGroup(topLayer); // if the map size is too big, webgl cannot do this on some browsers
    var tileNum = 0;
    for(var i = 0; i < customizedTilesGrid.height; i++) {
        
        for(var q = 0; q < customizedTilesGrid.width; q++) {
            
            if(customizedTilesGrid[i][q].customized) {
                var rect = customizedTilesGrid[i][q].rect;
                var bmd = game.make.bitmapData(rect.width, rect.height);
                
                bmd.copy(topLayerBMD, rect.x, rect.y, rect.width, rect.height, 0, 0);
                var base64 = bmd.canvas.toDataURL('image/jpeg', 0.60);
                base64 = {
                    'base64' : base64,
                    'x' : rect.x,
                    'y' : rect.y
                };
                
                customizedTiles[tileNum] = base64;
                tileNum++;
            }
            
        }
        
    }
    
    return customizedTiles;
}

You've then got all the image data you need in a nice, neatly packed array (the return value of getCustomizedBase64s)

And that's pretty much it. From here, it's just a matter of saving your base64s and x/y values, saving the data (ideally in a JSON) and reloading with the File API. I won't go over saving/loading data using the File API in this tutorial, but here's an idea of what your code should look like when adding the base64s back to the game world. "mapFileContents" is the object containing data from the loaded file. Note that I'm using jQuery here to loop through the customizedTiles object. I tend to use jQuery a lot as a utility. $.each provides a much less verbose way to loop through objects/arrays than the native javascript for loop. 

function addCustomizedTiles() {
    var customizedTiles = mapFileContents.customizedTiles;
    
    $.each(customizedTiles, function(key, object) {
            
            var tileX = object.x;
            var tileY = object.y;
            
            var image = game.add.image(tileX, tileY, 'customizedTile' + key);
            
            topLayer.addChild(image);
            
        });
}

** Normally when you attempt .toDataURL on a webgl canvas, your dataURL doesn't have anything except black pixels. To get around this, I set preserveDrawingBuffer on the canvas's webgl context. This has possible performance implications, but it will save the canvas the same way it would in a 2D context. If it is feasible, a better option would be to draw the entire canvas into a second canvas with a 2D context, then extract your strings from there. 

Tags: 

Converting to a database-driven model

I spent most of memorial day weekend pacing back and fourth in my apartment trying to devise the best possible drupal architecture to share and manage game content. 

Currently the games data consists mostly of URIs and object properties relevant to the various different kinds of game objects (trees, units, buildings, etc). The kind of information that would ideally fit in a database. But because the game runs on the client side, it made sense to put everything into a single JSON file. After all, it isn’t that much data and it isn’t going to change all that much, except when new versions of the game are released.  

Now that I want people to be able to add their own content to the game and share it publicly, I have to rethink that approach. The data isn’t static - it changes, and frequently, sometimes in the same user session.  And it isn’t a small amount of data we’re talking about anymore. The database size has the potential to become extremely large if enough people contribute to the public repo. Game content needs to load dynamically from the server instead of from a single static JSON file. In addition, data is retrieved/output based on parameters specific to users. 

Say Armando uploads a texture and puts it in the public repository. Emilio, browsing the public repository, loves Armando’s texture, so he click the “add to account” button. From that point on, Emilio will always have access to Armando’s texture in the map editor. The next time Emilio browses the public repository and sees Armando’s texture, a button, “remove from account” will appear in place of the “add to account” button. In addition, Emilio can remove the texture from his account from within the map editor interface. 

I won’t go into the nitty-gritty of how I rewrote the data model to satisfy both Armando’s and Emilio’s needs, but the end result is that I’m using the same (or variations of the same) server-side code (a la drupal views) to retrieve and output data from the database, wether that data is specific to Emilio’s account i.e.:

  • Stuff Emilio has uploaded and kept private 
  • Public assets Emilio has added to his account from other accounts

Or, if that data is universal, i.e:

  • Public assets 
  • Official game assets 

And, on the client-side, the JS functions I’m writing to load content into the game world will work from the same output structure by the above scenarios, regardless of wether that content is:

  • Added dynamically, from the database, after the game has loaded when a user clicks “add to account” when browsing the public repo
  • Added Emilio-specific content from the database at the beginning of the browser session 

In summary, i’m killing a whole flock of birds with just one stone. Granted it’s not just any old stone - it’s a special stone, a stone I spent all weekend chiseling, smoothing and perfecting. Because I’m thinking long-term here. I’m thinking about how this thing is going to scale and how efficiently the server will operate running 2 or 3 queries to load game content instead of just one. And it’s a heck of a lot easier to make a change in 1 place as opposed to 2 or 3. 

If it’s anything writing code for this game has taught me it’s how to abstract code in such a way that in can be re-usable in different scenarios. Of course, as a web dev, I’ve always been aware of this concept but it takes on a whole new meaning when developing a game.

Tags: 

Map editor launch date

My goal is to have a publicly accessible beta version of the map editor up by June 20th. By that time, I’ll have finished the sharing functionally which (i’m hoping) will greatly expedite things in the art department. By “sharing” I don’t mean sticking a Facebook Like and Twitter button in every nook and cranny of the game (what ‘sharing’, unfortunately, has come to mean these days), but sharing of custom artwork and maps. Here’s how it will work. 

You register an account at feudalwars.net and load up the map editor. Every time you upload a custom art asset, you will be presented with an option to make the asset public. This will put your artwork in a public repository which other players have access to. 

When you have finished creating your map, you can choose to export it which is a way of saving it permanently (outside the browser session). In the export window, you’ll be presented with an option to share your map publicly. If you select that option, the map will go to a public repository on export. I’m putting the option in the export feature to save bandwidth. I need to send all map data and process it on the server-side anyway so it only makes sense that data should make the trip to the server and back only once. 

Here’s what I have planned for the public repository:

  • Sort by asset type: artwork or full map. 
    • Artwork can be sorted by various types (e.g. textures, buildings, trees, bushes, etc) and an author-created tag. Each asset will have an auto-generated thumbnail of the asset, an author (linking to the author’s account), and an option to add the asset to your account. Once the asset is added to your account, you can use it inside the map editor. It will show up in the respective category, marked in some way to indicate it’s a custom asset and will likely have a tiny link to meta info. Clicking the meta info link will bring up various meta data: creation date, author, size, etc.  
    • Maps can be sorted by most recent and most popular (and probably various other sort filters, like size). Each map list item will have an auto-generated thumbnail of the map, an author (linking to the creator’s account), meta info, a download link and a link to open up the map in a separate browser tab. 

I realize that all of this sounds like a lot to accomplish in one month but Drupal, my CMS of choice, will do a lot of the SS heavy-lifting, including: session handling, user login + authentication, and, in general, retreiving, sorting and displaying any content stored in the database. 

Forseeable problems

1. Custom game assets won’t work with pathfinding. I’ve thought about that and have been working on developing a system for users to manually mark walkable/unwalkable areas of their custom game assets. It’s really not rocket science. In 9 time out of 10 scenarios, the walkable area of the image is simply the area with transparency. Then you consider proportion of the object’s width/height and its 3D projection on the plane. It’s something that can be done by eye. An interface with a grid overtop the game asset would work. Users could mark which nodes on the graph are walkable/unwalkable. As it is now, when you upload a custom asset, the system “guesses” as to what areas of the image are walkable and non-walkable. This guess will be the default if the user forgets to mark the image.  

2. Bandwidth. I’m currently trying to figure out a way to cut down on map file sizes. Because my editor performs complex and resource-intensive operations on bitmap objects, there really isn’t an easy way to procedurally regenerate the map by recording user inputs and feeding them back into the engine at high speeds, which is the only way I could possibly get small file sizes of such a data-rich environment. After debating this subject on the html5 game dev forum,I’ve decided to go the server-side route. The basic idea is that I’m cutting out areas of the map which are editing with the brush tool, converting them to string format (base64s), compressing them in some way, sending them (along with other map info) to the server for processing and, finally, receiving a zip file from the server as a response… yeah it’s just as complicated and difficult as it sounds. And it means the map editor isn’t 100% client-side i.e. you need to be online to save maps. I suppose I’ll need to get around this by adding the functionality to save your map to local storage. The data limit for LS is 5MB, so you would only be able to store 2 or 3 maps at a time, unless you manually changed your browser’s limit. I’ll need to explore that later. 

Tags: 

Plans for save/load game functionality in Phaser

The next big thing to work on is the save/load game functionality. I want to get this done ASAP because after that I can release a demo of the map editor for people to mess around with. They can contribute to the game by uploading their own art assets and creating ladder maps. I have a tentative plan for achieving the save/load game functionality in-browser and I'll outline it here.

The meta-data for all my game objects (things like unit type, tree type, etc) are neatly organized in a JSON file. The most important data I need to save for game objects (trees, units, buildings, etc) are x/y coordinates and the key for the JSON file which will tell me everything I need to know about the game object. I can recreate game object attributes by looking up their keyed values in the JSON file. There's also player data like which team the unit belongs to and stuff specific to different game objects types, such as the health of units, and their currently facing direction but I won't worry about that right now.

The second big part of this is saving the terrain (grass, snow, dirt, basically anything you draw onto the canvas using the brush tool) which is in an entirely separate layer from game objects. My plan is to utilize the toDataURL method to save the entire canvas (minus game objects i.e. objects placed on top of terrain) in a string format. Then I can recreate the canvas with my base64 string. 

So, in summary, I can recreate the static aspect of the map with the base64 string and the dynamic aspect (units, buildings, trees, etc) with my JSON. Users will be able to download the current game state in a text file (likely, a JSON) and upload it to load the map. 

Possible problems

  1. I'm not sure if the toDataURL method encodes the entire canvas into a base64 or if it encodes only the visible portion of the canvas. Or, it could be that Phaser is incapable of drawing an image to the entire canvas using image data. My experience in trying to draw the entire canvas has led me to believe that at least one of those is true or needs to be worked around. I know that if you try to draw the entire game canvas into a Phaser.BitmapData object, you only get the visible portion if you try adding it to the game as a  Phaser.Image or sprite. I've worked around this in the past by relying on the BitmapData.drawGroup method, which miraculously draws the entire group into a bmd, regardless of wether or not the entire group is visible. I don't have that option now because, when loading maps, I need to draw a base64 instead of an existing Phaser.Group. 
  2. Because my canvas is in webgl mode, I'll need to use preserveDrawingBuffer for toDataURL to even work. This has performance implications. An alternative is to draw my webgl canvas onto a canvas with 2d context, and save the base64 of the 2d context instead of the original webgl context. Something like this: context2d.drawImage( webglCanvas, 0, 0 ).
  3. If that map size is huge (and my game will have huge maps), the base64 string will be huge. Experimenting with a 2000 x 2000 pixel map, my base64 was 3MB ... that's 3MB of pure text. Probably a lot smaller than if I were to save the canvas as a PNG, but it's still a problematic file size. 3MB is big enough to crash notepad and the file size will only increase exponentially as the map size increases. Games like aoe2 didn't have to worry about this problem. Because texture placement was tile-based, they could procedurally recreate the map with a simple 2D matrix. But I need to save an entire image of the static layer of the map.

So, basically all my problems are related to the fact that I just had to have non-tiled based texture placement. I foresee many long and sleepless nights trying to figure out all the workarounds. Lots of sighing and grunting and hair-pulling... I guess that's the price of innovation! 

 

Tags: 

Pages