—    —  Home

   JLJac on January 19, 2016, 01:17:07 PM:

@David Berman thank you for your post and your gorgeous photos!

I second everything James wrote above, but I'll try to give my angle. Yep, we have thought about more recognizable architecture, but we gravitated away from it. For a few reasons, the main one definitely being that one James mentioned. If you can recognize too much in the environment ("That there's a fire post", "that there is a roof drain pipe") the environment wouldn't feel alien anymore. As the creature you play is supposed to not really grasp what's going on in the world around it, the player should be in on that impression. We are going for a thing that's more abstract or expressionistic - what's displayed on the screen is supposed to serve an emotional narrative, and that emotional tone has "not quite understanding what's going on" as a very important center piece.

Another is that recognizable objects cement the scale too much. Experiments with assets such as a door frame and similar has had the outcome that the viewer apply human scale to them by default - and then the slugcat and everything else is given a very distinct relative size which is something we're not really comfortable with. How big is a slugcat compared to a human? Waist-height, knee-height, almost as tall? We definitely prefer never to answer that question and not have the player think about it either. Slugcats, vultures and the other creatures exist in Rain World, and its their sizes compared to each other that are relevant.

Working with this style for several years now we may also have developed a few in-world reasons why you don't see much in terms of living-quarters, but I can't even dip my toe in that without major spoilers Wink

As for flying creatures bumping into walls, yes they do! And yes I'd like them to do that less hahaha  Cheesy I'll probably try to work with it a bit more before release, but it's difficult to get the creatures to move ... gracefully. The reason is that the animation isn't animated frame-by-frame, instead it's all AI driven, and I can only make those AI behaviors so good. My animation technique could probably hardly be applied to a horse, dog or human for this reason - it's all very clumsy and unnatural. With these fantasy critters though we have the benefit of the doubt, even if I realize that only stretches so far.

@io3 creations, Thank you, and nope! It's 2D sprites being squeezed and rotated, combined with a few two-dimensional triangle meshes and lots of smoke and mirrors. There aren't really much in the way of sprite sheets, just code. "You want to move your arm here, but the arm is here, apply force in this direction" - that sort of stuff.

Update 516

Save states coming along rather nicely! After some consultation with James I split the save file into a "Player Progression" object which keeps track of basically how much you have unlocked on your copy of Rain World on your computer. The "Player Progression" owns one or several "Save States", which are objects keeping track of a specific slugcat and the world its in.

I'm not too keen on having multiple save files that the player has to mess with in a menu as I feel that would break immersion a bit - feels much better that you hit "continue" and get back to where you left off, and whatever happens and is saved has then happened; gives some gravitas to the events in the game and ties together the narrative. A linear narrative for a playthrough is stronger IMO than one that is branched and split and where one thing maybe happened but if you go to this specific save file it didn't happen, etc. If there is a huge demand for multiple save files (people sharing the game with relatives in the same household or similar) I could perhaps be convinced otherwise, and now so could the system! The main idea for it though is that as you rescue pups and get to play as them, those different slugcats will effectually act as "save files" of their own, each having its own story line that you could load and save. But those would be a few parallel narratives, no branching.

Above these save files is, as mentioned, the "Player Progression" object. Progression object keeps track of stuff that should carry over between save files - for example we've put the map discovery data there for now, because as James put it "the whole point for playing ng+ is to go to the places you didn't get to explore last time around". Also it will keep track of a bunch of different stuff such as unlockables.

All of this seems to be working to satisfaction for now at least! Currently I'm working a bit with creatures saving, but most of that system was actually in place and ready to go. What's needed is mostly making the save states work with the "things sticking to things" engine which I have in place and which is about such as critters grabbing other critters or spears being lodged in critters.

Bat swarm room depletion and its saving and loading is also in since before, and just need a few touch ups and fitting into the new system.





   JLJac on January 20, 2016, 12:30:34 AM:

