| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "physics_layer.h" | |
| 6 #include "app_delegate.h" | |
| 7 #include "gameplay_scene.h" | |
| 8 | |
| 9 #include "physics_nodes/CCPhysicsSprite.h" | |
| 10 #include "CCLuaEngine.h" | |
| 11 | |
| 12 extern "C" { | |
| 13 #include "lua.h" | |
| 14 #include "tolua++.h" | |
| 15 #include "lualib.h" | |
| 16 #include "lauxlib.h" | |
| 17 #include "tolua_fix.h" | |
| 18 } | |
| 19 | |
| 20 // Pixels-to-meters ratio for converting screen coordinates | |
| 21 // to Box2D "meters". | |
| 22 #define PTM_RATIO 32 | |
| 23 #define SCREEN_TO_WORLD(n) ((n) / PTM_RATIO) | |
| 24 #define WORLD_TO_SCREEN(n) ((n) * PTM_RATIO) | |
| 25 #define VELOCITY_ITERATIONS 8 | |
| 26 #define POS_ITERATIONS 1 | |
| 27 | |
| 28 #define MAX_SPRITES 100 | |
| 29 | |
| 30 #define DEFAULT_DENSITY 1.0f | |
| 31 #define DEFAULT_FRICTION 0.2f | |
| 32 #define DEFAULT_RESTITUTION 0.1f | |
| 33 | |
| 34 | |
| 35 USING_NS_CC_EXT; | |
| 36 | |
| 37 PhysicsLayer* PhysicsLayer::create(int level_number) | |
| 38 { | |
| 39 PhysicsLayer* layer = new PhysicsLayer(level_number); | |
| 40 if (!layer) | |
| 41 return NULL; | |
| 42 layer->init(); | |
| 43 return layer; | |
| 44 } | |
| 45 | |
| 46 bool PhysicsLayer::init() { | |
| 47 if (!CCLayerColor::initWithColor(ccc4(0,0x8F,0xD8,0xD8))) | |
| 48 return false; | |
| 49 | |
| 50 setTouchEnabled(true); | |
| 51 | |
| 52 InitPhysics(); | |
| 53 | |
| 54 // Load level from lua file. For now we simple load level 1. | |
| 55 LoadLua(); | |
| 56 | |
| 57 // Calculate brush size | |
| 58 CCSpriteBatchNode* brush_batch = (CCSpriteBatchNode*)getChildByTag(TAG_BRUSH); | |
| 59 assert(brush_batch); | |
| 60 brush_ = CCSprite::createWithTexture(brush_batch->getTexture()); | |
| 61 brush_->retain(); | |
| 62 CCSize brush_size = brush_->getContentSize(); | |
| 63 brush_radius_ = MAX(brush_size.height/2, brush_size.width/2); | |
| 64 | |
| 65 // Schedule physics updates each frame | |
| 66 schedule(schedule_selector(PhysicsLayer::UpdateWorld)); | |
| 67 return true; | |
| 68 } | |
| 69 | |
| 70 PhysicsLayer::PhysicsLayer(int level_number) : | |
| 71 level_number_(level_number), | |
| 72 goal_reached_(false), | |
| 73 current_touch_id_(-1), | |
| 74 render_target_(NULL), | |
| 75 #ifdef COCOS2D_DEBUG | |
| 76 debug_enabled_(false), | |
| 77 #endif | |
| 78 box2d_density_(DEFAULT_DENSITY), | |
| 79 box2d_restitution_(DEFAULT_RESTITUTION), | |
| 80 box2d_friction_(DEFAULT_FRICTION) { | |
| 81 memset(stars_collected_, 0, sizeof(stars_collected_)); | |
| 82 } | |
| 83 | |
| 84 PhysicsLayer::~PhysicsLayer() { | |
| 85 brush_->release(); | |
| 86 delete box2d_world_; | |
| 87 #ifdef COCOS2D_DEBUG | |
| 88 delete box2d_debug_draw_; | |
| 89 #endif | |
| 90 } | |
| 91 | |
| 92 void PhysicsLayer::registerWithTouchDispatcher() { | |
| 93 CCDirector* director = CCDirector::sharedDirector(); | |
| 94 director->getTouchDispatcher()->addTargetedDelegate(this, 0, true); | |
| 95 } | |
| 96 | |
| 97 void PhysicsLayer::CreateRenderTarget() { | |
| 98 // create render target for shape drawing | |
| 99 assert(!render_target_); | |
| 100 CCSize win_size = CCDirector::sharedDirector()->getWinSize(); | |
| 101 render_target_ = CCRenderTexture::create(win_size.width, | |
| 102 win_size.height, | |
| 103 kCCTexture2DPixelFormat_RGBA8888); | |
| 104 render_target_->setPosition(ccp(win_size.width / 2, win_size.height / 2)); | |
| 105 addChild(render_target_); | |
| 106 } | |
| 107 | |
| 108 bool PhysicsLayer::LoadLua() { | |
| 109 CCScriptEngineManager* manager = CCScriptEngineManager::sharedManager(); | |
| 110 CCLuaEngine* engine = (CCLuaEngine*)manager->getScriptEngine(); | |
| 111 assert(engine); | |
| 112 lua_stack_ = engine->getLuaStack(); | |
| 113 assert(lua_stack_); | |
| 114 | |
| 115 lua_stack_->pushString("sample_game/game.lua"); | |
| 116 lua_stack_->pushCCObject(this, "PhysicsLayer"); | |
| 117 lua_stack_->pushInt(level_number_); | |
| 118 | |
| 119 // Call 'main' with three arguments pushed above | |
| 120 int rtn = lua_stack_->executeFunctionByName("main", 3); | |
| 121 if (rtn != 1) | |
| 122 return false; | |
| 123 | |
| 124 return true; | |
| 125 } | |
| 126 | |
| 127 bool PhysicsLayer::InitPhysics() { | |
| 128 b2Vec2 gravity(0.0f, -9.8f); | |
| 129 box2d_world_ = new b2World(gravity); | |
| 130 box2d_world_->SetAllowSleeping(true); | |
| 131 box2d_world_->SetContinuousPhysics(true); | |
| 132 | |
| 133 // Find visible rect, and convert to box2d space. | |
| 134 CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); | |
| 135 CCSize visible_size = CCDirector::sharedDirector()->getVisibleSize(); | |
| 136 float world_width = SCREEN_TO_WORLD(visible_size.width); | |
| 137 b2Vec2 world_origin(SCREEN_TO_WORLD(origin.x), SCREEN_TO_WORLD(origin.y)); | |
| 138 | |
| 139 // create the ground | |
| 140 b2BodyDef ground_def; | |
| 141 ground_def.position = world_origin; | |
| 142 b2Body* ground_body = box2d_world_->CreateBody(&ground_def); | |
| 143 | |
| 144 CCLog("origin: %.fx%.f", origin.x, origin.y); | |
| 145 CCLog("size: %.fx%f", visible_size.width, visible_size.height); | |
| 146 | |
| 147 // Define the ground box shape. | |
| 148 b2EdgeShape ground_box; | |
| 149 ground_box.Set(b2Vec2(0, 0), b2Vec2(world_width, 0)); | |
| 150 ground_body->CreateFixture(&ground_box, 0); | |
| 151 ground_body->SetUserData((void*)TAG_GROUND); | |
| 152 | |
| 153 box2d_world_->SetContactListener(this); | |
| 154 | |
| 155 #ifdef COCOS2D_DEBUG | |
| 156 box2d_debug_draw_ = new GLESDebugDraw(PTM_RATIO); | |
| 157 box2d_world_->SetDebugDraw(box2d_debug_draw_); | |
| 158 | |
| 159 uint32 flags = 0; | |
| 160 flags += b2Draw::e_shapeBit; | |
| 161 flags += b2Draw::e_jointBit; | |
| 162 flags += b2Draw::e_centerOfMassBit; | |
| 163 //flags += b2Draw::e_aabbBit; | |
| 164 //flags += b2Draw::e_pairBit; | |
| 165 box2d_debug_draw_->SetFlags(flags); | |
| 166 #endif | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 void PhysicsLayer::ToggleDebug() { | |
| 171 debug_enabled_ = !debug_enabled_; | |
| 172 | |
| 173 // Set visibility of all children based on debug_enabled_ | |
| 174 CCArray* children = getChildren(); | |
| 175 if (!children) | |
| 176 return; | |
| 177 for (uint i = 0; i < children->count(); i++) | |
| 178 { | |
| 179 CCNode* child = static_cast<CCNode*>(children->objectAtIndex(i)); | |
| 180 if (child == render_target_) | |
| 181 continue; | |
| 182 child->setVisible(!debug_enabled_); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 CCRect CalcBoundingBox(CCSprite* sprite) { | |
| 187 CCSize size = sprite->getContentSize(); | |
| 188 CCPoint pos = sprite->getPosition(); | |
| 189 return CCRectMake(pos.x - size.width, pos.y - size.height, | |
| 190 size.width, size.height/2); | |
| 191 } | |
| 192 | |
| 193 void PhysicsLayer::UpdateWorld(float dt) { | |
| 194 // update physics | |
| 195 box2d_world_->Step(dt, VELOCITY_ITERATIONS, POS_ITERATIONS); | |
| 196 } | |
| 197 | |
| 198 void PhysicsLayer::LuaNotifyContact(b2Contact* contact, | |
| 199 const char* function_name) { | |
| 200 // Return early if lua didn't define the function_name | |
| 201 lua_State* state = lua_stack_->getLuaState(); | |
| 202 lua_getglobal(state, function_name); | |
| 203 bool is_func = lua_isfunction(state, -1); | |
| 204 lua_pop(state, 1); | |
| 205 | |
| 206 if (!is_func) | |
| 207 return; | |
| 208 | |
| 209 // Only send to lua collitions between body's that | |
| 210 // have been tagged. | |
| 211 b2Body* body1 = contact->GetFixtureA()->GetBody(); | |
| 212 b2Body* body2 = contact->GetFixtureB()->GetBody(); | |
| 213 int tag1 = (int)body1->GetUserData(); | |
| 214 int tag2 = (int)body2->GetUserData(); | |
| 215 if (!tag1 || !tag2) | |
| 216 return; | |
| 217 | |
| 218 // Call 'ContactBegan' lua function passing in 'this' | |
| 219 // as well as the tags of the two bodies that collided | |
| 220 lua_stack_->pushCCObject(this, "PhysicsLayer"); | |
| 221 lua_stack_->pushInt(tag1); | |
| 222 lua_stack_->pushInt(tag2); | |
| 223 lua_stack_->executeFunctionByName(function_name, 3); | |
| 224 } | |
| 225 | |
| 226 void PhysicsLayer::BeginContact(b2Contact* contact) { | |
| 227 LuaNotifyContact(contact, "BeginContact"); | |
| 228 } | |
| 229 | |
| 230 void PhysicsLayer::EndContact(b2Contact* contact) { | |
| 231 LuaNotifyContact(contact, "EndContact"); | |
| 232 } | |
| 233 | |
| 234 void PhysicsLayer::LevelComplete() { | |
| 235 // fade out the goal and trigger gameover callback when its | |
| 236 // done | |
| 237 CCPhysicsSprite* goal = (CCPhysicsSprite*)getChildByTag(TAG_GOAL); | |
| 238 CCActionInterval* fadeout = CCFadeOut::create(0.5f); | |
| 239 CCFiniteTimeAction* fadeout_done = CCCallFuncN::create(this, | |
| 240 callfuncN_selector(PhysicsLayer::LevelCompleteDone)); | |
| 241 CCSequence* seq = CCSequence::create(fadeout, fadeout_done, NULL); | |
| 242 goal->runAction(seq); | |
| 243 } | |
| 244 | |
| 245 void PhysicsLayer::LevelCompleteDone(CCNode* sender) { | |
| 246 unschedule(schedule_selector(PhysicsLayer::UpdateWorld)); | |
| 247 setTouchEnabled(false); | |
| 248 GameplayScene* scene = static_cast<GameplayScene*>(getParent()); | |
| 249 scene->GameOver(true); | |
| 250 } | |
| 251 | |
| 252 void PhysicsLayer::DrawPoint(CCPoint& location) { | |
| 253 ClampBrushLocation(location); | |
| 254 render_target_->begin(); | |
| 255 brush_->setVisible(true); | |
| 256 brush_->setPosition(ccp(location.x, location.y)); | |
| 257 brush_->visit(); | |
| 258 brush_->setVisible(false); | |
| 259 render_target_->end(); | |
| 260 points_being_drawn_.push_back(location); | |
| 261 } | |
| 262 | |
| 263 void PhysicsLayer::draw() { | |
| 264 CCLayerColor::draw(); | |
| 265 | |
| 266 #ifdef COCOS2D_DEBUG | |
| 267 if (debug_enabled_) { | |
| 268 ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position); | |
| 269 kmGLPushMatrix(); | |
| 270 box2d_world_->DrawDebugData(); | |
| 271 kmGLPopMatrix(); | |
| 272 } | |
| 273 #endif | |
| 274 } | |
| 275 | |
| 276 void PhysicsLayer::ClampBrushLocation(CCPoint& point) { | |
| 277 CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); | |
| 278 CCSize visible_size = CCDirector::sharedDirector()->getVisibleSize(); | |
| 279 | |
| 280 float min_x = origin.x + brush_radius_; | |
| 281 float min_y = origin.y + brush_radius_; | |
| 282 if (point.x < min_x) point.x = min_x; | |
| 283 if (point.y < min_y) point.y = min_y; | |
| 284 | |
| 285 float max_x = origin.x + visible_size.width - brush_radius_; | |
| 286 float max_y = origin.y + visible_size.height - brush_radius_; | |
| 287 if (point.x > max_x) point.x = max_x; | |
| 288 if (point.y > max_y) point.y = max_y; | |
| 289 } | |
| 290 | |
| 291 void PhysicsLayer::DrawLine(CCPoint& start, CCPoint& end) { | |
| 292 ClampBrushLocation(start); | |
| 293 ClampBrushLocation(end); | |
| 294 | |
| 295 // calculate distance moved | |
| 296 float distance = ccpDistance(start, end); | |
| 297 | |
| 298 // draw the brush sprite into render texture at every point between the old | |
| 299 // and new cursor positions | |
| 300 render_target_->begin(); | |
| 301 for (int i = 0; i < int(distance + 0.5); i++) { | |
| 302 float difx = end.x - start.x; | |
| 303 float dify = end.y - start.y; | |
| 304 float delta = (float)i / distance; | |
| 305 brush_->setVisible(true); | |
| 306 brush_->setPosition( | |
| 307 ccp(start.x + (difx * delta), start.y + (dify * delta))); | |
| 308 | |
| 309 brush_->visit(); | |
| 310 brush_->setVisible(false); | |
| 311 } | |
| 312 render_target_->end(); | |
| 313 points_being_drawn_.push_back(end); | |
| 314 } | |
| 315 | |
| 316 bool PhysicsLayer::ccTouchBegan(CCTouch* touch, CCEvent* event) { | |
| 317 if (current_touch_id_ != -1) | |
| 318 return false; | |
| 319 | |
| 320 current_touch_id_ = touch->getID(); | |
| 321 | |
| 322 if (!render_target_) | |
| 323 CreateRenderTarget(); | |
| 324 | |
| 325 points_being_drawn_.clear(); | |
| 326 CCPoint location = touch->getLocation(); | |
| 327 DrawPoint(location); | |
| 328 return true; | |
| 329 } | |
| 330 | |
| 331 void PhysicsLayer::ccTouchMoved(CCTouch* touch, CCEvent* event) { | |
| 332 assert(touch->getID() == current_touch_id_); | |
| 333 CCPoint end = touch->getLocation(); | |
| 334 CCPoint start = touch->getPreviousLocation(); | |
| 335 DrawLine(start, end); | |
| 336 } | |
| 337 | |
| 338 void PhysicsLayer::ccTouchEnded(CCTouch* touch, CCEvent* event) { | |
| 339 assert(touch->getID() == current_touch_id_); | |
| 340 b2Body* body = CreatePhysicsBody(); | |
| 341 CCSprite* sprite = CreatePhysicsSprite(body); | |
| 342 addChild(sprite); | |
| 343 if (debug_enabled_) | |
| 344 sprite->setVisible(false); | |
| 345 | |
| 346 // release render target (it will get recreated on next touch). | |
| 347 removeChild(render_target_, true); | |
| 348 render_target_ = NULL; | |
| 349 current_touch_id_ = -1; | |
| 350 } | |
| 351 | |
| 352 CCRect CalcBodyBounds(b2Body* body) { | |
| 353 CCSize s = CCDirector::sharedDirector()->getWinSize(); | |
| 354 | |
| 355 float minX = FLT_MAX; | |
| 356 float maxX = 0; | |
| 357 float minY = FLT_MAX; | |
| 358 float maxY = 0; | |
| 359 | |
| 360 const b2Transform& xform = body->GetTransform(); | |
| 361 for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext()) { | |
| 362 b2Shape* shape = f->GetShape(); | |
| 363 if (shape->GetType() == b2Shape::e_circle) { | |
| 364 b2CircleShape* c = static_cast<b2CircleShape*>(shape); | |
| 365 b2Vec2 center = b2Mul(xform, c->m_p); | |
| 366 if (center.x - c->m_radius < minX) | |
| 367 minX = center.x - c->m_radius; | |
| 368 if (center.x + c->m_radius > maxX) | |
| 369 maxX = center.x + c->m_radius; | |
| 370 if (center.y - c->m_radius < minY) | |
| 371 minY = center.y - c->m_radius; | |
| 372 if (center.y + c->m_radius > maxY) | |
| 373 maxY = center.y + c->m_radius; | |
| 374 } else { | |
| 375 b2PolygonShape* poly = static_cast<b2PolygonShape*>(shape); | |
| 376 int32 vertex_count = poly->m_vertexCount; | |
| 377 | |
| 378 for (int i = 0; i < vertex_count; ++i) | |
| 379 { | |
| 380 b2Vec2 vertex = b2Mul(xform, poly->m_vertices[i]); | |
| 381 if (vertex.x < minX) | |
| 382 minX = vertex.x; | |
| 383 if (vertex.x > maxX) | |
| 384 maxX = vertex.x; | |
| 385 if (vertex.y < minY) | |
| 386 minY = vertex.y; | |
| 387 if (vertex.y > maxY) | |
| 388 maxY = vertex.y; | |
| 389 } | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 maxX = WORLD_TO_SCREEN(maxX); | |
| 394 minX = WORLD_TO_SCREEN(minX); | |
| 395 maxY = WORLD_TO_SCREEN(maxY); | |
| 396 minY = WORLD_TO_SCREEN(minY); | |
| 397 | |
| 398 float width = maxX - minX; | |
| 399 float height = maxY - minY; | |
| 400 float remY = s.height - maxY; | |
| 401 return CCRectMake(minX, remY, width, height); | |
| 402 } | |
| 403 | |
| 404 CCSprite* PhysicsLayer::CreatePhysicsSprite(b2Body* body) { | |
| 405 CCPhysicsSprite *sprite; | |
| 406 | |
| 407 // create a new texture based on the current contents of the | |
| 408 // render target | |
| 409 CCImage* image = render_target_->newCCImage(); | |
| 410 CCTexture2D* tex = new CCTexture2D(); | |
| 411 tex->initWithImage(image); | |
| 412 tex->autorelease(); | |
| 413 delete image; | |
| 414 | |
| 415 // Find the bounds of the physics body wihh the target texture | |
| 416 CCRect sprite_rect = CalcBodyBounds(body); | |
| 417 sprite_rect.origin.x -= brush_radius_; | |
| 418 sprite_rect.origin.y -= brush_radius_; | |
| 419 sprite_rect.size.width += brush_radius_; | |
| 420 sprite_rect.size.height += brush_radius_; | |
| 421 | |
| 422 CCSize s = CCDirector::sharedDirector()->getWinSize(); | |
| 423 CCPoint body_pos = ccp(WORLD_TO_SCREEN(body->GetPosition().x), | |
| 424 WORLD_TO_SCREEN(body->GetPosition().y)); | |
| 425 | |
| 426 | |
| 427 // Create a new sprite based on the texture | |
| 428 sprite = CCPhysicsSprite::createWithTexture(tex, sprite_rect); | |
| 429 sprite->setB2Body(body); | |
| 430 sprite->setPTMRatio(PTM_RATIO); | |
| 431 | |
| 432 // Set the anchor point of the sprite | |
| 433 float anchorX = body_pos.x - sprite_rect.origin.x; | |
| 434 float anchorY = body_pos.y + sprite_rect.origin.y + sprite_rect.size.height; | |
| 435 anchorY -= s.height; | |
| 436 | |
| 437 // anchor point goes from 0.0 to 1.0 with in bounds of the sprite itself. | |
| 438 sprite->setAnchorPoint(ccp(anchorX / sprite_rect.size.width, | |
| 439 anchorY / sprite_rect.size.height)); | |
| 440 return sprite; | |
| 441 } | |
| 442 | |
| 443 b2Body* PhysicsLayer::CreatePhysicsBody() { | |
| 444 assert(points_being_drawn_.size()); | |
| 445 CCPoint start_point = points_being_drawn_.front(); | |
| 446 | |
| 447 assert(points_being_drawn_.size()); | |
| 448 CCLog("new body from %d points", points_being_drawn_.size()); | |
| 449 // create initial body | |
| 450 b2BodyDef def; | |
| 451 def.type = b2_dynamicBody; | |
| 452 def.position.Set(SCREEN_TO_WORLD(start_point.x), | |
| 453 SCREEN_TO_WORLD(start_point.y)); | |
| 454 b2Body* body = box2d_world_->CreateBody(&def); | |
| 455 | |
| 456 const int min_box_length = brush_radius_; | |
| 457 | |
| 458 // Create an initial box the size of the brush | |
| 459 AddSphereToBody(body, &start_point); | |
| 460 AddSphereToBody(body, &points_being_drawn_.back()); | |
| 461 | |
| 462 // Add boxes to body for every point that was drawn by the | |
| 463 // user. | |
| 464 // initialise endpoint to be the second item in the list | |
| 465 // and iterate until it points to the final element. | |
| 466 PointList::iterator iter = points_being_drawn_.begin(); | |
| 467 ++iter; | |
| 468 for (; iter != points_being_drawn_.end(); iter++) { | |
| 469 CCPoint end_point = *iter; | |
| 470 float distance = ccpDistance(start_point, end_point); | |
| 471 // if the distance between points it too small then | |
| 472 // skip the current point | |
| 473 if (distance < min_box_length) { | |
| 474 if (iter != points_being_drawn_.end() - 1) | |
| 475 continue; | |
| 476 } | |
| 477 AddLineToBody(body, start_point, end_point); | |
| 478 start_point = *iter; | |
| 479 } | |
| 480 | |
| 481 points_being_drawn_.clear(); | |
| 482 return body; | |
| 483 } | |
| 484 | |
| 485 void PhysicsLayer::AddShapeToBody(b2Body *body, b2Shape* shape) { | |
| 486 b2FixtureDef shape_def; | |
| 487 shape_def.shape = shape; | |
| 488 shape_def.density = box2d_density_; | |
| 489 shape_def.friction = box2d_friction_; | |
| 490 shape_def.restitution = box2d_restitution_; | |
| 491 body->CreateFixture(&shape_def); | |
| 492 } | |
| 493 | |
| 494 void PhysicsLayer::AddSphereToBody(b2Body *body, CCPoint* location) { | |
| 495 b2CircleShape shape; | |
| 496 shape.m_radius = SCREEN_TO_WORLD(brush_radius_); | |
| 497 shape.m_p.x = SCREEN_TO_WORLD(location->x) - body->GetPosition().x; | |
| 498 shape.m_p.y = SCREEN_TO_WORLD(location->y) - body->GetPosition().y; | |
| 499 AddShapeToBody(body, &shape); | |
| 500 } | |
| 501 | |
| 502 void PhysicsLayer::AddLineToBody(b2Body *body, CCPoint start, CCPoint end) { | |
| 503 float distance = ccpDistance(start, end); | |
| 504 | |
| 505 float sx = start.x; | |
| 506 float sy = start.y; | |
| 507 float ex = end.x; | |
| 508 float ey = end.y; | |
| 509 float dist_x = sx - ex; | |
| 510 float dist_y = sy - ey; | |
| 511 float angle = atan2(dist_y, dist_x); | |
| 512 | |
| 513 float posx = SCREEN_TO_WORLD((sx+ex)/2) - body->GetPosition().x; | |
| 514 float posy = SCREEN_TO_WORLD((sy+ey)/2) - body->GetPosition().y; | |
| 515 | |
| 516 float width = SCREEN_TO_WORLD(abs(distance)); | |
| 517 float height = SCREEN_TO_WORLD(brush_->boundingBox().size.height); | |
| 518 | |
| 519 b2PolygonShape shape; | |
| 520 shape.SetAsBox(width / 2, height / 2, b2Vec2(posx, posy), angle); | |
| 521 AddShapeToBody(body, &shape); | |
| 522 } | |
| OLD | NEW |