How to create a snake like a body in Box2D and Cocos2DX?

My job is similar to a snake. I want to make a snake body.

The game logic is like this:

The snake moves up and down. The movement should be like real snake movement.

Here, I was hit.

How to make a snake’s body?

Any ideas or references should help me.

Thanks in advance.

Okay, this will be a very long answer.

I used some code from other projects and the “snake” part to combine a quick example. You The entire (cocos2d-x) code base can be found here on github.

The easiest (and first) thing to do is to build the snake body. From the Box2D point of view, you can use a series of segments To build them, each segment is connected by a revolute joint.

>You want to start from a single head
>and then iterate using offsets relative to it to create segments
They are lined up in a row.
>When creating each subdivision, use a to link it to the previous subdivision
rotation joint.
>As you get closer to the tail, start to gradually reduce your height.
> /p>

The following are our goals:

This is the “rough” code I used to create it:

// Constructor< br /> MovingEntity(b2World& world,const Vec2& position) :
Entity(Entity::ET_MISSILE,10),
_state(ST_IDLE)
{
// Create the body.
b2BodyDef bodyDef;
bodyDef.position = position;
bodyDef.type = b2_dynamicBody;
Body* body = world.CreateBody(&bodyDef);
assert(body! = NULL);
// Store it in the base.
Init(body);

// Now attach fixtures to the body.
FixtureDef fixtureDef;< br /> PolygonShape polySh ape;
vector vertices;

const float32 VERT_SCALE = .5;
fixtureDef.shape = &polyShape;
fixtureDef.density = 1.0;
fixtureDef.friction = 1.0;
fixtureDef.isSensor = false;

// Nose
vertices.clear();
vertices.push_back(Vec2(4* VERT_SCALE,2*VERT_SCALE));
vertices.push_back(Vec2(4*VERT_SCALE,-2*VERT_SCALE));
vertices.push_back(Vec2(8*VERT_SCALE,-0.5*VERT_SCALE));
vertices.push_back(Vec2(8*VERT_SCALE,0.5*VERT_SCALE));
polyShape.Set(&vertices[0],vertices.size());
body->CreateFixture(&fixtureDef );
body->SetLinearDamping(0.25);
body->SetAngularDamping(0.25);

// Main body
vertices.clear();
vertices.push_back(Vec2(-4*VERT_SCALE,2*VERT_SCALE));
vertices.push_back(Vec2(-4*VERT_SCALE,-2*VERT_SCALE));
vertices.push_back(Vec2 (4*VERT_SCALE,-2*VERT_SCALE)); vertices.push_back(Vec2(4*VERT_SCALE,2*VERT_SCALE));
polyShape.Set(&vertices[0],vertices.size());
body->CreateFixture(&fixtureDef) ;

// NOW, create several duplicates of the "Main Body" fixture
// but offset them from the previous one by a fixed amount and
// overlap them a bit.
const uint32 SNAKE_SEGMENTS = 4;
Vec2 offset(-4*VERT_SCALE,0*VERT_SCALE);
b2Body* pBodyA = body;
b2Body* pBodyB = NULL;< br /> b2RevoluteJointDef revJointDef;
revJointDef.collideConnected = false;

// Add some "regular segments".
for(int idx = 0; idx {
// Create a body for the next segment.
bodyDef.position = pBodyA->GetPosition() + offset;
pBodyB = world.CreateBody(&bodyDef);< br /> _segments.push_back(pBodyB);
// Add some damping so body parts don't'flop' ar ound.
pBodyB->SetLinearDamping(0.25);
pBodyB->SetAngularDamping(0.25);
// Offset the vertices for the fixture.
for(int vidx = 0; vidx {
vertices[vidx] += offset;
}
// and create the fixture.
polyShape.Set (&vertices[0],vertices.size());
pBodyB->CreateFixture(&fixtureDef);

// Create a Revolute Joint at a position half way
// between the two bodies.
Vec2 midpoint = (pBodyA->GetPosition() + pBodyB->GetPosition());
revJointDef.Initialize(pBodyA, pBodyB, midpoint);
world.CreateJoint (&revJointDef);
// Update so the next time through the loop, we are
// connecting the next body to the one we just
// created.
pBodyA = pBodyB;
}
// Make the next bunch of segments get "smaller" each time
// to make a tail.
for(int idx = 0; idx {
// Create a body for the next segment.< br /> bodyDef.position = pBodyA->GetPosition() + offset;
pBodyB = world.CreateBody(&bodyDef);
_segments.push_back(pBodyB);
// Add some damping so body parts don't'flop' around.
pBodyB->SetLinearDamping(0.25);
pBodyB->SetAngularDamping(0.25);
// Offset the vertices for the fixture.
for(int vidx = 0; vidx {
vertices[vidx] += offset;
vertices[vidx].y *= 0.75;< br /> }
// and create the fixture.
polyShape.Set(&vertices[0],vertices.size());
pBodyB->CreateFixture(&fixtureDef);

// Create a Revolute Joint at a position half way
// between the two bodies.
Vec2 midpoint = (pBodyA->GetPosition() + pBodyB->GetPosition());
revJointDef.Initialize(pBodyA, pBodyB, midpoint);
world.CreateJoint(&revJointDef);
// Update so the next time through the loop, we are
// connecting the next body to the one we just
// created.
pBodyA = pBodyB;
}
// Give the tail some real "drag" so that it pulls the
// body straight when it can.
pBodyB->SetLinearDamping(1.5);
pBodyB->SetAngularDamping(1.5 );

// Setup Parameters
SetMaxAngularAcceleration(4*M_PI);
// As long as this is high, they forces will be strong
// enough to get the body close to the target position
// very quickly so the entity does not "circle" the
// point.
SetMaxLinearAcceleration(100);
SetMaxSpeed(10 );
SetMinSeekDistance(1.0);
}

This will be your first part, a basic Body. Here are some notes about the code:

>I increased the damping of the body, even more tail, so it can
drag and “pull down” the remaining links. This makes it look smoother when you drag it.
>Adjacent body parts will not collide, but non-adjacent parts will collide, so the snake
can “hit” itself. You You can choose whether other parts should collide or
no.

Now, getting the body to move the way you want is a bit tricky. I will show you a picture (and video) first, so you You can see where I got it. All of these are in the code base I referenced, so you can adjust it if you want.

First of all, this is what I got after dragging it a bit Screenshots of what it looks like.

I took some videos, you can see it colliding, slowing down, etc. (see it here).

When you see it in motion, it It’s still not perfect, but I think it looks pretty good for a few hours of work.

To make the snake move, I took the method of “dragging” its head. When I drag it When, the head rotates towards my finger (or you can make it follow a path in the code, chase something, etc.) and move its head towards the target. The rest of the body “drags”, which makes it look pretty “Good”.

The controller uses two different mechanisms to move the body:

Use the body direction of the seeking behavior

Use the “search” behavior in the text, Its behavior is as follows:

The following is the code of the ApplyThrust(…) method of the MovingEntity class.

void ApplyThrust()
{
// Get the distance to the target.
Vec2 toTarget = GetTargetPos()-GetBody()->GetWorldCenter();
toTarget.Normalize();
Vec2 desiredVel = GetMaxSpeed() *toTarget;
Vec2 currentVel = GetBody()->GetLinearVelocity();
Vec2 thrust = desiredVel-currentVel;
GetBody()->ApplyForceToCenter(Ge tMaxLinearAcceleration()*thrust);
}

This method applies thrust to move b2Body toward the target direction. It has the maximum speed (GetMaxSpeed()) and the maximum linear acceleration (GetMaxLinearAcceleration()) as The properties of the class.

If you follow the code and draw the vector, you will see that its role is to apply thrust to drive your speed to point to the location of the target.

One way to look at it: it is like a feedback loop (in a vector) to keep your speed matching the desired speed. If you just consider it in terms of scalar, it will be easier to see.

If you move to the right at a speed of 5m/s (currentVel) and your maximum speed (desiredVel) is 6m/s, then the thrust will push to the right and push to the right faster (desiredVel – currentVel = 1). That is, you will accelerate to the right.

If you move to the right at a speed of 7 m/s (currentVel) and your maximum speed (desiredVel) is 6 m/s, The thrust will be negative, pointing to the left, slowing you down (desiredVel – currentVel = -1).

From physical update to update, this makes your body move towards the target at the speed you want Direction to move.

In your case, you just want to move left and right, let gravity pull down your body. All of this should work well in the context of physics .You can control the speed of the agent’s acceleration/deceleration by controlling the linear acceleration.

Using the PID controller to rotate the body

This is a bit complicated (seems like the previous part is not).

>

Our idea is to apply torque to your body based on the difference between the angle you want and the angle your body is facing. The PID controller uses the current angle difference (multiplied by the proportional constant), the most recent historical difference The rate of change of value (integral) and angle difference (variable). The first two make the body rotate, and the last one makes it slow down when it reaches the target angle.

You can see more details on the theory and implementation here .

All of these are encapsulated in a class in the code, called PIDController.

Note: PIDController in the code base is universal. It is for box2d, physical or its The purpose is unknown. It is like a sorting algorithm… It only cares about the data it is input and how the parameters you set work. It can be easily used in other environments…and has about 100 years.

Hope this will get you in the right direction. This may be a bit overkill, but I dig a bit These things are so interesting.

My job is similar to snakes. I want to make snakes.

The game logic is like this:

The snake moves up and down. The movement should be like a real snake movement.

Here, I was hit.

How to make a snake’s body?

Any ideas or references should help me.

Thanks in advance.

Ok, this Will be a very long answer.

I used some code from other projects and the “snake” part to combine a quick example. You can find the entire (cocos2d-x) code base here on github.

The easiest (and first) thing to do is to build the snake body. From the Box2D point of view, you can build them with a series of segments, each connected by a revolving joint Get up.

>You want to start from the beginning of the single
>and then iterate using the offset relative to it to create segments
they line up in a row.
>In the creation of each In the case of a subdivision, use a to link it to the previous subdivision
rotation joint.
>As you get closer to the tail, start to gradually reduce your height.

The following is our goal:

This is the “rough” code I used to create it:

// Constructor
MovingEntity(b2World& world,const Vec2& position) :
Entity(Entity::ET_MISSILE,10),
_state(ST_IDLE)
{
// Create the body.
b2BodyDef bodyDef;
bodyDef .position = position;
bodyDef.type = b2_dynamicBody;
Body* body = world.CreateBody(&bodyDef);
assert(body != NULL);
// Store it in the base.
Init(body);

// Now attach fixtures to the body.
FixtureDef fixtureDef;
PolygonShape polyShape;
vector< Vec2> vertices;

cons t float32 VERT_SCALE = .5;
fixtureDef.shape = &polyShape;
fixtureDef.density = 1.0;
fixtureDef.friction = 1.0;
fixtureDef.isSensor = false;

// Nose
vertices.clear();
vertices.push_back(Vec2(4*VERT_SCALE,2*VERT_SCALE));
vertices.push_back(Vec2(4* VERT_SCALE,-2*VERT_SCALE));
vertices.push_back(Vec2(8*VERT_SCALE,-0.5*VERT_SCALE));
vertices.push_back(Vec2(8*VERT_SCALE,0.5*VERT_SCALE));
polyShape.Set(&vertices[0],vertices.size());
body->CreateFixture(&fixtureDef);
body->SetLinearDamping(0.25);
body- >SetAngularDamping(0.25);

// Main body
vertices.clear();
vertices.push_back(Vec2(-4*VERT_SCALE,2*VERT_SCALE));< br /> vertices.push_back(Vec2(-4*VERT_SCALE,-2*VERT_SCALE));
vertices.push_back(Vec2(4*VERT_SCALE,-2*VERT_SCALE));
vertices.push_back( Vec2(4*VERT_SCALE,2*VERT_SCALE) );
polyShape.Set(&vertices[0],vertices.size());
body->CreateFixture(&fixtureDef);

// NOW, create several duplicates of the "Main Body" fixture
// but offset them from the previous one by a fixed amount and
// overlap them a bit.
const uint32 SNAKE_SEGMENTS = 4;
Vec2 offset(-4*VERT_SCALE,0*VERT_SCALE);
b2Body* pBodyA = body;
b2Body* pBodyB = NULL;
b2RevoluteJointDef revJointDef;
revJointDef.collideConnected = false;< br />
// Add some "regular segments".
for(int idx = 0; idx {
// Create a body for the next segment.
bodyDef.position = pBodyA->GetPosition() + offset;
pBodyB = world.CreateBody(&bodyDef);
_segments.push_back(pBodyB);
// Add some damping so body parts don't'flop' around.
pBodyB->SetLinearDamping(0.25);
pBodyB->SetAngularDamping(0.25);
// Offset the vertices for the fixture.
for(int vidx = 0; vidx {
vertices[vidx] += offset;
}
// and create the fixture.
polyShape.Set(&vertices[0],vertices.size());
pBodyB ->CreateFixture(&fixtureDef);

// Create a Revolute Joint at a position half way
// between the two bodies.
Vec2 midpoint = (pBodyA->GetPosition( ) + pBodyB->GetPosition());
revJointDef.Initialize(pBodyA, pBodyB, midpoint);
world.CreateJoint(&revJointDef);
// Update so the next time through the loop , we are
// connecting the next body to the one we just
// created.
pBodyA = pBodyB;
}
// Make the next bunch of segments get "smaller" each time
// to make a tail.
for(int i dx = 0; idx {
// Create a body for the next segment.
bodyDef.position = pBodyA->GetPosition() + offset;
pBodyB = world.CreateBody(&bodyDef);
_segments.push_back(pBodyB);
// Add some damping so body parts don't'flop' around.
pBodyB->SetLinearDamping(0.25 );
pBodyB->SetAngularDamping(0.25);
// Offset the vertices for the fixture.
for(int vidx = 0; vidx {
vertices[vidx] += offset;
vertices[vidx].y *= 0.75;
}
// and create the fixture.
polyShape .Set(&vertices[0],vertices.size());
pBodyB->CreateFixture(&fixtureDef);

// Create a Revolute Joint at a position half way
// between the two bodies.
Vec2 midpoint = (pBodyA->GetPosition() + pBodyB->GetPosition());< br /> revJointDef.Initialize(pBodyA, pBodyB, midpoint);
world.CreateJoint(&revJointDef);
// Update so the next time through the loop, we are
// connecting the next body to the one we just
// created.
pBodyA = pBodyB;
}
// Give the tail some real "drag" so that it pulls the
// body straight when it can.
pBodyB->SetLinearDamping(1.5);
pBodyB->SetAngularDamping(1.5);

// Setup Parameters
SetMaxAngularAcceleration (4*M_PI);
// As long as this is high, they forces will be strong
// enough to get the body close to the target position
// very quickly so the entity does not "circle" the
// point.
SetMaxLinearAcceleration(100);
SetMaxSpeed(10);
SetMinSeekDistance(1.0);
}

This will be your first part, a basic body. Here are some notes about the code:

>I increased the damping of the body and even more tails, so it can
Drag and “pull down” The remaining link. This makes it look smoother when
dragging it.
>Adjacent body parts will not collide, but non-adjacent parts will collide, so the snake
can “click You can choose whether other parts should collide or not.

Now, it’s a bit tricky to get the body to move the way you want. I’ll show you a picture (and Video) so that you can see where I got it. All of these are in the code base I referenced, so you can adjust it if you want.

First of all, this is where I drag it I took a screenshot of what the snake looks like after a while.

I took some videos, and you can see it colliding, slowing down, etc. (see it here).

When you see it In sports, it is still not perfect, but I think it looks pretty good for a few hours of work.

To make the snake move, I took the method of “dragging” its head. When I drag it, the head rotates towards my finger (or you can make it follow a path in the code, chase something, etc.) and move its head towards the target. The other parts of the body “drag”, this Make it look “good”.

The controller uses two different mechanisms to move the body:

Use the body direction to seek behavior

Use in the text “Search” behavior, its behavior is as follows:

The following is the code of the ApplyThrust(…) method of the MovingEntity class.

void ApplyThrust()
{
// Get the distance to the target.
Vec2 toTarget = GetTargetPos()-GetBody()->GetWorldCenter();
toTarget.Normalize();
Vec2 desiredVel = GetMaxSpeed()*toTarget;
Vec2 currentVel = GetBody()->GetLinearVelocity();
Vec2 thrust = desiredVel-currentVel;
GetBody()->ApplyForceToCenter(GetMaxLinearAcceleration()* thrust);
}

This method applies thrust to make b2Body face the target It has the maximum speed (GetMaxSpeed()) and the maximum linear acceleration (GetMaxLinearAcceleration()) as attributes of the class.

If you follow the code and draw the vector, you will see that its role is to apply Thrust to drive your speed to point to the position of the target.

Another way of looking at it: it is like a feedback loop (in a vector) to keep your speed at the desired level Velocity matching. If you just consider it in terms of a scalar, it will be easier to see.

If you move to the right at a speed of 5 m/s (currentVel) and your maximum velocity (desiredVel) is 6m/s, then the thrust will push to the right, and push to the right faster (desiredVel-currentVel = 1). That is, you will accelerate to the right.

If you push at 7m/s Move the speed to the right (currentVel) and your maximum speed (desiredVel) is 6 m/s, the thrust will be negative, point to the left, slow down your speed (desiredVel – currentVel = -1) .

< p>From physical update to update, this makes your body move in the direction of the target at the speed you want.

In your case, you just want to move left and right, letting gravity Pull down your body. All of this should work well in the context of physics. You can control the speed at which the agent accelerates/decelerates by controlling the linear acceleration.

Use PID controller for Body rotation

This is a bit complicated (as if the previous part is not).

Our idea is based on the difference between the angle you want and the angle your body faces. The body applies torque. The PID controller uses the current angle difference (multiplied by the proportional constant), the most recent history difference (integral), and the rate of change of the angle difference (variable). The first two make the body rotate, and the last one makes it reach the goal Slow down when angled.

You can see more details on the theory and implementation here.

All of this is encapsulated in a class in the code called PIDController.

Note: The PIDController in the code base is universal. It doesn’t know anything about box2d, physics or its purpose. It’s like a sorting algorithm… It only cares about the data it is input and how the parameters you set Work. It can be easily used in other environments… and has about 100 years of time.

Hope this will get you in the right direction. This may be a bit overkill, but I​​ Dig these things a bit, so it’s fun.

Leave a Comment

Your email address will not be published.