热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

19、Cocos2dx3.0游戏开发找小三之Action:流动的水没有形状,漂流的风找不到踪迹、、、

重开发者的劳动成果,转载的时候请务必注明出处:http:blog.csdn.nethaomengzhuarticledetails30478985
重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/30478985

流动的水没有形状,漂流的风找不到踪迹、、、
直睡的陵迁谷变,石烂松枯,斗转星移,整个宇宙在不停的运动着、、、

前面详细介绍了游戏的基本组成元素--场景、 层、 精灵和渲染树等, 也详细介绍了 Node 提供的定时器。
为了让整个世界运动起来,让每一个精灵运动,可以利用定时器,不断修改节点的属性,实现简单的动态效果。
然而,这种方法会导致为了实现简单的动态效果,十分烦 琐地维护一批定时器。
Cocos2d-x 为了解决这个问题,引入了动作机制。

Action是动作类的基类
所有的动作都派生自这个类,它创建的一个对象代表了一个动作。
动作作用于Node,因此, 任何一个动作都需要由 Node 对象来执行。

以下代码实现了一个精灵用 10秒钟的时间移动到了点(100, 100):
auto sprite = Sprite::create("sprite.png");
auto action = MoveTo::create(1.0f, Point(0, 0));
sprite->runAction(action);

需要注意的是,一个 Action 只能使用一次,
这是因为动作对象不仅描述了动作,还保存了这个动作持续过程中不断改变 的一些中间参数。
对于需要反复使用的动作对象,可以通过 copy 方法复制使用。

Action 作为一个基类,其实质是一个接口(即抽象类),
由它派生的实现类(如运动和转动等)才是我们实际使用的动 作。

Action 的绝大多数实现类都派生自 FiniteTimeAction,这个类定义了在有限时间内可以完成的动作。
FiniteTimeAction定义了 reverse 方法,通过这个方法可以获得一个与原动作相反的动作(称作逆动作),例如隐藏一 个精灵后,用逆转动作再显示出来。
当然,并非所有的动作都有对应的逆动作,
例如类似"放大到"等设置属性为常量的动 作不存在逆动作,而设置属性为相对值的动作则往往存在相应的逆动作。

由 FiniteTimeAction 派生出的两个主要类分别是瞬时动作(ActionInstant)和持续性动作(ActionInterval),
这两类动作与复合动作配合使用,能得到复杂生动的动作效果。

瞬时动作
瞬时动作是指能立刻完成的动作,是 FiniteTimeAction 中动作持续时间为 0 的特例。
更准确地说,这类动作是在下一帧会立刻执行并完成的动作,如设定位置、设定缩放等。
这些动作原本可以通过简单地对 Node 赋值完成,但是把它们包装 
为动作后,可以方便地与其他动作类组合为复杂动作。

一些常用的瞬时动作:
Place
该动作用于将节点放置到某个指定位置,其作用与修改节点的 Position 属性相同。
例如,将精灵放置到屏幕坐标(100, 100) 处,再执行曲线运动 curveMove 的代码如下: 
FiniteTimeAction* placeAction = Place::create(Point(100, 100));
Action* action = Sequence::create(placeAction, curveMove, NULL);
其中 Sequence 又称为动作序列,是一种复合动作,它在初始化时,会接受多个动作,当它被执行时,这些动作会按顺序 逐个执行,形成有序的一列动作。

FlipX 和 和 FlipY
这两个动作分别用于将精灵沿 X 和 Y 轴反向显示,其作用与设置精灵的 FlipX 和 FlipY 属性相同。
将其包装为动作类也是 为了便于与其他动作进行组合。
例如,我们想使精灵从屏幕的一端游动到另一端,然后按原路返回。
为了更自然一点 我们设置一个序列,精灵先执行移动的动作,在精灵到达另一端时反向显示,然后再执行移动回起点的动  作,相关代码如下:
FiniteTimeAction* flipXAction = FlipX::create(true);
Action* action = Sequence::create(curveMove, flipXAction, curveMove->reverse(), NULL);
其中 reverse 的作用是取得原动作的逆动作。在这个例子中,精灵沿 X 轴翻转后将会沿原路返回起点。

