Incidentally, I just finished reading an section in a book that discusses the way maps work from an ethnographic perspective. When you're a local, the landscape is this mesh of lived experience, emotional memories, that sort of thing. A map abstracts from that lived experience to provide you with a view from elsewhere, both literally (maps are projections of the landscape from above) and culturally (locals don't need maps). Experientially and culturally speaking, a map is a tool to allow you to access an unfamiliar space without having to become familiar with it. If you do become familiar with a space via a map, your experience is mediated by the map's abstraction. The map comes to define (and thus distort, because abstraction is by definition a selective representation) the territory it describes, rather than letting the territory directly inform your experience.
So there you go. Be a local! Ethnographic theory has your back.
A really interesting read! Agreed on all points!
Hey Joar, would you be willing to describe some of the physics involved in stuff like the tails and dangling parts of vultures and such, I haven't learned enough math yet to get to things rotating around points with gravity or anything like that, but I'm starting to want to try some stuff in my games, and google is being unhelpful. Found the simple pendulum formula, which I can at least read, if not fully understand how it works, but I'm not sure what you use. (you probably use that for the ropes at least, if so, could you explain it to me as you would a baby? I'd appreciate that;))
If you're busy that's totally understandable,
Nico
The magic trick used for everything creature physics related in this game comes down to a couple of lines of code. Let's take a look:
public class Chunk{
public Vector2 pos;
public Vector2 vel;
public Chunk(Vector2 initPos){
pos = initPos;
vel = new Vector2(0f, 0f);
}
//Called every frame
public void Update(){
pos += vel;//Apply velocity to position
vel *= 0.98f;//Air friction
vel.y -= 0.8f;//Gravity, with Unity's (non?)inverted y-axis. If you're using something else, flip it.
if (pos.y < 20f){// Putting a simple floor in the simulation space so the chunks don't fall off screen when you try it ;)
pos.y = 20f;
vel.y = 0f;
}
}
}
This here is a class representing some physical object, or rather part of a physical object. I'll call it a Chunk. As you have a game with stuff that's moving around on the screen and is affected by gravity, I take it you know what's going on in this code
Now, the magic trick! First a simplified example:
public void ConnectChunks(Chunk A, Chunk B){
float wantedDist = 10f;
float currentDist = Vector2.Distance(A.pos, B.pos);
Vector2 dir = (B.pos - A.pos).normalized;
A.pos -= (wantedDist - currentDist) * dir * 0.5f;
A.vel -= (wantedDist - currentDist) * dir * 0.5f;
B.pos += (wantedDist - currentDist) * dir * 0.5f;
B.vel += (wantedDist - currentDist) * dir * 0.5f;
}
Explanaition - we want the chunks to be 10 units apart. If they are further away from each other, we pull them together by the distance needed. If they're closer, we push them away from each other.
(Small side note, I think the "(B.pos - A.pos).normalized" is correct, but it could be the other way around, haha! Try both and see what works, if you get stuff twitching out and disappearing from the screen, you have it in the wrong order.)
Ok, so let's step it up a notch. Notice that *0.5f? That means both chunks are affected equally. If we affect A more than B by the movement, it will appear as if B is heavier. Say that you add a mass parameter to the chunk class, you can do this:
public void ConnectChunks(Chunk A, Chunk B){
float wantedDist = 10f;
float currentDist = Vector2.Distance(A.pos, B.pos);
float elasticity = 0.8f;
float massFac = A.mass/(A.mass+B.mass);
Vector2 dir = (B.pos - A.pos).normalized;
A.pos -= (wantedDist - currentDist) * dir * (1f - massFac) * elasticity;
A.vel -= (wantedDist - currentDist) * dir * (1f - massFac) * elasticity;
B.pos += (wantedDist - currentDist) * dir * massFac * elasticity;
B.vel += (wantedDist - currentDist) * dir * massFac * elasticity;
}
If A weights 1000 units, and B weights 2 units, we get a massFac of 1000 / (1000 + 2) = 0.998. If you look at the code, you'll see that this means that A will be moved pretty much not at all, and B will do almost the entire movement. This is why it takes 700 leeches to drown a vulture in rain world
Oh and I threw elasticity in there as well, but that's pretty straightforward.
I give zero guarantee that this is anywhere in the same galaxy cluster as approximating real physics, but it does what I want. I've heard that this technique is called "atomic bond physics" (in Swedish, don't know about English) and that makes a lot of sense, but I haven't seen it utilized much elsewhere, which is a shame seeing how it's so simple and effective.
Of course you can make it so that one of the Chunks is not affected at all, while the other do all the moving. Actually this is a good place to start - have one chunk, and lock the other connection to the mouse position, and you get a little swingy thingy to play with. In my game the creatures have a set of body chunks that affect each other, and then they have a cosmetic layer on top of that which is just connected to these, but can't pull at them - effectually a massFac of 1.0f. This means that when the creature is offscreen I can just drop the cosmetic layer (or "skin" as I've come to call it) and the actual game object will still behave the same.
A tail or tentacle in RW is a bunch of these that are connected to each other in succession.
This stuff locks two chunks to each other. If you want to turn it into a (wonky) collision physics engine, you just need to add "if (currentDist < wantedDist)" and the chunks won't pull at each other, only push at each other if they're actually overlapping.
Everything in my game is just variations and elaborations on this theme! Though honestly not very big elaborations, the majority of it is just straight up this here code. Good luck