Might is Right, the game

Congrats @Usnul !!! So many good reviews already too! Very impressive

1 Like

I’ve been working on something interesting for a week or so. Meep game engine has a pretty comprehensive terrain system. It works with height maps and build geometry in rectangular chunks inside a WebWorker, asynchronously, when said chunk first appears inside a view frustum of an active camera.

Here’s a preview with each chunk having different color:

That has worked for me for all these years, but as it happens - there’s an invetable defect that I’m sure many of you have seen before in lots of games - stretching of textures at sharp angles. The cause of that is the UV map, the map is build uniformly, it’s basically a UV map for a planar grid.

I’ve written a UV optimizer, to fix some of that stretching, it re-distributes UVs at each vertex based on the amount of tension, basically treating the UV map as a some kind of stretchy super-heavy fabric that is allowed to move about to equalize the tension at any given point. There will be some stretch, that’s inevitable, but it’s no longer localized, instead it propagates across the entire UV map.

The solver is iterative, it finds a set of connecting edges for every vertex and then equalizes the tension across those edges by moving the UV coordinate for that vertex.

Here’s what that looks like in action for 7 iterations:

Here’s 1000:

I went with 21 iterations for now, it’s good enough and still dirt-cheap to compute:

Here is another scene at 21 iterations for comparison:
Before:


After:

Here’s with just the terrain and mountains in checker grid for clarity:
Before:


After(21 iterations):

It’s not exactly what I thought it would look like when I set out to write this thing, but I kind of like it.

The main point for me is that it reduces stretching and only adds 1-2ms of build time per tile, which is entirely reasonable for me.

Anyone know of other ways to reduce UV stretching?

4 Likes

I’m using triplanar mapping in Tesseract for volumetric terrain and partially for regular terrain as it requires all texture fetches 3 times for every map, partially as it’s only required for steep areas.

1 Like

that triple fetch has put me off the idea so far, it feels like there’s already a pretty heavy shader load in my terrain. Does it run okay on mobile for you? I mean using multiple textures as well as tri-planar projection.

Yes but that depends on many factors, the regular terrain is just 1 drawcall most times, and i use an atlas for every map type to reduce switching textures. I also use a spatial weightmap technique (1 index + 1 weightmap for all materials) instead a weightmap layer per material, so i understand that it becomes heavy with the latter as there are already many fetches then.

There are other ways to reduce stretches, basically like your approach relaxing the coordinates. Triplanar mapping sure gives the best result, anything between works only to some degree, but can already help enough as long as it’s just relatively smooth hills, but it also can have some advantage for non-organic materials, as triplanar mapping always straight blends the axes what works well for organic materials, but the issue becomes more clear by using something like a checkerboard.

1 Like

This looks great!

1 Like

Added tile decal image to terrain shader, something I wanted to do for a while. Fairly small and simple change, but really helps bring graphics up a notch.

Before:

After:

Having played around with different patterns, here’s the decal image I ended up with:
tile_square_styled_star6_128

Here’s what that looks like in combat:


And before:

for those curious, here’s a relevant piece of the shader:

vec4 computeGridOverlayTexel(const in vec2 grid_uv, const in vec2 grid_resolution){
	vec2 grid_texel = grid_uv * ( grid_resolution - 1.0) + 0.5;
	
	vec2 uv = grid_texel / grid_resolution;
	
	vec4 tile_data = texture2D(diffuseGridOverlayMap, uv);
	
	if(tile_data.a == 0.0){
		return vec4(0.0);
	}
	
	vec2 tile_uv = mod(grid_texel , 1.0);
	
	vec4 tile_color = texture2D(diffuseGridOverlaySprite, tile_uv);
	
	if(tile_color.a <= 0.01){
		return vec4(0.0);
	}
	
	return tile_color * tile_data;
}

//... somewhere in main

vec4 gridOverlayColor = computeGridOverlayTexel(vUvGrid, gridResolution);
vec4 diffuseColor = blendAlpha( diffuseColor , gridOverlayColor );
5 Likes

Hi Usnul,

Congratulation on this achievement.
Do you mind me asking how worth has your effort been so far financially?
I’m asking because I am working on a game too, but I always end up feeling “what’s the point”.
So many games on steam, it feels like unless you are able to advertise like crazy the game won’t sell.

Once again, it’s off topic on this forum, and I would perfectly understand if you didn’t want to share those details.

1 Like

I don’t mind. It’s a mixed bag. So far, I made ~2.5k $.

