热门标签 | 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);

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




推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 本文总结了Java中日期格式化的常用方法,并给出了示例代码。通过使用SimpleDateFormat类和jstl fmt标签库,可以实现日期的格式化和显示。在页面中添加相应的标签库引用后,可以使用不同的日期格式化样式来显示当前年份和月份。该文提供了详细的代码示例和说明。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
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社区 版权所有