Last active
January 10, 2018 11:30
-
-
Save tokoroten/af922e4488104c7e8495290cc3c7de73 to your computer and use it in GitHub Desktop.
box2dで遊んでみる
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <Siv3D.hpp> | |
# include <HamFramework.hpp> | |
class Ball | |
{ | |
public: | |
static const double SIZE; | |
static const Polygon POLYGONS[]; | |
static const Color COLORS[]; | |
static Font FONT; | |
static const int CHAIN_TIME; | |
static const int BOMBED_TIME; | |
int mColor = 0; | |
bool isLive = true; | |
bool isBurning = false; | |
int mBurningCounter = 0; | |
int mConnectedCount = 0; | |
private: | |
PhysicsBody mBody; | |
public: | |
static void classInit() | |
{ | |
FONT = Font(12); | |
} | |
public: | |
Ball(PhysicsBody body, int color) : | |
mBody(body), mColor(color) | |
{ | |
mBody.setDamping(0.8); | |
} | |
~Ball() { | |
} | |
Ball(const Ball& ball): | |
mColor(ball.mColor), isLive(ball.isLive), mBody(ball.getBody()), mConnectedCount(0) | |
{} | |
Ball &operator=(const Ball &ball) | |
{ | |
mColor = ball.mColor; | |
isLive = ball.isLive; | |
mBody = ball.mBody; | |
mConnectedCount = ball.mConnectedCount; | |
isBurning = ball.isBurning; | |
mBurningCounter = ball.mBurningCounter; | |
return *this; | |
} | |
const bool operator==(const Ball& ball) const{ | |
return &mBody == &ball.getBody(); | |
} | |
const PhysicsBody& getBody() const { return mBody; } | |
PhysicsBody& getBodyUnsafe() { return mBody; } | |
void setLinkedNum(int count) { | |
mConnectedCount = count; | |
} | |
void run() | |
{ | |
if (isLive == false) { | |
return; | |
} | |
{ | |
const auto& center = Vec2(0, 0); | |
const auto deltaVec = center - mBody.getPos(); | |
//const auto r = deltaVec.length(); | |
const auto nVec = deltaVec.normalized(); | |
const auto f = nVec * 100.0 * SIZE * SIZE; | |
mBody.applyForce(f); | |
} | |
if (mConnectedCount >= 3) { | |
isBurning = true; | |
} | |
if (isBurning) { | |
mBurningCounter++; | |
} | |
if (mBurningCounter >= BOMBED_TIME) { | |
isLive = false; | |
} | |
} | |
void draw() const | |
{ | |
if (isLive == false) { | |
return; | |
} | |
const auto color = COLORS[mColor]; | |
const auto pos = mBody.getPos(); | |
const auto angle = mBody.getAngle(); | |
auto polygon = POLYGONS[mColor]; | |
polygon = polygon.rotated(angle); | |
polygon.draw(pos, isBurning ? Palette::White : color); | |
polygon.drawFrame(pos, SIZE/10, Palette::White); | |
} | |
void drawFont() const | |
{ | |
wchar_t ws[4]; | |
swprintf_s(ws, 4, L"%d", mConnectedCount); | |
FONT.drawAt(ws, mBody.getPos(), Palette::Black); | |
} | |
void bombedFrom(Vec2 &pos) | |
{ | |
const auto dv = mBody.getPos() - pos ; | |
const auto r = dv.length() + 0.001; | |
const auto v = dv.normalized(); | |
const auto f = v / (r*r) * 1000000; | |
mBody.applyForce(f); | |
} | |
}; | |
Font Ball::FONT; | |
const double Ball::SIZE = 2.0; | |
const int Ball::CHAIN_TIME = 20; | |
const int Ball::BOMBED_TIME = 120; | |
const Polygon Ball::POLYGONS[] = { | |
Geometry2D::CreateNgon(3, Ball::SIZE), | |
Geometry2D::CreateNgon(4, Ball::SIZE), | |
Geometry2D::CreateNgon(5, Ball::SIZE), | |
Geometry2D::CreateNgon(16, Ball::SIZE), | |
Geometry2D::CreatePlus(Ball::SIZE, Ball::SIZE*0.2), | |
Geometry2D::CreateStar(Ball::SIZE), | |
}; | |
const Color Ball::COLORS[] = { | |
Palette::Red, | |
Palette::Green, | |
Palette::Blue, | |
Palette::Yellow, | |
Palette::Cyan, | |
Palette::Magenta, | |
}; | |
class BallGame | |
{ | |
private: | |
PhysicsWorld mWorld; | |
Array<Ball*> mBallList; | |
Ball* mHold; | |
public: | |
BallGame(): | |
mHold(new Ball(mWorld.createCircle({0, 0}, Ball::SIZE), 0)) | |
{ | |
init(); | |
}; | |
~BallGame() {}; | |
void init() | |
{ | |
Ball::classInit(); | |
mWorld.setGravity({ 0,0 }); | |
for (auto i : step(100)) | |
{ | |
const auto pos = (RandomVec2() + RandomVec2()) * 20 * Ball::SIZE; | |
const auto color = int(Random() * 6); | |
const auto body = mWorld.createCircle(pos, Ball::SIZE); | |
mBallList.push_back(new Ball(body, color)); | |
} | |
const auto pos = Mouse::PosF(); | |
const auto color = int(Random() * 6); | |
const auto body = mWorld.createCircle(pos, Ball::SIZE); | |
mHold = new Ball(body, color); | |
} | |
void fireCheck() | |
{ | |
for (auto& ball1 : mBallList) { | |
const auto pos1 = ball1->getBody().getPos(); | |
auto linked = 0; | |
for (auto& ball2 : mBallList){ | |
if (ball1 == ball2) { | |
continue; | |
} | |
if (ball2->mBurningCounter == Ball::BOMBED_TIME -1) | |
{ | |
ball1->bombedFrom(ball2->getBody().getPos()); | |
} | |
if (ball1->mColor != ball2->mColor) { | |
continue; | |
} | |
const auto pos2 = ball2->getBody().getPos(); | |
const auto l = (pos2 - pos1).length(); | |
const auto size = Ball::SIZE * 2.2; | |
if (l < size) { | |
linked++; | |
if (ball2->mBurningCounter >= Ball::CHAIN_TIME) { | |
linked = 10; | |
} | |
} | |
} | |
ball1->setLinkedNum(linked); | |
} | |
} | |
void removeDeadBall() | |
{ | |
Array<Ball*> removed; | |
for (auto it = mBallList.begin(); it != mBallList.end(); ) { | |
if ((*it)->isLive == false) { | |
removed.push_back(*it); | |
it = mBallList.erase(it); | |
} | |
else { | |
++it; | |
} | |
} | |
for (auto& ball : removed) { | |
delete ball; | |
} | |
} | |
void run() | |
{ | |
// update hold | |
mHold->getBodyUnsafe().setPos(Mouse::PosF()); | |
// input | |
if (Input::MouseL.clicked) { | |
mBallList.push_back(mHold); | |
const auto pos = Mouse::PosF(); | |
const auto color = int(Random() * 6); | |
const auto body = mWorld.createCircle(pos, Ball::SIZE); | |
mHold = new Ball(body, color); | |
} | |
if (Input::Key1.pressed) | |
{ | |
const auto pos = RandomVec2() * 100 * Ball::SIZE; | |
const auto color = int(Random() * 6); | |
auto body = mWorld.createCircle(pos, Ball::SIZE); | |
body.applyLinearImpulse(-pos * 100000000); | |
mBallList.push_back(new Ball(body, color)); | |
} | |
if (Input::Key2.clicked) | |
{ | |
const auto base_pos = RandomVec2() * 80 * Ball::SIZE; | |
for (auto i : step(20)) | |
{ | |
const auto pos = base_pos + RandomVec2()*20*Random(); | |
const auto color = int(Random() * 6); | |
auto body = mWorld.createCircle(pos, Ball::SIZE); | |
body.applyLinearImpulse(-base_pos * 100000000); | |
mBallList.push_back(new Ball(body, color)); | |
} | |
} | |
removeDeadBall(); | |
// move blls | |
for (auto& ball : mBallList) { | |
ball->run(); | |
} | |
fireCheck(); | |
mWorld.update(); | |
} | |
void draw() const | |
{ | |
mHold->draw(); | |
for (const auto& ball : mBallList) { | |
ball->draw(); | |
//ball.drawFont(); | |
} | |
} | |
}; | |
void Main() | |
{ | |
//ScalableWindow::Setup({1920, 1080}); | |
Window::Resize(1920, 1080); | |
CameraBox2D bx2dCamera(Vec2(0, 0), 3.0); | |
auto game = BallGame(); | |
game.init(); | |
const auto font = Font(12); | |
while (System::Update()) | |
{ | |
bx2dCamera.update(); | |
{ | |
const auto t1 = bx2dCamera.createTransformer(); | |
const auto t2 = ScalableWindow::CreateTransformer(); | |
game.run(); | |
game.draw(); | |
} | |
bx2dCamera.draw(Palette::Orange); | |
//draw some ui here | |
font(Profiler::FPS(), L"fps").draw(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://www.youtube.com/watch?v=uCT06kOpZY8