—    —  Home

   jamesprimate on August 13, 2015, 06:39:51 PM:

I wanted to plane many with all video game visor as a joke, but by now it had became a bandwagon :p

i dont know what you mean






   jamesprimate on August 14, 2015, 05:46:56 PM:

twitter seems to like it  Hand Metal Right

https://twitter.com/brandonnn/status/631942065316691968





   jamesprimate on August 15, 2015, 10:12:41 PM:

views from the wall:



detail: https://i.imgur.com/jVhyDuO.png



detail: https://i.imgur.com/1ZE6mQf.png





   JLJac on August 18, 2015, 12:25:57 PM:

Oh don't worry guys Grin I've just been quiet because I've been doing some classic non-devlog stuff these last couple of days, like finishing up the last region, providing tiles for the new region etc. But yeah, maybe this deer thing got a tiiiiiiiny bit annoying somewhere halfway through page 3  Cheesy

Both James and I like the deer, and that's generally what we go by. I'm a fan of the beard suggestion though, maybe I will try something like that out in polish pass! However, the deer in its current form took something like 2.5 weeks alone, and we just have to put a pin in it for now.

At the moment I'm making tiles and palettes for this new region we've gotten into. This one is going to have a lot of palettes and fun custom work, as we plan for it to be kind of the big end-of-game scene and want to spice stuff up quite a bit! Now we are starting to tread some spoiler territory though, and maybe not everything in this region will make it to the devlog as we want you guys to experience it for yourselves. Super excited to finally be reaching that point of the development!





   jamesprimate on August 18, 2015, 03:14:35 PM:


Two things:

1) Is the final game still planned to be an interconnected open world?

2) If so, and there are no skill-based gates, keys, etc., how do you make sure the final regions are the ones the player reaches last? That the big end-of-game scene in the aftermentioned region is encountered towards the end of the game? I'm guessing narrative events funnel you toward certain regions...

1) oh yes, totally. thats been my life for teh past 2 years

2) there are quite a few soft lock-and-key-ish aspects, and a few main ones that have to be figured out in order to traverse some of the later endgame regions. but none of them are hard barriers per se, they are more to guide the player to some essential spots where certain narrative / development events can take place. but in replay, in NG+ or just a fresh game, a player who has previously gone through the game should have pretty much full run of the map with the knowledge they accumulated. if you know what you are doing and have a plan and some outside resources (or are really lucky), you can access any point from the start.





   JLJac on August 19, 2015, 01:31:46 PM:

Update 463

Today I made a huuuuuuuuge tile:



This is in another league than any other tile so far. Maybe the largest chimney got close, but that one had basically no complexity - this one is huge and full of details. James will be able to make some really impressive rooms with this one!

The hollows can be stuffed with custom machinery, which has turned out to look really good in testing. Really looking forward to see what comes of this one!





   JLJac on August 21, 2015, 10:52:10 AM:

Update 464

More tile work! Huge chains:



A random machinery tileset:



The idea for the random machines is that they'll be used mostly as "padding" around larger and more deliberate machine parts - not necessarily on large areas by themselves. My hope is that this will allow James to make some cool super-intricate looking machines.

James is working on an area now that is looking preeeeetty awesome! There'll be a lot of very large tiles, some intricate machinery, and some cool visual effects. Much looking forward to see what's gonna come out of this!





   JLJac on August 21, 2015, 11:38:02 PM:

Thanks! Actually "quasi 3D" is a pretty good way to describe all the background graphics in the game. The level editor creates 30 bitmaps, each representing a layer in the z-dimension and then bakes them together into a composite which saves the depth value of each pixel. This means that the final image you view could be thought of as a still projection of a crude little voxel space. Most assets are created layer-by-layer and then interpreted by the editor so that they all line up, forming a rough (and very flat) 3d shape.



This is why making new assets takes so long - I can't just draw them, I have to figure the three dimensional shape out, lay it out as layers, write the instructions for the editor to place everything in the correct layer, etc.

