cocos2d-x节点(b2Body.h)API

本文来自http://blog.csdn.net/runaying ,引用必须注明出处!

cocos2d-x节点(b2Body.h)API

温馨提醒:为了大家能更好学习,强烈推荐大家看看本人的这篇博客 Cocos2d-X权威指南笔记

//模拟现实世界中的静态物体,动态物体,匀速直线运动的物体,并返回它们的各种状态

///cocos2d-x-3.0alpha0/external/Box2D/Dynamics
//模拟现实世界中的静态物体,动态物体,匀速直线运动的物体,并返回它们的各种状态

#ifndef B2_BODY_H
#define B2_BODY_H

#include <Box2D/Common/b2Math.h>
#include <Box2D/Collision/Shapes/b2Shape.h>
#include <memory>

class b2Fixture;
class b2Joint;
class b2Contact;
class b2Controller;
class b2World;
struct b2FixtureDef;
struct b2JointEdge;
struct b2ContactEdge;

///  body 类型.
/// static: zero mass, zero velocity(速度), 可以手动移动            //速度一定,位置可以手动设置
/// kinematic(运动学): zero mass, 由用户设置 non-zero velocity(速度), moved by solver(运算器)        //用户可以设置速度位置由系统计算
/// dynamic(动态): positive(真实的) mass,由力决定 non-zero velocity(速度), moved by solver(运算器)    //类似与现实世界中的物体,mass 是时时的,因为物体的速度,状态会影响 mass ,速度由力来决定
//
enum b2BodyType
{
    b2_staticBody = 0,
    b2_kinematicBody,
    b2_dynamicBody

    // TODO_ERIN
    //b2_bulletBody,
};

/// 定义 body 所需要的所有数据构建一个正确的 body
//您可以安全地 re-use 定义的 body
//构建后把 shapes 添加到 body
struct b2BodyDef
{
    ///此构造函数设置定义的 body (使用默认值).
    b2BodyDef()
    {
        userData = NULL;
        position.Set(0.0f, 0.0f);
        angle = 0.0f;
        linearVelocity.Set(0.0f, 0.0f);
        angularVelocity = 0.0f;
        linearDamping = 0.0f;
        angularDamping = 0.0f;
        allowSleep = true;
        awake = true;
        fixedRotation = false;
        bullet = false;
        type = b2_staticBody;
        active = true;
        gravityScale = 1.0f;
    }

    /// The body type: static, kinematic(动力学), or dynamic(动态).
    /// Note: 如果动态的 body 质量是 0, 质量将被设置成 1.
    b2BodyType type;

    /// body 在世界坐标中的位置. 避免在 origin(原点) 处创建 body
    /// 因为这可能会导致许多重叠的 shapes
    b2Vec2 position;

    /// body 在 world 中的角度 ,以弧度为单位
    float32 angle;

    /// body's origin(原点)在世界坐标系中的线速度
    b2Vec2 linearVelocity;

    /// body 的角速度.
    float32 angularVelocity;

//    使用线性阻尼,以降低线速度。阻尼参数
//    可以大于1.0F ,但阻尼作用会变得非常敏感
//      阻尼参数越大同步时间越长
    float32 linearDamping;

    /// 使用阻尼角,以减少角速度。阻尼参数
    //    可以大于1.0F ,但阻尼作用会变得非常敏感
    //      阻尼参数越大同步时间越长
    float32 angularDamping;

    /// 把这个标志设置为 false 如果这个 body 不应该进入睡眠. 需要注意的是
    //这会增加CPU的使用率。
    bool allowSleep;

    /// 这个 body 初始化时是 awake / sleeping?
    bool awake;

    ///如果这个 body 不应该旋转,这个字符串就非常有用了
    bool fixedRotation;

    ///这是一个快速移动的 body,应该防止它快速穿过其它 body
//    请注意所有的 body 都无法从  kinematic/static body 之内穿过
    /// @warning 你应该尽量减少使用这个 flag,因为它会增加处理时间
    bool bullet;

