Enabling/disabling CCButtons in an array - objective-c

I'm building a puzzle game with 20 levels using Cocos2D. When a player first opens the game, all the levels should be locked except for level 1. When the player passes level 1, then level 2 button should be enabled and so on...
I put the CCButtons in an array so that I could disable unlocked level buttons in a for loop (rather than each individually), but enabling/disabling the object references from the array doesn't work...
For example, this works: _level19.enabled = false;
But this doesn't work: levels[19].enabled = false;
Here is the relevant code block after I initialized CCButton* _level1 to CCButton* _level20.
-(void) didLoadFromCCB {
// Only set level buttons as enabled if player has unlocked that level
CCButton* levels[20] = {_level1, _level2, _level3, _level4, _level5, _level6, _level7, _level8, _level9,
_level11, _level12, _level13, _level14, _level15, _level16, _level17, _level18, _level19, _level20};
// CCButtons are automatically enabled so disable all buttons that haven't been unlocked
for (NSInteger j = [GameState sharedInstance].levelsUnlocked; j > 20; j++) {
levels[j].enabled = false;
}
}
Any help would be appreciated!

j > 20 seems like a typo. You want to get inside the loop only if your j value is greater than 20 , and then fetch a value from levels array of count 20 which would throw an out of bounds exception.
I am guessing, this should work for you
for (NSInteger j = [GameState sharedInstance].levelsUnlocked; j < 20; j++) {
levels[j].enabled = false;
}

Related

Spawning Enemies on Game Maker

I am coding a game on game maker studio in which I want a number of enemies to be spawned randomly on my grid every time the game is run. However, I am only getting one enemy on my map each time I run it.
Below is the Create instance for my enemy object.
x_speed_ = 0;
y_speed_ = 0;
max_speed_ = 1.5;
move_speed = 1;
acceleration_ = .3;
path_start(follow_path, move_speed, continue_path, true);
Also, this is the code in the Create instance for the level that is used to place the enemies on my grid.
for(var n = 1; n < 8; n++) {
i = irandom_range(1, grid_width-2);
j = irandom_range(1, grid_height-2);
instance_create_layer(i, j, "Instances", object_enemy);
}
Can anyone spot the reason why I'm not getting multiple enemies in my level?
I can think of 2 possible scenarios in the given context:
the "Level" object is not placed in the room, so it doesn't run the said code.
the randomiser fails to be random, so it spawns 8 enemies on the exact same location.

Looping over an NSmutatable Array starting from a certain index

I have a quick question how can I loop over an NSMutable array starting from a certain index.
For Example I have these double loops I want k to start from the same index as l.
for (Line *l in L)
{
for (Line *k in L)
{
............
}
}
To elaborate further, lets say L has 10 object so l start from 0-10 and k from 0 -10. What I want is if l is equal 1 k should start from 1-10 rather than 0 - 10 and when l is equal 2 k should start from 2- 10 rather than 0. Any help is Appreciated
Objective-C is an extension of C, lookup the C for loop and you'll have your answer. HTH
Addendum
I was going to let you benefit from the learning experience of looking up the C for yourself, however at the time of writing all other answers since added give the code but it is not complete, so here is what you need to produce the l and k values in the order you wish:
for(NSInteger lIndex = 0; lIndex < L.count; lIndex++)
{
Line *l = L[lIndex]; // index into your array to get the element
for(NSInteger kIndex = lIndex; kIndex < L.count; kIndex++)
{
Line *k = L[kIndex];
// process your l and k
}
}
As you can see the for has three sub-parts which are the initialisation, condition, and increment. The initialisation is performed first, then the condition to determine whether to execute the for body, and the increment is executed after the statements in the body and before the condition is tested to determine if another iteration should be performed. A for loop is roughly (there are some differences that are unimportant here) to the while loop:
initialisation;
while(condition)
{
body statements;
increment;
}
You simply need to modify for-statement.
NSInteger indexYouNeed;
NSInteger iterationCount;
for (int i = indexYouNeed; i < iterationCount; i++) {
/* Your code here */
}
You may find this link helpfulll.
You have to use an indexed (ordinary) for loop instead of fast enumeration (for-in):
int l;
for (l=startValue; l<=endValue; l++)
{
int i;
for (int i=l; i<=endValue; i++)
{
…
}
}