When it comes to the actual visual 3D effect, some assets work better than others, and I'm really happy about these chains! However, even the boring boxy assets have a bit of the effect going on. If you look at the chains screenshot you can aaaaaalmost see how on the left hand box, you get a little glimpse of its right face, and on the right hand box you get a little glimpse of the left face.

The saved depth value of each pixel is used for basically every shader effect that looks good in the game, that's like the one magic trick Smiley The shadows playing over objects in the background for example are very simple - just fetch the depth of pixel (x,y), depending on that depth step a certain amount of pixels diagonally up/left to say, pixel (x-6, y-8). Once there, check if there is something rendered in the sprite layer at that location - if so, the pixel should be shadowed.





   jamesprimate on August 22, 2015, 05:33:22 AM:

#screenshotsaturday

showing off some of these new tiles on The Leg:



detail: https://i.imgur.com/YYlMI60.png






   jamesprimate on August 22, 2015, 09:25:38 AM:

Yessssssss





   JLJac on August 24, 2015, 12:57:53 PM:

Update 465

Working on a new creature! This one is going to need a bit of rope physics, which I'm painstakingly trying to figure out. I did try my hand at this with the lantern mouse, but there I could always assume a static base position - here I have to consider both ends of the rope moving as a possibility.

I've figured out that as long as the rope ends manage their own terrain collision, the rope itself should only have to care about convex corners, which should simplify the task a bit by making the things necessary to think about a lot fewer.

I have managed to get something together that works theoretically. In practice though, it's not perfect yet - sometimes the "sweep" the rope does for corners will miss a corner, and the rope can only create one new bend point in a frame, as well as some other problems. The theory should be sound though, so if I work with it some more I imagine this solution should work.






   jamesprimate on August 25, 2015, 05:27:22 AM:

new kickstarter update! this one actually has a lot of stuff the devlog hasn't seen yet:

https://www.kickstarter.com/projects/rain-world/project-rain-world/posts/1333057





   jamesprimate on August 25, 2015, 05:51:38 AM:


Btw, saw on Steam that the release timeframe was pushed to 2016


nah thats a typo, it should actually say 2106





   JLJac on August 25, 2015, 09:22:16 PM:

Quick question: is the raindeer hide final? Just seems odd to me that entire body, even the antlers, is black.
For now ~ I want to do a bit of color variation on them, but we just had to, had to, had to move on haha! Hopefully I'll get an opportunity to return to them, and for then I do have some ideas.

Update 466

Grappling hook!








   jamesprimate on August 25, 2015, 10:06:26 PM:

every new technical demonstration has enough complexity to drive a whole game on its own!

case in point: spider slug





   JLJac on August 25, 2015, 10:23:56 PM:

The rope script is decently solid, and uncharacteristically clean/self contained compared to the utter mess my code usually is, so if anyone's interested in it I can hit you up with the source.



This version of the script assumes square tiles and only account for 4 types of corners, up/left, up/right, down/right, down/left - but I think it would be possible to adapt it to work with other types of terrain. You'll need to run your own collision code for whatever objects are attached at the ends of the rope, but if that code works and makes sure that the ends are not overlapping terrain when the rope gets its update command it should not clip through any corners or anything.

Working with this I kind of felt the inspiration coming on for some kind of touchscreen puzzle game, but any side projects are like 1200 light years from possible now and for the foreseeable future, so if anyone else is interested I'd be happy to hand it over  Smiley





   JLJac on August 25, 2015, 11:22:26 PM (Last Edit: August 25, 2015, 11:35:47 PM):

I did check it out! The effect is similar, but I think the algorithmic approach is more different than same. As you see in the gif, my rope thing can wrap several times around the same object, cross itself etc. The convex hull algorithm is about mathematically finding the perimeter of an object - it's a way more "mathematically clean" line. For example they mention that one of the definitions of their line is that every angle is a left turn,  that certainly doesn't go for my line haha!

