第七章 物理引擎

大家对下面几款非常流行的游戏一定是耳熟能详,如”愤怒的小鸟”,”超级火柴人高尔夫”,”神仙道”。它们背后都是靠物理引擎驱动的。

Cocos2d用来描述二维世界,cocos2d支持Box2d和chipmunk,Box2d是用C++写的,chipmunk是用c语言写的,相对而言,Box2d更流行一些,因此本书主要接受Box2d,对chipmunk只稍作介绍。有兴趣的同学可以自己下去学习。

7.1 物理引擎

7.1.1 物理引擎的基本概念

       Box2D是用C++写的。开发者是Erin Catto,他从2005年开始就在每一届的Game DevelopersConference(GDC)上进行关于物理模拟的演讲。2007年的9月,他公开发布了Box2D引擎。从那以后,Box2D的开发工作一直很活跃。因为很受欢迎, 所以cocos2d整合了Box2D与之一起发布。                                             Box2D是一个用于游戏的刚体仿真库。程序员可以在他们的游戏里使用它。它可以是物体的运动更加可信,让游戏看起来更有交互性。从游戏的视觉来看,物理引擎就是一个程序性动画的系统,而不是有动画师去移动你的物体。牛顿就是你的导演。                                                                                                                     Box2D 是用可移植的 C++ 来写成的。引擎中定义的大部分类型都有 b2 前缀,可以把它和我们游戏中的其他元素区分开来。

       Box2D中的基本对象:

 

       刚体(rigid body):一块十分坚硬的物质,它上面的任何亮点之间的距离都是完全不变的。它就像钻石一样坚硬。我们也可以理解为物理学中的质点,只有位置,没有大小,它又可以区分为以下几类:

Ø  静态刚体:静态刚体没有质量,没有速度,只可以手动来改变他的位置。

Ø  棱柱刚体:棱柱刚体没有质量,但是可以有速度,可以自己更新位置。

Ø  动态刚体:动态刚体有质量也有速度。

在以后的讨论中我们将用物体(body)来代替刚体。

       形状(shape): 一块严格依附于物体(body)的2D碰撞集合结构(collision geomerty)。形状具有磨擦(friction)和恢复(restitution)的材料性质。形状可以通过关节添加到物体上。

夹具(fixture): 一个固定装置将一个形状捆绑到一个body上,并添加材料属性,例如密度,摩擦力,恢复等。

约束(constraint): 一个约束就是消除物体自由度的物理连接。在 2D 中,一个物体有 3 个自由度。如果我们把一个物体钉在墙上(像摆锤那样),那我们就把它约束到了墙上。这样,此物体就只能绕着这个钉子旋转,所以这个约束消除了它 2 个自由度。还有一种不须你创建的接触约束,一个防止刚体穿透,以及用于模拟摩擦和恢复的特殊约束。你永远不必创建一个接触约束,它们会被Box2D创建。

关节(Joint): 它是一种用于把两个物体或多个物体固定到一起的约束。Box2D支持的关节类型有:旋转,棱柱,距离等等。关节可以支持限制和马达。

Ø  关节限制:一个关节限制(joint limit)限定了一个关节的运动范围。例如中标的钟摆只能在某个范围角度内运动。

Ø  关节马达(joint motor)一个关节马达能依照关节的自由度来驱动所连接的物体。例如你可以用一个齿轮来驱动钟摆的旋转。

世界(world): 世界是遵循物理的空间,以上的所有都存在于世界中,可以创建多个世界,但很少这样用。创建世界需要两个步骤,一是生成重力向量,二是根据重力生成世界对象。

7.1.2物理引擎的局限性

物理引擎有它自身的局限性:它们必须在模拟效果时使用一些捷径,也就是说简化物体的复杂性,因为真实世界过于复杂,完全放到物理引擎中进行模拟是 不可能的。这就是为什么要使用刚体的原因。在某些极端情况下,物理引擎有 可能会捕捉不到某些已经发生的碰撞 – 例如,当刚体以很快的速度移动时,一 个刚体可能直接穿透另一个刚体。虽然在量子物理学中这样的穿透情况会发生, 但是我们看到的真实世界中的物体是不会相互穿透的。

刚体有时候会相互穿透卡在一起,特别是在使用了关节将它们连接在一起以后。 卡在一起的刚体会努力要分开,但是为了满足关节的连接要求,它们又不得不卡在一起,结果是卡在一起的刚体会产生颤动。

我们也可能碰到游戏运行的问题。如果我们在游戏里使用了很多刚体,你永远

不会知道这些刚体相互作用后的最终结果。最终,有些玩家会把自己卡死在刚体中,或者他们也可能会发现如何利用物理模拟的漏洞,跑到游戏中他们本来不应该去的区域。

 

7.2 Box2d设计思路

7.2.1 内存管理

Box2D的许多设计都是决策都是为了能够快速的使用内存。

       Box2D不倾向分配大量的小对象(50-300字节)。这样通过malloc或new在系统堆(heap)上分配内存效能太低效,并且容易产生内存碎片。

       Box2D的解决方案是使用小型对象分配器(SOA),SOA维护了许多不定尺寸的可生长的池,当有内存分配请求的时候,SOA会返回一块最匹配的内存,当内存释放掉以后,它会回到池中。这些操作都十分快速,因而只会产生很小的堆流量。

       因为Box2D使用了SOA,所以你永远也不必去new火malloc物体,形状活关节,都只需要分配一个b2World,它为你体总了创建物体,形状和关节的工厂。

      

   

 

       7.2.2 工厂和定义

       如上所述,内存管理在Box2D API的设计中担当了一个中心角色,所以当你创建一个b2Body或一个b2Joint的时候,你需要用b2World的工厂函数。