#save files: Maybe we could have a system where it's possible to create different profiles, which would create potentially multiple "Player progression" object with "save states" - that would be really easy as I could just save to a few different files. Then you could have one for you and on for your sibling or whatever, and you wouldn't get each other's map exploration etc. Also you could create several ones for yourself I guess, but we do have some plans for allowing you to try different play styles within the same "progression" - that's basically what ng+ is gonna be for.

#asian signs: actually I was an exchange student to South Korea when initiating the project, so they are loosely based off of Korean hangeul writing Smiley Rain World has two distinct alphabets though, the other lending its aesthetic from cyrillic letters.





   jamesprimate on January 20, 2016, 03:21:52 AM:

Rain World has two distinct alphabets though, the other lending its aesthetic from cyrillic letters.

3 now!






   JLJac on January 20, 2016, 03:44:50 AM:

Rain World has two distinct alphabets though, the other lending its aesthetic from cyrillic letters.

3 now!



Whaaaaat





   jamesprimate on January 20, 2016, 06:01:30 AM:

Rain World has two distinct alphabets though, the other lending its aesthetic from cyrillic letters.

3 now!



Whaaaaat

Sky Islands circular text!






   JLJac on January 20, 2016, 06:15:34 AM:

Just a font variation of the asian alphabet  Wink






   JLJac on January 20, 2016, 02:33:58 PM:

That is a cool font variation (and great looking screenshot generally)! At first glance it shares a little similarity to the first half of the 'Utopian' language of Thomas More's book Utopia, which was coincidently published 500 years ago this year: http://www.omniglot.com/conscripts/utopian.htm

Great answers from both of you on human (or otherwise non-human but equivalent) signifiers and the world/location in general. I think that the fact that this is a well thought out (and, of course, constantly evolving) process is demonstrable in the results - the abstraction (and thus the simultaneous alienation of the audience/slugcat) works, and adds to the mystery and intrigue of the world, ultimately capturing that hard-to-do thing of constructing a location as a character in its own right.
Thank you! And all kudos to James for the world building, he really is making it "a character in its own right"!

This game has crossed the line of being beautiful and motivating, to being so amazing that it's slightly demotivating because I'll never be able to make something like this.
I don't think the indie community will see something of this caliber again for a long time.
The only compliment I can give to you is that stuff like this is why I love games, and why I love making them.

Thank you for the amazing praise! Don't be demotivated - go pack to page one of this devlog and see for yourself what it used to look like. We started really humble - a few ideas and some knowledge of how to code in lingo(!) for macromedia director(!!!) and then slooooooowly worked our way to where we are now.

It's basically time + experimentation = talent
I'm going to disagree.

Pure experimentation is like playing the lottery.  Very very very very few people get lucky that way.

Some are lucky and have a nack for certain things but if you are not gifted then you can still learn certain principles and what works from other's works.  However, much like tone deaf people won't be able to create good music, real talent tends to involve more than just hard work, trial and error or experimentation.  There's some aspect that you either have and can build on ... or you don't. 

If you don't, then you focus on what you're good at and team up with people who are good in other areas. :D
I'm going to partly disagree! The way I see it, "talent" is basically the same as creativity - having ideas and wanting to express them. That's what keeps you pushing through all those thousands of hours of work, and then you get better at the craft as you go. That part might be something you're born with, idk. For sure there are some people like that guy in count of monte cristo who got thrown in jail and made ink with his blood to be able to continue writing, and then there are people who have every opportunity and never create art. I for one am certainly not an ink-from-own-blood type, if I get sick or something I forget art and focus on surviving, but I've always taken every opportunity to draw or write or whatever and I don't get tired of it ~ and do think that thing has contributed to the incredibly lucky situation I'm in today, where I can work on this amazingly fun project full time (and then some)!

So if you really want to *make stuff* you'd have to be in extraordinarily bad luck to not get good at it sooner or later, I believe. A very big part is knowing what you want to make. If you look at those screenshots Gimmy posted above here, you'll see that the artist basically had the idea for what style he was going for from the get-go, and those years were spent removing the stuff that didn't align with that style and exaggerating stuff that was in line with it (at least that's my interpretation). What's cool about it though is not the craftsmanship itself, but the stylistic idea which was always in there but which the increased technical skill made come alive in the later work.

