box2d 粗略的模拟水浮力
来源:互联网 发布:手机麻将透视软件 编辑:程序博客网 时间:2024/03/29 02:22
准备工作,首先修改 box2d 的 b2Body 类,
增加一个public 修饰的 bool 类型标识变量 m_isInWater,用于标识物体当前是否在水中。
然后,切到 box2d 的 b2World 类,在 CreateBody 方法的尾部添加一行初始化标识变量的代码:
b2Body* b2World::CreateBody(const b2BodyDef* def){b2Assert(IsLocked() == false);if (IsLocked()){return NULL;}void* mem = m_blockAllocator.Allocate(sizeof(b2Body));b2Body* b = new (mem) b2Body(def, this);// Add to world doubly linked list.b->m_prev = NULL;b->m_next = m_bodyList;if (m_bodyList){m_bodyList->m_prev = b;}m_bodyList = b;++m_bodyCount; /** Added By Bruce Yang on 2011.11.25.12.49~ */ b->m_isCuttable = true; // body 默认设置为可被切割的~ b->m_isBalloon = false; // body 默认设置为非气球~ b->m_isInWater = false; // body 默认设置不在水中(即使出生就在水中也不要紧,contactListener会立即做相应设置)~return b;}contactListener 的相关代码:
//// MyContactListener.m// GameScene//// Created by Bruce Yang on 2/18/10.// Copyright (c) 2012年 EricGameStudio. All rights reserved.//#import "MyContactListener.h"MyContactListener::MyContactListener() : _contacts() { }MyContactListener::~MyContactListener() { }/** * 处理物体落水受到浮力的情况~ * 在刚入水的时候,物体的速度将骤减,然后受到一个持续向上的浮力,直到物体脱离水区域为止~ * 本来在 x 轴方向是不应该受到浮力的影响的,但考虑到水的粘滞性,x 轴方向的速度收缩为原来的 0.8 倍~ * 还有就是,角速度的大小也会受到液体粘滞性的影响,因此角速度也要做相应的处理~ */void addBuoyancyTag(MyContact contact) { float ySpeedDecreaseFactor = 0.3f; float xSpeedDecreaseFactor = 0.7f; float rSpeedDecreaseFactor = 0.7f; if(contact.fixtureA == [BYSingle getInstance].buoyancy) { // 1.y方向的速度在入水的临界点骤减为原来的 0.3 倍~ b2Body* body = contact.fixtureB->GetBody(); b2Vec2 oldSpeed = body->GetLinearVelocity(); body->SetLinearVelocity(b2Vec2(oldSpeed.x * xSpeedDecreaseFactor, oldSpeed.y * ySpeedDecreaseFactor)); body->SetAngularVelocity(body->GetAngularVelocity() * rSpeedDecreaseFactor); // 2.标识为 “受水浮力影响” 状态~ body->m_isInWater = true; } if(contact.fixtureB == [BYSingle getInstance].buoyancy) { b2Body* body = contact.fixtureA->GetBody(); b2Vec2 oldSpeed = body->GetLinearVelocity(); body->SetLinearVelocity(b2Vec2(oldSpeed.x * xSpeedDecreaseFactor, oldSpeed.y * ySpeedDecreaseFactor)); body->SetAngularVelocity(body->GetAngularVelocity() * rSpeedDecreaseFactor); body->m_isInWater = true; }}// 移除 “受水浮力影响” 标识(切割水中物体的时候会出错,蛋疼)~void removeBuoyancyTag(MyContact contact) { if(contact.fixtureA == [BYSingle getInstance].buoyancy) { contact.fixtureB->GetBody()->m_isInWater = false; } if(contact.fixtureB == [BYSingle getInstance].buoyancy) { contact.fixtureA->GetBody()->m_isInWater = false; }}void MyContactListener::BeginContact(b2Contact* contact) { MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; // added by Bruce Yang on 2012.04.13.13.34~ addBuoyancyTag(myContact); _contacts.push_back(myContact);}void MyContactListener::EndContact(b2Contact* contact) { MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; // added by Bruce Yang on 2012.04.13.13.34~ removeBuoyancyTag(myContact); vector<MyContact>::iterator pos; pos = find(_contacts.begin(), _contacts.end(), myContact); if (pos != _contacts.end()) { _contacts.erase(pos); }}void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {}void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) {}
主场景的tick方法:-(void) tick: (ccTime) dt { int32 velocityIterations = 8;int32 positionIterations = 1; _world->Step(dt, velocityIterations, positionIterations); /** Iterate over the bodies in the physics world */for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext()) { if(b->GetUserData() != NULL) { // Synchronize the AtlasSprites position and rotation with the corresponding(相应的) body CCSprite *actor = (CCSprite*)b->GetUserData(); CGPoint po = CGPointMake(b->GetPosition().x*PTM_RATIO, b->GetPosition().y*PTM_RATIO); if(![MGameScene isPositionOutOfBounds:po]) {// 如果没有越界的话,实时更新~ actor.position = po; actor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()); // 给接触水区域的物体施加持续向上的浮力~ if(b->m_isInWater) { float absG = fabs(_world->GetGravity().y); float mass = b->GetMass(); float density = 0; if(b->GetFixtureListCount() != 0) { density = b->GetFixtureList()->GetDensity(); } else { density = 1.2f; } float volumn = mass / density; // mass = rho * volumn,水的密度是1.0, // 但为了使密度为 1.0 的冰块不致于很慢的沉入水中,将水的密度调为 0.9 以减小浮力~ float waterMass = 0.9f * volumn; b->ApplyForceToCenter(b2Vec2(0, waterMass * absG)); } } else { if(actor.tag != TAG_STATE_READY_TO_BE_REMOVED) { [actor removeFromParentAndCleanup:YES]; } [MGameScene byDestroyBody:b]; // 对于越界的 body,一律销毁之~ } }}}值得一提的是:
我开始是将表示变量放在 CCSprite 类里面的,这样会出现一个问题:
contactListener 当物体脱离水区域调用 removeBuoyancyTag() 方法的时候
如果在水中将该 body 切割的话(切割会将旧 body 销毁,并生成两份新的 body),从 body 里面取出 CCSprite 对象会报出错误,
后来在我将 isInWater 这个标识放到 b2Body 里面后,干掉了这个bug(没做细致的测试,不过试了蛮多次,没发现出问题)~
- box2d 粗略的模拟水浮力
- 一个有关浮力的物理题
- Box2D 物理引擎---创建一个简单的模拟物理世界
- 使用Qt的鼠标支持,模拟实现粗略的画板连线
- RSS的粗略介绍
- 粗略的博客需求
- soure 的粗略分析
- JUNIT的粗略介绍
- C++的粗略学习
- JDBC的粗略介绍
- Box2d进阶 使用光线投射实现Box2d爆炸效果模拟
- box2d 模拟真实世界的物体碰撞 类似愤怒的小鸟
- 论物体上浮至漂浮所受浮力与重力的关系
- Java C#的粗略比较
- Java C#的粗略比较
- NBear的优缺点粗略分析
- 粗略看Hibernate的代码
- 寒假粗略的任务计划
- android 网络判断
- maven 项目依赖管理
- 【状态压缩】【动态规划】坑爹题
- 阻止保存要求重新创建表的更改
- Oracle常用函数
- box2d 粗略的模拟水浮力
- 【学习点滴-js】js学习总结。
- 关于在Github创建仓库的过程
- Hibernate映射文件中id的 generator class
- c# 安装FxCop步骤
- 根据IP地址查出对应城市
- android 使用广播监听网络状态
- C++计算最大公约数(辗转相除法)
- Java对象的强、软、弱和虚引用