Show 和 和 Hide
这两个动作分别用于显示和隐藏节点,其作用与设置节点的 Visible 属性的作用一样。
例如,为了使精灵完成运动之后隐藏 起来,我们使用如下代码: 
FiniteTimeAction* hideAction = Hide::create();
Action* action = Sequence::create(curveMove, hideAction, NULL);

CallFunc
CallFunc 系列动作包括 CallFunc、CallFuncN、__CCCallFuncND,以及 __CCCallFuncO四个动作,
用来在动作中进行 方法的调用(之所以不是函数调用,是因为它们只能调用某个类中的实例方法,而不能调用普通的 C 函数)。
当某个对象 执行 CallFunc 系列动作时,就会调用一个先前被设置好的方法,以完成某些特别的功能。 

在CallFunc 系列动作的 4 个类中:
CallFunc 调用的方法不包含参数,
CallFuncN 调用的方法包含一个 Node*类型 的参数, 表示执行动作的对象。 
__CCCallFuncND 调用的方法包含两个参数, 不仅有一个节点参数, 还有一个自定义参数 (Node* 与 void*)。__CCCallFuncO调用的方法则只包含一个 Ref*类型的参数。
实际上,CallFunc 系列动作的后缀"N"表示 Node 参数,指的是执行动作的对象,
"D"表示 Data 参数,指的是用户自定义 的数据,"O"表示对象,指的是一个用户自定义的 Ref参数。

在不同的情况下,我们可以根据不同的需求来选择不同的 CallFunc 动作。
考虑一种情况,我们创建了许多会在屏幕中移动的精灵,希望精灵在移动结束之后就从游戏中删除。 
为了实现这个效果,我们可以创建一系列动作:首先让精灵移动,然后调用一个 removeSelf(Node* nodeToRemove)方法 来删除 nodeToRemove 对象。在 removeSelf 方法中需要访问执行此动作的精灵,因此我们就采用 CallFuncN 来调用 removeSelf 方法。

持续性动作
持续性动作是在持续的一段时间里逐渐完成的动作,如精灵从一个点连续地移动到另一个点。
与瞬时动作相比,持续性动 作的种类更丰富。
由于这些动作将持续一段时间,所以大多数的持续性动作都会带有一个用于控制动作执行时间的实型参 数duration。
每一种持续性动作通常都存在两个不同的变种动作,分别具有 To 和 By 后缀:
后缀为 To 的动作描述了节点属性值的绝对变 化,例如 MoveTo 将对象移动到一个特定的位置;
而后缀为 By 的动作则描述了属性值相对的变化,如 MoveBy 将对象移 动一段相对位移。

根据作用效果不同,可以将持续性动作划分为以下 4 大类:
位置变化动作
属性变化动作
视觉特效动作
控制动作

位置变化动作
针对位置(position)这一属性,引擎为我们提供了 3 种位置变化动作类型。
MoveTo 和 MoveBy:用于使节点做直线运动。设置了动作时间和终点位置后,节点就会在规定时间内,从当前位置直线 移动到设置的终点位置。它们的初始化方法分别为:
static MoveTo* create(float duration, const Point& position);
static MoveBy* create(float duration, const Point& deltaPosition);
其中,duration 参数表示动作持续的时间,position 参数表示移动的终点或距离。
对于 MoveTo,节点会被移动到 position对应的 位置;
对于 MoveBy,节点会相对之前的位置移动 position的距离。 

JumpTo 和 JumpBy:使节点以一定的轨迹跳跃到指定位置。它们的初始化方法如下:
static JumpTo* create(float duration, const Point& position, float height, int jumps);
static JumpBy* create(float duration, const Point& position, float height, int jumps);
其中 position 表示跳跃的终点或距离,height 表示最大高度,jumps 表示跳跃次数。

BezierTo 和 BezierBy: 使节点进行曲线运动, 运动的轨迹由贝塞尔曲线描述。 
static BezierTo* create(float t, const ccBezierConfig& c);
static BezierBy* create(float t, const ccBezierConfig& c);
贝塞尔曲线是描述任意曲线的有力工具,
在许多软件(如 Adobe Photoshop)中,钢笔工具就是贝塞尔曲线的应用。

