Monday, August 27, 2018

2d - How to Create Snakelike Objects


I am working on a 2D action platformer in Python, though my question is a general one about creating snakelike objects which move in a variety of patterns.


I have noticed this kind of object in many 2D games. For example, this boss in Contra has snakelike arms.



enter image description here


And this enemy from Super Metroid clearly seems to be composed of multiple segments.


enter image description here


I want to create snakelike objects in my game, though I don't know where to begin or what I may need to add to my physics engine to support them.


So far, all my enemies and hazards consist of single sprites and are programmed using simple attributes like velocity, acceleration, parametric curves, etc.


Maybe I need to create a class for the segments, designate one segment instance as the leader, and update the positions of the other segments based on the position of the segment in front of it. But how do I program different patterns of movement? Do I need to learn about so-called joints and implement them between the segments? I currently don't have them in my engine.


I know I could easily create a segmented object where each non-leader segment is moved to the previous position of the segment in front of it (like in classic Snake, described here), but I want more complex patterns than this. Sometimes I may want the object to be flailing from an anchored point, and other times I may want it to be following some pattern across the screen.


I really don't know where to begin in trying to create this kind of object and would greatly appreciate any advice.


How do you implement snakelike objects with a variety of movement patterns?


(Given the ubiquity of this kind of object in games, I was surprised that I couldn't easily find much about it online. I think a detailed write-up on it would be cool.)




Answer



Yes, you would add a distance-constraint (known also as ball-socket joint) between the segments, and keep doing your normal physics on each segment.


There is a really simple and effective way to satisfy these constraints, which can be implemented in only a few lines of code.


The idea is that you reduce the error in a constraint partially, over and over for all constraints, in a loop. If you keep reducing the error by, let's say 20% in each iteration, it will eventually settle to a stable state where all the constraints are satisfied.


Note that it helps to keep the head position of the snake as-is, to make the tail follow the head, instead of vice versa.


So in pseudo code:


for i in range 1..10:
for each link between segments:
actual_dist = distance(body0, body1)
error = actual_dist - desired_dist

// fix 20% of the error in body0/body1 distance.
if body0 is not snakehead:
move body0 (0.1*error) units towards body1
if body1 is not snakehead:
move body1 (0.1*error) units towards body0

..which is all you need to have the tail follow the head.


NOTE: you get a slightly faster convergence, and more stable solution if you reduce the error in the links in a random order! So in the 10 times we scan over the links, we update them in a different order.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...