That's my thoughts on creativity!

Re: save states - I might be in the minority, but it'd be very important to me to be able to have multiple save profiles so that I can also play the game and not have wait until my wife is finished.

Noted  Hand Thumbs Up Right Hand Thumbs Up Right Hand Thumbs Up Right

Update 517
Got another polished region with functional shelters and a gate between them from James, and spent the day getting save states to work on an inter-region basis. Seems to be working out! Lots of special cases to test, such as if you're in one region, go into another for a bit, then go back and save, will your map exploration progress in that swiftly visited region be saved? Etc etc etc.

Currently I'm working on getting the map to display in the "Sleep" screen - we want to have it there so you can plot your next raid before actually hitting play and starting the rain counter. The problem with that is that in the sleep screen the world is unloaded, so can't easily ask rooms for their positions etc. I've solved that by having the game process hand over a little batch of data to the sleep screen in its dying breath before being shut down, and that seems to be working out. Still a bit of fiddling to do, but hope to have something basic to show you within not too long!





   jamesprimate on January 21, 2016, 03:32:05 AM:

The levels for instance... I basically started from zero a year and a half ago, not due to any grand passion I had to be a level designer but simply because someone needed to do them. Joar was too busy with creatures and I didn't trust anybody else to realize the clear vision I had for the world. 12-16hr a day 7 days a week will get you pretty good pretty quickly  Tears of Joy  Cry





   jamesprimate on January 21, 2016, 06:51:57 AM:

*proof of no life*

eh the point being that if i (a person with no real interest in level design or visual arts background) can get some good looking stuff, then you can too! its just a matter of how much grind you are willing to grind.

grind.





   JLJac on January 21, 2016, 12:20:07 PM:

Update 518

Sleep screen and map swarm room indicators coming along!



Probably don't have to mention that the illustration and the button are place holders...





   jamesprimate on January 21, 2016, 02:08:09 PM:

I recognize that layout like the back of my hand Smiley

Haha I'll bet you do! New version has quite a few new tricks though, can't wait for you to see it   Wink

So I had a nightmare of a day. Long story short: anal multiple redundancy file backup practices are well worth the fuss. Everybody take this opportunity to go backup your files right now!





   JLJac on January 22, 2016, 02:09:25 AM:

No! Any tips very very very welcome!





   JLJac on January 22, 2016, 02:50:33 PM:

Update 519

Did some small AI touches to lantern mice and in the general AI modules affecting the behavior of all critters. Also some general maintenance work with the save states etc. At the moment though, I'm working on A SECRET CREATURE! There are quite a few of them in there now - not anywhere near as many as the amount of critters devoted devlog followers have seen, and some of them are just variations/subspecies of already shown creatures, but still a fair few. Wouldn't want to rob you of the experience of discovering a new creature every now and then!





   JLJac on January 24, 2016, 01:45:09 AM:

YES! The code:

Code:

CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

sampler2D _MainTex; //the map texture
sampler2D _mapFogTexture; //the map "exploration" texture

uniform float _RAIN;

uniform float2 _screenSize; //screen size in pixels
uniform float2 _mapSize; //map size in pixels
uniform float2 _mapPan; //the pan position on the map

struct v2f {
    float4  pos : SV_POSITION;
   float2  uv : TEXCOORD0;
    float2 scrPos : TEXCOORD1;
    float4 clr : COLOR;
};

float4 _MainTex_ST;

v2f vert (appdata_full v)
{
    v2f o;
    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
    o.scrPos = ComputeScreenPos(o.pos);
    o.clr = v.color;
    return o;
}



