用cocos2d-x模拟单摆运动的程序

来源:互联网 发布:法甲德佩数据 编辑:程序博客网 时间:2024/05/01 14:53

需求

物理原理课需要制作关于单摆在在不同摆角下运动状态的课程报告,所以就想着做出一个有图形界面的单摆演示程序。由于图形界面只有cocos2d-学的还算可以,所以就用这个来做(实际上用MFC或者用WPF做效果会更好一点?……)

理论基础

周期求解

单摆在偏角不太大的情况(高中课本认为小于5°均可)下,单摆的运动可以近似地视为简谐运动。
周期公式
T0=2πlg
但是在摆角较大时该公式误差很大。所以需要引入其他的公式。
在刘凤祥《单摆运动周期的近似解》中得出一个近似周期公式
T=T010.062Θ2
程序使用该公式求得单摆的近似周期。

瞬时角速度

推导出瞬时角速度的微分方程,然后用龙格库塔法求解,在程序中求得瞬时角速度。
直接上图……
来自《关于单摆方程C++语言数值解法》——黄海平
有了瞬时角速度之后就可以用update函数移动摆球并表现在图形界面中。

程序代码

#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"#include "ui/CocosGUI.h"#include "Consts.h"class HelloWorld : public cocos2d::Layer{public:    enum kState    {        kState_Stop,        kState_Running,        kState_Paused    };    HelloWorld();    ~HelloWorld();    static cocos2d::Scene* createScene();    virtual bool init();    CREATE_FUNC(HelloWorld);public:    void sliderEvent(cocos2d::Ref* sender, cocos2d::ui::Slider::EventType type);    void textFieldEvent(cocos2d::Ref* sender, cocos2d::ui::TextField::EventType type);    void StartTouchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);    void PauseTouchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);public:    virtual void update(float delta);protected:    cocos2d::CustomCommand _customCommand;private:    double _startAngel, _l, _T;    int _halfT;    double _currentAngel, _currentW, _currentTime;    kState _state;    cocos2d::Vec2 _ballPos, _vertexPos, _graphVertexPos;private:    cocos2d::ui::Text * m_TText;    cocos2d::ui::Text * m_WText;    cocos2d::ui::Text * m_AngelText;    cocos2d::ui::Text * m_CurrentAngelText;    cocos2d::ui::Slider * m_AngelSlider;    cocos2d::ui::TextField * m_LTextField;    cocos2d::ui::Button * m_PauseButton;    cocos2d::Sprite * m_ball;    cocos2d::DrawNode * m_drawNode;    cocos2d::DrawNode * m_graphNode;private:    double getW();    double getT();};#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"#include "cocostudio/CocoStudio.h"#include "ui/CocosGUI.h"// draw#include "renderer/CCRenderer.h"#include "renderer/CCCustomCommand.h"USING_NS_CC;using namespace cocostudio::timeline;using namespace cocos2d::ui;HelloWorld::HelloWorld(){    m_TText = nullptr;    m_WText = nullptr;    m_AngelText = nullptr;    m_CurrentAngelText = nullptr;    m_AngelSlider = nullptr;    m_LTextField = nullptr;    _vertexPos = Vec2(300, 550);    _graphVertexPos = Vec2(300, 120);}HelloWorld::~HelloWorld(){}Scene* HelloWorld::createScene(){    auto scene = Scene::create();    auto layer = HelloWorld::create();    scene->addChild(layer);    return scene;}bool HelloWorld::init(){    if ( !Layer::init() )    {        return false;    }    // init variables    _state = kState_Stop;    // DrawNode    m_drawNode = DrawNode::create();    this->addChild(m_drawNode, 10);    m_graphNode = DrawNode::create();    this->addChild(m_graphNode, 9);    m_graphNode->drawLine(Vec2(0, 120), Vec2(600, 120), Color4F::RED);    m_graphNode->drawLine(Vec2(300, 0), Vec2(300, 240), Color4F::RED);    m_graphNode->drawPoint(_vertexPos, 20, Color4F::BLUE);    // init UI    auto rootNode = CSLoader::createNode("MainScene.csb");    addChild(rootNode);    m_TText = static_cast<ui::Text*>(rootNode->getChildByName("Panel_RT")->getChildByName("Text_T_Data"));    m_WText = static_cast<ui::Text*>(rootNode->getChildByName("Panel_RT")->getChildByName("Text_W_Data"));    m_CurrentAngelText = static_cast<ui::Text*>(rootNode->getChildByName("Panel_RT")->getChildByName("Text_CurrentAngel_Data"));    m_AngelText = static_cast<ui::Text*>(rootNode->getChildByName("Panel_RB")->getChildByName("Text_Angel_Data"));    m_AngelSlider = static_cast<ui::Slider*>(rootNode->getChildByName("Panel_RB")->getChildByName("Slider_Angel"));    m_AngelSlider->setMaxPercent(90);    m_AngelSlider->addEventListener(CC_CALLBACK_2(HelloWorld::sliderEvent, this));    m_LTextField = static_cast<ui::TextField*>(rootNode->getChildByName("Panel_RB")->getChildByName("TextField_l"));    m_LTextField->addEventListener(CC_CALLBACK_2(HelloWorld::textFieldEvent, this));    auto startBtn = static_cast<ui::Button*>(rootNode->getChildByName("Panel_RB")->getChildByName("Button_Start"));    startBtn->addTouchEventListener(CC_CALLBACK_2(HelloWorld::StartTouchEvent,this));    m_PauseButton = static_cast<ui::Button*>(rootNode->getChildByName("Panel_RB")->getChildByName("Button_Pause"));    m_PauseButton->addTouchEventListener(CC_CALLBACK_2(HelloWorld::PauseTouchEvent, this));    // init Sprite    m_ball = Sprite::create("ball.png");    m_ball->setAnchorPoint(Vec2(0.5, 0.5));    m_ball->setPosition(_vertexPos);    this->addChild(m_ball);    return true;}void HelloWorld::sliderEvent(Ref *pSender, cocos2d::ui::Slider::EventType type){    if(type == Slider::EventType::ON_PERCENTAGE_CHANGED)    {        Slider* slider = dynamic_cast<Slider*>(pSender);        int percent = slider->getPercent();        m_AngelText->setString(StringUtils::format("%d", percent));        _startAngel = (double)percent / 180 * PI;        _currentAngel = _startAngel;        _ballPos = Vec2(_vertexPos.x + _l * 100 * sin(_currentAngel), _vertexPos.y - _l * 100 * cos(_currentAngel));        m_ball->setPosition(_ballPos);    }}void HelloWorld::textFieldEvent(Ref *pSender, cocos2d::ui::TextField::EventType type){    switch (type)    {    case TextField::EventType::ATTACH_WITH_IME:    {        TextField* textField = dynamic_cast<TextField*>(pSender);/*        Size screenSize = Director::getInstance()->getWinSize();        textField->runAction(MoveTo::create(0.225f,            Vec2(screenSize.width / 2.0f, screenSize.height / 2.0f + textField->getContentSize().height / 2.0f)));*/    }    break;    case TextField::EventType::DETACH_WITH_IME:    {        TextField* textField = dynamic_cast<TextField*>(pSender);/*        Size screenSize = Director::getInstance()->getWinSize();        textField->runAction(MoveTo::create(0.175f, Vec2(screenSize.width / 2.0f, screenSize.height / 2.0f)));*/    }    break;    case TextField::EventType::INSERT_TEXT:    {        TextField * textField = dynamic_cast<TextField*>(pSender);        std::string str = textField->getString();        int num = atoi(str.c_str());        log("%d", num);        _l = num;    }        break;    case TextField::EventType::DELETE_BACKWARD:        break;    default:        break;    }}void HelloWorld::StartTouchEvent(Ref *pSender, Widget::TouchEventType type){    switch (type)    {    case Widget::TouchEventType::BEGAN:        break;    case Widget::TouchEventType::MOVED:        break;    case Widget::TouchEventType::ENDED:    {        _currentAngel = _startAngel;        _currentW = 0;        _currentTime = 0;        _state = kState_Running;        m_PauseButton->setTitleText("PAUSE");        // set T        _T = getT();        m_TText->setText(StringUtils::format("%lf", _T));        this->scheduleUpdate();    }    break;    case Widget::TouchEventType::CANCELED:        break;    default:        break;    }}void HelloWorld::PauseTouchEvent(Ref *pSender, Widget::TouchEventType type){    switch (type)    {    case Widget::TouchEventType::BEGAN:        break;    case Widget::TouchEventType::MOVED:        break;    case Widget::TouchEventType::ENDED:    {        if(_state == kState_Running)        {            _state = kState_Paused;            this->unscheduleUpdate();            auto button = dynamic_cast<ui::Button*>(pSender);            button->setTitleText("RESUME");        }        else if(_state == kState_Paused)        {            _state = kState_Running;            this->scheduleUpdate();            auto button = dynamic_cast<ui::Button*>(pSender);            button->setTitleText("PAUSE");        }    }    break;    case Widget::TouchEventType::CANCELED:        break;    default:        break;    }}void HelloWorld::update(float delta){    // double W = getW();    // update data    double k1,k2,k3,k4,l1,l2,l3,l4;    {        k1 = _currentW;        l1 = -(G / _l) * sin(_currentAngel);        k2 = _currentW + delta * l1 / 2.0;        l2 = -(G / _l) * sin(_currentAngel + delta * k1 / 2.0);        k3 = _currentW + delta * l2 / 2.0;        l3 = -(G / _l) * sin(_currentAngel + delta * k2 / 2.0);        k4 = _currentW + delta * l3;        l4 = -(G / _l) *sin(_currentAngel * delta * k3);        _currentTime += (double)delta;        _currentAngel += delta * (k1 + 2 * k2 + 2 * k3 + k4) / 6.0;        log("%lf", _currentAngel);        _currentW += delta * (l1 + 2 * l2 + 2 * l3 + l4) / 6.0;    }    m_WText->setText(StringUtils::format("%.4lf", _currentW));    m_CurrentAngelText->setText(StringUtils::format("%.1lf", _currentAngel / PI * 180));    // draw    _ballPos = Vec2(_vertexPos.x + _l * 100 * sin(_currentAngel), _vertexPos.y - _l * 100 * cos(_currentAngel));    m_ball->setPosition(_ballPos);    m_drawNode->clear();    m_drawNode->drawLine(_vertexPos, _ballPos, Color4F::BLUE);    // graph    m_graphNode->drawPoint(Vec2(_graphVertexPos.x + _currentAngel * 200, _graphVertexPos.y + _currentW * 50), 2, Color4F::RED);}double HelloWorld::getW(){    double W;    W = sqrt(2 / _l*_l) * sqrt(9.8*_l*(cos(_currentAngel) - cos(_startAngel)));    if (_halfT % 2 == 0)        W = -W;    return W;}double HelloWorld::getT(){    double T;//  double T1, T2, T3;//  T3 = sqrt(_l / G);//  T1 = 2 * PI * sqrt(_l / G);//  T2 = 1 - 0.062*_startAngel*_startAngel;    T = (2 * PI * sqrt(_l / G)) /        (1 - 0.062*_startAngel*_startAngel);//  T = T1 / T2;    return T;}

程序截图以及下载

By 金甲虫Scarb
下载地址:
http://download.csdn.net/detail/jjhfen00/9330825

0 0