|
|
|
 |
Reply From: |
SIsilicon |
Lucky for you I have some experience in constraints solving. Assuming your chain chomp local scene tree looks something like this,

Then the code for your chain chomp would go as follows.
extends StaticBody2D
Constants
const NUMBER_OF_LINKS = 4
const CHAIN_LENGTH = 200
const DIST_BETWEEN_LINKS = CHAIN_LENGTH / NUMBER_OF_LINKS
const ITERATIONS = 10
const GRAVITY = Vector2(0, 300)
The first group of constants define the size of the chain.
NUMBER_OF_LINKS
must be the same as the number of chain sprites in the tree.
ITERATIONS
defines the number of times we solve the constraints in one frame. The bigger the number is the better.
The rest are self explanatory.
Variable initialization
var prev_link_positions = []
var links = []
func _ready():
for i in range(NUMBER_OF_LINKS):
links.append(get_child(i))
prev_link_positions.append(get_child(i).position)
I prefer to use verlet integration when working with physics constraints. So we’ll have to store an array of vectors which hold the chain links’ previous positions. The second array holds reference to the chain link nodes.
They all then get initialized in the _ready
method.
func _physics_process(delta):
Force applying & Verlet integration
for i in range(links.size()):
var acceleration = GRAVITY
acceleration *= delta * delta
var prev_position = links[i].position
links[i].position = 2*links[i].position - prev_link_positions[i] + acceleration
prev_link_positions[i] = prev_position
We apply a constant gravity force to each chain link and update their position and previous position.
Constraint solving
for iteration in range (ITERATIONS):
for i in range(NUMBER_OF_LINKS):
var link = links[i]
var prev_link_position = Vector2() if i == 0 else links[i-1].position
var next_link_position = $Head.position if i == NUMBER_OF_LINKS-1 else links[i+1].position
var vec_to_link
vec_to_link = prev_link_position - link.position
link.position += vec_to_link.normalized() * max(vec_to_link.length() - DIST_BETWEEN_LINKS, 0) / 2.0
vec_to_link = next_link_position - link.position
link.position += vec_to_link.normalized() * max(vec_to_link.length() - DIST_BETWEEN_LINKS, 0) / 2.0
We solve the constraints on each link several times. The constraints here keep the links connected to the base, head and each other.
Overall the code looks like this.
extends StaticBody2D
const NUMBER_OF_LINKS = 4
const CHAIN_LENGTH = 200
const DIST_BETWEEN_LINKS = CHAIN_LENGTH / NUMBER_OF_LINKS
const ITERATIONS = 10
const GRAVITY = Vector2(0, 300)
var prev_link_positions = []
var links = []
func _ready():
for i in range(NUMBER_OF_LINKS):
links.append(get_child(i))
prev_link_positions.append(get_child(i).position)
func _physics_process(delta):
# You add code to move the head here.
for i in range(links.size()):
var acceleration = GRAVITY
acceleration *= delta * delta
var prev_position = links[i].position
links[i].position = 2*links[i].position - prev_link_positions[i] + acceleration
prev_link_positions[i] = prev_position
for iteration in range (ITERATIONS):
for i in range(NUMBER_OF_LINKS):
var link = links[i]
var prev_link_position = Vector2() if i == 0 else links[i-1].position
var next_link_position = $Head.position if i == NUMBER_OF_LINKS-1 else links[i+1].position
var vec_to_link
vec_to_link = prev_link_position - link.position
link.position += vec_to_link.normalized() * max(vec_to_link.length() - DIST_BETWEEN_LINKS, 0) / 2.0
vec_to_link = next_link_position - link.position
link.position += vec_to_link.normalized() * max(vec_to_link.length() - DIST_BETWEEN_LINKS, 0) / 2.0
Brilliant explanation, thanks so much!
Diet Estus | 2018-12-12 05:01