像 CCSprite 对象一样移动 Box2d 实体
在cocos2d中,您可以轻松使用CCSprites并以各种方式移动它们。最重要的是 - 他们可以缓入/缓出。对于大多数游戏来说,这对于平滑移动等是可取的。
id action = [CCMoveTo actionWithDuration:dur position:pos];
move = [CCEaseInOut actionWithAction:action rate:2];
[self runAction: move];
当移动 box2d 主体时,附加到它的精灵会在 box2d 步骤()之后更新。移动精灵然后更新身体在这里不是一个选择,因为它完全违背了物理框架的目的。
因此,我已经成功实现的另一个选项是通过将精灵本身视为力学实体来计算精灵的位移、速度和加速度。每次我在精灵上调用 update() 以便角色可以决定移动到哪里等时,我的超类还存储以前的位置和速度。这些值除以 PTM_RATIO 后存储为符合 box2d 的值。
在 CCSprite 的子类中,称为 FMSprite:
-(CGPoint) displacement {
return ccpSub(self.position, lastPos);
}
-(b2Vec2) getSpriteVelocity:(ccTime)dt {
return b2Vec2(self.displacement.x / dt / PTM_RATIO,
self.displacement.y / dt / PTM_RATIO);
}
-(b2Vec2) getSpriteAccel:(ccTime)dt {
b2Vec2 currVel = [self getSpriteVelocity:dt];
if (dt == 0) {
return b2Vec2(0,0);
} else {
float accelX = (currVel.x - lastVel.x)/dt;
float accelY = (currVel.y - lastVel.y)/dt;
return b2Vec2(accelX, accelY);
}
}
// This is called each update()
-(void) updateLast:(ccTime)dt {
// MUST store lastVel before lastPos is updated since it uses displacement
lastVel = [self getSpriteVelocity:dt];
lastPos = ccp(self.X, self.Y);
}
// Leave this method untouched in subclasses
-(void) update:(ccTime)dt {
[self updateObject:dt];
// Store previous update values
[self updateLast:dt];
}
// Override this method in subclasses for custom functionality
-(void) updateObject:(ccTime)dt {
}
然后,我将“FMSprite”子类化为“FMObject”,它存储 b2Body 等。
为了移动身体,我必须首先移动精灵并跟踪其加速度,通过它我可以找到跟随精灵运动所需的力(使用质量)。由于我无法移动对象的精灵(与主体同步),因此我制作了另一个名为“信标”的精灵,将其作为子对象添加到对象中,然后移动它。我们需要做的就是拥有一个函数,使用我之前提到的力来将 box2d 主体的位置与这个信标精灵同步。
-(void) followBeaconWithDelta:(ccTime)dt {
float forceX = [beacon getSpriteAccel:dt].x * self.mass;
float forceY = [beacon getSpriteAccel:dt].y * self.mass;
[self addForce:b2Vec2(forceX, forceY)];
}
结果非常出色,b2body 可以平滑地缓和运动,移动到您想要的任何位置,无需使用其自身的任何力,而是复制 CCSprite 的运动并复制其运动。由于都是力,所以在与其他b2Body物体碰撞时不会造成抖动和扭曲。如果有人有任何其他方法可以做到这一点,请发布答案。谢谢!
In cocos2d, you can ease in CCSprites and move them around in all kinds of ways. Most importantly - they can have easing in/out. For most games this is desirable for smooth movement etc.
id action = [CCMoveTo actionWithDuration:dur position:pos];
move = [CCEaseInOut actionWithAction:action rate:2];
[self runAction: move];
When moving a box2d body, the sprite attached to it is updated after the box2d step(). Moving the sprite and then updating the body is not an option here, as it entirely defeats the purpose of the physics framework.
So the other option, which I have successfully implemented, is to calculate the displacement, velocity and acceleration of a sprite by treating it as a mechanics entity in its own right. Each time I call my update() on the sprite so the character can decide where to move etc, my superclass also stores the previous position and velocity. These are stored as box2d compliant values by dividing by the PTM_RATIO.
In the subclass of CCSprite, called FMSprite:
-(CGPoint) displacement {
return ccpSub(self.position, lastPos);
}
-(b2Vec2) getSpriteVelocity:(ccTime)dt {
return b2Vec2(self.displacement.x / dt / PTM_RATIO,
self.displacement.y / dt / PTM_RATIO);
}
-(b2Vec2) getSpriteAccel:(ccTime)dt {
b2Vec2 currVel = [self getSpriteVelocity:dt];
if (dt == 0) {
return b2Vec2(0,0);
} else {
float accelX = (currVel.x - lastVel.x)/dt;
float accelY = (currVel.y - lastVel.y)/dt;
return b2Vec2(accelX, accelY);
}
}
// This is called each update()
-(void) updateLast:(ccTime)dt {
// MUST store lastVel before lastPos is updated since it uses displacement
lastVel = [self getSpriteVelocity:dt];
lastPos = ccp(self.X, self.Y);
}
// Leave this method untouched in subclasses
-(void) update:(ccTime)dt {
[self updateObject:dt];
// Store previous update values
[self updateLast:dt];
}
// Override this method in subclasses for custom functionality
-(void) updateObject:(ccTime)dt {
}
I have then subclassed "FMSprite" into "FMObject", which stores a b2Body etc.
In order to move the body, I must first move a sprite and track its acceleration, through which I can find the required force (using the mass) needed to follow the sprite's motion. Since I can't move the object's sprite (which is synchronized to the body), I make another sprite called a "beacon", add it as a child to the object, and move it around. All we need to do then is to have a function to synchronize the position of the box2d body with this beacon sprite using the forces I mentioned before.
-(void) followBeaconWithDelta:(ccTime)dt {
float forceX = [beacon getSpriteAccel:dt].x * self.mass;
float forceY = [beacon getSpriteAccel:dt].y * self.mass;
[self addForce:b2Vec2(forceX, forceY)];
}
The result is brilliant, a smooth easing motion of the b2body moving where ever you want it to, without playing around with any of its own forces, but rather copying that of a CCSprite and replicating its motion. Since it's all forces, it won't cause jittering and distortions when colliding with other b2Body objects. If anyone has any other methods to do this, please post an answer. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我所做的与你的不同,但也可以像CCSprite对象一样移动Box2d实体,甚至使用CCAction。
最重要的是创建一个包含ccSprite和b2body的对象。
然后,重写setPosition方法。
setPosition方法计算位置变化了多少,并将其设置给b2body。
我希望我能理解你的问题并且答案对你有帮助......
What I do is different from yours, but can also Moving Box2d Bodies Like CCSprite Objects and even use the CCAction.
The most important thing is to create an object that contain ccSprite and b2body.
And then, rewrite the setPosition method.
The setPosition method calculate how much the position change,and set it to the b2body.
I hope I have understanding your question and the answer is helpful for you...