Reverse enumerating through a random NSArray Objective C - nsarray

I'm currently making an app that plays videos from an array. I've hooked the array up to a randomizer so that when the user hits a "next" button, a video from the array is selected at random. The next button works fine, but what I'm struggling with is the back button. I want the user to be able to return to the previous video by hitting a "back" button. I have researched several ways to do this but none have worked. If someone could take a look at my code below and give me some suggestions That would be greatly appreciated! Take note that I only selected 1 index from the array to save space. Also, I know that there are several other posts about reverse enumeration and like I said, none have brought me success. If done a ton of research and this is my last resort.
#implementation MajesticViewController
#synthesize arrayName = _arrayName;
- (void)viewDidLoad
{
[super viewDidLoad];
//Heres the array containing the videos
_arrayName = [NSArray arrayWithObjects:
// video 0- losing you
#"<iframe width=\"279\" height=\"199\" src=\"http://www.youtube.com/embed/YjvRydejkYY\" frameborder=\"0\" allowfullscreen></iframe>", #"<iframe width=\"279\" height=\"199\" src=\"http://www.youtube.com/embed/nosOsDG38nQ?rel=0\" frameborder=\"0\" allowfullscreen></iframe>", nil];
[self pickSong:_arrayName];
}
//This is the next button
-(IBAction)newSongButton:(id)sender
{
[self pickSong:_arrayName];
}
//This randomly picks the next video
-(void)pickSong:(NSArray *)arrayName
{
int r = arc4random() % 47;
//int r = 46; /////tester
if (r==0)
{
NSString *randomResponse = [arrayName objectAtIndex:0];
[[self myWebView] loadHTMLString:randomResponse baseURL:nil];
}

Just create an ivar or property that keeps track of the previous object if you need to go back.
If need more, make a simple stack using an array, that tracks x number of previous objects.
You can find them in the new sorted/shuffle array by using indexOfObject

Related

Why cannot addItem into QGraphicsScene from a QVector<QGraphicsItem>?

I want to undo or redo actions in a QGraphicsScene that is linked to a QGraphicsView: For that, I use QGraphicsEllipse (to draw points while moving and clicking on the QGraphicsView) in my mouseMoveEvent method, I push every QGraphicsEllipse in a QVector<QGraphicsItem>, and when the QAction "undo" is triggered the program must delete the last ellipses (determined number of ellipses) drawn in my QGraphicsView thanks to my QGraphicsScene.
When I clear my QGraphicsScene and try to add all QGraphicsItems that were pushed in my QVector<QGraphicsItem>, I got an error: my app goes down!
if(index < historyIndex.size()){
for (int i = 0; i < scHistory.size() - historyIndex[index]; i++){
scene->addItem((QGraphicsItem*)scHistory[i]);
}
index++;
}
QVector<QGraphicsItem *> scHistory;
QGraphicsScene::addItem takes the ownership of the element added, check the doc. It means that it is now in charge of destructing the element, which happens when you clear the scene with QGraphicsScene::clear. From that point on, your vector is full of dangling pointers.
One quick fix is to replace the call to QGraphicsScene::clear with a manual removal of items through QGraphicsScene::removeItem, which doesn't destroy the item (it returns the ownership to the caller). Then, destroy only those elements that are actually out of the scene, and add back the rest. Another option, more efficient, is to remove only the elements you need, keeping the rest, so you also increase performance by avoiding add back a large number of items from the history.
Without a full knowledge of your code, the second options may be something like:
if(_indexHistoryRoam < _indexHistory.size()){
// Remove only items beyond history
const int range = _sceneHistory.size() - _indexHistory[_indexHistoryRoam];
for (int i = range; i < _sceneHistory.size(); i++){
scene->removeItem((QGraphicsItem*)_sceneHistory[i]);
delete _sceneHistory[i]; // item must be destroyed to avoid a leak
}
_indexHistoryRoam++;
} else { // force removal of all elements
scene->clear();
}
scene->update();

Loop through all buttons in a QButtonGroup

In my project, I have a QButtonGroup with 256 pushbuttons in it. I also gave each button an id like this:
void MainWindow::AddBlocksToGroup()
{
QButtonGroup* blockGroup = new QButtonGroup(this);
blockGroup->addButton(ui->Oblock_0, 0);
...
blockGroup->addButton(ui->Oblock_255, 255);
}
I am trying to loop through all the buttons in the group and change their text but I keep getting errors when my program reaches the part where I loop through the buttons. This is what I currently have to loop through them:
for(int i = 0; i <= 255; i++)
{
blockGroup->button(i)->setText("Test"); //Read access violation?
}
I always get a read access violation in my loop when my program reaches this point. Why is this?
Thanks for your time.
I would do this for the iteration code:
foreach(QAbstractButton *button, blockGroup->buttons()) {
button->setText("Test");
}
If this still gives you crashes, then there's something else going on in your program that is invalidating those button pointers.
I know it has been a long time, you probably have already solved this. If not, maybe you need to check whether blockGroup->buttons() return value is an empty list or not. If it is an empty list, then your program crashes.
You seem to be creating a local variable called blockGroup in your AddBlocksToGroup() function. Perhaps what you are trying to do is initialize your MainWindow member variable that uses the same name?
So instead of: QButtonGroup* blockGroup = new QButtonGroup(this);
you should do: blockGroup = new QButtonGroup(this);

Collision of two sprite lists - SFML 2.0

I am making a simple game in SFML 2 and it came smoothly so far. I created two sf::Sprite lists, one for enemies and one for lasers. The enemies spawn randomly off-screen and the lasers are created whenever input is given. I created a collision loop for both the lists and executed my code. There are no compile time and run time errors. The laser-enemy collision works fine for the first 3 to 4 enemies but after that, the collision does not occur. What might be causing this problem? Please help me on this. Thanks. Here's my code.
std::list<sf::Sprite>::iterator enemyit = enemy.begin(), next;
std::list<sf::Sprite>::iterator greenlaserit = greenlaser.begin(), reload;
while(enemyit != enemy.end())
{
next = enemyit;
next++;
while(greenlaserit != greenlaser.end())
{
reload = greenlaserit;
reload++;
if(enemyit->getGlobalBounds().intersects(greenlaserit->getGlobalBounds()))
{
enemy.erase(enemyit);
greenlaser.erase(greenlaserit);
++erased;
}
greenlaserit = reload;
}
enemyit = next;
}
It seems to be that you are doing a lot of iterator manipulation and that is likely to be where the problem is occurring.
If you can use c++11, I would suggest looking into the for each loop (http://www.cprogramming.com/c++11/c++11-ranged-for-loop.html), to keep things really simple to read and understand (and thus, easier to debug).
You could do something like this:
std::list<sf::Sprite> enemies;
std::list<sf::Sprite> lasers;
for (sf::Sprite enemy: enemies) {
for (sf::Sprite laser : lasers) {
if (enemy.getGlobalBounds().intersects(laser.getGlobalBounds())) {
enemies.remove(enemy);
lasers.remove(laser);
}
}
}
Edit: otherwise, one method I have found for figuring out an iterator problem is stepping through it by hand. I draw two rectangles with cells for each location, and keep track of the iterators and run through the logic step by step. Before each iteration of your logic, write down your expected results. Then go through it by hand and see if your results match your expectations.

Killing the invaders doesn't work in C++

I know that in order to kill invaders in C++, I need to make a collider.
However, nothing will ever kill the invaders in that game.
Here's the code in the header:
bool DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight);
This is the function I'm initializing:
bool Game::DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight) {
if (Xbpos+BulWidth < Xipos || Xbpos > Xipos+InvWidth) return false;
if (Ybpos+BulHeight < Yipos || Ybpos > Yipos+InvHeight) return false;
return true;
}
And this is what happens if somebody presses the space key:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
}
Does anybody know what's going wrong?
The problem isn't C++. The problem is how you are using it. The only way you'll get a kill with your code as written is if the invader is right on top of you. But that's too late. The alien invader has already killed you.
What you need to do is make those bullets into objects that you propagate over time, just like your invaders are objects that you propagate over time. The response to the user pressing a space key should be to add a new instance of a bullet to the set of active bullets. Each of those active bullets has a position that changes with time. On each time step, you should advance the states of the active invaders per the rules that dictate how invaders move and advance the states of the active bullets per the rules that dictate how bullets move. Remove bullets when they reach the top of the screen, and if an alien invader reaches the bottom of the screen, game over.
After propagating, removing off-screen bullets, and checking for game over, you want to check for collisions between each of the N bullets with each of the M invaders. When a collision is detected, remove the bullet from the set of active bullets and delete the alien invader from the set of active invaders. And of course you'll want some nifty graphics to show the user that another alien bit the dust.
Aside: Being an NxM problem, this check might be the biggest drain on CPU usage. You can speed this up with some simple heuristics.
You could manage the collections of alien invaders and bullets yourself, carefully using new and delete so as to prevent your invaders and bullets from killing your program with a memory leak. You don't have to do this. C++ gives you some nifty tools to manage these collections. Use one of the C++ standard library collections instead of rolling your own collection. For example, std::vector<AlienInvader> invaders; or std::list<AlienInvader> invaders, and the same for bullets. You'll be deleting from the middle a lot, which suggests that std::list or std::deque might be more appropriate than std::vector here.
You test the collision for the fired item just when they are created
Shouldn't be the test collision done in the main loop for each existing item at each frame ?
Don't worry, C++ has got all you need to kill invaders :)))
It's not easy to give advice based on so little code, but here the only logical error seems to be you test for collision only when space is pressed; you should test for it in an outside loop probably:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
}
From a logical point of view, pressing Space should fire a bullet: the starting position for the bullet is set, and so is its speed on the Y axis (so that it goes up).
The code that check for collision should go outside of this if block. In fact, this block of code is executed only if you're still pressing space -that is: still firing-. Should collision be checked only if you're "still firing"? Do the fact that you fired a bullet and started waiting for it to destroy the invader interfere in some way with the fact that this bullet can reach the invader and, indeed, destroy it? Of course not!
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
You want collision to be checked in an outside loop, the same that probably also contains the checks for key presses. In this way, even if you're just looking at the screen and waiting, the program keeps testing the condition and, when it's fulfilled, code associated with the event of collision is executed (that is: an invader is "inactivated").
You say //Space , is that what it is or should it be 32 (if ASCII) instead of 57? Does the program flow into the if==57 block?
Your code looks fine, but you need two loops around the collision checker: one for checking all invaders (not just one of them) and another one to check at every bullet position along its trajectory, not just the moment when it leaves the gun.
I will assume we have an auxiliary function that moves the bullet and returns whether it is still inside the screen:
bool BulletIsInScreen();
Then we can write the loops:
if (code == 57) { // Space
while (BulletIsInScreen()) {
for (size_t i = 0; i < counter; ++i) { // counter is the number of invaders,
// according to your comment to your own answer
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[i].MyBullet.Xbpos, Invaders[i].MyBullet.Ybpos,
Invaders[i].MyBullet.BulWidth, Invaders[i].MyBullet.BulHeight,
Invaders[i].Xipos, Invaders[i].Yipos,
Invaders[i].InvWidth, Invaders[i].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[i].Active = false;
printf("Collide!\n");
}
}
}
}
Now this should work as expected.

How is it that lastTimeTargetAdded is ever not 0

Im beginning work with Cocos2d and have been working off this tutorial (link is for part 9) the past few days.
In reading the source and trying to understand it I have reached a section that doesnt make any sense to me.
-(void)gameLogic:(ccTime)dt {
static double lastTimeTargetAdded =0;
double now = [[NSDate date] timeIntervalSince1970];
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
if(lastTimeTargetAdded == 0 || now - lastTimeTargetAdded >= delegate.curLevel.spawnRate) {
[self addTarget];
lastTimeTargetAdded = now;
}
}
called via this:
[self schedule:#selector(gameLogic:) interval:0.2];
With the fact that lastTimeTargetAdded is created and set each time the function runs how is it ever not 0? And if thats the case what is the point of lastTimeTargetAdded = now? With the if statement being an OR (||) it never evaluates the other side of it so why is that even there?
I understand well enough what the function does just not so much how it does it. This method is suppose to spawn creeps based on their spawn rate. Making sure all the creeps in the wave arent just dumped on screen. And the method does do that well enough.
it is a static var ... the first statement sets to 0 only on the first invocation of gameLogic. On each subsequent invocation, lastTimeTargetAdded has the value that was set in the previous invocation.