I spent around ~1k on marketing
I invested around 5 years of full time effort into it (that’s roughly equivalent of full time job)
I spent about 32k on assets
Development expenses ~360$ in server costs per year, ~200$ in license costs, over 5 years that’s 2.8k

So total investment is: 5y of my time + 36k $

What do you rate your time at, that’s a tough question, where I live, my rate is around 100k/year, making it about 500k $ over 5 years.


That said, the game is in Early Access, so it’s not a full release yet.

Is it worth it?

  • Honestly, I don’t think it is, not financially. I have learned a lot from this so far.

Why do I do it?

  • It’s interesting
  • I’m learning about making games, not just the code part but the whole release cycle
  • It’s a passion project for me

Do I hope to make a ton of cash from this? - sure :wink:

hope that helps!

4 Likes

Thanks a lot, that’s very interesting.
I’ll subscribe to this thread, don’t hesitate to share more on this as time goes on.

In any case, congrats on your dedication toward your passion, that’s very impressive. I hope I’ll be able to commit enough to finish my project.

I mean… 32k, I wouldn’t know where to find them… but thankfully my game wouldn’t require as much illustrations, and I can do the graphics myself.

1 Like

Hey Alex, do you mind if I ask you about your thoughts on using an engine like Unity instead? Have you seriously considered it, or maybe even regretted not using it? Especially now, with your game ported to native with Electron & Steam.
Or perhaps it was just that much more interesting to build it yourself with Three? :smiley:

Im very curious how it stands from a passion and business perspective.

Btw as a proud Might is Right beta tester, I’m patiently waiting for the full release :nerd_face:

3 Likes

I think Unity is a better choice for a smaller team, Unreal is also great. I have played around with both, but I do have more experience with Unity personally, and I think that its marketplace is am amazing resource, allowing you to get ready-made subsystems for your game on the cheap.

I started working on meep around 7 years ago, back then it was a mixture of learning 3d as well as making a game, it started out as an engine for a tower defense game. I was working as a JS developer, so it was also a great tool to learn new JS tech that was coming out with HTML5.

When I started working on Might is Right, I intended it to be an online co-op game, that idea was scrapped along the way. However, I envisioned it being played in a browser, with no download required. Thinking of enabling people to play it on just about any device. I looked around for a good WebGL game engine, and the pickings were really sparse. Unity had some alpha-level support with severely reduced feature set and barely any updates, there was Playcanvas that was basically a toy at the time and was missing majority of the features that I needed. So I decided to develop meep further and build Might is Right on that.

As a business decision it was really misguided; I found out later, when trying to market the game that the most complex thing about game development is not the actual development, but the marketing. Having an amazing HTML5 game is basically irrelevant if you don’t have a platform to sell it on. I approached various web-game distribution platforms with it, but they either offered me something laughable, like 100$ one-off payment or monetization schemes that I didn’t care for. Such as in-game ads. I quickly learned that the world simply is not ready for pay-to-own web games.

I think that whatever game you’re making, if you’re spending a lot of time building systems and engine parts - you’re in the wrong business. Large companies can afford to do that and even then they don’t. That’s why there are a ton of game middle-ware companies out there with everything from physics, particles, sound and AI to tooling. I don’t regret my path to this point, as it has been super fun, but if you’re starting out with the goal of making actual games - I don’t recommend it.

Thanks for that, your comments really had a huge impact for the better. The full release will probably be in a couple of months.

5 Likes

This is all very interesting, thank you for sharing! I have many more questions, but we probably don’t want to turn this thread into an interview :sweat_smile:

But if you ever find yourself with some time on your hands, then perhaps an article somewhere, about your long journey, would be something to consider. Im sure the whole community of not just Three.js’ers, but all web game developers, would greatly appreciate a resource from someone of your experience. Hell, you could probably write an entire book about it, if you ever wanted to :smiley:

I’ll be looking forward to it! And not a problem, it was my pleasure! Feel free to add DolphinIQ - feedback provider in the credits, anytime :rofl:

2 Likes

Baked soft shadows from static objects into various scenes:

Original:


With soft shdows:

here’s the shadow map (y is flipped):

Original:


With soft shadows:

Baking was done using a GLTF exporter and blender with some custom code to pull out various visual constructs from the engine.

my terrain shader is not exported, so the ground is just white, but what matters is that the vertex positions are there and the UVs are correct.

7 Likes

awesome game! I want to start developing my own game in Three.js, could you guide me where to start? could you give me your email? I’ll be very happy!