    ///  body 是否开始激活?
    bool active;

    /// 使用这个存储应用程序特定的 body 数据
    void* userData;

    ///应用到这个 body 的中立比例.
    float32 gravityScale;
};

/// A rigid(精密) body. 这些是通过 b2World::CreateBody 创建的.
class b2Body
{
public:
    /// 创建一个 fixture(定制器) 把它附加到这个 body. 使用此功能,如果你需要的
    ///设置一些固定参数,如摩擦。其它情况,你可以使用shape 创建 fixture(定制器)
//    如果密度不为零时,此功能会自动更新物体的质量。
    /// 联系一直存在,不会创建直到下一个步骤
    /// @param def 定义的 fixture(定制器)
    /// @warning 这个功能锁定在 回调函数里面
    b2Fixture* CreateFixture(const b2FixtureDef* def);

    /// 创建一个固定形状,将它附加到这个身体
    /// 这是一个方便的功能.  如果你需要使用 b2FixtureDef 设置参数
    /// 如 friction(摩擦), restitution(恢复), user data, or filtering(过滤).
    /// 如果密度不为零时,此功能会自动更新物体的质量
    /// @param shape 要克隆的形状.
    /// @param density  shape 的密度 (静态物体设置为零).
    /// @warning 这个功能锁定在 回调函数里面
    b2Fixture* CreateFixture(const b2Shape* shape, float32 density);

    /// 销毁一个 fixture. 从 broad-phase 里面移除这个 fixture,破坏与这个 fixture 关联的所有联系这将
    // /如果身体是动态的,这个 fixture 具有一定的密度,它会自动调整物体的质量,
    /// 当 body 被销毁时,关联到 body 的所有 fixtures 都会直接被删除
    /// @param fixture the fixture to be removed.
    /// @warning 这个功能锁定在 回调函数里面.
    void DestroyFixture(b2Fixture* fixture);

    /// 为这个 body 设置位置和旋转角
    /// 这打破了任何联系,唤醒其它 body
    /// 操作一个 body 转换,可能会 导致其它 non-physical 行为.
    /// @param position body 在世界坐标系的位置
    /// @param angle 世界坐标系的角度以弧度为单位
    void SetTransform(const b2Vec2& position, float32 angle);

    /// 获取这个 body 的转换.
    /// @return 这个 body 在世界坐标系中的转换.
    const b2Transform& GetTransform() const;

    /// 获取 body 在世界坐标系中的位置.
    /// @return body 在世界坐标系中的位置..
    const b2Vec2& GetPosition() const;

    /// 获取角度以弧度为单位.
    /// @return 当前世界坐标系的角度以弧度为单位
    float32 GetAngle() const;

    /// 获取的质量中心 在世界坐标系中的位置.
    const b2Vec2& GetWorldCenter() const;

    /// 获取本地的质量中心的位置。.
    const b2Vec2& GetLocalCenter() const;

    /// 设定的质心的线速度.
    /// @param v 新的质心的线速度。.
    void SetLinearVelocity(const b2Vec2& v);

    /// Get 质心的线速度..
    /// @return 质心的线速度.
    b2Vec2 GetLinearVelocity() const;

    /// Set 角速度.
    /// @param omega 新的角速度 radians/second.
    void SetAngularVelocity(float32 omega);

    /// Get 角速度.
    /// @return 新的角速度 radians/second.
    float32 GetAngularVelocity() const;

    /// 这世界坐标点应用力,如果力不作用在质量中心,他会发生旋转,影响角速度,唤醒这个 body
    /// @param force  world 力矢量,通常以牛顿(N)为单位
    /// @param point 应用里面的某个点的 world 位置
    void ApplyForce(const b2Vec2& force, const b2Vec2& point);

    /// 在质量中心施加一个力,这将唤醒这个 body
    /// @param force  world 力矢量,通常以牛顿(N)为单位
    void ApplyForceToCenter(const b2Vec2& force);