每一条贝塞尔曲线都包含一个起点和一个终点。
在一条曲线中,起点和终点都各自包含一个控制点,而控制点到端点的连 线称作控制线。
控制线决定了从端点发出的曲线的形状,包含角度和长度两个参数:角度决定了它所控制的曲线的方向,
即这段曲线在这一控制点的切线方向;长度控制曲线的曲率。控制线越长,它所控制的曲线离控制线越近。

使用时我们要先创建 ccBezierConfig 结构体, 设置好终点 endPosition 以及两个控制点controlPoint_1 和controlPoint_2 后,再把结构体传入 BezierTo 或 BezierBy 的初始化方法中:
ccBezierConfig bezier;
bezier.controlPoint_1 = Point(20, 150);
bezier.controlPoint_2 = Point(200, 30);
bezier.endPosition = Point(160, 30);
FiniteTimeAction * beizerAction = BezierTo::create(actualDuration / 4, bezier);


属性变化动作
属性变化动作的特点是通过属性值的逐渐变化来实现动画效果。 
例如, 下面要介绍的第一个动作 ScaleTo, 它会在一段时间内不断地改变游戏元素的 scale 属性,
使属性值平滑地变化到一个新值,从而使游戏元素产生缩放的动画 效果。 

ScaleTo 和 ScaleBy:产生缩放效果,使节点的缩放系数随时间线性变化。对应的初始化方法为:
static ScaleTo* create(float duration, float s);
static ScaleBy* create(float duration, float s);
其中,s 为缩放系数的最终值或变化量。

RotateTo 和 RotateBy:产生旋转效果。对应的初始化方法为:
static RotateTo* create(float duration, float deltaAngle);
static RotateBy* create(float duration, float deltaAngle);
其中 deltaAngle的单位是角度,正方向为顺时针方向。

FadeIn 和 FadeOut:产生淡入淡出效果,其中前者实现了淡入效果,后者实现了淡出效果。对应的初始化方法为:
static FadeIn* create(float d);
static FadeOut* create(float d);

以下介绍的几个类似的动作。
FadeTo:用于设置一段时间内透明度的变化效果。其初始化方法为:
static FadeTo* create(float duration, GLubyte opacity);
参数中的 Glubyte 是 8 位无符号整数,因此,opacity 可取 0 至 255 中的任意整数。
与透明度相关的动作只能应用在精灵 (Sprite)上,且子节点不会受到父节点的影响。

TintTo 和 TintBy:设置色调变化。这个动作较为少用,其初始化方法为:
static TintTo* create(float duration, GLubyte red, GLubyte green, GLubyte blue);
static TintBy* create(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue);
与 FadeTo 类似,redgreen 和 blue的取值范围也为 0~255。

视觉特效动作
用于实现一些特殊的视觉效果
Blink:使目标节点闪烁。其初始化方法为:
static Blink* create(float duration, int blinks);
其中,blinks是闪烁次数。

Animation:播放帧动画,用帧动画的形式实现动画效果。

控制动作
控制动作是一类特殊的动作,用于对一些列动作进行精细控制。
利用这一类动作可以实现一些实用的功能,因此它们是十 分常用的。 
这类动作包括 DelayTime、 Repeat 和RepeatForever 等。
DelayTime可以将动作延时一定的时间, 
Repeat 可以把现有的动作重复一定次数,
RepeateForever 可以使一个动作不断重复下去。
事实上,控制动作与复合动作息息相关。

复合动作
简单动作显然不足以满足游戏开发的要求, 在这些动作的基础上, 
Cocos2d-x 为我们提供了一套动作的复合机制, 允许我们组合各种基本动作,产生更为复杂和生动的动作效果。
复合动作是一类特殊的动作,因此它也需要使用 Node 的 runAction 方法执行。
而它的特殊之处在于,作为动作容器,复合动作可以把许多动作组合成一个复杂的动作。
因此,我们 通常会使用一个或多个动作来创建复合动作,再把动作交给节点执行。
复合动作十分灵活,这是由于复合动作本身也是动作,因此也可以作为一个普通的动作嵌套在其他复合动作中。