Feels like necroposting, but… I’ve recently been upgrading my terrain engine and I went with very similar approach. It might be exactly the same even. I checked out unity’s terrain implementation and it looks to be largely similar as well.

For those curious, there are 3 parts to this solution:

  • texture array, this is used to describe each individual material being used
  • weight texture, this is RGBA texture where each channel represents a “weight” of a material. This way each pixel can have a smooth mix of up to 4 materials.
  • material index map. This is also an RGBA texture where each channel represents material index. This is a counter-part to weight texture, when you look up both a weight and an index - you know which material to use and how much of it should be used in the final mix.

I’m quite happy with the implementation that I ended up with. The only snag so far is this: I’m not sure how to add support for compressed textures. Any clues? :slight_smile:

The issue is in using the DataTexture2DArray, it’s a raw texture format.

1 Like

I’ve been thinking of doing some color-grading, I tried using standard WebGLRenderer.toneMapping options, but they all produce an effect that doesn’t go well my what I have in mind. Here’s an example of ACESFilmicToneMapping, that looks the best to my eye:

and here’s the original, un-processed version:

On one hand, toneMapping does produce more saturation, which can look nice in a lot of cases, but it removed a lot of half-tone detail and makes shadows look much darker than what I want. Is there a simple solution to do color-grading and/or tone mapping in a more flexible way? I know I can just do a screen-space pass and change the color in whatever way I want, but I don’t want to add that extra pass if possible.

1 Like

I’ve been working on improving the user experience recently. Wanted to add segmented health bars into the game for the longest time, but never got to actually doing it.

Past couple of days I actually got the time to do it. Here’s the result:

The idea is dead-simple. Segmentation helps provide a visual cue to the player of how much health a unit has relative to other units. Since bars provide a normalized cue only - i.e. you can only tell the percentage.

When you look at a bar of health, without any extra marking you can only tell the % of remaining health, but now whether that’s actually a lot or not. For example, a unit with 10 maximum health having 2 health left might be in a worse situation than a unit with 20 health left out of maximum 100. To help player process that - we break up the bar into segments, each segment representing an arbitrary fixed amount of health. That way you can look at someone with 2 segments left and immediately know that he’s in a worse situation than someone with 20 segments left.

Here’s an illustration of what that looks like:
2020-07-18 14_24_42-Might is Right

To help visualize this relative health notion - here’s an example from DoTA:
image

You can clearly tell that a Pudge with 3509 HP has more health than Pudge with 2449 health without having to read the numbers, just by looking at the segments and thinking “that’s more segments”.

Anywho, back to Might is Right. I initially created 2 segmentations, “minor” and “major”, like in DoTA, where in DoTA it’s 200hp and 1000hp respectively. I played around with that design and quickly came to a realization that in my game, health doesn’t scale so neatly. You start off with maybe 50hp, and by the end of the game you fight bosses with 30k+ hp, those numbers are simply too far apart.

You end up with a mess of indistinct lines.

So… after a bit of thinking, I framed the problem differently. The segments are just symbols, DoTA uses 2 symbols (major and minor), but there’s nothing stopping me from having more. So I did that, I created a larger scale with different segmentation styles.

That ended up being quite readable.

When I tried it in the game, it ended up looking unclear. Because of the numbers being overlayed on top of the health bar. You can’t see the segments clearly behind those numbers.

After much though I got rid of the numbers. Initially they were very important, as the game is mostly deterministic and chess-like. But, because there are so many different customization mechanics in the game right now - those absolute values are much less meaningful now (or so I think). To compensate for missing numerical values, I added a highlight to the health bars, to visualize how much damage/healing an ability would do. What do you guys think, is this UI readable?

4 Likes

A small update, I’ve added path visualization into the game. It’s a fairly standard feature in many turn-based strategies, when you issue a move command, a visual representation of the traversal path is displayed to the user and as the character walks, the path markings get erased behind the character.

I implemented this as a separate sub-system in the engine, it borrows from SVG path styling specification, having 4 styling elements:

  • start marker
  • end marker
  • main marker
  • marker spacing (this is a guide, more like “minimum spacing”, since actual placements are justified based on the path length).

Each marker specification has some properties as well, such as rotational alignment to path as well local transform (rotation, position, scale). Each marker is a full-blown entity, similar to a Prefab in Unity. So you can have animated 3d kittens, particle effects, sounds etc if you wanted to. I just use a 3d model of a simple golden sphere.

I used the same system to visualise enemy AI pathing also, using slightly different styling (red ‘copper’ spheres).

7 Likes

really cool!! amazing work!

1 Like