Index: nacltoons/src/physics_layer.cc |
diff --git a/nacltoons/src/physics_layer.cc b/nacltoons/src/physics_layer.cc |
deleted file mode 100644 |
index 4f109cb0938e74cf1d0e4968bb8da09725844e6a..0000000000000000000000000000000000000000 |
--- a/nacltoons/src/physics_layer.cc |
+++ /dev/null |
@@ -1,522 +0,0 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "physics_layer.h" |
-#include "app_delegate.h" |
-#include "gameplay_scene.h" |
- |
-#include "physics_nodes/CCPhysicsSprite.h" |
-#include "CCLuaEngine.h" |
- |
-extern "C" { |
-#include "lua.h" |
-#include "tolua++.h" |
-#include "lualib.h" |
-#include "lauxlib.h" |
-#include "tolua_fix.h" |
-} |
- |
-// Pixels-to-meters ratio for converting screen coordinates |
-// to Box2D "meters". |
-#define PTM_RATIO 32 |
-#define SCREEN_TO_WORLD(n) ((n) / PTM_RATIO) |
-#define WORLD_TO_SCREEN(n) ((n) * PTM_RATIO) |
-#define VELOCITY_ITERATIONS 8 |
-#define POS_ITERATIONS 1 |
- |
-#define MAX_SPRITES 100 |
- |
-#define DEFAULT_DENSITY 1.0f |
-#define DEFAULT_FRICTION 0.2f |
-#define DEFAULT_RESTITUTION 0.1f |
- |
- |
-USING_NS_CC_EXT; |
- |
-PhysicsLayer* PhysicsLayer::create(int level_number) |
-{ |
- PhysicsLayer* layer = new PhysicsLayer(level_number); |
- if (!layer) |
- return NULL; |
- layer->init(); |
- return layer; |
-} |
- |
-bool PhysicsLayer::init() { |
- if (!CCLayerColor::initWithColor(ccc4(0,0x8F,0xD8,0xD8))) |
- return false; |
- |
- setTouchEnabled(true); |
- |
- InitPhysics(); |
- |
- // Load level from lua file. For now we simple load level 1. |
- LoadLua(); |
- |
- // Calculate brush size |
- CCSpriteBatchNode* brush_batch = (CCSpriteBatchNode*)getChildByTag(TAG_BRUSH); |
- assert(brush_batch); |
- brush_ = CCSprite::createWithTexture(brush_batch->getTexture()); |
- brush_->retain(); |
- CCSize brush_size = brush_->getContentSize(); |
- brush_radius_ = MAX(brush_size.height/2, brush_size.width/2); |
- |
- // Schedule physics updates each frame |
- schedule(schedule_selector(PhysicsLayer::UpdateWorld)); |
- return true; |
-} |
- |
-PhysicsLayer::PhysicsLayer(int level_number) : |
- level_number_(level_number), |
- goal_reached_(false), |
- current_touch_id_(-1), |
- render_target_(NULL), |
-#ifdef COCOS2D_DEBUG |
- debug_enabled_(false), |
-#endif |
- box2d_density_(DEFAULT_DENSITY), |
- box2d_restitution_(DEFAULT_RESTITUTION), |
- box2d_friction_(DEFAULT_FRICTION) { |
- memset(stars_collected_, 0, sizeof(stars_collected_)); |
-} |
- |
-PhysicsLayer::~PhysicsLayer() { |
- brush_->release(); |
- delete box2d_world_; |
-#ifdef COCOS2D_DEBUG |
- delete box2d_debug_draw_; |
-#endif |
-} |
- |
-void PhysicsLayer::registerWithTouchDispatcher() { |
- CCDirector* director = CCDirector::sharedDirector(); |
- director->getTouchDispatcher()->addTargetedDelegate(this, 0, true); |
-} |
- |
-void PhysicsLayer::CreateRenderTarget() { |
- // create render target for shape drawing |
- assert(!render_target_); |
- CCSize win_size = CCDirector::sharedDirector()->getWinSize(); |
- render_target_ = CCRenderTexture::create(win_size.width, |
- win_size.height, |
- kCCTexture2DPixelFormat_RGBA8888); |
- render_target_->setPosition(ccp(win_size.width / 2, win_size.height / 2)); |
- addChild(render_target_); |
-} |
- |
-bool PhysicsLayer::LoadLua() { |
- CCScriptEngineManager* manager = CCScriptEngineManager::sharedManager(); |
- CCLuaEngine* engine = (CCLuaEngine*)manager->getScriptEngine(); |
- assert(engine); |
- lua_stack_ = engine->getLuaStack(); |
- assert(lua_stack_); |
- |
- lua_stack_->pushString("sample_game/game.lua"); |
- lua_stack_->pushCCObject(this, "PhysicsLayer"); |
- lua_stack_->pushInt(level_number_); |
- |
- // Call 'main' with three arguments pushed above |
- int rtn = lua_stack_->executeFunctionByName("main", 3); |
- if (rtn != 1) |
- return false; |
- |
- return true; |
-} |
- |
-bool PhysicsLayer::InitPhysics() { |
- b2Vec2 gravity(0.0f, -9.8f); |
- box2d_world_ = new b2World(gravity); |
- box2d_world_->SetAllowSleeping(true); |
- box2d_world_->SetContinuousPhysics(true); |
- |
- // Find visible rect, and convert to box2d space. |
- CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); |
- CCSize visible_size = CCDirector::sharedDirector()->getVisibleSize(); |
- float world_width = SCREEN_TO_WORLD(visible_size.width); |
- b2Vec2 world_origin(SCREEN_TO_WORLD(origin.x), SCREEN_TO_WORLD(origin.y)); |
- |
- // create the ground |
- b2BodyDef ground_def; |
- ground_def.position = world_origin; |
- b2Body* ground_body = box2d_world_->CreateBody(&ground_def); |
- |
- CCLog("origin: %.fx%.f", origin.x, origin.y); |
- CCLog("size: %.fx%f", visible_size.width, visible_size.height); |
- |
- // Define the ground box shape. |
- b2EdgeShape ground_box; |
- ground_box.Set(b2Vec2(0, 0), b2Vec2(world_width, 0)); |
- ground_body->CreateFixture(&ground_box, 0); |
- ground_body->SetUserData((void*)TAG_GROUND); |
- |
- box2d_world_->SetContactListener(this); |
- |
-#ifdef COCOS2D_DEBUG |
- box2d_debug_draw_ = new GLESDebugDraw(PTM_RATIO); |
- box2d_world_->SetDebugDraw(box2d_debug_draw_); |
- |
- uint32 flags = 0; |
- flags += b2Draw::e_shapeBit; |
- flags += b2Draw::e_jointBit; |
- flags += b2Draw::e_centerOfMassBit; |
- //flags += b2Draw::e_aabbBit; |
- //flags += b2Draw::e_pairBit; |
- box2d_debug_draw_->SetFlags(flags); |
-#endif |
- return true; |
-} |
- |
-void PhysicsLayer::ToggleDebug() { |
- debug_enabled_ = !debug_enabled_; |
- |
- // Set visibility of all children based on debug_enabled_ |
- CCArray* children = getChildren(); |
- if (!children) |
- return; |
- for (uint i = 0; i < children->count(); i++) |
- { |
- CCNode* child = static_cast<CCNode*>(children->objectAtIndex(i)); |
- if (child == render_target_) |
- continue; |
- child->setVisible(!debug_enabled_); |
- } |
-} |
- |
-CCRect CalcBoundingBox(CCSprite* sprite) { |
- CCSize size = sprite->getContentSize(); |
- CCPoint pos = sprite->getPosition(); |
- return CCRectMake(pos.x - size.width, pos.y - size.height, |
- size.width, size.height/2); |
-} |
- |
-void PhysicsLayer::UpdateWorld(float dt) { |
- // update physics |
- box2d_world_->Step(dt, VELOCITY_ITERATIONS, POS_ITERATIONS); |
-} |
- |
-void PhysicsLayer::LuaNotifyContact(b2Contact* contact, |
- const char* function_name) { |
- // Return early if lua didn't define the function_name |
- lua_State* state = lua_stack_->getLuaState(); |
- lua_getglobal(state, function_name); |
- bool is_func = lua_isfunction(state, -1); |
- lua_pop(state, 1); |
- |
- if (!is_func) |
- return; |
- |
- // Only send to lua collitions between body's that |
- // have been tagged. |
- b2Body* body1 = contact->GetFixtureA()->GetBody(); |
- b2Body* body2 = contact->GetFixtureB()->GetBody(); |
- int tag1 = (int)body1->GetUserData(); |
- int tag2 = (int)body2->GetUserData(); |
- if (!tag1 || !tag2) |
- return; |
- |
- // Call 'ContactBegan' lua function passing in 'this' |
- // as well as the tags of the two bodies that collided |
- lua_stack_->pushCCObject(this, "PhysicsLayer"); |
- lua_stack_->pushInt(tag1); |
- lua_stack_->pushInt(tag2); |
- lua_stack_->executeFunctionByName(function_name, 3); |
-} |
- |
-void PhysicsLayer::BeginContact(b2Contact* contact) { |
- LuaNotifyContact(contact, "BeginContact"); |
-} |
- |
-void PhysicsLayer::EndContact(b2Contact* contact) { |
- LuaNotifyContact(contact, "EndContact"); |
-} |
- |
-void PhysicsLayer::LevelComplete() { |
- // fade out the goal and trigger gameover callback when its |
- // done |
- CCPhysicsSprite* goal = (CCPhysicsSprite*)getChildByTag(TAG_GOAL); |
- CCActionInterval* fadeout = CCFadeOut::create(0.5f); |
- CCFiniteTimeAction* fadeout_done = CCCallFuncN::create(this, |
- callfuncN_selector(PhysicsLayer::LevelCompleteDone)); |
- CCSequence* seq = CCSequence::create(fadeout, fadeout_done, NULL); |
- goal->runAction(seq); |
-} |
- |
-void PhysicsLayer::LevelCompleteDone(CCNode* sender) { |
- unschedule(schedule_selector(PhysicsLayer::UpdateWorld)); |
- setTouchEnabled(false); |
- GameplayScene* scene = static_cast<GameplayScene*>(getParent()); |
- scene->GameOver(true); |
-} |
- |
-void PhysicsLayer::DrawPoint(CCPoint& location) { |
- ClampBrushLocation(location); |
- render_target_->begin(); |
- brush_->setVisible(true); |
- brush_->setPosition(ccp(location.x, location.y)); |
- brush_->visit(); |
- brush_->setVisible(false); |
- render_target_->end(); |
- points_being_drawn_.push_back(location); |
-} |
- |
-void PhysicsLayer::draw() { |
- CCLayerColor::draw(); |
- |
-#ifdef COCOS2D_DEBUG |
- if (debug_enabled_) { |
- ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position); |
- kmGLPushMatrix(); |
- box2d_world_->DrawDebugData(); |
- kmGLPopMatrix(); |
- } |
-#endif |
-} |
- |
-void PhysicsLayer::ClampBrushLocation(CCPoint& point) { |
- CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); |
- CCSize visible_size = CCDirector::sharedDirector()->getVisibleSize(); |
- |
- float min_x = origin.x + brush_radius_; |
- float min_y = origin.y + brush_radius_; |
- if (point.x < min_x) point.x = min_x; |
- if (point.y < min_y) point.y = min_y; |
- |
- float max_x = origin.x + visible_size.width - brush_radius_; |
- float max_y = origin.y + visible_size.height - brush_radius_; |
- if (point.x > max_x) point.x = max_x; |
- if (point.y > max_y) point.y = max_y; |
-} |
- |
-void PhysicsLayer::DrawLine(CCPoint& start, CCPoint& end) { |
- ClampBrushLocation(start); |
- ClampBrushLocation(end); |
- |
- // calculate distance moved |
- float distance = ccpDistance(start, end); |
- |
- // draw the brush sprite into render texture at every point between the old |
- // and new cursor positions |
- render_target_->begin(); |
- for (int i = 0; i < int(distance + 0.5); i++) { |
- float difx = end.x - start.x; |
- float dify = end.y - start.y; |
- float delta = (float)i / distance; |
- brush_->setVisible(true); |
- brush_->setPosition( |
- ccp(start.x + (difx * delta), start.y + (dify * delta))); |
- |
- brush_->visit(); |
- brush_->setVisible(false); |
- } |
- render_target_->end(); |
- points_being_drawn_.push_back(end); |
-} |
- |
-bool PhysicsLayer::ccTouchBegan(CCTouch* touch, CCEvent* event) { |
- if (current_touch_id_ != -1) |
- return false; |
- |
- current_touch_id_ = touch->getID(); |
- |
- if (!render_target_) |
- CreateRenderTarget(); |
- |
- points_being_drawn_.clear(); |
- CCPoint location = touch->getLocation(); |
- DrawPoint(location); |
- return true; |
-} |
- |
-void PhysicsLayer::ccTouchMoved(CCTouch* touch, CCEvent* event) { |
- assert(touch->getID() == current_touch_id_); |
- CCPoint end = touch->getLocation(); |
- CCPoint start = touch->getPreviousLocation(); |
- DrawLine(start, end); |
-} |
- |
-void PhysicsLayer::ccTouchEnded(CCTouch* touch, CCEvent* event) { |
- assert(touch->getID() == current_touch_id_); |
- b2Body* body = CreatePhysicsBody(); |
- CCSprite* sprite = CreatePhysicsSprite(body); |
- addChild(sprite); |
- if (debug_enabled_) |
- sprite->setVisible(false); |
- |
- // release render target (it will get recreated on next touch). |
- removeChild(render_target_, true); |
- render_target_ = NULL; |
- current_touch_id_ = -1; |
-} |
- |
-CCRect CalcBodyBounds(b2Body* body) { |
- CCSize s = CCDirector::sharedDirector()->getWinSize(); |
- |
- float minX = FLT_MAX; |
- float maxX = 0; |
- float minY = FLT_MAX; |
- float maxY = 0; |
- |
- const b2Transform& xform = body->GetTransform(); |
- for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext()) { |
- b2Shape* shape = f->GetShape(); |
- if (shape->GetType() == b2Shape::e_circle) { |
- b2CircleShape* c = static_cast<b2CircleShape*>(shape); |
- b2Vec2 center = b2Mul(xform, c->m_p); |
- if (center.x - c->m_radius < minX) |
- minX = center.x - c->m_radius; |
- if (center.x + c->m_radius > maxX) |
- maxX = center.x + c->m_radius; |
- if (center.y - c->m_radius < minY) |
- minY = center.y - c->m_radius; |
- if (center.y + c->m_radius > maxY) |
- maxY = center.y + c->m_radius; |
- } else { |
- b2PolygonShape* poly = static_cast<b2PolygonShape*>(shape); |
- int32 vertex_count = poly->m_vertexCount; |
- |
- for (int i = 0; i < vertex_count; ++i) |
- { |
- b2Vec2 vertex = b2Mul(xform, poly->m_vertices[i]); |
- if (vertex.x < minX) |
- minX = vertex.x; |
- if (vertex.x > maxX) |
- maxX = vertex.x; |
- if (vertex.y < minY) |
- minY = vertex.y; |
- if (vertex.y > maxY) |
- maxY = vertex.y; |
- } |
- } |
- } |
- |
- maxX = WORLD_TO_SCREEN(maxX); |
- minX = WORLD_TO_SCREEN(minX); |
- maxY = WORLD_TO_SCREEN(maxY); |
- minY = WORLD_TO_SCREEN(minY); |
- |
- float width = maxX - minX; |
- float height = maxY - minY; |
- float remY = s.height - maxY; |
- return CCRectMake(minX, remY, width, height); |
-} |
- |
-CCSprite* PhysicsLayer::CreatePhysicsSprite(b2Body* body) { |
- CCPhysicsSprite *sprite; |
- |
- // create a new texture based on the current contents of the |
- // render target |
- CCImage* image = render_target_->newCCImage(); |
- CCTexture2D* tex = new CCTexture2D(); |
- tex->initWithImage(image); |
- tex->autorelease(); |
- delete image; |
- |
- // Find the bounds of the physics body wihh the target texture |
- CCRect sprite_rect = CalcBodyBounds(body); |
- sprite_rect.origin.x -= brush_radius_; |
- sprite_rect.origin.y -= brush_radius_; |
- sprite_rect.size.width += brush_radius_; |
- sprite_rect.size.height += brush_radius_; |
- |
- CCSize s = CCDirector::sharedDirector()->getWinSize(); |
- CCPoint body_pos = ccp(WORLD_TO_SCREEN(body->GetPosition().x), |
- WORLD_TO_SCREEN(body->GetPosition().y)); |
- |
- |
- // Create a new sprite based on the texture |
- sprite = CCPhysicsSprite::createWithTexture(tex, sprite_rect); |
- sprite->setB2Body(body); |
- sprite->setPTMRatio(PTM_RATIO); |
- |
- // Set the anchor point of the sprite |
- float anchorX = body_pos.x - sprite_rect.origin.x; |
- float anchorY = body_pos.y + sprite_rect.origin.y + sprite_rect.size.height; |
- anchorY -= s.height; |
- |
- // anchor point goes from 0.0 to 1.0 with in bounds of the sprite itself. |
- sprite->setAnchorPoint(ccp(anchorX / sprite_rect.size.width, |
- anchorY / sprite_rect.size.height)); |
- return sprite; |
-} |
- |
-b2Body* PhysicsLayer::CreatePhysicsBody() { |
- assert(points_being_drawn_.size()); |
- CCPoint start_point = points_being_drawn_.front(); |
- |
- assert(points_being_drawn_.size()); |
- CCLog("new body from %d points", points_being_drawn_.size()); |
- // create initial body |
- b2BodyDef def; |
- def.type = b2_dynamicBody; |
- def.position.Set(SCREEN_TO_WORLD(start_point.x), |
- SCREEN_TO_WORLD(start_point.y)); |
- b2Body* body = box2d_world_->CreateBody(&def); |
- |
- const int min_box_length = brush_radius_; |
- |
- // Create an initial box the size of the brush |
- AddSphereToBody(body, &start_point); |
- AddSphereToBody(body, &points_being_drawn_.back()); |
- |
- // Add boxes to body for every point that was drawn by the |
- // user. |
- // initialise endpoint to be the second item in the list |
- // and iterate until it points to the final element. |
- PointList::iterator iter = points_being_drawn_.begin(); |
- ++iter; |
- for (; iter != points_being_drawn_.end(); iter++) { |
- CCPoint end_point = *iter; |
- float distance = ccpDistance(start_point, end_point); |
- // if the distance between points it too small then |
- // skip the current point |
- if (distance < min_box_length) { |
- if (iter != points_being_drawn_.end() - 1) |
- continue; |
- } |
- AddLineToBody(body, start_point, end_point); |
- start_point = *iter; |
- } |
- |
- points_being_drawn_.clear(); |
- return body; |
-} |
- |
-void PhysicsLayer::AddShapeToBody(b2Body *body, b2Shape* shape) { |
- b2FixtureDef shape_def; |
- shape_def.shape = shape; |
- shape_def.density = box2d_density_; |
- shape_def.friction = box2d_friction_; |
- shape_def.restitution = box2d_restitution_; |
- body->CreateFixture(&shape_def); |
-} |
- |
-void PhysicsLayer::AddSphereToBody(b2Body *body, CCPoint* location) { |
- b2CircleShape shape; |
- shape.m_radius = SCREEN_TO_WORLD(brush_radius_); |
- shape.m_p.x = SCREEN_TO_WORLD(location->x) - body->GetPosition().x; |
- shape.m_p.y = SCREEN_TO_WORLD(location->y) - body->GetPosition().y; |
- AddShapeToBody(body, &shape); |
-} |
- |
-void PhysicsLayer::AddLineToBody(b2Body *body, CCPoint start, CCPoint end) { |
- float distance = ccpDistance(start, end); |
- |
- float sx = start.x; |
- float sy = start.y; |
- float ex = end.x; |
- float ey = end.y; |
- float dist_x = sx - ex; |
- float dist_y = sy - ey; |
- float angle = atan2(dist_y, dist_x); |
- |
- float posx = SCREEN_TO_WORLD((sx+ex)/2) - body->GetPosition().x; |
- float posy = SCREEN_TO_WORLD((sy+ey)/2) - body->GetPosition().y; |
- |
- float width = SCREEN_TO_WORLD(abs(distance)); |
- float height = SCREEN_TO_WORLD(brush_->boundingBox().size.height); |
- |
- b2PolygonShape shape; |
- shape.SetAsBox(width / 2, height / 2, b2Vec2(posx, posy), angle); |
- AddShapeToBody(body, &shape); |
-} |