Synchronous CCLayers - running levels in complex defined order - cocos2d-iphone

I'm building a game that has dozens of dynamically generated mini-levels. To simplify, let's say I've got three types of levels, A, B, and C, and each one can take an integer difficulty. LevelA, LevelB, and LevelC are subclasses of CCLayer, and I've been loading them into a GameScene that's a subclass of CCScene, one at a time. I'm not married to this method; it's just what's been working.
What I can't figure out is how to control the flow of levels in an overarching way.
The simple way to load a new level seems to be replicate the [[CCDirector sharedDirector] replaceScene:[newScene node]] model - so something like: [[GameScene sharedScene] replaceGameplayLayer:[LevelA newLevelWithDifficulty:5]]].
This works fine, but only if the call to the next level comes within the code for the current level. So if I'm in an A-level, I can load up a corresponding B-level every time I hit 10 points - something like:
-(void)checkScore {
if (score >= 10) {
[[GameScene sharedScene] replaceGameplayLayer:[LevelB newLevelWithDifficulty:currentLevelDifficulty]];
}
}
And then do the same in the LevelB class to load up C-levels, or some other configuration.
But what if I want to plan out a level order? A1, B1, C1, C2, C3, C4, C5, A2, etc? I'd like to be able to treat each level as a synchronous line in a function. Like:
-(void)playGame {
[LevelA newLevelWithDifficulty:1];
[LevelB newLevelWithDifficulty:1];
for (int i = 0; i < 5; i++) {
[LevelC newLevelWithDifficulty:i];
}
// ...etc...
}
I'm not sure how to tackle the problem though. Is it even possible? It's easy enough to make that checkScore method just kill the current Level at 10 points, but how would I keep LevelB from happening until it did?
I hope this question makes sense. Any help you could offer would be appreciated.

you could create in your scene an array of levels in the appropriate sequence ... but creating them all ahead of time would be expensive (textures, etc ...). So devise a key system that uniquely identifies the level and difficulty. Next, your scene could register for a notification (read up on NSNotificationCenter and NSNotification), and each level could signal completion by posting a notification. You could have multiple notifications, for example one for levelComplete, gameOver and gameVictory.
When the scene gets the levelComplete notification, you could fade out the layer, look up the next level info, instanciate an instance of the class, add it, and fade it in. ....
just one way of doing something like that. Others available.
I have level descriptor plists that contain the class name, the music to play, victory and gamover conditions, etc .... and use a scheme like this to sequence levels without swapping scenes. Works for me. ymmv :)

Related

Too deep hierarchy of signals-slots in Qt