重复( Repeat/RepeatForever )
有的情况下,动作只需要执行一次即可,但我们还常常遇到一个动作反复执行的情况。
对于一些重复的动作 我们可以通过 Repeat 与 RepeatForever 这两个方式重复执行: 
static Repeat* create(FiniteTimeAction *action, unsigned int times);
static RepeatForever* create(ActionInterval *action);
其中,action参数表示需要重复的动作,第一个方法允许指定动作的重复次数,第二个方法使节点一直重复该动
作直到动作被停止。

并列( Spawn )
指的是使一批动作同时执行。Spawn 从 ActionInterval 派生而来的,它提供了两个工厂方法:
static Spawn* create(FiniteTimeAction *action1, ...) CC_REQUIRES_NULL_TERMINATION;
static Spawn* createWithTwoActions(FiniteTimeAction *action1, FiniteTimeAction *action2);
其中第一个静态方法可以将多个动作同时并列执行,参数表中最后一个动作后需要紧跟 NULL 表示结束。第二个则只能指定 两个动作复合, 不需要在最后一个动作后紧跟 NULL。 
此外, 执行的动作必须是能够同时执行的、 继承自 FiniteTimeAction 的动作。
组合后,Spawn 动作的最终完成时间由其成员中最大执行时间的动作来决定。

序列( Sequence )
除了让动作同时并列执行,我们更常遇到的情况是顺序执行一系列动作。
Sequence 提供了一个动作队列,它会顺序执行 一系列动作。
Sequence 同样派生自 ActionInterval。
与 Spawn 一样,Squence 也提供了两个工厂方法:
static Sequence* create(FiniteTimeAction *action1, ...) CC_REQUIRES_NULL_TERMINATION;
static Sequence* createWithTwoActions(FiniteTimeAction *actionOne, FiniteTimeAction *actionTwo);
它们的作用分别是建立多个和两个动作的顺序执行的动作序列。
同样要注意复合动作的使用条件,部分的非延时动作(如 RepeatForever)并不被支持。

在实现 Sequence 和 Spawn 两个组合动作类时,有一个非常有趣的细节:
成员变量中并没有定义一个可变长的容器来容 纳每一个动作系列, 而是定义了m_pOne和m_pTwo两个动作成员变量。 如果我们创建了两个动作的组合, 
那么m_pOne与m_pTwo 就分别是这两个动作本身;
当我们创建更多动作的组合时,引擎会把动作分解为两部分来看待,
其中后一部分只包含最后 一个动作,而前一部分包含它之前的所有动作,

引擎把 m_pTwo 设置为后一部分的动作,把 m_pOne 设置为其余所有动作的 组合。
例如,
语句
 sequence = Sequence::create(action1, action2, action3, action4, NULL);
就等价于:
Sequence s1 = Sequence::createWithTwoActions(action1, action2);
Sequence s2 = Sequence::createWithTwoActions(s1, action3);
sequence = Sequence::createWithTwoActions(s2, action4);

Spawn 与 Sequence 所采用的机制类似,在此就不再赘述了。

采用这种递归的方式,而不是直接使用容器来定义组合动 作,实际上为编程带来了极大的便利。
维护多个动作的组合是一个复杂的问题,现在我们只需要考虑两个动作组合的情况 就可以了。