下面是创建函数

 

 

 

    1 b2BodyDefcontainerBodyDef;

     2 b2Body*containerBody = world->CreateBody(&containerBodyDef);

 

      

       下面是对应的摧毁函数:

    world->DestroyBody(&containerBody);

7.2.3 单位

       Box2D使用浮点数,所以必须使用一些公差来保证它们正常工作。这些公差已经被调谐得适合米,千克,秒单位。尤其是,Box2D被调谐的能良好的处理0.1到10米之间的移动物体,这意味着从茶杯,粉笔盒到卡车大小的对象都能良好的工作。但是在你创建的Box2D世界中的刚体的大小限定在越接近1米越好。不过这并不意味着你不能有长度小于0.1米的刚体,或者长度大于10米的刚体。但是,太小或者太大的刚体很可能会在游戏运行过程中产生错误和奇怪的行为。

       作为一个2D物理引擎,如果能够使用像素作为单位是很诱人的,很不幸,那将导致不良模拟,会造成古怪的行为。一个200像素长的物体在Box2D看来就有45层建筑物那么大。想象一下使用一个被调谐好的玩偶和木桶去模拟高楼大厦的运动,那一定很怪异。

       我们一定习惯了,用像素来计算屏幕中的位置,因为这样对我们来说更为直观,我们可以通过下面的方式进行b2Vec2和CGPoint的转变,这意味着你不能够在需要CGPoint的地方 使用b2Vec2,反过来也不行。而且,Box2D里的点需要转换成米为单位,或者从 米为单位转换回以像素为单位。为了避免出错,比如忘记转换单位,或者打错了字,或者把x轴坐标使用了两次,我强烈建议你把这些重复的转换代码封装到方法中去,首先定义一个转变基数:

#definePTM_RATIO 32

 

PTM_RATIO用于定义32个像素在Box2D世界中等同于1米。一个有32像素宽和高的盒子形状的刚体等同于1米宽和高的物体。在Box2D中,4x4像素的大小是 0.125x0.125。你可以通过PTM_RATIO把刚体的尺寸设置成最适合Box2D的尺寸, 而PTM_RATIO设置为32,对于拥有1024x768像素的iPad来说也是很合适的。

 

[Microsoft1] 

-(b2Vec2)toMeters:(CGPoint)point


{

       return b2Vec2(point.x / PTM_RATIO,point.y / PTM_RATIO);

 }

-(CGPoint)toPixels:(b2Vec2)vec

{

       return ccpMult(CGPointMake(vec.x, vec.y),PTM_RATIO);

 }

 

 

 

这样我们就可以很容易的进行b2Vec2和CGPoint的转变

1 CGPoint point = CGPointMake(100, 100);b2Vec2 vec = b2Vec2(200, 200);

2 CGPoint pointFromVec; pointFromVec = [selftoPixels:vec];

3 b2Vec2 vecFromPoint; vecFromPoint = [selftoMeters:point];

 

 

7.2.4 用户数据

       b2shape,b2Body和b2Joint类都允许你通过一个void指针来附加用户数据。这在你测试Box2D数据结构,以及你想把它们联系到自己的引擎中是较为方便的。

       举个典型的例子,在角色上的刚体中附加到角色的指针,这就构成了一个循环引用。如果你有角色,你就能得到刚体,如果你有刚体,你就能得到角色。

       这是一些需要用户数据的案例:

Ø  使用碰撞结果给角色施加伤害。

Ø  当玩家进入一个包围盒时播放一段脚本事件。

Ø  当Box2D通知你一个关于即将摧毁时访问一个游戏结构。

 

7.3世界(world)

7.3.1 什么是世界

       b2World类包含着物体和关节,它管理者物理模拟的方方面面,并允许异步查询(就想AABB查询)你与Box2Dderek大部分交互都将通过b2World对象来完成。一个世界是一个物理引擎的开始,我们从创建一个世界开始,讲逐步告诉你怎么创造一个物理引擎,一个自己定义的世界。

7.3.2 创建和摧毁一个世界

       创建一个世界和摧毁一个世界很简单,你只需要提供一个重力向量和是否允许物体休眠。

       要创建或摧毁一个世界你需要使用new:

 

 

 

 

1 -(id) init

