I'm currently programming a game using cocos2dx engine and I have a level manager that keeps track of the current level and the scene that needs to be loaded. I want to avoid long if statements, such as this:
Scene* scene;
if (level == 1)
{
scene = Game_Scene1::createScene();
}
else if (level == 2)
{
scene = Game_Scene2::createScene();
}
else if (level == 3)
{
scene = Game_Scene3::createScene();
}
(...)
else if (level == 10)
{
scene = Game_Scene10::createScene();
}
Director::getInstance()->replaceScene(TransitionFade::create(0.5, scene, Color3B(0,0,0)));
The screateScene() method is a static method
static cocos2d::Scene* createScene();
What could I do to "remove" the if statement? So it would look something like this:
Scene* scene = getScene(level, sceneClass::createScene());
and it would take the correct class (that is: Game_Scene1, Game_Scene2 etc.)
Is there a nice solution for such problem? The title says template but I'm not really sure if the solution for this is a template.
One simple solution would be to used a table of pointer functions.
You could declare your table as
typedef cocos2d::Scene *(*PtfCreateScene)();
PtfCreateScene tab[10];
tab[0] = Game_Scene1::create_scene;
tab[1] = Game_Scene2::create_scene; ...
Using this solution you can then call the associated create_scene function using level as an index. Thus avoiding the if branchings .
scene = tab[level - 1]();
You will have to check the correctness of the index to avoid out of memory access.
Hope I answered your question. Don't hesitate to ask if you need more explanation.
Related
I tried this code to get the first visible row in a scrolling Table inside a BorderLayout.CENTER, but it didn't work, seems the points returned do not reflect the visible cells, unless I am missing a sort of calculation,
thank you for your insights,
#Override
protected void onScrollY(int scrollY) {
super.onScrollY(scrollY); //To change body of generated methods, choose Tools | Templates.
Component c=getComponentAt(50, scrollY);
if (c instanceof Table){
System.err.println("table "+getWidth()+" "+getHeight()+" s "+scrollY);
return;
}
Button b=(Button) c;
System.err.println("c: "+b.getText());
}
getComponentAt(x,y) takes absolute (screen) coordinates. The scrollY value is a relative coordinate in that container.
So what you want is something like:
Component c = getComponentAt(getAbsoluteX()+50, getAbsoluteY() + scrollY)
Also worth nothing that getComponentAt(x,y) will only return components that are focusable or have been set to grab pointer events. If you just want to find the first paintable immediate child of this container, and you're using a BoxLayout.Y_AXIS layout, then you might be better to just iterate through the children until you find one where y is at least the scrollY.
e.g.
Component c = null;
for (Component child : this) {
if (child.getY() + child.getHeight() > scrollY) {
c = child;
break;
}
}
....
I am trying to make my basic loading screen transition over to game level screen. So what i wanted to do is, once the loading screen is active (or has appeared onscreen), I want at this point to start loading my game state. What it is doing at the moment is loading everything at the start, and this does take a while.
So currently my project starts off with a main menu. Then when i press enter, its starts the loading screen. I have my manual state change using keypresses like so:
void Game::update()
{
static bool enterPreviouslyPressed = false;
static bool escapePreviousPressed = false;
const Uint8 *keys = SDL_GetKeyboardState(NULL);
if (keys[::SDL_SCANCODE_ESCAPE] && !escapePreviousPressed && typeid(*fsm->getState()) == typeid(GameState))
{
fsm->setState(menuState);
}
else if (keys[::SDL_SCANCODE_RETURN] && !enterPreviouslyPressed && typeid(*fsm->getState()) == typeid(MainMenuState))
{
fsm->setState(loadingState);
}
else if ((keys[::SDL_SCANCODE_RETURN] && !enterPreviouslyPressed) && typeid(*fsm->getState()) == typeid(LoadScreenState))
{
fsm->setState(gameState);
}
else if (keys[::SDL_SCANCODE_ESCAPE] && !escapePreviousPressed && typeid(*fsm->getState()) == typeid(MainMenuState))
{
exit(0);
}
enterPreviouslyPressed = keys[::SDL_SCANCODE_RETURN] != 0;
escapePreviousPressed = keys[::SDL_SCANCODE_ESCAPE] != 0;
fsm->update();
}
I did this to initially does this so i could change states manually to check that everything works. I was wondering if there was an easy(ish) way, like boolean flags for example or another simpler way to do this. I wasn't able find any tutorials online so wondering if someone knows the best solution as to how to do this. I did see a question on here, kindda similar but I wasn't sure if it answered my question as the person did this in threads which I am not familiar with how to implement. Apologies if I dont seem to have the logic correct - so please advise otherwise.
Looks fairly standard, except I would simplify it by keeping two keyboard state variables declared as class variables, like:
const Uint8 *curKeys = SDL_GetKeyboardState(NULL), *prevKeys;
// ...
void Game::update() {
prevKeys = curKeys;
curKeys = = SDL_GetKeyboardState(NULL);
//and so then compare curKeys to prevkeys
//and ditch the booleans
// ...
}
I'm making a thread software with VTK, where I need to change the model itself in real time, while I need to change his method of rendering. Everything is working fine, but, the problem start with the interactor->start(); , the model data gets updated just fine, but it's only showed on screen when I move The camera. Also I have selected some methods for generating a 3D data from a imagedata file, for that I need to close the vtk window (interactor window) and then the code will reopen it and send the new data generated to it...
I would need something like these:
int force close_window = false; int refresh_interactor = false;
I managed to make the Window close, but only with vtkcommand::Keypressed command, but idk how do I do with a new command :S, I tried the vtkcommand::UserEvent but I didn't found a good information about how to deal with that data (like some way to call it)
the way I'm dealing with VTK is with two threads, the first one, is just about the vtk iren loop, and the second one would manage the models and check if iren requires to be updated.
In my dream code it should be something like this:
=======================================================
bool VTKWindow()
{
...
vtkSmartPointer ator = vtkSmartPointer::New();
iren = vtkSmartPointer::New();
RenWindow = vtkSmartPointer::New();
render->SetBackground(.1, .2, .3);
RenWindow->AddRenderer(renderer);
iren->SetRenderWindow(RenWindow);
if(data_type == voxel_type)
{
Render->AddViewProp(VoxelData);
}
else
{
actor->SetMapper(PolyData);
Render->AddActor(Actor);
}
RenWindow->Render();
iren->Start();
}
void ManageVTK()
{
while true loop...
if(force close_window == true)
do some command to exit the iren loop
if(refresh_interactor == true)
do some command to refresh iren
}
Sorry for the english, it's not my native language, and also sorry about the question format, it's the first time I'm using stackoverflow
It may sounds stupid, but, I found a kind of solution for the problem.
I saw on related links this guy vtkRenderWindowInteractor event loop and threading and, it's almost the same problem...
class VTKNewEvent : public vtkCommand{
public:
vtkTypeMacro(VTKNewEvent , vtkCommand);
static VTKNewEvent * New(){
return new VTKNewEvent ;
}
void Execute(vtkObject * caller, unsigned long vtkNotUsed(eventId), void * vtkNotUsed(callData)){
vtkRenderWindowInteractor *iren = static_cast<vtkRenderWindowInteractor*>(caller);
if (iren_close == true){
iren->GetRenderWindow()->Finalize // Stop the interactor
iren->TerminateApp();
iren_close = false;
}
if (iren_update== true){
renderJanela->Render();
iren_update= false;
}
}
};
bool VTKWindow(){
vtkSmartPointer<VTKNewEvent > IrenRefresh= vtkSmartPointer<VTKNewEvent>::New();
...
iren->CreateRepeatingTimer(1);//this makes that IrenRefresh will be called at every 1ms
iren->AddObserver(vtkCommand::TimerEvent, IrenRefresh);
iren->Start();
...
}
it's simple, but, maybe not the best, but it did Th job, I hope this link will help people that are starting into the VTK world, since threads + rendering loop wasn't a simple job to understand what was going on
I have several layers in the scene, like TLayer,HLayer,TouchLayer. How can I get HLayer in HLayer? The solution I take is that I pass Layer to other Layer. However I met some problems recently. I push the Scene and pop Scene while TouchLayer still exists. So my problem is that is it right to pass HLayer to TouchLayer. Or is there a better way to do it in Cocos2d-x?
In the init() function in Scene:
this->setbackgroundLayer(BackgroundLayer::create());
CC_BREAK_IF(!backgroundLayer);
this->addChild(backgroundLayer);
this->setTLayer(TcharacterLayer::create(backgroundLayer->tianzige));
CC_BREAK_IF(!TLayer);
this->addChild(TLayer);
this->setHLayer(HcharacterLayer::create(testCharacter,backgroundLayer->tianzige_draw));
CC_BREAK_IF(!HLayer);
this->addChild(HLayer);
this->settouchLayer(TouchLayer::create(TLayer,HLayer));
CC_BREAK_IF(!touchLayer);
this->addChild(touchLayer);
I made my own create function:
TouchLayer* TouchLayer::create(TcharacterLayer* t,HcharacterLayer* h){
TouchLayer* pRet = new TouchLayer();
if (pRet && pRet->init(t,h))
{
pRet->autorelease();
return pRet;
}else
{
delete pRet;
pRet = NULL;
return NULL;
}
}
Here's how we've done this in the past. Define a set of tags for our layers.
typedef enum {
kBgLayerTag,
kHLayerTag,
kTLayerTag,
kTouchLayerTag
} MyLayerTags
Then while creating the layers set layer specific tags:
this->setTLayer(TcharacterLayer::create(backgroundLayer->tianzige));
CC_BREAK_IF(!TLayer);
TLayer->setTag(kTLayerTag);
this->addChild(TLayer);
And in TouchLayer access the TLayer and others like:
TcharacterLayer* myTLayer = this->getParent()->getChildByTag(kTLayerTag);
Sure, there is nothing wrong in adding a layer as a child. I would do that this way :
BackgroundLayer has all the necessary layers as children (remember to add TouchLayer as the last one and then pass Touch to others) and then you only add BackgroundLayer to your scene. There is even more simple way (probably better): to make BackgroundLayer inherit all the previous ones - but that depends on how much scenes you are going to make.
Edit:
1)
BackgroundLayer * bglayer = BackgroundLayer::create();
TcharacterLayer * tcharlayer = TcharacterLayer::create();
HcharacterLayer * hcharlayer = HcharacterLayer::create();
TouchLayer * tlayer = TouchLayer::create();
bglayer->addChild(tcharlayer);
bglayer->addChild(hcharlayer);
bglayer->addChild(tlayer);
this->addChild(bglayer);
(assuming this as a CCScene)
2)
class BackgroundLayer : public TcharacterLayer, HcharacterLayer, TouchLayer
{
...
}
In the first case you can give each layer a specific tag and then get the layer by getChildByTag(int tag) or just create fields in the BackgroundLayer class for each layer.
How to implement transition between several scenes that use opengl?
I have 2 different scenes. each create its frame and render buffers and bind it. But then I try to switch between these scenes - nothing happens... I tried to delete all buffers when swithing but it's doesn't work. The First scene is still visible..
Well, in my experience you may need to dispose of the textures for the first scene's visuals.
A quick idea is using psm studio's approach to OpenGLES.
public TitleScene ()
{
this.Camera.SetViewFromViewport();
_texture = new Texture2D("Application/images/title.png",false);
_ti = new TextureInfo(_texture);
SpriteUV titleScreen = new SpriteUV(_ti);
titleScreen.Scale = _ti.TextureSizef;
titleScreen.Pivot = new Vector2(0.5f,0.5f);
titleScreen.Position = new Vector2(Director.Instance.GL.Context.GetViewport().Width/2,
Director.Instance.GL.Context.GetViewport().Height/2);
this.AddChild(titleScreen);
public override void Update (float dt)
{
base.Update (dt);
var touches = Touch.GetData(0).ToArray();
if((touches.Length >0 && touches[0].Status == TouchStatus.Down) || Input2.GamePad0.Cross.Press)
{
Director.Instance.ReplaceScene(new MenuScene());
}
}
~TitleScene()
{
_texture.Dispose();
_ti.Dispose ();
}
}
I hope this will give you some help on what you are missing.