Number of filled rows in a SapTable

I'm using Silk4J and I have a table which is reported as SapTable in the Locator Spy. From that table, I'm trying to get all the texts of the second column, but it hangs or terminates with an exception. In the following you find the code for my tries. Finally I reached the last row of the table, but it hangs there again.
In all examples I'm using a while loop instead of a for loop, because I want to insert more conditions later.
Try 1: Straight forward (I thought)
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
}
However, this code prints all visible columns, then hangs.
Try 2: adding a PageDn keypress via Silk
Since try 1 printed only the visible cells, I thought adding a keypress every page could help. That was my code:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
window.sendVKey(VKey.PAGE_DOWN);
}
Unfortunately this results in an exception "The virtual key is not enabled".
Try 3: adding a PageDn keypress via AwtRobot
Since the built-in sendVKey method did not work, but pressing the PageDn manually works, I switched to an AwtRobot:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
}
}
Pressing the key now works and I can see the table scroll to the next entry. However, my test application still hangs.
Try 4: Resetting the row count
Using the Locator Spy again, I found out that the index of the row is reset to zero, so I mimiced that in my code:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
row = 0; // <--
}
}
In this case, it prints the first N (number of visible) items of the list, scrolls to position N+1, prints the name of the first (!) row and then hangs when accessing the item with index 1 (after the reset).
Try 5: Sleeping
With some sleeping, I can reach the end of the table:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
row = 0;
Thread.sleep(1000); // <--
}
}
In this case, I get all items in the table. But since I don't know when the table ends, it does another getCell() call, which results in a hang again.
The question
I'm really stuck. I've also looked for other methods like getting the real number of rows in the table (getRowCount() doesn't), but didn't find one yet.
How do I get the real number of rows of a SapTable in Silk4J?
It took some trying - the underlying SAP automation API is not really helpful in this case - but here is how you can make it work:
private List<String> fetchItems() {
SapTable table = desktop.find("sap.Table");
SapVerticalScrollBar scrollBar = table.find("/SapVerticalScrollBar");
// the scrollbar maximum value seems to be a more reliable
// way to get the number of items than getRowCount
int itemCount = scrollBar.getMaximum() + 1;
List<String> items = new ArrayList<String>();
int currentAbsoluteRow = 0;
// the first loop iterates through the table page by page
for (int firstRowInPage = 0;
firstRowInPage < itemCount;
firstRowInPage = scrollToNextPage(firstRowInPage)) {
// this loop goes through the items of the current page
for (int currentRowInPage = 0;
currentRowInPage < table.getVisibleRowCount();
currentRowInPage++) {
if(++currentAbsoluteRow > itemCount) {
// we've read all the available items
return items;
}
SapComponent cell = table.getCell(currentRowInPage, 1);
items.add(cell.getProperty("Text").toString());
}
}
return items;
}
private int scrollToNextPage(int firstRowInPage) {
SapTable table = desktop.find("sap.Table");
SapVerticalScrollBar scrollBar = table.find("/SapVerticalScrollBar");
firstRowInPage += scrollBar.getPageSize();
scrollBar.scrollTo(firstRowInPage);
return firstRowInPage;
}
Some pitfalls that I encountered:
getRowCount() returned a higher count than there was in actual items
getVisibleRowCount() returns the number of items that would fit on the current page, even if not all rows were filled with actual items
The returned cell objects are only valid as long as the cell is on the screen, so you'll need to pull the information you want before you scroll to the next page.

Actionscript 3: How to make movieclip variables work with variables on stage (Healthbar Help)

I am totally new at this whole programming thing, and I really need help. So basically, I'm trying to make a healthbar that will increase or decrease depending on what button is clicked. I made a healthbar movieclip with 101 frames (I included zero) and put this in the actionscript layer of the movieclip:
var health:Number = 0;
if(health == 0)
{
gotoAndStop("1")
}
if(health == 1)
{
gotoAndStop("2")
}
if(health == 2)
{
gotoAndStop("3")
}
and on and on like so. Basically, on the stage itself, I have a button called fortyfiveup_btn that is commanded to do this:
var health:Number = 0;
fortyfiveup_btn.addEventListener(MouseEvent.CLICK, fortyfiveupClick);
function fortyfiveupClick(event:MouseEvent):void{
health = health+45
}
I quickly realized that both health variables, the one for the button and the one for the healthbar will not interact. How can I make it so if the button is clicked, the health goes to the relevant frame or percentage?
Thanks for any answers, and I appreciate all the help I can get :)
If the answer == yes to my comment you should do this:
You need to give the movieclip an instancename (perhaps lifebar) and from stage you can access the health inside the "lifebar" with lifebar.health.
So you need this inside your stage:
//You can delete the var health:Number = 0;
fortyfiveup_btn.addEventListener(MouseEvent.CLICK, fortyfiveupClick);
function fortyfiveupClick(event:MouseEvent):void{
//You can write this, too: lifebar.health += 45;
lifebar.health = lifebar.health+45;
}
You can even optimize your lifebar script, don't use 101 times the if(health == x) you can use this, too:
gotoAndStop(health + 1);
(I think this is inside an ENTER_FRAME event?)
EDIT:
Some error countermeasures:
//Don't let health decrease below 0
if(health < 0) health = 0;
//And don't above 100
else if(health > 100) health = 100;
gotoAndStop(health + 1);
Use int instead of Number when you don't use decimal numbers and uint when you don't use negative integers (this bugs when the number can drop under 0, so for your health we take int):
health:int = 0;