    /// 应用力矩,这会影响到角速度
    /// 不影响质量的中心的线速度,唤醒 body
    /// @param torque 围绕z轴(移出屏幕), 通常 N-m(N/米).
    void ApplyTorque(float32 torque);

    /// 应用一个冲量到一个点上,这将立即改变速度。(这句话的意思是突然在一个点上作用一个力)
    /// 如果这个点不再应用程序的质心上,它还会修改角速度. 唤醒 body.
    /// @param impulse  world 的矢量冲量, 通常 N-seconds or kg-m/s.
    /// @param point 应用里面的某个点的 world 位置
    void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point);

    /// 应用一个有角度的冲量
    /// @param impulse 角度冲量的单位是 kg*m*m/s
    void ApplyAngularImpulse(float32 impulse);

    /// 获取 body 的总质量
    /// @return the mass, 通常是以 kilograms (kg) 为单位.
    float32 GetMass() const;

    /// 获取 body 的转动惯量,(本地点)
    /// @return 旋转惯性, 通常是以 kg-m^2.为单位
    float32 GetInertia() const;

    /// 获取这个身体的质量数据
    /// @return 一个包含 质量,惯性和body的中心
    void GetMassData(b2MassData* data) const;

    ///设置质量属性,覆盖 fixtures 的质量属性
    /// Note 这改变了质心的位置.
    /// Note t创建或销毁 fixtures 可以改变质量.
    /// 如果 body 不是动态的这个函数没有效果.
    /// @param massData  mass 属性.
    void SetMassData(const b2MassData* data);

// 计算 fixtures 的质量,这将重置质量属性
    /// 通常不需要调用这个,除非你调用了 SetMassData 覆盖了质量随后你需要复位质量.
    void ResetMassData();

    /// 获取给定坐标点,在世界坐标系中的位置
    /// @param localPoint 相对于 body's 原点的测量点.
    /// @return 相同的点用 world 坐标系表示.
    b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const;

    ///用世界坐标系表示给定的本地坐标
    /// @param localVector 固定在 body 上的矢量.
    /// @return 相同的向量用 world 坐标系表示
    b2Vec2 GetWorldVector(const b2Vec2& localVector) const;

    /// 使用给定世界坐标系的点获取一个相对于 body 原点的本地点
    /// @param 一个 world 坐标系中的点.
    /// @return 相对于 body 原点的本地坐标点
    b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const;

    /// 把指定的世界坐标系中的向量转换为一个本地向量
    /// @param world 坐标系中的向量.
    /// @return 对应的本地向量
    b2Vec2 GetLocalVector(const b2Vec2& worldVector) const;

    ///获取关联到这个 body 的 world point 在 world 中的线性速度
    /// @param 一个 world 坐标系中的点
    /// @return 一个点的 world 速度
    b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;

    /// 获取 local 点的 world 速度
    /// @param 一个本地坐标系中的点
    /// @return 一个点的 world 速度
    b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const;

    ///获取这个 body 的线性阻尼
    float32 GetLinearDamping() const;

    /// Set 这个 body 的线性阻尼
    void SetLinearDamping(float32 linearDamping);

    /// Get body 的阻尼角度
    float32 GetAngularDamping() const;

    /// Set body 的阻尼角度
    void SetAngularDamping(float32 angularDamping);

    /// Get 这个 body 的重力比例
    float32 GetGravityScale() const;

    /// Set 这个 body 的重力比例
    void SetGravityScale(float32 scale);

    /// Set body 的类型。这可能会改变的质量和速度。
    void SetType(b2BodyType type);

    /// Get 这个 body 的类型
    b2BodyType GetType() const;

//    这个 body 是否应该像子弹那样有连续碰撞检测
    void SetBullet(bool flag);