I am writing GUI applicaton in Qt. Currently I waste too much time on routine. It seems something wrong with my architecture. Please tell me how can I change my approach to improve code.
What I am doing:
My program can be decomposed as hierarchy of classes (not inheritance but composition). In example:
class D { /* something */ };
class C { /* something */ };
class B { C c1; C c2; D d1; };
class A { D d1; C c1; };
So, actually it is a tree hierarchy where leaf nodes (class C, class D) are "models" in Qt terminology which hold data. At the top of hierarchy MainWindow (class A) is placed, which holds first level of "views" (class D, i.e. subwidget) and leaf node with data (class C, i.e. text field).
To pass information down from main window to data I use function calls from mainwindow (pushbuttons) to leaf nodes. After that data changes and tells parents about it with signal slot mechanism. Parents continue to pass message up with signaling.
I am really bored by establishing all these communication. Now I have up to 5 levels, however it is not that much in usual code when using composition. Please tell me how can I change my approach. Due to complexity of these connections, development of the code extremely slow, almost stopped.
It is hard to give a concrete example, because there are a lot of code, but the idea of problem which is very difficult to solve is following:
There are two QTreeView, which differently shows data from own model inherited from QAbstractItemModel (tree inside model is not that tree in previous discussion, this tree is only single level of hierarchy). I want to select objects in one QTreeView and change by that selection in second QTreeView. There are total 2 QTreeView, 2 different QAbstractItemModel instances, 2 trees of own objects (for each QAbstractItemModel), and single data.
Sounds like you might have become a victim of going through too many examples. Examples tend to cram functionality where it doesn't belong, creating the possibility to develop bad programming habits.
In actual production things need to be more compartmentalized. The main window should not be the container of the "application logic", all it needs to concern itself with is holding together the main widgets.
But that doesn't seem to be your case, judging by the necessity to delegate things "from mainwindow (pushbuttons) to leaf nodes" as you put it.
On a grander scale, it is not advisable to mix application logic with UI at all, much less cram it all in the main window. The application logic should be its own layer, designed so that it can work without any GUI whatsoever, and then the GUI is another layer that simply hooks up to the logic core.
The logic core should not be monolith either, it should be made of individual components focusing on their particular task.
Your use case doesn't really require any crazy amount of connections, just some basic handlers for the UI elements, which should target the logic core API rather than GUI elements as you appear to be doing now.
Your clarification unfortunately makes absolutely no sense to me, it is still completely unclear what you exactly you want to do.
Let's assume your situation is something like this:
Tree 1 shows a folder structure.
Tree 2 shows the file content of the folder, selected in tree 1.
Data is an editor for the file, assuming a text file, selected in tree 2.
So, in pseudocode, presuming that app is your application core logic object:
Clicking an item in tree 1 says app.setFolder(tree1.selectedItem())
Clicking an item in tree 2 says app.setFile(tree2.selectedItem())
Clicking the editor "save" button says app.save(editorUI.dataField.text())
logic layer gui layer
app mainWindow
folder <-----------select----------- tree1
file <-----------select----------- tree2
save(newData) { editor
if (file) file.rewrite(newData) textField
} saveBtn: app.save(textField.text())
Since there is only a single data source, you could do the following:
Create a general model for that data source. The model should represent the data source generally, without consideration of what the views need.
Create two proxy viewmodels that adapt the general model to the needs of the views.
Couple the selection models of the views that display the viewmodels.
Given the selection models on top of the two proxy models that map to the same source, we can propagate the selection change between them. We leverage the selection mapping provided by the proxy. The QAbstractProxyModel has a functional implementation of mapSelectionxxxx.
void applySel(const QItemSelectionModel *src, const QItemSelection &sel,
const QItemSelection &desel, const QItemSelectionModel *dst) {
// Disallow reentrancy on the selection models
static QHash<QObject*> busySelectionModels;
if (busySelectionModels.contains(src) || busySelectionModels.contains(dst))
return;
busySelectionModels.insert(src);
busySelectionModels.insert(dst);
// The models must be proxies
auto *srcModel = qobject_cast<QAbstractProxyItemModel*>(src->model());
auto *dstModel = qobject_cast<QAbstractProxyItemModel*>(dst->model());
Q_ASSERT(srcModel && dstModel);
// The proxies must refer to the same source model
auto *srcSourceModel = srcModel->sourceModel();
auto *dstSourceModel = dstModel->sourceModel();
Q_ASSERT(srcSourceModel && (srcSourceModel == dstSourceModel));
// Convey the selection
auto const srcSel = srcModel->mapSelectionToSource(sel);
auto const srcDesel = srcModel->mapSelectionToSource(desel);
auto const dstSel = dstModel->mapSelectionFromSource(srcSel);
auto const dstDesel = dstModel->mapSelectionFromSource(srcDesel);
// we would re-enter in the select calls
dst->select(dstSel, QItemSelectionModel::Select);
dst->select(dstDesel, QItemSelectionModel::Deselect);
// Allow re-entrancy
busySelectionModels.remove(src);
busySelectionModels.remove(dst);
}
The above could be easily adapted for a list of destination item selection models, in case you had more than two views.
We can use this translation to couple the selection models of the views:
void coupleSelections(QAbstractItemView *view1, QAbstractItemView *view2) {
auto *sel1 = view1->selectionModel();
auto *sel2 = view2->selectionModel();
Q_ASSERT(sel1 && sel2);
connect(sel1, &QItemSelectionModel::selectionChanged,
[=](const QItemSelection &sel, const QItemSelection &desel){
applySel(sel1, sel, desel, sel2);
});
connect(sel2, &QItemSelectionModel::selectionChanged,
[=](const QItemSelection &sel, const QItemSelection &desel){
applySel(sel2, sel, desel, sel1);
});
}
The above is untested and written from memory, but hopefully will work without much ado.

