#include "oxygine-framework.h" #include "Box2D/Box2D.h" #include "Box2DDebugDraw.h" using namespace oxygine; //it is our resources //in real project you would have more than one Resources declarations. It is important on mobile devices with limited memory and you would load/unload them Resources gameResources; //DECLARE_SMART is helper, it does forward declaration and declares intrusive_ptr typedef for your class DECLARE_SMART(MainActor, spMainActor); const float SCALE = 100.0f; b2Vec2 convert(const Vector2& pos) { return b2Vec2(pos.x / SCALE, pos.y / SCALE); } Vector2 convert(const b2Vec2& pos) { return Vector2(pos.x * SCALE, pos.y * SCALE); } DECLARE_SMART(Circle, spCircle); class Circle : public Sprite { public: Circle(b2World* world, const Vector2& pos, float scale = 1) { setResAnim(gameResources.getResAnim("circle")); setAnchor(Vector2(0.5f, 0.5f)); setTouchChildrenEnabled(false); b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position = convert(pos); b2Body* body = world->CreateBody(&bodyDef); setUserData(body); setScale(scale); b2CircleShape shape; shape.m_radius = getWidth() / SCALE / 2 * scale; b2FixtureDef fixtureDef; fixtureDef.shape = &shape; fixtureDef.density = 1.0f; fixtureDef.friction = 0.3f; body->CreateFixture(&fixtureDef); body->SetUserData(this); } }; DECLARE_SMART(Static, spStatic); class Static : public Box9Sprite { public: Static(b2World* world, const RectF& rc) { //setHorizontalMode(Box9Sprite::TILING_FULL); //setVerticalMode(Box9Sprite::TILING_FULL); setResAnim(gameResources.getResAnim("pen")); setSize(rc.getSize()); setPosition(rc.getLeftTop()); setAnchor(Vector2(0.5f, 0.5f)); b2BodyDef groundBodyDef; groundBodyDef.position = convert(getPosition()); b2Body* groundBody = world->CreateBody(&groundBodyDef); b2PolygonShape groundBox; b2Vec2 sz = convert(getSize() / 2); groundBox.SetAsBox(sz.x, sz.y); groundBody->CreateFixture(&groundBox, 0.0f); } }; class MainActor: public Actor { public: b2World* _world; spBox2DDraw _debugDraw; MainActor(): _world(0) { setSize(getStage()->getSize()); spButton btn = new Button; btn->setX(getWidth() - btn->getWidth() - 3); btn->setY(3); btn->attachTo(this); btn->addEventListener(TouchEvent::CLICK, CLOSURE(this, &MainActor::showHideDebug)); addEventListener(TouchEvent::CLICK, CLOSURE(this, &MainActor::click)); _world = new b2World(b2Vec2(0, 10)); spStatic ground = new Static(_world, RectF(getWidth() / 2, getHeight() - 10, getWidth() - 100, 30)); addChild(ground); spCircle circle = new Circle(_world, getSize() / 2, 1); addChild(circle); } void doUpdate(const UpdateState& us) { //in real project you should make steps with fixed dt, check box2d documentation _world->Step(us.dt / 1000.0f, 6, 2); //update each body position on display b2Body* body = _world->GetBodyList(); while (body) { Actor* actor = (Actor*)body->GetUserData(); b2Body* next = body->GetNext(); if (actor) { const b2Vec2& pos = body->GetPosition(); actor->setPosition(convert(pos)); actor->setRotation(body->GetAngle()); //remove fallen bodies if (actor->getY() > getHeight() + 50) { body->SetUserData(0); _world->DestroyBody(body); actor->detach(); } } body = next; } } void showHideDebug(Event* event) { TouchEvent* te = safeCast(event); te->stopsImmediatePropagation = true; if (_debugDraw) { _debugDraw->detach(); _debugDraw = 0; return; } _debugDraw = new Box2DDraw; _debugDraw->SetFlags(b2Draw::e_shapeBit | b2Draw::e_jointBit | b2Draw::e_pairBit | b2Draw::e_centerOfMassBit); _debugDraw->attachTo(this); _debugDraw->setWorld(SCALE, _world); _debugDraw->setPriority(1); } void click(Event* event) { TouchEvent* te = safeCast(event); if (event->target.get() == this) { spCircle circle = new Circle(_world, te->localPosition); circle->attachTo(this); } if (event->target->getUserData()) { //shot to circle spActor actor = safeSpCast(event->target); b2Body* body = (b2Body*)actor->getUserData(); Vector2 dir = actor->getPosition() - te->localPosition; dir = dir / dir.length() * body->GetMass() * 200; body->ApplyForceToCenter(b2Vec2(dir.x, dir.y), true); spSprite sprite = new Sprite(); sprite->setResAnim(gameResources.getResAnim("shot")); Vector2 local = actor->parent2local(te->localPosition); sprite->setPosition(local); sprite->setAnchor(Vector2(0.5f, 0.5f)); sprite->attachTo(actor); } } }; void example_preinit() { } void example_init() { //load xml file with resources definition gameResources.loadXML("res.xml"); //lets create our client code simple actor //prefix 'sp' here means it is intrusive Smart Pointer //it would be deleted automatically when you lost ref to it spMainActor actor = new MainActor; //and add it to Stage as child getStage()->addChild(actor); } void example_destroy() { gameResources.free(); } void example_update() { }