//   这个 body 是否像子弹那样有连续碰撞检测
    bool IsBullet() const;

    /// 你可以禁止这个 body 睡眠,如果你禁止睡眠,这个 body 将一直醒着
    void SetSleepingAllowed(bool flag);

    ///是否允许这个 body 睡眠
    bool IsSleepingAllowed() const;

    /// 设置这个 body 的睡眠状态,一个睡眠的 body 有一个较低的 CPU 占用
    /// @param flag set to true to put body to sleep, false to wake it.
    void SetAwake(bool flag);

    /// 获取这个 body 的睡眠状态
    /// @return true if the body is sleeping.
    bool IsAwake() const;

    /// 设置 body 的 active 状态,一个无效的body 不可以被 模拟、碰撞、唤醒
    /// 如果这个 flag 的值是 true,所有的 fixtures 都会添加到 broad-phase.
    /// 如果这个 flag 的值是 false,所有的 fixtures 都会从到 broad-phase 里面移除,所有的联系都会被销毁
    /// Fixtures 必须被添加了,其它情况不受影响。你可以继续 添加/消除 fixtures 到一个不活跃的 body
    /// fixtures 在一个不活跃的 body 上,他就不会参与 碰撞,射线投射,或查询。
    /// 添加 fixtures 到一个不活跃的 body 上,它也会不活跃
    /// 不活跃的 body 仍然保持它的 b2Word 对象
    void SetActive(bool flag);

    /// 获取 body 的 active 状态
    bool IsActive() const;

    /// 设置 body 有固定的旋转。这会导致质量被重置。
    void SetFixedRotation(bool flag);

    /// body 是否有固定的旋转
    bool IsFixedRotation() const;

    /// 获取联系到这个 body 的所有 fixtures 列表
    b2Fixture* GetFixtureList();
    const b2Fixture* GetFixtureList() const;

    /// Get the list of all joints attached to this body.
    b2JointEdge* GetJointList();
    const b2JointEdge* GetJointList() const;

    ///获取添加到这个 body 的所有联系
    /// @warning this list changes during the time step and you may
    /// miss some collisions if you don't use b2ContactListener.
    b2ContactEdge* GetContactList();
    const b2ContactEdge* GetContactList() const;

    /// 获取 world's body 列表里面的下一个 body.
    b2Body* GetNext();
    const b2Body* GetNext() const;

    /// 获取 body 里面提供的用户指针数据
    void* GetUserData() const;

    /// Set  body 里面提供的用户指针数据
    void SetUserData(void* data);

    /// Get the parent world of this body.
    b2World* GetWorld();
    const b2World* GetWorld() const;

//    把 body 的阻尼输出到一个日志文件
    void Dump();

private:

    friend class b2World;
    friend class b2Island;
    friend class b2ContactManager;
    friend class b2ContactSolver;
    friend class b2Contact;
    
    friend class b2DistanceJoint;
    friend class b2GearJoint;
    friend class b2WheelJoint;
    friend class b2MouseJoint;
    friend class b2PrismaticJoint;
    friend class b2PulleyJoint;
    friend class b2RevoluteJoint;
    friend class b2WeldJoint;
    friend class b2FrictionJoint;
    friend class b2RopeJoint;

    // m_flags
    enum
    {
        e_islandFlag        = 0x0001,
        e_awakeFlag            = 0x0002,
        e_autoSleepFlag        = 0x0004,
        e_bulletFlag        = 0x0008,
        e_fixedRotationFlag    = 0x0010,
        e_activeFlag        = 0x0020,
        e_toiFlag            = 0x0040
    };

    b2Body(const b2BodyDef* bd, b2World* world);
    ~b2Body();

    void SynchronizeFixtures();
    void SynchronizeTransform();

    // 这个用来防止连接机构碰撞
    // 它可能 lie(不一样),这取决于collideConnected标志
    bool ShouldCollide(const b2Body* other) const;

    void Advance(float32 t);

    b2BodyType m_type;

    uint16 m_flags;

    int32 m_islandIndex;

    b2Transform m_xf;        //  body 的转换原点
    b2Sweep m_sweep;        // the swept motion for CCD //CCD 的打扫运动

    b2Vec2 m_linearVelocity;
    float32 m_angularVelocity;

    b2Vec2 m_force;
    float32 m_torque;

    b2World* m_world;
    b2Body* m_prev;
    b2Body* m_next;

    b2Fixture* m_fixtureList;
    int32 m_fixtureCount;

    b2JointEdge* m_jointList;
    b2ContactEdge* m_contactList;

    float32 m_mass, m_invMass;

    // 质心的转动惯量
    float32 m_I, m_invI;

    float32 m_linearDamping;
    float32 m_angularDamping;
    float32 m_gravityScale;

    float32 m_sleepTime;

    void* m_userData;
};