2 {

3  if((self = [super init]))

4  {

5     b2World*world;

6     b2Vec2gravity = b2Vec2(0.0f, -10.0f);

   7     bool allowBodiesToSleep =true;

 8    world = new b2World(gravity,allowBodiesToSleep);

 9 }

 

 

 

7.3.3 使用一个世界

 

7.3.3.1 模拟

 

       世界类用于驱动模拟。也就是说我们可以决定可以多长时间刷新物理世界,它包括物体的速度和位置等信息的刷新。我们需要制定一个刷新的时间间隔和迭代次数。

       例如下面的代码是按制定的最快的速度刷新,每次刷新是速度会迭代8次,而位置的计算迭代一次。

 

 

-(void) update:(ccTime)delta

{

  

   float timeStep = 0.03f;

   int32 velocityIterations = 8;

   int32 positionIterations = 1;

   world->Step(timeStep,velocityIterations, positionIterations);

}

 

 

Box2D建议的刷新的频率是固定的。

那为什么我们还要允许我们自己定义这些参数呢?当我们的游戏运行负担比较轻的时候,我们可以给用户一个较高的刷新频率,这样用户就能获得更好的体验;当我们的游戏负担比较重的时候,我们可以使用一个较低的刷新频率,已获得一个用户还算满意的游戏体验。

 

7.3.3.2 扫描世界

 

       如上所述,世界就是一个物体和关节的容器,当我们刷新世界的时候,肯定是想让世界的物体或者关节发生某种变化。你可以获取世界中所有物体和关节遍历它们。例如,你可能需要需要改变某个精灵的位置或者唤醒世界中的所有物体,

我们在-(void) update:(ccTime)delta方法中添加如下代码

 

 

 

for (b2Body*body = world->GetBodyList(); body != nil; body = body->GetNext())

{

   CCSprite* sprite =(CCSprite*)body->GetUserData();

   if (sprite != NULL)

   {

       // update the sprite's position to wheretheir physics bodies are

       sprite.position = [selftoPixels:body->GetPosition()];

       float angle = body->GetAngle();

       sprite.rotation =CC_RADIANS_TO_DEGREES(angle) * -1;

   }  

}

 

7.4物体(Body) 

       静态物体(b2_statiBody)

       一个静态物体不会在模拟中一种,并且它行动起来就像其有无限的质量。内部原因讲,Box2D将质量存储为零,静态物体能被用户手动操作移动。静态物体含有零向量,不会与其它静态物体或者运动的物体碰撞。

 

       运动但不受力物体(b2_kinematicBody)

       运动但不受力物体凭借向量可以在模拟中运动,它们不受力的作用。可以通过用户手动操作而做运动,但通常情况下,运动但不受力物体通过设置其向量来操作移动。其行为看起来也好像有无限的重量,但是,Box2D将质量存储为零,运动但不受力物体也不会与静态物体或者运动物体碰撞。

      

       动态物体(b2_dynamicBody)

       动态的body被完全模拟,他们可以通过用户手动操作而移动,但通常情况下,他们在力的作用下移动,动态body可以与任何类型的body碰撞,一个动态的body旺旺是有限制的,必须为非零质量。如果你想把动态body的质量设为零,它将自动获得一千克的质量。

 

7.4.1 物体定义

 

       前面我们已经创建了一个世界,现在我们创建一个物体绑到世界上。

       在物体创建之前,你必须创建一个物体定义(b2BodyDef)来初始化物体所需的数据。

       我们先来熟悉一个b2BodyDef的各种属性

      

      

      

 

 

b2BodyDefcontainerBodyDef;

   containerBodyDef.type= b2_dynamicBody;

   containerBodyDef.position.Set(0.0f,2.0f);

   containerBodyDef.angle= 0.25f*b2_pi;

   containerBodyDef.linearDamping = 0.0f;

    containerBodyDef.angularDamping=0.01f;

    containerBodyDef.allowSleep= true;

containerBodyDef.awake= true

containerBodyDef.userData= &myaction;

    containerBodyDef.fixedRotation= true;//固定选装

    containerBodyDef.bullet= true;

              

   

   物体类型(type)属性:在初始化一个物体的时候,你就应该确定好改物体的类型,静态物体,动态但不受力物理还是动态物体。并轻易不要修改它。

 

    位置(position)和角度(angle)属性:定义物理之后,我们可以初始化一个位置和物体的角度,而不是所有的物体从原点建立,而后移到你所需要的位置上面。

 

    阻尼(linearDamping和angularDamping):阻尼是用来减小物体的速度的,阻尼与摩擦不同,因为只有接触才回产生摩擦,阻尼也不是摩擦的取代,这两个效果要一起使用。阻尼参数范围是0到无穷大,0是没有阻尼,无穷就是满阻尼。

    休眠参数(allowSleepawake):模拟是非常昂贵的,我们应当尽量减少模拟物体,当一个物体休息时,我们应当停止他们的模拟。

    子弹(bullet):有的时候,在同一个时间有大量的刚体在运动,我们肯定不希望这些物体能够相互穿来穿去的,这被称作隧道效应。

    默认情况下,Box2D会通过连续碰撞检测来防止动态物体穿越静态物体。但动态物体之间是不使用连续碰撞检测的,这是为了保持游戏的性能。告诉移动的物体在Box2D中被称为子弹(bullet),子弹能够检测到碰撞,而不会引起穿壁而过的情况。

    用户数据(userData):用户数据是个空指针,它给你提供了一个挂钩来将你的应用程序对象连接到物体上,对所有物体的用户数据,你需要一个一致的对象类型。

   

7.4.2 创建物体

             上面我们已经知道了如何定义一个物体的属性,前面我们已经说过,所有的物体创建和销毁都是有世界(World)来完成的,这使得世界可以通过一个高效的分配器来创建物体,并且把物体添加到世界上。我们在上面的-(id) init添加如下代买,把创建一个物体并绑定到世界(World)上

 

 

[Microsoft2] 

        b2BodyDef containerBodyDef;

       containerBodyDef.type = b2_dynamicBody;

b2Body* containerBody =world->CreateBody(&containerBodyDef);

 

 

 

7.4.3 使用物体

 

创建一个物体之后,一般我们不应该改变它的属性,而应该遵循物理规则使其产生变化,但是一些特殊情况,我们也可以读取和修改其属性。这些可修改的属性有:质量数据,状态信息,位置和速度等。

使用最多的是通过力和冲量等改变物体的运动。

你可以对一个物体应用力,扭矩,以及冲量。当应用一个力或者冲量时,你需要提供一个世界位置。这常常会导致对质心的一个扭矩。

 

void ApplyForce(const b2Vec2& force,const b2Vec2& point);

 

void ApplyTorque(float32 torque);

 

void ApplyAngularImpulse(float32 impulse);

 

 

    应用力,扭矩力或冲量会唤醒物体,有时这是不合需求的。例如,你可能想应用一个稳定的力,并允许物体休眠来提升性能,这时,你需要这要来改变物体的属性。

 

 

  if(containerBody->IsSleepingAllowed() ==false)

   {

        containerBody->ApplyForce(myForce, myPoint);

   }

7.5形状

       形状就是物体上的碰撞几何结构,另外形状也用于定义物体的质量。也就是说,你来指定密度,Box2D可以帮你计算出质量。

       形状具有磨擦和恢复的性质。形状还可以携带筛选信息,是你可以防止某些游戏对象之间的碰撞。

       形状永远属于某物体,单个物体可以拥有多个形状。

       形状不能直接创建在物体上,形状应创建在夹具上,夹具再创建在物体。

       通用的形状数据会保存在b2Shape中,一些特殊的形状数据会保存在其派生类中。

       下面我们讲一些基本的形状定义

 

       7.5.1 圆形定义

 

       b2CircleShape扩充了b2Shape并增加一个半径和一个局部位置。

      

 

            

       b2CircleShape  circle;    

       circle.m_p.Set(2.0f,3.0f);

circle.m_radius = 0.5f;

                          

 

 

7.5.2 多边形定义

 

       b2PolygonShape用于定义凸多边形。

       当创建多边形定义时,你需要给出所用的顶点数目。这些顶点必须按照相对于右手坐标系之Z轴逆时针(CCW)的顺序定义。

       下面给出一个三角形的多边形定义的代码

      

 

 

   b2Vec2 vertices[3];

    vertices[0].Set(0.0f, 0.0f);

    vertices[1].Set(1.0f, 0.0f);

    vertices[2].Set(0.0f, 1.0f);

    int32count = 3;

    b2PolygonShape polygon;

polygon.Set(vertices, count);

 

 

7.5.3 边缘形状

 

       边缘形状就是线段。它可以帮助你设计游戏的曲面静态环境。边缘形状的一个最主要的限制就是它们只会与圆形或者多边形碰撞,但本身不会碰撞,Box2D碰撞算法要求—两个碰撞形状其中的至少一个含有体积。边缘外形没有体积,所以边缘性状和边缘形状是不可碰撞的。

       定义边缘形状,需要制定线段的起点和终点。

 

 

 

      

 

 

7.6夹具

我们已经知道形状需要通过夹具才能附属到物体上,Box2D提供了b2Fixture类将shape附属到body上。

 

7.6.1 创建Fixture及夹具属性

 

       Fixture是通过初始化fixture定义并把定义传递给父类body创建的。

   我们在上面的类中添加一个新方法-(void) bodyCreateFixture:(b2Body*)body 来把形状附属到物体上

 

 

 

 

-(void)bodyCreateFixture:(b2Body*)body

{

   // Define another box shape for our dynamicbodies.

   b2PolygonShape dynamicBox;

   float tileInMeters = TILESIZE / PTM_RATIO;

   dynamicBox.SetAsBox(tileInMeters * 0.5f,tileInMeters * 0.5f);

  

   // Define the dynamic body fixture.

   b2FixtureDef fixtureDef;

   fixtureDef.shape = &dynamicBox;

   fixtureDef.density = 0.3f;

   fixtureDef.friction= 0.5f;   

   fixtureDef.restitution = 0.6f;

   fixtureDef.isSensor= true

   body->CreateFixture(&fixtureDef);

  

}

 

 

 

这创建了fixture,并把它附属到body上,你没必要去存储fixture指针,因为父辈body被破坏时,fixture会自动被破坏。

你可以在父辈body上破坏fixture,也可以用这种方法创建一个易碎的对象。也可以自己破坏(DestroyFixture)

 

在上面我们不但创建了一个fixture,并且设定了一些基本属性。

 

Density是设置密度的,fixture的密度可以用来计算父辈body的质量性能。密度可以为零或者为正数。

对所有的fixture,你应该使用相似的密度,这样可以提高堆的稳定性。

 

Friction是设置摩擦系数的,摩擦的参数经常会设置在0到1之间,0意味着没有参数,1会产生强摩擦。计算两个物体形状之间的摩擦公式是

 

float friction=sqr(fixture1->GetFriction()*fixture2->GetFriction())

 

restitution是设置恢复的,想象一下,在桌面上方丢一个小球。恢复的值通常设置到0至1之间,0意味着小球不会弹起,这称为非弹性碰撞;1的意思是小球的速度会得到精确的反射,这称为弹性碰撞。恢复是通过下面的公式计算的:

 

Float32 restitution =b2Max(fixture1->getRestitution(), fixture2->getRestitution());

 

isSensor是传感器开关,有时候游戏逻辑需要判断两个形状是否交叉,但却不应该相互有碰撞反应。这时候可以通过传感器来完成,传感器会侦测碰撞而不产生碰撞反应。

 

你可以将任一形状标记为传感器,传感器可以是静止或动态的。记得,每个物体上可以有多个形状,并且传感器和实体形状是可以混合的。

 

7.7关节

关节的作用是把物体约束到世界里,或约束到其他物体上。在游戏中典型的例子是木偶,跷跷板和滑轮。关节可以用许多不同的方法结合起来,创造出又去的活动。

 

有些关节提供了限制(limit),以便你控制运动范围。有些关节还提供了马达(motor),它可以以指定的速度驱动关节,直到你指定了更大的力或扭矩。

 

关节马达有许多不同的用途,你可以使用关节来控制位置,只要提供一个与目标之距离成正比例的关节速度即可。你还可以模拟关节摩擦;将关节速度置零,并且提供一个小的,但有效的做大力或扭矩;那么马达就会努力保持关节不动,直到负载变得过大。

 

7.7.1 距离关节

 

       距离关节是最简单的关节之一,它描述了两个物体上的两个点之间的距离应该是常量。当你指定一个距离关节时,两个物体必须已在应有的位置上。随后,你指定两个世界坐标中的锚点。第一个锚点连接到物体worldAnchorOnbody1 ,第二个锚点连接到物体worldAnchorOnbody2。这些点隐含了距离约束的长度。

 

 

b2DistanceJointDefjointDisDef;

jointDisDef.Initialize(bodyA,bodyB, worldAnchorOnbody1  , worldAnchorOnbody2);

jointDisDef.collideConnected= true;

 

 

 

7.7.2 旋转关节

       一个旋转关节会强制两个物体共享一个锚点,即所谓的铰接点。选装关节只有一个自由度,两个物体相对旋转。这称之为关节角。

 

       要指定一个旋转关节,你需要提供两个物体以及一个世界坐标的锚点。初始化函数会假定物体已经在应有位置了。

       下面我们在上面的函数添加一个-(void) addSomeJoinedBodies:(CGPoint)pos

 

 

-(void)addSomeJoinedBodies:(CGPoint)pos

{

   // Create a body definition and set it to bea dynamic body

   b2BodyDef bodyDef;

   bodyDef.type = b2_dynamicBody;

  

   // position must be converted to meters

   bodyDef.position = [self toMeters:pos];

   bodyDef.position = bodyDef.position +b2Vec2(-1, -1);

   bodyDef.userData = [selfaddRandomSpriteAt:pos];

   b2Body* bodyA =world->CreateBody(&bodyDef);

   [self bodyCreateFixture:bodyA];

 

   bodyDef.position = [self toMeters:pos];

   bodyDef.userData = [selfaddRandomSpriteAt:pos];

   b2Body* bodyB =world->CreateBody(&bodyDef);

   [self bodyCreateFixture:bodyB];

 

   bodyDef.position = [self toMeters:pos];

   bodyDef.position = bodyDef.position +b2Vec2(1, 1);

   bodyDef.userData = [selfaddRandomSpriteAt:pos];

   b2Body* bodyC = world->CreateBody(&bodyDef);

   [self bodyCreateFixture:bodyC];

   

  

   

 

   b2RevoluteJointDef jointDef;

   jointDef.Initialize(bodyA, bodyB,bodyB->GetWorldCenter());

   bodyA->GetWorld()->CreateJoint(&jointDef);

 

   jointDef.Initialize(bodyB, bodyC,bodyC->GetWorldCenter());

   bodyA->GetWorld()->CreateJoint(&jointDef);

 

   // create an invisible static body to attachto

   bodyDef.type = b2_staticBody;

   bodyDef.position = [self toMeters:pos];

   b2Body* staticBody =world->CreateBody(&bodyDef);

jointDef.Initialize(staticBody, bodyA,bodyA->GetWorldCenter());

   bodyA->GetWorld()->CreateJoint(&jointDef);

}

 

7.7.3 移动关节

 

       移动关节允许两个物体沿指定轴相对移动,它会阻止相对旋转。因此,移动关节只有一个自由度。

移动关节的定义有些类似于旋转关节,只是旋转角度换成了平移,扭矩换成了力。以这样的类似,我们来看一个带有关节限制以及马达摩擦的移动关节定义:

 

 b2PrismaticJointDef jointRef2;

 b2Vec2 worldAxis(1.0f,0.0f);

jointRef2.Initialize(bodyA,bodyB, bodyA->GetWorldCenter(),   worldAxis);

 

 

 

       其它的关节类型包括滑轮关节,齿轮关节,鼠标关节,摩擦关节,绳子关节和焊接关节等。

7.8 接触

       接触(contact)是由Box2D创建的用于管理fixture间碰撞的对象。接触不同的种类,它们都会派生字b2Contact,用于管理不同类型形状之间的接触。例如,有管理多边形之间碰撞的类,有管理圆形之间碰撞的类,有管理边缘形状之间碰撞的类。

 

       7.8.1接触监听器

 

       通过实现b2ContactListener你就可以接受接触数据。当一个触点被创建时,当它持有超过一个时间步时,以及当它被摧毁时,这个监听器就会发出报告,请留意两个形状之间可能会有多个触电。接触监听器支持几种事件:开始(begin),结束(end),求解前(pre-solve),求解后(post-solve)。

 

       我们首先创建一个ContactListener类,头文件如下:

 

 

#import"Box2D.h"

 

classContactListener : public b2ContactListener

{

private:

    void BeginContact(b2Contact* contact);

    void EndContact(b2Contact* contact);

};

 

 

       我们在ContactListener.mm实现两个方法

 

 

#import "ContactListener.h"[Microsoft3] 

#import "cocos2d.h"

 

void ContactListener::BeginContact(b2Contact*contact)

{

       b2Body*bodyA = contact->GetFixtureA()->GetBody();

       b2Body*bodyB = contact->GetFixtureB()->GetBody();

       CCSprite*spriteA = (CCSprite*)bodyA->GetUserData();

       CCSprite*spriteB = (CCSprite*)bodyB->GetUserData();

      

       if(spriteA != NULL && spriteB != NULL)

       {

       spriteA.color= ccMAGENTA;

       spriteB.color= ccMAGENTA;

       }

}

 

 

void ContactListener::EndContact(b2Contact*contact)

{

       b2Body*bodyA = contact->GetFixtureA()->GetBody();

       b2Body*bodyB = contact->GetFixtureB()->GetBody();

       CCSprite*spriteA = (CCSprite*)bodyA->GetUserData();

       CCSprite*spriteB = (CCSprite*)bodyB->GetUserData();

      

       if(spriteA != NULL && spriteB != NULL)

       {

       spriteA.color= ccWHITE;

       spriteB.color= ccWHITE;

       }

}

 

事件

说明

Begin 事件

当两个fixture开始有重叠时,事件会被触发。传感器和非传感器都会触发这事件。这事件只能在时间步内(也就是b2World::step函数内部)发生。

End 事件

当两个fixture不再重叠时,事件会被触发。传感器和非传感器都会触发这事件,当一个body被摧毁时,事件也有可能被触发。所有这些时间也有可能发生在时间步之外。

 

Pre-Solve事件

当碰撞检测之后,但是碰撞求解之前,事件会被触发。这样可以给你一个机会,根据当前情况来决定是否使这个接触失效。

Post-Solve事件

当你可以得到碰撞冲量(collision impulse)的结果时,Pos-Solve事件会发生,如果你不关心冲量,你可能只需要实现pre-solve事件。

 

 

7.9 Chipmunk                                                    

       Chipmunk的原理和Box2D差不多,毕竟我们所处的是同一个物理世界。二则的差别只是在实现的方式,Chipmunk 用的是 C。d但Chipmunk有一个很受欢迎的Objective-C接口,叫做SpaceManager。你可以利用SpaceManger很容易地把cocos2d精灵添加到刚体上,添加调试用的绘图等。

7.9.1 Chipmunk的物理世界

 

       在Chipmunk的世界里,世界叫做cpSpace,它基本等同于Box2D里面的World,我们可以通过下面的方式来创建一个cpSpace,同样的我们在init方法里面添加如下代码

      

      

cpInitChipmunk();

space =cpSpaceNew();

space->iterations= 8;

space->gravity= CGPointMake(0, -100);

 

 

在使用任何Chipmunk方法之前,第一件必须做的事情是调用cpInitChipmunk方 法。然后,你可以使用 cpSpaceNew来生成space,并且设置space的迭代次数 – 在我们的例子中我将其设置为8。这个迭代次数和我在Box2D例子里的update 方法中用到的值是一样的。Chipmunk只有一种迭代– elasticIterations这项已经过时不用了。如果你熟悉Chipmunk,你需要注意到这一点。如果你的游戏不需要刚体可以叠在一起,你可以用小于8的迭代次数;否则,你会发现叠在一 起的刚体要经过很长时间才会停止颤动和滑动,最终停下来。

你可能注意到Chipmunk可以使用应用于iPhone SDK中的CGPoint结构。Chipmunk 内部使用的结构叫做cpVect,但是在cocos2d中你可以使用任何一个。我在这里使用了一个CGPoint将重力设为-100 – 这个数值所产生的重力将会和Box2D项目中用到的重力大致相同。

       在dealloc里面调用pSpaceFree进行内存释放:    cpSpaceFree(space);

 

7.9.2生成包含屏幕的静态刚体

      

       Chipmunk刚体和Box2D的不同之处你不需要把像素转换成以米为单位。你可以直接使用屏幕的像素尺寸来定义四个角,你也可以在Chipmunk的刚体上使用像素为单位。

       首先我们在init方法定义屏幕四个角的变量并生成刚体(cpBody):

      

 

CGSizescreenSize = [CCDirector sharedDirector].winSize;


CGPointlowerLeftCorner = CGPointMake(0, 0);


CGPointlowerRightCorner = CGPointMake(screenSize.width, 0);


CGPointupperLeftCorner = CGPointMake(0, screenSize.height);


CGPointupperRightCorner = CGPointMake(screenSize.width, screenSize.height);

float mass =INFINITY; float inertia = INFINITY;

cpBody*staticBody = cpBodyNew(mass, inertia);

 

 

    [Microsoft4] :Chipmunk中的质量(Mass)和惯性(Inertia)是和Box2D中的密(Density)和摩擦力(Friction)相对应的。惯性和摩擦力的区别是:前者决定着刚体开始移动时的阻力,后者决定着当刚体与别的刚体发生碰撞时会丢失的动能。

       下面我们将定义刚体的形状(shape),这个形状组成了屏幕边界:

cpSegmentShapeNew方法用于生成4个新线段,用于定义屏幕的4个边。为了方便 起见,shape变量在这里被重复利用,但是shape变量要求在每次调用cpSegmentShapeNew方法以后都要设置弹性值(elasticity)(这和Box2D中的回 复力(restitution)是一样的)和摩擦力(friction)。然后,我们通过cpSpaceAddStaticShape方法将每个shape作为静态刚体添加到space中去。

 

 

 

[Microsoft5] 

[Microsoft6] 

cpShape* shape; float elasticity = 1.0f;

float friction = 1.0f; float radius = 0.0f;

shape = cpSegmentShapeNew(staticBody, lowerLeftCorner,lowerRightCorner, radius);

shape->e = elasticity;
shape->u = friction;

cpSpaceAddStaticShape(space, shape);

shape = cpSegmentShapeNew(staticBody, upperLeftCorner,upperRightCorner, radius);

shape->e = elasticity;
shape->u = friction;


cpSpaceAddStaticShape(space, shape);

shape = cpSegmentShapeNew(staticBody, lowerLeftCorner,upperLeftCorner, radius);

shape->e = elasticity;


shape->u = friction;
cpSpaceAddStaticShape(space, shape);

shape = cpSegmentShapeNew(staticBody, lowerRightCorner,upperRightCorner, radius); shape->e = elasticity;
shape->u = friction;

cpSpaceAddStaticShape(space, shape);

 

 

7.9.3添加盒子

 

我们通过使用cpBodyNew方法来生成代表盒子的动态刚体,这个方法需要两个参 数:质量(mass)和惯性力矩(moment of inertia)。惯性力矩决定着刚体移 动时遇到的阻力,它是通过 cpMomentForBox这个帮助方法(helper method)来计算的。cpMomentForBox以刚体的质量和盒子的尺寸作为参数。

 

 

-(void) addNewSpriteAt:(CGPoint)pos

{

             float mass = 0.5f;

             float moment =cpMomentForBox(mass, TILESIZE, TILESIZE);

             cpBody* body =cpBodyNew(mass, moment);

            

             body->p = pos;

             cpSpaceAddBody(space,body);

            

             float halfTileSize= TILESIZE * 0.5f;

             int numVertices =4;

             CGPoint vertices[]=

             {

              CGPointMake(-halfTileSize,-halfTileSize),

              CGPointMake(-halfTileSize,halfTileSize),

              CGPointMake(halfTileSize,halfTileSize),

              CGPointMake(halfTileSize,-halfTileSize),

             };

 

             CGPoint offset =CGPointZero;

             float elasticity =0.3f;

             float friction =0.7f;

            

             cpShape* shape =cpPolyShapeNew(body, numVertices, vertices, offset);

             shape->e =elasticity;

             shape->u =friction;

             shape->data =[self addRandomSpriteAt:pos];

             cpSpaceAddShape(space,shape);

}

 

 

 

在我们的例 子里,盒子的尺寸就是瓷砖的尺寸,也就是32x32像素大小。然后我们通过cpSpaceAddBody方法来更新刚体的位置信息(p)和把刚体添加到 space中。请注意:和Box2D不同,你不需要在Chipmunk里把像素转换成米;你 可以直接使用像素坐标。

接着,我创建了一系列的顶点(Vertex),这些顶点将会作为定义盒子的四个 角。因为盒子的四个角的位置是相对于盒子的中心点来放置的,所以它们离开 中心点的位置都是瓷砖尺寸的一半大小。否则,盒子将会变成两倍于瓷砖的大 小。我们将生成的刚体,顶点数组,顶点数组的顶点数量和一个可选的偏移值 (offset)(在我们的例子里设成了CGPointZero),传给cpPolyShapeNew方法。 得到的结果是盒子形状(shape)的cpShape指针。获取的形状指针拥有和Box2D 例子中的盒子类似的弹性和摩擦力属性。然后,精灵被赋值给这个指针的data 属性,接着我们通过cpSpaceAddShape方法把shape指针添加到space中。

7.9.4更新盒子的精灵

 

和Box2D一样,你必须每一帧都更新精灵的位置和旋转信息来使它和动态刚体的 位置和旋转同步。这需要在update方法中进行实现:

 

-(void) update:(ccTime)delta

{

floattimeStep = 0.03f;

cpSpaceStep(space,timeStep);

//call forEachShape C method to update sprite positions

cpSpaceHashEach(space->activeShapes,&forEachShape, nil);

cpSpaceHashEach(space->staticShapes,&forEachShape, nil);

}

 

和Box2D一样,你必须使用step方法推进物理模拟。在Chipmunk中,我们需要使用cpSpaceStep方法,此方法以space和timeStep作为参数。我们使用的timeStep是固定的数值,因为如果使用delta时间的话会使物理模拟变得不稳定

7.9.5 Chipmunk的碰撞测试

       Chipmunk的碰撞测试也是由C写的回调方法来处理的。我们的项目中,添加 cotactBegin和contactEnd这两个静态方法,它们的功能和Box2D中的一样:在碰撞后会把发生碰撞的盒子颜色变成洋红色。

      

 

 

 

 

 

 

// C callback methods for collisionhandling

static int contactBegin(cpArbiter*arbiter, struct cpSpace* space, void* data)

{

     boolprocessCollision = YES;

    

     cpShape*shapeA;

     cpShape*shapeB;

     cpArbiterGetShapes(arbiter,&shapeA, &shapeB);

    

     CCSprite*spriteA = (CCSprite*)shapeA->data;

     CCSprite*spriteB = (CCSprite*)shapeB->data;

     if(spriteA != nil && spriteB != nil)

     {

      spriteA.color= ccMAGENTA;

      spriteB.color= ccMAGENTA;

     }

    

     returnprocessCollision;

}

 

static void contactEnd(cpArbiter*arbiter, cpSpace* space, void* data)

{

     cpShape*shapeA;

     cpShape*shapeB;

     cpArbiterGetShapes(arbiter,&shapeA, &shapeB);

    

     CCSprite*spriteA = (CCSprite*)shapeA->data;

     CCSprite*spriteB = (CCSprite*)shapeB->data;

     if(spriteA != nil && spriteB != nil)

     {

      spriteA.color= ccWHITE;

      spriteB.color= ccWHITE;

     }

}

 

如果测得碰撞并且方法正常运[Microsoft7] 行的话,contactBegin会返回YES。如果返回的是NO 或者0,你可以忽略碰撞。为了得到精灵,首先你必须从cpArbiter得到 shape。CpArbiter就像b2Contact一样,包含着碰撞各方的信息。通过cpArbiterGetShapes方法,把两个shape传给它作为赋值只用,你会得到发生碰撞的两个刚体shapeA和shapeB。然后,你可以通过shapeA和shapeB获取它们各自的CCSprite指针。如果两个精灵指针都有效的话,它们的颜色将会发生变化。和Box2D一样,这些回调方法不会被自动调用。在HelloWorldScene的init方法中,在space生成以后,你必须使用 cpSpaceAddCollisionHandler方法把上述 两个回调方法添加进space里

unsigned int defaultCollisionType =0;

cpSpaceAddCollisionHandler(space,defaultCollisionType, defaultCollisionType,
&contactBegin, NULL, NULL,

&contactEnd, NULL);

 

7.9.6 Chipmunk中的关节

Chipmunk[Microsoft8] 实现起来比Box2D复杂,如果你会任何大多数设置静态和动态刚体的代码。你可以直接跳到最后关于生成关节的代码。我们在这而只贴出生成关节的代码

 

cpConstraint* constraint1 =cpPivotJointNew(staticBody, bodyA, staticBody->p);

cpConstraint*constraint2 = cpPivotJointNew(bodyA, bodyB, bodyA->p);

cpConstraint*constraint3 = cpPivotJointNew(bodyB, bodyC, bodyB->p);

cpSpaceAddConstraint(space,constraint1);

cpSpaceAddConstraint(space,constraint2);

cpSpaceAddConstraint(space,constraint3);

 

 

 

    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 


 [Microsoft1]代码前的行号别丢掉

 [Microsoft2]框太宽了

 [Microsoft3]插入代码框

 [Microsoft4]正常字体大小按示例格式修改

 [Microsoft5]空行太大

 [Microsoft6]边框大小为1~35 行号

 [Microsoft7]缩进呢

 [Microsoft8]段起缩进

 [Microsoft9]14 号字体

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 解决系统丢包问题

    当系统经常出现丢包问题时(ifconfig可以看到),修改rx_ring可以解决这个问题。sudo /sbin/ethtool -g eth0 | /bin/grep "RX:" | /bin/sed "1q"|/bin/cut -f 3 |xargs /sbin/ethtool -G eth0 rx[huanglqhadoop99 ~]$ sud…...

    2024/3/13 18:55:24
  2. 做完双眼皮眼牵强感

    ...

    2024/3/13 18:55:23
  3. 双眼皮术后眼睛痛抬眼无力

    ...

    2024/3/15 5:39:22
  4. :angularjs学习总结(~~很详细的教程) 很不错的一篇帖子 适合快速了解angularjs整体结构 有个整体印象

    1 前言 前端技术的发展是如此之快,各种优秀技术、优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢。 AngularJS是google在维护,其在国外已经十分火热,可是国内的使用情况却有不小的差距&am…...

    2024/3/29 6:55:42
  5. 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(3)

    chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目。 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对…...

    2024/3/20 2:57:49
  6. angularjs学习总结

    1 前言 前端技术的发展是如此之快,各种优秀技术、优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢。 AngularJS是google在维护,其在国外已经十分火热,可是国内的使用情况却有不小的差距&am…...

    2024/3/26 21:05:03
  7. 扬州雷岳崇双眼皮案例

    ...

    2024/3/15 14:56:41
  8. 《angularjs权威教程》记录

    说明:《angularjs权威教程》出版较早,于2014年出版,主要介绍angualrjs1的内容 优化启发:(1)尽可能的精简控制器,在控制器中进行DOM操作或者数据数据操作是不好的实践 《第2章》控制器&#xf…...

    2024/3/25 6:25:04
  9. angularjs学习总结(~~很详细的教程)

    根据公司需要研究了一段时间的 angular js .总结的详细教程分享给大家. 1 前言 前端技术的发展是如此之快,各种优秀技术、优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢。 AngularJS是google在维护,…...

    2024/3/15 14:56:37
  10. 双眼皮眼神呆滞没神

    ...

    2024/3/15 14:56:37
  11. Flink从1.7到1.12版本升级汇总

    点击上方蓝色字体,选择“设为星标”回复”面试“获取更多惊喜一 .前言最进再看官方flink提供的视频教程,发现入门版本因为时间关系都是基于1.7.x讲解的. 在实际操作中跟1.12.x版本还是有差距的, 所以整理一下从1.7 版本到1.12版本之间的相对大的变动. 做到在学习的过…...

    2024/3/15 14:56:36
  12. AngularJS的基本知识详解

    1、 AngularJS是什么? AngularJs(后面就简称ng了)是一个用于设计动态web应用的结构框架。 首先,它是一个框架,不是类库,是像EXT一样提供一整套方案用于设计web应用。它不仅仅是一个JavaScript框架&#xff…...

    2024/3/15 14:56:34
  13. 双眼皮形状怎么选择

    ...

    2024/3/28 16:55:21
  14. AngularJS notes -- from 《AngularJS权威教程》(1)

    1. 当AngularJS认为某个值可能发生变化时,它会运行自己的事件循环来检查这个值是否变“脏”。 调用$digest(). 2. 只要遇到 $ 符号,你都可以只把它看作一个Angular对象。 3. ng-app范围内属于angularJS应用。 4. ng-controller范围内属于某个控制器。 5.…...

    2024/3/15 14:56:35
  15. 双眼皮第七天了还会变窄吗

    ...

    2024/3/15 14:56:32
  16. 内双眼皮内眼角圆

    ...

    2024/3/13 18:55:36
  17. 双眼皮微调需要开刀吗

    ...

    2024/3/13 18:55:37
  18. 刚割的双眼皮不对称

    ...

    2024/3/15 20:45:25
  19. 细长眼割什么样一大一小双眼皮调整

    ...

    2024/3/13 18:55:34
  20. 做双眼皮抽脂的危害

    ...

    2024/3/17 22:53:22

最新文章

  1. 1.Mysql基础入门—MySQL-mysql 8.0.11安装教程

    1.Mysql基础入门—MySQL-mysql 8.0.11安装教程 摘要个人简介下载Mysql安装Mysql配置环境变量 摘要 MySQL 8.0.11的安装过程涉及几个关键步骤,首先访问MySQL官方网站下载页面,选择操作系统相对应的MySQL版本进行下载。对于Windows用户,启动下…...

    2024/3/29 17:06:59
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 亚远景科技-ASPICE如何适配汽车电子电气产品特征与行业发展

    随着当今汽车工业的蜕变,我们正迎来一个被誉为“软件定义汽车”的新时代。在这个时代,软件不仅是汽车的灵魂,更是其主导力量,它通过无形的代码赋予汽车各种突破性的特性与功能。昔日以硬件为重心的汽车行业,如今正在加…...

    2024/3/29 3:59:44
  4. POJO简介

    文章目录 简介POJO与ELB的区别POJO真正的意思 常见的POJO类DTODAOPOVOEntity 简介 什么是POJO?POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB(EJB是Enterprise Java Beans技…...

    2024/3/28 23:44:05
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/3/27 10:21:24
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/3/24 20:11:25
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/3/29 2:45:46
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/3/29 16:26:39
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/3/29 5:19:52
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/3/28 17:01:12
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/3/29 11:11:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/3/29 1:13:26
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/3/29 8:28:16
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/3/29 7:41:19
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/3/24 20:11:18
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/3/29 9:57:23
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/3/29 0:49:46
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/3/24 20:11:15
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/3/27 7:12:50
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/3/24 20:11:13
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/3/26 11:21:23
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/3/28 18:26:34
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/3/28 12:42:28
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/3/28 20:09:10
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57