下面是 Spawn 的一个初始化方法,就是利用 递归的思想 简化了编程的复杂度:
Spawn* Spawn::create(const Vector& arrayOfActions)
{
    Spawn* ret = nullptr;
    do 
    {
        auto count = arrayOfActions.size();
        CC_BREAK_IF(count == 0);
        auto prev = arrayOfActions.at(0);
        if (count > 1)
        {
            for (int i = 1; i (prev);
    }while (0);

    return ret;
}

众所周知,递归往往会牺牲一些效率,但能换来代码的简洁。

在这两个复合动作中,细节处理得十分优雅,
所有的操作都 只需要针对两个动作实施,多个动作的组合会被自动变换为递归
void Spawn::update(float time)
{
    if (_one)
    {
        _one->update(time);
    }
    if (_two)
    {
        _two->update(time);
    }
}

Spawn* Spawn::reverse() const
{
    return Spawn::createWithTwoActions(_one->reverse(), _two->reverse());
}

延时( DelayTime )
DelayTime 是一个"什么都不做"的动作,类似于音乐中的休止符,
用来表示动作序列里一段空白期,通过占位的方式将不 同的动作段串接在一起。
实际上,这与一个定时期实现的延迟没有区别,
但相比之下,使用 DelayTime 动作来延时就可 以方便地利用动作序列把一套动作连接在一起。
DelayTime 只提供了一个工程方法,如下所示:
static DelayTime* create(float d);
其中仅包含一个实型参数d,表示动作占用的时间。

变速动作
大部分动作的变化过程是与时间成线性关系的,即一个动作经过相同时间产生的变化相同,
例如,MoveBy 会使节点在同 样长的时间内经过同样的位移。
这是因为 Cocos2d-x 把动作的速度变化控制抽离了出来,形成一个独立的机制。
普通动作配合  变速动作,可以构造出很有趣的动作效果。
与复合动作类似,变速动作也是一种特殊的动作,它可以把任何一种动作按照改变后的速度执行。
因此,在初始化变速动 作时,需要传入一个动作。

变速动作包括 Speed 动作与 Ease 系列动作,下面来详细介绍这些动作。
Speed
Speed 用于线性地改变某个动作的速度,因此,可以实现成倍地快放或慢放功能。
static Speed* create(ActionInterval* action, float speed);
为了改变一个动作的速度,首先需要将
目标动作包装到 Speed 动作中:
RepeatForever* repeat = RepeatForever::create(animation);
Speed* speed = Speed::create(repeat, 1.0f);
speed->setTag(action_speed_tag);
sprite->runAction(speed);
在上面的代码中, 我们创建了一个 animation 动作的 CCRepeatForever 复合动作 repeat, 使动画被不断地重复执行。 然后, 我们又使用 repeat 动作创建了一个 CCSpeed 变速动作。
create 初始化方法中的两个参数分别为目标动作与变速比率。
设置 变速比率为 1,目标动作的速度将不会改变。
最后,我们为 speed 动作设置了一个 tag 属性,并把动作交给精灵,让 精灵执行变速动作。
此处设置的 tag 属性与 Node 的 tag 属性类似,用于从节点中方便地查找动作。
接下来,在需要改变速度的地方,我们通过修改变速动作的 speed 属性来改变动作速度。
下面的代码将会把上面设置的动 画速度变为原来的两倍:
Speed * speed = sprite->getActionByTag(action_speed_tag);
speed->setSpeed(2.0f);

ActionEase
虽然使用 Speed 能够改变动作的速度,然而它只能按比例改变目标动作的速度。
如果我们要实现动作由快到慢、速度随 时间改变的变速运动, 
需要不停地修改它的speed属性才能实现, 显然这是一个很烦琐的方法。 
下面将要介绍的ActionEase 系列动作通过使用内置的多种自动速度变化来解决这一问题。 
ActionEase 系列包含 15 个动作,
它们可以被概括为 5 类动作:指数缓冲、Sine 缓冲、弹性缓冲、跳跃缓冲和回震缓冲。
每一类动作都有 3 个不同时期的变换:In、Out 和 InOut。

下面使用时间变换图像表示每组 ActionEase 动作的作用效果,
其中横坐标表示实际动画时间,纵坐标表示变换后的动画时间。
因此,线性动作的图像应该是一条自左下角到右上角的直 线。



ActionEase 的使用方法与 Speed 类似。以 Sine 缓冲为例,以下代码实现了 InSine 变速运动:
EaseSineIn* sineIn = EaseSineIn::create(action);
sineIn->setTag(action_sine_in_tag);
sprite->runAction(sineIn);

创建自定义动作
为了抽象出独立的旋转跟踪动作,根据精灵的移动路径设置合适的旋转角度。 
Action 包含两个重要的方法:step 与 update。
step 方法会在每一帧动作更新时触发,该方法接受一个表示调用时间间 隔的参数 dt,dt 的积累即为动作运行的总时间。
引擎利用积累时间来计算动作运行的进度(一个从 0 到 1 的实数),并调 用 update 方法更新动作。
update 方法是 Action 的核心,它由 step 方法调用,接受一个表示动作进度的参数,
每一个动 作都需要利用进度值改变目标节点的属性或执行其他指令。
自定义动作只需要从这两个方法入手即可,我们通常只需要修 改 update 方法就可以实现简单的动作。

Action的step和update方法定义:
    //! called every frame with it's delta time. DON'T override unless you know what you are doing.
    virtual void step(float dt);

    /** 
    called once per frame. time a value between 0 and 1

    For example: 
    - 0 means that the action just started
    - 0.5 means that the action is in the middle
    - 1 means that the action is over
    */
    virtual void update(float time);

让动作更平滑流畅
如何让动作看起来更加自然并优雅, 实际上,这是一个涉及玩家注意力的问题。
对于新出现的变化效果,玩家需要时间转移注意力适应这个变化,
而后如果效 果持续稳定、变化不明显,则会降低玩家的注意力,使玩家感觉疲惫。
在这种情况下,一个冗长的匀速动作效果就会造成 游戏不自然不优雅。

不妨为动作添加一些变速效果,将玩家有限的注意力集中到我们希望玩家关注的效果上。
进场动作:由快到慢,快速进入后缓慢停下,在停止前给玩家足够的视觉时间分辨清楚进入的图像。
出场动作:先慢后快,展示了出场趋势和方向后快速移出屏幕,不拖泥带水。
这个变速效果就很自然地交给前面提到的 Ease 系列动作实现了。

针对具体的需求,我们选择了 EaseExponential 动作 来实现变速效果。
以暂停游戏时弹出的菜单为例:
点击暂停游戏后,菜单从屏幕顶端向下滑出;
点击恢复游戏后,菜单向上收起。

弹出菜单的代码如下:
Menu* menu = Menu::create(item0, item1, item2, item3, NULL);
menu->alignItemsVerticallyWithPading(5.0f);
menu->setPosition(ccp(size.width/2, size.height));
menu->setTag(menu_pause_tag);
this->addChild(menu, 5);
MoveTo* move = MoveTo::create(0.5f, Point(size.width/2, size.height/2));

Action* action = EaseExponentialOut::create(move);
menu->runAction(action);

收起菜单的代码如下: 
Size size = Director::getInstance()->getWinSize();
Menu* menu = (Menu*)this->getChildByTag(menu_pause_tag);
Point point = Point (size.width/2, size.height + menu->getContentSize().height/2);
MoveTo* move = MoveTo::create(0.5f, point);

Action* action = EaseExponentialIn::create(move);
menu->runAction(action);

郝萌主友情提示:
优雅自然的动作,能加强游戏的表现性,能吸引更多的玩家、、、




推荐阅读
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • 本文详细探讨了 org.apache.hadoop.ha.HAServiceTarget 类中的 checkFencingConfigured 方法,包括其功能、应用场景及代码示例。通过实际代码片段,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 本文详细介绍了优化DB2数据库性能的多种方法,涵盖统计信息更新、缓冲池调整、日志缓冲区配置、应用程序堆大小设置、排序堆参数调整、代理程序管理、锁机制优化、活动应用程序限制、页清除程序配置、I/O服务器数量设定以及编入组提交数调整等方面。通过这些技术手段,可以显著提升数据库的运行效率和响应速度。 ... [详细]
  • Coursera ML 机器学习
    2019独角兽企业重金招聘Python工程师标准线性回归算法计算过程CostFunction梯度下降算法多变量回归![选择特征](https:static.oschina.n ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本文详细介绍了在不同操作系统中查找和设置网卡的方法,涵盖了Windows系统的具体步骤,并提供了关于网卡位置、无线网络设置及常见问题的解答。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 深入理解 .NET 中的中间件
    中间件是插入到应用程序请求处理管道中的组件,用于处理传入的HTTP请求和响应。它在ASP.NET Core中扮演着至关重要的角色,能够灵活地扩展和自定义应用程序的行为。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
author-avatar
热情article文章_673_621
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有