half4 frag (v2f i) : COLOR
{

//This here is it!
float dst = clamp(distance(i.scrPos, half2(0.5, 0.5)), 0, 1);//distance to center of screen
half2 displace = normalize(i.scrPos-half2(0.5, 0.5)) * (1-dst)*pow(dst,lerp(4,6,dst))*2; //the displace vector. Spent lots of time tuning this one to get it right, not knowing that I'd have to backwards-engineer it later!
displace.y *= 0.5 / 3.0; //Displace less vertically, as the screen is wider than tall (and divide by three because the map texture is 3x as tall as the actual map size, accommodating the 3 layers)
displace.x /= _mapSize.x / 500; //divide the displace with the size of the map texture getting a consistent amount of displace on different-sized maps (500 is a tuned value to get the right amount of displace)
displace.y /= _mapSize.y / 500;

float h = 0.5; //the blue color channel tells the shader which layer it should render - if statement because the floats become a bit distorted in passing to the shader
if(i.clr.z == 0) h = 0;
else if (i.clr.z == 1) h = 1;

//get the grab coordinate on the map texture
half2 grabPos = half2(_mapPan.x + (i.uv.x - 0.5) * (_screenSize.x / _mapSize.x) / lerp(3.25, 4.75, i.clr.y), (_mapPan.y / 3.0) +  ((2.0*h)/3.0) + ((i.uv.y - 0.5)  * (_screenSize.y / _mapSize.y) / lerp(3.25, 4.75, i.clr.y)) / 3.0);
grabPos -= displace; //applying the displace. If I comment this out, I get a flat-looking map onto which I *can* place markers accurately.

if(grabPos.y < lerp(0.0, 2.0, h)/3.0) grabPos.y = lerp(0.0, 2.0, h)/3.0; //clamping the grab coord in the vertical third of the texture that is this layer of the map
else if(grabPos.y > lerp(1.0, 3.0, h)/3.0) grabPos.y = lerp(1.0, 3.0, h)/3.0;

half4 grabCol = tex2D(_MainTex, grabPos);

//this stuff below here is just about giving the pixel the right color once I have the right texture coordinate - not really relevant to the problem at hand

if(grabCol.y > 0.5 || tex2D(_mapFogTexture, grabPos).x < 0.5) return half4(0,0,0,0.7 * i.clr.w * (1.0 - i.clr.x));

float lght = grabCol.x;

if(lght >= 0.3 && lght <= 0.7 && grabCol.y == 0)
return half4(1,1,1,1 * i.clr.w);
else if(lght < 0.3){
return half4(0,0,0,0.7 * i.clr.w * (1.0 - i.clr.x));
}
else if(grabCol.z > grabCol.x*lerp(0.5, 0.9, sin((grabPos.x - (_RAIN*75/_mapSize.x))*_mapSize.x*0.25)))
return half4(0.05,0.05,0.8,i.clr.w*lerp(0.5, 0.1, i.clr.x));
else {
if(tex2D(_mapFogTexture, grabPos).x < 0.54)
return half4(0,0,1,i.clr.w);
else
return half4(0.25,0.25,0.25,0.4 * i.clr.w * (1.0 - i.clr.x));
}
}
ENDCG


Please keep in mind that I'm a self-taught savage that never intended for anyone to read this code, so it might be baaaaaaad.

The map is three layers, each of which occupy a vertical third of the map texture. The sprite knows which layer to draw from by its blue color channel - actual map object has three sprites with blue colors 0, 0.5 and 1. Those map sprites are the same size as the screen, ie 1024*768 or 1366*768 in case of wide screen.





   JLJac on January 24, 2016, 08:20:06 AM:

Exactly the same result up when 0<x<1 yep! The corners are however in a range where x is up to the square root of two, and then you get these weird effects with a simple x^5 function:



It's a super-distortion where the image sort of doubles back and becomes mirrored around some edge, presumably the perimeter where the distance is equal to one.





   JLJac on January 24, 2016, 08:37:15 AM (Last Edit: January 24, 2016, 08:55:35 AM):

Actually using the formula I've copied straight from my code the reason becomes pretty evident - the distortion is allowed to taper after a bit instead of shooting exponentially for the stars.



Also one thing that I tend to forget is that the dst value is not 1 at the edges, but 0.5 ~

One curve that looks almost identical though is y = x^5 - x^7... That one is so simple, has got to be possible to do backwards! Gosh I wish I had some sort of math education :S





   JLJac on January 24, 2016, 11:21:54 PM:

