如何实现屏幕之间的转换

昨天晚上,我把我的比赛展示给了我的朋友,他们说这有点跳动。

他给的例子是在小精灵游戏中,当一场战斗开始播放音乐时,屏幕闪烁然后像素出来,然后小宠物从侧面滑动,出现战斗菜单。

在我的游戏中,你正在走路,突然间你正盯着战斗菜单,我确实看到了他的观点。

我正在为我的游戏循环使用一个switch语句,1是一个字段,2是战斗,在战斗中我运行一个if语句,如果战斗激活做战,否则显示结果屏幕/等待用户input。

我想为过渡做一个状态,但是他们需要一个场地 – >战斗,战斗 – >场地,城镇 – >场地,而且这个场地似乎有很多重复的代码,但是我不能想象当我玩像宠物小精灵一样的animation的时候,暂停状态

有了这种types或架构,像我的伴侣那样,屏幕之间的过渡将如何平滑?

C ++和directX

编辑:我遇到的问题是,一旦状态被改变,更新路由的状态不会被调用,所以所有的精灵消失,因为它们是纹理,只有背景保持,所以我不能只是播放animation,然后改变状态,或者它会看起来更糟。

我为iPhone构建了一个2d引擎的通用转换系统。 我将尽力解释它。 这只是一种方法,实现有更多不相关的东西。

假设你的引擎是分层的,如果不是,那么为什么游戏引擎必须是分层的呢?有很多原因。 我们可以有两个从SceneNode类inheritance的IState和ITransition接口。 喜欢这个:

在这里输入图像描述

那么,SceneNode可以更新,这意味着父级调用子方法“更新”和启用,接收或不input事件(所以你可以禁用用户事件时,执行转换)。

每一个国家都有一个名称,每一个转换都存在着转换之间的新旧状态。

好。 现在我们可以有两个管理者,Transition和StateManager,这些管理者的目的是拥有所有Transitions和States的registry并提供function。 这些经理可以是单身人士从任何地方都可以访问。

在这里输入图像描述

使用addTransition,我们将一个自定义转换附加到一对菜单中,顺序非常重要。 当我们调用changeState时,管理器负责testing是否已经添加了一个转换,如果存在则执行它。

有了这个简单的体系结构,我们将编程MainMenu到Battle之间的转换。

当前的场景图是:

在这里输入图像描述

我的转换实现:

TransitionMenuToBattle : public ITransition { public: void enter() { getOldState()->setActive( false ); getRoot()->addChild( this ); addChild( blackSprite ); } void update( float delta ) { // make fade of blackSprite // ... if ( blackSprite->getAlpha() == OPAQUE ) { getRoot()->addChild( getNewState() ); getNewState()->setActive( false ); } if ( blackSprite->getAlpha() == INVISIBLE ) exit(); } void exit() { getRoot()->removeChild( this ); getNewState()->setActive( true ); } }; 

input法完成后,场景图是:

在这里输入图像描述

在update中调用exit方法时:

在这里输入图像描述

退出方法结束时:

在这里输入图像描述

当游戏开始时,我们需要添加转换:

 TransitionFactory::get()->addTransition( "StateMainMenu", "StateBattle", new TransitionMenuToBattle( ) ); 

然后,例如在MainMenu的一个buttoncallback中,我们可以调用TransitionFactory :: get() – > changeMenu(“StateMainMenu”,“StateBattle”); 或者把这个方法包装进去:

 IState::changeMenu( std::string newMenu ) { TransitionFactory::get()->changeMenu( getStateMenu(), newMenu ); } 

您可以按照自己的想法复杂化过渡。 转换可以访问两个状态,它可以做两个重叠元素。 转换可以接收他构造函数中需要的东西。 如果TransitionManager检测到在两个状态之间没有添加的转换可以具有默认行为。

你可以做一个单一的“过渡”状态,你将要把哪个状态作为对象的一些variables来表示。

如果你不愿意从switch语句改变你的架构到使用状态devise模式(这很好,因为你知道你的代码最好),那么这将是非常丑陋的。

假设你正在使用一个相当标准的更新循环的体系结构,也许你可以有一个标志检查是否需要转换,并在下一次更新检查更新循环开始时设置标志,如果它打开,然后进行转换并等待转换完成,然后再closures标志。

快速,肮脏的伪代码将是:

 bool bStateChangeRequested; while( bUpdate ) { if( bStateChangeRequested ) { PlayTransition(); WaitForTransitionToComplete(); } DoStateStuff(); } 

希望有帮助,虽然我会强烈推荐国家devise模式来解决这个问题。 它会使一切变得更清洁和更好组织,所以在将来的迭代中要考虑一下。

在你的switch语句中调用一个转换例程。 对于一个荒谬的过度简化的伪答案:

 void changeState ( int destinationState, int *currentState ) { // check that destination state is valid // check that current state can transition to destination state doTransition ( *currentState, destinationState); *currentState = destinationState } 

[编辑]要使用已经存在的switch语句来调用它,你可以这样做:

 switch (destinationState): { 1: {changeState ( 1, &currentState); break; } // switch from some state to fields 2: {changeState ( 2, &currentState); break; } // switch from some state to battle } 

然后,你仍然需要编写doTransition()来实现这个过渡animation。 doTransition会做你淡入淡出/无论你想要做什么。

我使用SFML库来完成我所有的graphics和窗口以及其他东西,但是一个方法是使用一些variables:

 #include <SFML/Graphics.hpp> bool FaderHappens = false; bool FaderTrue = false; bool gameStarted = false; bool gameStartedSub1 = false; float FaderVar = 0; int main() { while (window.isOpen()) { sf::RenderWindow window(sf::VideoMode(840, 680), "Your Program Name",sf::Style::Default); window.setFramerateLimit(65); sf::RectangleShape Fader(sf::Vector2f(850, 550)); while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(); if (YOUR_EVENT) { FaderHappens = true; FaderTrue = true; } if (FaderTrue == true && FaderHappens == true) { if (gameStartedSub1 == false) { FaderVar = FaderVar + 63.75; } } if (FaderVar == 255 && FaderHappens == true && FaderTrue == true) { if (gameStarted == false && gameStartedSub1 == false) { gameStartedSub1 = true; } FaderTrue = false; } if (FaderTrue == false && FaderHappens == true) { FaderVar = FaderVar - 63.75; } if (FaderVar == 0 && FaderTrue == false && FaderHappens == true) { FaderHappens = false; } Fader.setFillColor(sf::Color(0, 0, 0, FaderVar)); window.draw(Fader); window.display(); } } 

这应该让你对进行渐变animation的逻辑有一个基本的了解。 63.75s可以改变,使animation更慢或更快,但请注意,您input的数字必须是数字255除以任何整数(否则将永远循环)。 如果有些东西混在一起,我感到抱歉,因为我从自己的项目中拿走了这个东西,并试图不显示不相关的代码。 我相信它是清除任何错误,虽然。