QTableView slow scrolling when many cells are visible at once

Background: I'm developing application using Qt 5.5.1, compiling with msvc2013. In this app I use my own implementation of QTableView, along with custom QStyledItemDelegate (needed custom cell editing) and QAbstractTableModel. I intend this view to work with massive amount of data that I wrap inside mentioned model. I allow the user few data editing options, custom sorting, 'invalid' rows windup etc.
The problem: scrolling speed of my QTableView subclass is slow - it gets slower the more table is shown (by resizing window), e.g. ~250 cells shown (in fullscreen) = slow, ~70 cells shown (small window) = fast.
Whad did I try so far:
First was to check if my model is slowing things down - I have measured times (using QTime::elapsed()) reading 10k samples and it shown 0 or 1ms. Then I have simply altered QTableView::data method to always return predefined string and not acquire any real data.
QVariant DataSet_TableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ItemDataRole::DisplayRole) {
return QVariant("aRatherLongString"); //results in slow scrolling
//return QVariant("a"); // this instead results in fast scrolling
}
else return QVariant();
}
As you can see, the speed seems to be affected by number of characters vieved per cell, and not by underlying connections to data source.
In my custom implementation of QStyledItemDelegate I have tried same 'trick' as above - this time overriging displayText method:
QString DataSet_TableModel_StyledItemDelegate::displayText(const QVariant &value, const QLocale &locale) const
{
return "a" //fast
// return "aRatherLongString"; //slow
// return QStyledItemDelegate::displayText(value, locale); //default
}
After some thought with a friend we concluded that maybe we could disable drawing/painting/updating of cells until whole scroll action is done. It might cause some flickering, but it's worth a try. Unfortunately we dont really know how to aproach this. We have everriden QTableView methods: scrollContentsBy(int dx, int dy) and verticalScrollbarAction(int action) - we have captured scroll action properly (either method intercepts it) and tried to somehow disable repainting like this:
void DataSet_TableView::verticalScrollbarAction(int action) {
this->setUpdatesEnabled(false);
QTableView::verticalScrollbarAction(action);
this->setUpdatesEnabled(true);
}
...but it did not have any visible effect.
How should we approach it? Do we need to use setUpdatesEnabled() on items that are put inside cells directly? (not sure what those are - widgets?)
Here are screenshots taken as part of testing this problem:
Predefined text, no calls to underlying data structure - slow scrolling, 'full screen'
Predefined text, no calls to underlying data structure - fast scrolling, windowed
Request: Could you kindly help me pinpoint the cause of this and suggest solution if possible? Is it limitation of the classes that I use?
First of all, you should also run your application in release mode to check your perfomance, in my experience, the performance decreases greatly when using debug mode.
Secondly, you need to be aware that the model data method and delegates methods are called every time you resize, scroll, focus out, right click etc. These actions trigger those methods to be called for each displayed cell, therefore you would need to make sure that you don't do any unnecessary processing.
The items inside cells are delegates that call their own methods (eg: paint).
Some C++ specific optimisations would be helpful in the implementation of these methods, like using a switch instead of an if statement, see explanation here and here. The usage of Conditional (Ternary) Operators might also speed up the things, more information here, here and some information about expensive checkings here.
Also, QVariant handles text in different ways, as exemplified below, you should try both ways and check if there is any difference in speed. Some conversions are more expensive than others.
v = QVariant("hello"); // The variant now contains a QByteArray
v = QVariant(tr("hello")); // The variant now contains a QString