Hm hm hm... The problem is that what I'm after is that decline that makes it hit zero at x = 1. This actually makes sense if you consider the graphical result I'm after. If you consider the zoom level at the corners as a default, there should be zero distortion out there. At the center of the screen you can't have any radial distortion or else you end up overshooting the center coordinate and get weird circular artifacts. So, what remains to be distorted is the area in-between, ie 0<x<1.

Another problem is that what may appear as very small differences on a graph becomes large and noticeable in the actual shader. For example, the simpler function y = x5 - x7 looks similar to the more complicated y = 2*(x4+2x - x5+2x) when plotted, but in the shader it makes the difference that the entire center area suddenly looks flat rather than bulging with the bulge now concentrated to the sides, which isn't as visually exciting.

My friend suggested a lookup-table as a solution. That might be worth trying?





   JLJac on January 25, 2016, 01:02:41 AM (Last Edit: January 25, 2016, 01:42:33 AM):

Offset texture sounds like a good idea - it's basically just a 2D lookup table, right?

Now, specifically how specifically would I use it? Say that I have a texture where the r channel of each pixel represents ...

HEY hold on a minute! That function 0.275*pow(dst, 3.14) you posted actually yields a VERY similar result to the original one! I could totally roll with that! So, let's inverse it then  Grin That would be a pretty simple log calculation, right?


EDIT: Using the wolfram alpha inverterter I got an inverted function:

however I can't seem to be able to milk it for the right results - guess I just lack knowledge on how to apply it -.- Just doing a straight up displacement using that new curve obviously doesn't work because as you can see from its convex shape I get super much displacement in the center of the image, which is the opposite of how the displacement in the shader goes about.

Will have to ponder it a bit!





   JLJac on January 25, 2016, 04:11:56 AM:

Dude, you don't even want to know. I've fallen into a programming habit where I have basically everything as floats between 0 and 1 and use lerps within lerps within lerps, and pows, so many pows. Because pow has a really nice effect on a 0<=f<=1 float, being that it sort of shits the value upwards or downwards (exponent below or above 1) whilst keeping the edge cases 0 and 1 in the same places. So then I can change the tendency of a value, but still know where I have my edge cases, like so:

if(Random.value < Mathf.pow(anger, Mathf.lerp(1.5f, 0.3f, personality.mean)))
    Attack();

In the above case the chance of attacking will always be 0% if anger is 0, and always be 100% if anger is 1, but in the cases in-between the curve is skewed depending on the personality.mean variable. I love it, and it has soooooooo many floating point exponents  WTF

And... this has of course leaked into my shader code as well. So, yeah, thanks for the heads up. Might need to go in there and clean a bit of that up if it's a big problem. I haven't noticed any performance issues with it though, neither in the c# or the shaders. Admittedly haven't tried on a lot of computers, so the problem might surface during beta testing - but we have run it on a few computers including a weak laptop and haven't had any issues so far.





   JLJac on January 25, 2016, 04:46:31 AM:

Don't think I'd generate the texture in CG though, in my setup I just have shader CG code that runs for each frame times each pixel. So better then to generate it on game start up and then just feed the texture to the shader.

It would solve the problem for sure. I actually wouldn't even need a 2D texture - the direction of the displacement is always the same (towards center) so what I need is just the magnitude of it which could be stored in a 1D texture, where the r value of each pixel is magnitude in one direction and the g value is magnitude in the other. Easy!

The reason I'm hesitating is that it feels slightly... inelegant. Don't want to generate and keep a texture in the ram which I have to keep a reference to etc... When it should be possible to do it all in pure math. Also I'm starting to have a little bit of an issue with the time the game takes to boot (think it's just the sheer amount of code compiling - it's a second or two so not a problem as a loading time for a finished game but a bit annoying in development where you have to jump in and out again and again) so I'm not in love with the idea of adding another potentially time consuming procedure on start up.

Hm hm hm. Gonna try the maths approach a little bit more, then I'll probably give up and do the texture either way!