inline b2BodyType b2Body::GetType() const
{
    return m_type;
}

inline const b2Transform& b2Body::GetTransform() const
{
    return m_xf;
}

inline const b2Vec2& b2Body::GetPosition() const
{
    return m_xf.p;
}

inline float32 b2Body::GetAngle() const
{
    return m_sweep.a;
}

inline const b2Vec2& b2Body::GetWorldCenter() const
{
    return m_sweep.c;
}

inline const b2Vec2& b2Body::GetLocalCenter() const
{
    return m_sweep.localCenter;
}

inline void b2Body::SetLinearVelocity(const b2Vec2& v)
{
    if (m_type == b2_staticBody)
    {
        return;
    }

    if (b2Dot(v,v) > 0.0f)
    {
        SetAwake(true);
    }

    m_linearVelocity = v;
}

inline b2Vec2 b2Body::GetLinearVelocity() const
{
    return m_linearVelocity;
}

inline void b2Body::SetAngularVelocity(float32 w)
{
    if (m_type == b2_staticBody)
    {
        return;
    }

    if (w * w > 0.0f)
    {
        SetAwake(true);
    }

    m_angularVelocity = w;
}

inline float32 b2Body::GetAngularVelocity() const
{
    return m_angularVelocity;
}

inline float32 b2Body::GetMass() const
{
    return m_mass;
}

inline float32 b2Body::GetInertia() const
{
    return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
}

inline void b2Body::GetMassData(b2MassData* data) const
{
    data->mass = m_mass;
    data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
    data->center = m_sweep.localCenter;
}

inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const
{
    return b2Mul(m_xf, localPoint);
}

inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const
{
    return b2Mul(m_xf.q, localVector);
}

inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const
{
    return b2MulT(m_xf, worldPoint);
}

inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const
{
    return b2MulT(m_xf.q, worldVector);
}

inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const
{
    return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c);
}

inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const
{
    return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
}

inline float32 b2Body::GetLinearDamping() const
{
    return m_linearDamping;
}

inline void b2Body::SetLinearDamping(float32 linearDamping)
{
    m_linearDamping = linearDamping;
}

inline float32 b2Body::GetAngularDamping() const
{
    return m_angularDamping;
}

inline void b2Body::SetAngularDamping(float32 angularDamping)
{
    m_angularDamping = angularDamping;
}

inline float32 b2Body::GetGravityScale() const
{
    return m_gravityScale;
}

inline void b2Body::SetGravityScale(float32 scale)
{
    m_gravityScale = scale;
}

inline void b2Body::SetBullet(bool flag)
{
    if (flag)
    {
        m_flags |= e_bulletFlag;
    }
    else
    {
        m_flags &= ~e_bulletFlag;
    }
}

inline bool b2Body::IsBullet() const
{
    return (m_flags & e_bulletFlag) == e_bulletFlag;
}

inline void b2Body::SetAwake(bool flag)
{
    if (flag)
    {
        if ((m_flags & e_awakeFlag) == 0)
        {
            m_flags |= e_awakeFlag;
            m_sleepTime = 0.0f;
        }
    }
    else
    {
        m_flags &= ~e_awakeFlag;
        m_sleepTime = 0.0f;
        m_linearVelocity.SetZero();
        m_angularVelocity = 0.0f;
        m_force.SetZero();
        m_torque = 0.0f;
    }
}