My approach is less pure maths, more hands on. Whenever a rope segment moves (and it's only the first and the last rope segments that can move) I sweep over the area it covered in its movement and check all the corner points in there. The corner point that is closest to where the segment was before it started to move is picked as the position for a new bend on the rope.





   JLJac on August 26, 2015, 05:25:44 AM:

@JobLeonard, your sketch illustrates the method I use nicely Smiley I don't see the need for the convex hull though - I just use a line/vector distance to check which point that the rope hit first (on your sketch that top left one) and because that point will be convex and far out from the middle, it'll be one of the convex hull vertices either way, without having to explicitly calculate it. The concave points (such as the one in that crevice on the shape in your sketch) there's really no reason to bother with at all, because as long as the tips of the rope have terrain collision those can never end up inside a sweep.

@Christian, TheWing, yep, 45 unless you hold up, then straight up. And a little bit of auto aim - if the original aim direction seems to be all empty of terrain it'll check a few angles to the sides as well and see if any of those hit something.

@Paul, wow yeah, that looks super similar! Let me know what was and wasn't the same in the code!

Code:
public class Rope
{
    public Room room;
    public Vector2 A, B, lastA, lastB;
    public float totalLength;
    public List<Corner> bends;
    float thickness;

    public RopeDebugVisualizer visualizer;
    public List<Corner> corners;

    public Vector2 AConnect
    {
        get
        {
            if (bends.Count == 0) return B;
            else return bends[0].pos;
        }
    }
    public Vector2 BConnect
    {
        get
        {
            if (bends.Count == 0) return A;
            else return bends[bends.Count - 1].pos;
        }
    }

    public struct Corner
    {
        public FloatRect.CornerLabel dir;
        public Vector2 pos;
        public Corner(FloatRect.CornerLabel dir, Vector2 pos)
        {
            this.dir = dir;
            this.pos = pos;
        }
    }

    public Rope(Room room, Vector2 initA, Vector2 initB, float thickness)
    {
        this.room = room;
        A = initA;
        lastA = initA;
        B = initB;
        lastB = initB;
        totalLength = Vector2.Distance(initA, initB);

        bends = new List<Corner>();
        corners = new List<Corner>();

        this.thickness = thickness;

        //finds all the corners and stores them in a list. This could also be done locally on the fly, for very large spaces with lots of corners that might be preferable performance-wise.
        for (int x = 0; x < room.TileWidth; x++)
            for (int y = 0; y < room.TileHeight; y++)
                if (room.GetTile(x, y).Solid) {
                    if (!room.GetTile(x - 1, y).Solid) {
                        if (!room.GetTile(x, y - 1).Solid && !room.GetTile(x - 1, y - 1).Solid)
                            corners.Add(new Corner(FloatRect.CornerLabel.D, room.MiddleOfTile(x, y) + new Vector2(-10f - thickness, -10f - thickness)));
                        if (!room.GetTile(x, y + 1).Solid && !room.GetTile(x - 1, y + 1).Solid)
                            corners.Add(new Corner(FloatRect.CornerLabel.A, room.MiddleOfTile(x, y) + new Vector2(-10f - thickness, 10f + thickness)));
                    }
                    if (!room.GetTile(x + 1, y).Solid) {
                        if (!room.GetTile(x, y - 1).Solid && !room.GetTile(x + 1, y - 1).Solid)
                            corners.Add(new Corner(FloatRect.CornerLabel.C, room.MiddleOfTile(x, y) + new Vector2(10f + thickness, -10f - thickness)));
                        if (!room.GetTile(x, y + 1).Solid && !room.GetTile(x + 1, y + 1).Solid)
                            corners.Add(new Corner(FloatRect.CornerLabel.B, room.MiddleOfTile(x, y) + new Vector2(10f + thickness, 10f + thickness)));
                    }
                }

        //  visualizer = new RopeDebugVisualizer(this);

    }

    public void Reset()
    {
        bends.Clear();
    }

    public void Update(Vector2 newA, Vector2 newB)
    {
        lastA = A;
        lastB = B;
        A = newA;
        B = newB;

        //sweep terrain to add bend points
        if (bends.Count == 0)
            CollideWithCorners(lastA, A, lastB, B, 0, 0);
        else {
            CollideWithCorners(BConnect, BConnect, lastB, B, bends.Count, 0);
            CollideWithCorners(lastA, A, AConnect, AConnect, 0, 0);
        }

        //delete bend points where the rope has come free of the corner
        if (bends.Count > 0) {//could optimize here by making it only check first and last bend point
            List<int> deleteBends = new List<int>();
            for (int i = 0; i < bends.Count; i++) {
                Vector2 prev = A;
                Vector2 nxt = B;
                if (i > 0) prev = bends[i - 1].pos;
                if (i < bends.Count - 1) nxt = bends[i + 1].pos;
                if (!DoesLineOverlapCorner(prev, nxt, bends[i])) {
                    deleteBends.Add(i);
                }
            }
            for (int i = deleteBends.Count - 1; i >= 0; i--)
                bends.RemoveAt(deleteBends[i]);
        }

        //Calculating new total length of rope
        if (bends.Count == 0)
            totalLength = Vector2.Distance(A, B);
        else {
            totalLength = Vector2.Distance(A, AConnect) + Vector2.Distance(BConnect, B);
            for (int i = 1; i < bends.Count; i++)
                totalLength += Vector2.Distance(bends[i - 1].pos, bends[i].pos);
        }


        if (visualizer != null) visualizer.Update();
    }

    private void CollideWithCorners(Vector2 la, Vector2 a, Vector2 lb, Vector2 b, int bend, int recursion)
    {
        Corner? firstCollision = null;
        float firstCollisionDist = float.MaxValue;
        foreach (Corner c in corners)
            if (DoesLineOverlapCorner(a, b, c)
                && c.pos != la && c.pos != a && c.pos != lb && c.pos != b
                // && Custom.BetweenLines(c.pos, la, a, lb, b) && Custom.BetweenLines(c.pos, la, lb, a, b)//old sweep function that would give some false positives
                && (Custom.PointInTriangle(c.pos, a, la, b) || Custom.PointInTriangle(c.pos, a, lb, b) || Custom.PointInTriangle(c.pos, a, la, lb) || Custom.PointInTriangle(c.pos, la, lb, b))
                && Mathf.Abs(Custom.DistanceToLine(c.pos, la, lb)) < Mathf.Abs(firstCollisionDist)) {
                firstCollision = c;
                firstCollisionDist = Custom.DistanceToLine(c.pos, lastA, lastB);
            }

        if (firstCollision.HasValue) {
            Vector2 bendPoint = firstCollision.Value.pos;
            bends.Insert(bend, firstCollision.Value);

            Vector2 divPoint = Custom.ClosestPointOnLine(la, lb, bendPoint);

            CollideWithCorners(divPoint, bendPoint, lb, b, bend + 1, recursion + 1);
            CollideWithCorners(la, a, divPoint, bendPoint, bend, recursion + 1);
        }
    }

    public bool DoesLineOverlapCorner(Vector2 l1, Vector2 l2, Corner corner)
    {
        IntVector2 cornerDir = new IntVector2((corner.dir == FloatRect.CornerLabel.A || corner.dir == FloatRect.CornerLabel.D) ? -1 : 1,
            (corner.dir == FloatRect.CornerLabel.A || corner.dir == FloatRect.CornerLabel.B) ? 1 : -1);

        if (l1.y != l2.y)
            if ((cornerDir.x < 0 && (Custom.HorizontalCrossPoint(l1, l2, corner.pos.y).x < corner.pos.x))
                || (cornerDir.x > 0 && (Custom.HorizontalCrossPoint(l1, l2, corner.pos.y).x > corner.pos.x)))
                return false;

        if (l1.x != l2.x)
            if ((cornerDir.y < 0 && (Custom.VerticalCrossPoint(l1, l2, corner.pos.x).y < corner.pos.y))
                || (cornerDir.y > 0 && (Custom.VerticalCrossPoint(l1, l2, corner.pos.x).y > corner.pos.y)))
                return false;

        return true;
    }

}





   JLJac on August 26, 2015, 07:03:32 AM:

@Franklins Ghost, thanks! I actually did spend too much time swinging around once I implemented the thing, so I had to remove the player from the development room to be able to continue hahaha :D

@JobLeonard, yup exactly, when hitting a corner I split the rope in two at that point and then apply the same logic on both the new segments recursively - stepping down in a tree like way until all the intersecting points have been handled. I actually only calculate distance for the points that are inside the sweep area, but what points are inside the sweep area is determined using a triangle/point overlap which calls the line/point distance three times haha  Cheesy So yeah...

Working with Rain World has made me become pragmatic rather than idealistic when it comes to optimization - usually all attempts at optimization of stuff like this are utterly soaked by some pathfinding line that is called 14 000 times per frame, outweighing anything that could or couldn't be done differently in a thing like this astronomically. So I've started to gravitate towards writing the easiest, cleanest solution, and then if there is a performance problem optimize it. So far, no problem with performance! Most rooms seem to have less than 100 convex corners anyways, so it blazes through those pretty quickly. If I were to optimize however, I'd take out the tiles that are affected by the sweep and find the corner points in there frame by frame. As most swipes are probably very small and not overlapping any corners that'd likely save some time. For a non-tile based situation like your sketch you could divide the space into sections and only check the points in the affected sections.

I do think that the convex hull algorithm could be useful as an optimization in a non-tile based scenario, but it would have to be complemented by something, as not every convex vertex is necessarily part of the convex hull:



@Christian, no comments  Who, Me? Yet  Who, Me?





   jamesprimate on August 27, 2015, 06:52:11 AM (Last Edit: August 27, 2015, 07:38:38 AM):

Quote from: Princessa
will it be possible to play the game without killing stuff and eating bats? Again, if not, please consider.

Most of the fundamental mechanics of Rain World are built around the core idea of the player creature being at the center of an ecological triangle as both predator and prey. Through that we're able to explore the concept of resource scarcity on a micro and macro scale through the narrative design, the world design and down through the gameplay, etc. What happens when an ecology of creatures (or civilizations) are forced to compete for a pool of dwindling resources in a world with a climate dangerously out of whack? I want the player to feel the existential pressures of this, the bleak prospect of comfort and even survival slipping further and further out of reach as time goes by, not through "enemies" or "bad guys" but only due to the consequences of the player characters basic needs for survival and the natural self-preservation behaviors of those around it. For me, thats the thesis of the game and something i feel very strongly about conveying, for reasons that should be fairly obvious.

That said, I really like the idea of the game not forcing a players hand, allowing the game to be playable in a variety of ways provided they fit the criteria of the central game mechanics of "get sufficient food" and "survive rain cycle". These are "emergent narrative paths" that open up based on how the player naturally approaches the game and i'd like to support and encourage them where possible. "Vegan Slugcat" is hard because it compromises a good deal of teh structure already in place, but if things work out in a certain way it could *possibly* be explored as an achievement path later in the polish phase. But other than the necessary sustenance it should currently def be possible to get through the game as a pacifist using entirely stealth and misdirection. In fact, Joar even has a system in place to reward altruistic behavior, though we'll keep quiet on the specifics of it for now.

Note: from my experience of the alpha, it is entirely possible to play the game without purposelessly killing other animals. In fact, it is appropriately difficult (often impossible) to just run around murdering all of the predators hunting you.

This is def a key element as well. Its not fleshed out yet, but there is also a system in place where the more aggressively you play, the more aggressive the creatures around you become. If you kill weaker creatures, it opens up their ecological niche to other more dangerous creatures, etc. Plays to both the thesis of the game and creates a challenging "warrior" emergent narrative path, etx etx.

A lot of this stuff is really "balance focused", so nothing were touching right now and very subject to change. Plenty of work to do just getting the core game and geography in place.