Touch Event on Sprite with Cocos2d-x 3.x?

In my scene I have a vector with multiple custom sprites. When I tap on one of them, I want an action to be fired on another element on the scene, can be another sprite in the vector, or another node. I have been researching the best way to do this, but I'm not quite sure how to implement it. The options are:
Add a touch listener to the scene, and verify if it was tapped inside the bounds of the sprite with rect. containsPoint(point). And after that, I have to get the sprite that was tapped to do the action I want. For me, it doesn't seems very clean to do it this way. And if two sprites are overlaped, I have to verify if the sprite is behind or in the front in order to retrieve the desired sprite. I followed this example: Touch Event example
Add a touch listener in the subclass of the sprite (my custom sprite). And add onTouchBegan and onTouchEnded inside it. But this way, I don't know how to modify an attribute of another sprite, or another element in the scene (Is it possible to use Delegates like Objective-C does?). I followed this example: Subclass Sprite Example
My main problem is that I don't understand very well how to make a node interact with another node in the scene. I have seen a lot of tutorials, but in all of them, when you interact with a node, it only changes its attributes, not other nodes' attributes.
Thanks in advance.
I shall propose "EventCustom" way :)
You can add in your touchBegan / touchEnded methods (wherever you put them... you got the point...) additional code for passing an EventCusto to the _eventDispatcher and get it announced to the world ;)
EventCustom *e = new EventCustom("MyAwesomeEvent");
e->setUserData(ptrMyFantasticData); //This function takes a void pointer. cheers :)
_eventDispatcher->dispatchEvent(e);
You may subclass the EventCustom class but that is hardly necessary. You can always hang an object to it with setUserData().
Now the objects which need to react to the event can listen to it by
_myCustomListener = EventListenerCustom::create(
"MyAwesomeEvent",
CC_CALLBACK_1(
ListeningClass::onMyAwesomeEvent,
this
)
);
_eventDispatcher->addEventListenerWithXXXXXPriority(_myCustomListener, XXX);
//ScreenGraphPriority / FixedPriority depends on situation. Either should work.
It's always a good practice to remove your listeners when you go off, so somewhere, perhaps in onExit(), where you removed touch listeners remove this listener too, as
_eventDispatcher->removeEventListener(_myCustomListener);
Going a bit off the track, a clarification:
CC_CALLBACK_X are a bit tricky names. The X indicates the no. of args the target function will get. Here, event dispatcher will pass 1 arg i.e. ptr to object of EventCustom you handed it, so we use CC_CALLBACK_1. The next arg - here "this" - is the object on which the method will be invoked.
In short, we may say that this callback is going to result into a function call this->onMyAwesomeEvent(e);
For CC_CALLBACK_2 onwards, we can specify additional args, 3rd arg onwards.
Coming back to the issue at hand, ListeningClass::onMyAwesomeEvent will look something like
void ListeningClass::onMyAwesomeEvent(EventCustom *e)
{
MyFantasticData *d = (MyFantasticData *) e->getUserData();
CCLOG("[ListeningClass::onMyAwesomeEvent] %d", d->getMyPreciousInt());
}
Hope it helps :)
Set your elements tags or names with setTag and setName. Then if element x is touched, get them with getChildByTag or getChildByName and do what you need to do.
With the second option you list above.
To make a node interact with another node in the scene you can add touch callback function to your custom sprite object like that:
https://github.com/Longpc/RTS/tree/master/Classes/base/dialogBase
and in main scene you can define function to handle this callback. So you can do every thing to unit in you scene

How to do a lot simpler version of UT kismet (C++ and Lua)