inline bool b2Body::IsAwake() const
{
    return (m_flags & e_awakeFlag) == e_awakeFlag;
}

inline bool b2Body::IsActive() const
{
    return (m_flags & e_activeFlag) == e_activeFlag;
}

inline void b2Body::SetFixedRotation(bool flag)
{
    if (flag)
    {
        m_flags |= e_fixedRotationFlag;
    }
    else
    {
        m_flags &= ~e_fixedRotationFlag;
    }

    ResetMassData();
}

inline bool b2Body::IsFixedRotation() const
{
    return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;
}

inline void b2Body::SetSleepingAllowed(bool flag)
{
    if (flag)
    {
        m_flags |= e_autoSleepFlag;
    }
    else
    {
        m_flags &= ~e_autoSleepFlag;
        SetAwake(true);
    }
}

inline bool b2Body::IsSleepingAllowed() const
{
    return (m_flags & e_autoSleepFlag) == e_autoSleepFlag;
}

inline b2Fixture* b2Body::GetFixtureList()
{
    return m_fixtureList;
}

inline const b2Fixture* b2Body::GetFixtureList() const
{
    return m_fixtureList;
}

inline b2JointEdge* b2Body::GetJointList()
{
    return m_jointList;
}

inline const b2JointEdge* b2Body::GetJointList() const
{
    return m_jointList;
}

inline b2ContactEdge* b2Body::GetContactList()
{
    return m_contactList;
}

inline const b2ContactEdge* b2Body::GetContactList() const
{
    return m_contactList;
}

inline b2Body* b2Body::GetNext()
{
    return m_next;
}

inline const b2Body* b2Body::GetNext() const
{
    return m_next;
}

inline void b2Body::SetUserData(void* data)
{
    m_userData = data;
}

inline void* b2Body::GetUserData() const
{
    return m_userData;
}

inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point)
{
    if (m_type != b2_dynamicBody)
    {
        return;
    }

    if (IsAwake() == false)
    {
        SetAwake(true);
    }

    m_force += force;
    m_torque += b2Cross(point - m_sweep.c, force);
}

inline void b2Body::ApplyForceToCenter(const b2Vec2& force)
{
    if (m_type != b2_dynamicBody)
    {
        return;
    }

    if (IsAwake() == false)
    {
        SetAwake(true);
    }

    m_force += force;
}

inline void b2Body::ApplyTorque(float32 torque)
{
    if (m_type != b2_dynamicBody)
    {
        return;
    }

    if (IsAwake() == false)
    {
        SetAwake(true);
    }

    m_torque += torque;
}

inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point)
{
    if (m_type != b2_dynamicBody)
    {
        return;
    }

    if (IsAwake() == false)
    {
        SetAwake(true);
    }
    m_linearVelocity += m_invMass * impulse;
    m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
}

inline void b2Body::ApplyAngularImpulse(float32 impulse)
{
    if (m_type != b2_dynamicBody)
    {
        return;
    }

    if (IsAwake() == false)
    {
        SetAwake(true);
    }
    m_angularVelocity += m_invI * impulse;
}

inline void b2Body::SynchronizeTransform()
{
    m_xf.q.Set(m_sweep.a);
    m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
}

inline void b2Body::Advance(float32 alpha)
{
    // 提前新的安全时间. 这个不同步 broad-phase.
    m_sweep.Advance(alpha);
    m_sweep.c = m_sweep.c0;
    m_sweep.a = m_sweep.a0;
    m_xf.q.Set(m_sweep.a);
    m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
}

inline b2World* b2Body::GetWorld()
{
    return m_world;
}

inline const b2World* b2Body::GetWorld() const
{
    return m_world;
}

#endif


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值