我的工作类似于蛇.我想制作蛇体.
游戏逻辑是这样的:
蛇上下移动.移动应该像真正的蛇运动.
在这里,我受到了打击.
如何制作蛇的身体?
任何想法或参考应该对我有所帮助.
提前致谢.
Fuz*_*ers 12
好的,这将是一个很长的答案.
我使用其他项目中的一些代码和"蛇"部分组合了一个快速示例.你可以在github上找到整个(cocos2d-x)代码库.
最容易(也是第一件)要做的就是建造蛇体.从Box2D的角度来看,你可以用一系列段来构建它们,每个段都通过一个旋转关节连接起来.
以下是我们的目标:

这是我用来创建它的"粗略"代码:
// 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;
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;
b2RevoluteJointDef revJointDef;
revJointDef.collideConnected = false;
// Add some "regular segments".
for(int idx = 0; idx < SNAKE_SEGMENTS; 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.size(); 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 < SNAKE_SEGMENTS; 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.size(); 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());
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);
}
Run Code Online (Sandbox Code Playgroud)
这将是你的第一部分,一个基本的身体.以下是有关代码的一些注意事项:
现在,让身体按照你想要的方式移动会有点棘手.我先给你看一张图片(和视频),这样你就可以看到我的位置了.所有这些都在我引用的代码库中,因此如果您愿意,可以调整它.
首先,这是我将它拖了一下之后蛇的样子的截图.

我拍了一些视频你可以看到它碰撞,减速等等(见这里).
当你看到它在运动中,它仍然不完美,但我认为它看起来相当不错的几个小时的工作.
为了使蛇移动,我采取了"拖动"它的头部的方法.当我拖动它时,头部朝我的手指旋转(或者你可以使它遵循代码中的路径,追逐某些东西等)并将其头部朝向目标.身体的其他部分"拖拽",这使它看起来很"好".
控制器使用两种不同的机制来移动身体:
使用寻求行为的身体方向
正文使用"搜索"行为,其行为如下:
下面是MovingEntity类的ApplyThrust(...)方法的代码.
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);
}
Run Code Online (Sandbox Code Playgroud)
该方法施加推力以使b2Body朝向目标方向移动.它具有最大速度(GetMaxSpeed())和最大线性加速度(GetMaxLinearAcceleration())作为类的属性.
如果您按照代码并绘制矢量,您将看到它的作用是施加推力以驱动您的速度,使其指向目标的位置.
另一种看待它的方法:它就像一个反馈循环(在矢量中),以保持你的速度与所需的速度匹配.如果您只是根据标量来考虑它,它会更容易看到.
如果你以5米/秒的速度向右移动(currentVel)并且你的最大速度(desiredVel)是6米/秒,那么推力将向右推,向右推得更快(desiredVel - currentVel = +1 ).也就是说,你会加速到右边.
如果你以7米/秒的速度向右移动(currentVel)并且你的最大速度(desiredVel)是6米/秒,推力将为负,指向左侧,减慢你的速度(desiredVel - currentVel = -1) .
从物理的更新到更新,这使您的身体以您想要的速度朝目标方向移动.
在你的情况下,你只想向左和向右移动,让重力拉下你的身体.所有这一切都应该在物理学的背景下很好地发挥作用.您可以通过控制线性加速度来控制代理加速/减速的速度.
使用PID控制器进行车身旋转
这有点复杂(好像前一部分不是).
我们的想法是根据您想要的角度与您的身体所面对的角度之间的差异向身体施加扭矩.PID控制器不使用当前角度差(倍比例常数),在最近的历史(差值积分),并在角度(差的变化率衍生物).前两个让身体转动,最后一个让它在达到目标角度时减速.
所有这些都封装在代码中的一个类中,称为PIDController.
注意:代码库中的PIDController是通用的.它对box2d,物理或它的用途一无所知.它就像一个排序算法......它只关心它被输入的数据以及你设置的参数如何工作.它可以很容易地在其他环境中使用......并且有大约100年的时间.
希望这能让你朝着正确的方向前进.这可能有点矫枉过正,但我有点挖掘这些东西,所以很有趣.
| 归档时间: |
|
| 查看次数: |
2087 次 |
| 最近记录: |