I know this is a non trivial question, but I have spent last week thinking about how to do this, and I can't fidn a good way.
Mainly I have a 2D level editor. I can put entities in the world, add tiles, collisions, etc... What I want is to be able to script easy things visually. For example if I have a lever and a door, I want to select the level select its "onactivate" event and link it to the "close" action of the door.
The editor loads a xml with the possible entities, and what actions each publishes, in the case of the lever (activate/deactivate) and the door (open/close).
Now the difficult part. I need to translate this into running code. I have thought about some solutions but all seems awkard to me. For eample, for the lever/door event I could autogenerate code in a lua function with name Lever1_onactivate_Door1_open() that will register a LuaListener in the Lever1 instance listener cue foro the onactivate event (in C++), and let it be called later, when the onEnter for the trigger is triggered.
Could anyone explain how ussually this kind of things are done? One of my probs is that I want to integrate this into my event system as I exposed, to have an orthogonal arquitecture.
Thanks in advance,
Maleira.
In games like Doom, this is approximately done as follows: when pressing the Use key [func: P_UseLines], the nearest wall that it would apply to is searched for [func: P_UseTraverse] and, provided you are in range and have the right angle of turn, calls an action (called "special") associated with the line in [func: P_ActivateLine], which essentially maps it to a preexisting function in the end.
In other words, a simple lookup in a function pointer array:
/* Premise */
struct line_t {
...
int special;
...
};
struct line_t *line = activation_line;
/* Function call from p_spec.cpp */
LineSpecials[line->special](line, ...);
LineSpecials would be an array of function pointers:
int LS_Door_Open(struct line_t *, ...)
{
...
}
typedef int (*lnSpecFunc)(struct line_t *, ...);
lnSpecFunc LineSpecials[256] = {
...
/* 13 */ LS_Door_Open,
...
};

How to implement simple tick-based engine in c++?

I'm writing a text game and I need a simple combat system, like in MUDs, you issue commands, and once in a while "tick" happens, when all those commands execute, player and monsters deal damage, all kinds of different stuff happens. How do I implement that concept?
I thought about making a variable that holds last tick time, and a function that just puts events on stack and when that time is (time +x) executes them all simutaniously. Is there any easier or cleaner variant to do that?
What would be possible syntax for that?
double lastTickTime;
double currentTime;
void eventsPile(int event, int target)
{
// how do i implement stack of events? And send them to execute() when time is up?
}
void execute(int event, int target)
{
if ((currentTime - lastTickTime) == 2)
{
eventsHandler(event, target);
}
else
{ // How do I put events on stack?
}
}
The problem with simple action stack is that the order of actions will probably be time based - whoever types fastest will strike a first hit. You should probably introduce priorities in the stack, so that for instance all global events trigger first, then creatures' action events, but those action events are ordered by some attribute like agility, or level. If a creature has higher agility then that it gets the first hit.
From what I've seen, most such engines are event, rather than time, based. with a new tick being triggered some interval after the last tick ended. (thus mostly avoiding the issue of ticks taking longer than the interval)
This also simplifies implementation; you simply have a game loop that triggers a tick event, then sleeps/yields for the required interval. Which is trivial.
It can further be simplified by modeling the world as a tree, where each element manages propagating events (such as ticks) to their children. so long as you avoid / manage 'loops', this works well (I've done it).
This effectively reduces the tick system to something like this (psudocode):
while (isRunning) {
world->tick();
sleep(interval);
}
In most cases, theres little need to get much fancier than adjusting for the length of the previous duration.
Any individual entities actions would be part of their own action queue, and handled during their own "tick" events.
Usually user commands would be split into "ingame" and "meta" commands, anything ingame would merely amend their character's action queue, to be processed in their next tick, as per normal for any other entity.
Simple round-based combat follows naturally from this foundation. realtime can be modeled with a finer division of ticks, with optional 'time-pooling'.
Use a timer executing every x ms (whereas x is your ticktime), execute any actions put on the stack in that method.