Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: nacltoons/src/physics_layer.cc

Issue 12579005: [nacltoons] Rename core classes in accordance with doc. (Closed) Base URL: https://nativeclient-sdk.googlecode.com/svn/trunk/src
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698