How to interchange the position of each of my four ui-elements randomly? - algorithm for the 24 possibilities

I have a program with four different buttons. I want to interchange the position of the buttons randomly. For example: 1 2 3 4 Later: 3 4 1 2 Later: 1 3 2 4
Is there a algorithms for that? The only way I can think is to make a random number from 1 to 24 (24 possibilities) and then code all the possible button postitions.
int foo = arcrandom() % 23;
switch(foo){
case 0:
button1postiton = 100; //just an example
button2position = 200;
button3position = 300;
button4position = 400;
break;
case 2:
button1postiton = 200;
//blablabla and so on and so on
}
But is there a more efficient way?
Thanks!
You could shuffle the buttons or their positions, e.g. with a Fisher-Yates shuffle.
There is code in this website to get a list of all permutations of an array (see method perm2), it is coded for char arrays, but can be modified to do int arrays as well and to other languages as well, then you can use mjv's idea.
http://www.cs.princeton.edu/introcs/23recursion/Permutations.java.html
If in Java, this is what I would try....
Once you get all the possible permutations maybe in a vector, I think you can use a grid bag layout and change the grid constraints, picking one of the elements of the vector randomly. I have not tried this out, but I am thinking along the lines of
Vector permutations = ... //get the permutation using a class similar to the one in the website for an array of ints {0,1,2,3}
//The panel
JPanel pane;
JButton button;
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//Choose one permutation at random
int foo = arcrandom() % 23;
int current[] = permutations.get(foo);
//Add the buttons in the chosen order
button = new JButton("Button 1");
c.gridx = current[0];
c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = current[1];
c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = current[2];
c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 4");
c.gridx = current[3];
c.gridy = 0;
pane.add(button, c);
Let me know if this works!
Start with a random number 0 <= r < 24
Start with your first position. Derive rr = r % 4 and r = r / 4. Those are the remainder and quotient respectively after division by 4.
The remainder specifies a position. Swap position 0 with the specified position.
For the next position, derive rr = r % 3 and r = r / 3. Again the remainder specifies a position, this time 0, 1 or 2, but relative to your current position (1).
Swap position 1 with position rr+1.
For the next position, derive rr = r % 2 and r = r / 2. Again the remainder specifies a position, this time 0 or 1, and relative to your current position again (2).
Swap position 2 with position rr+2.
For position 3, there is nothing to do.
Note - for each swap, one possibility is to swap a position with itself. Obviously no swap is needed for that.
This is probably the Fisher-Yates shuffle - I had no idea it had a name until today.
Thanks for all your answers! I used the Fisher-Yates shuffle! I found here a nice tutorial, how to use the algorithm in Objective-C: gorbster.net