Creating a nicely coded level select screen - actionscript-3

Currently developing my first full flash game, and I'm now implementing multiple levels, which means I have to make a level select screen. I have no problem with actually accomplishing this, but the only way I know how to do this would be to make a different level select screen available every time somebody passed a new level (ie, after passing level 2, now there are 2 buttons available, for level 1 and 2 instead of just level 1).
Of course, this is highly inefficient. I want to be able to do this for all my levels in one go. I already know in advance that I will be having 9 levels, so a 3x3 grid system of buttons is possible (maybe using 2 for loops, for x and y position?).
Navigating between level select and other pages is no problem, I should be able to do that. My real problem is creating the actual level select screen to display different amounts of clickable buttons depending on how far one has progressed in the game. I mean I'm guessing I just create some boolean values for the user, and once a level is passed I change those booleans to true, then link the boolean to creating a button instead of a static text field. Then would I just position each button individually on the level select screen? If somebody could shed some light ( and by light I mean code =p ) about how to accomplish making this type of level select screen, it would be greatly appreciated, particularly the part about adding the buttons to the stage vs. the textfields.
Also, is it a waste to create 9 different buttons? It would be nice to just create 1 button and then just change the text field on them to display the level number. Can I accomplish this using a dynamic text field and just altering the text in that text field?

Basically yes, you can do whatever you see fit, just prepare for all of this. This is mostly architecture question than actual programming question. About progress, you can either track the highest available level and only display those that are available, or display level progress (say one level was complete with 1 star, the other with 2 stars, and you make buttons with stars on them), etc. Also, you might look at say Angry Birds level selector, it has 15 buttons, why could you not make 9?
About how to add a custom button to stage - first, it's better if you wrap the whole level selector into a Sprite, write AS3 code for it having level buttons placed at specific coordinates, a close button (aka "no I want to review other options before selecting level" one), other data like a text field with level name, etc etc, whatever you see fit. An example (with only level buttons, mostly in pseudocode):
public class LevelSelector extends Sprite {
private static const thumbnailClasses:Array=[Level01Bitmap,Level02Bitmap,...];
// embed these
private var gridXOffset:Number=60;
private var gridYOffset:Number=60;
private var gridXDimension:int=3; // how many buttons in row
private var gridXBase:Number=30;
private var gridYBase:Number=10;
// other initialized data
private var buttons:Vector.<LevelButton>; // buttons stored here
public function LevelSelector() {
buttons=new Vector.<LevelButton>();
// other initialization
for (var i:int=0;i<thumbnailClasses.length;i++) {
var b:LevelButton=new LevelButton();
b.x=(i%gridXDimension)*gridXOffset+gridXBase;
b.y=Math.floor(i/gridXDimension)*gridYOffset+gridYBase;
b.picture=(new thumbnailClasses[i]()).bitmapData;
// assuming thumbnails are embedded bitmap class names
addChild(b);
b.enabled=levelIsAvailable(i); // query level availability
b.stars=getLevelPerformance(i); // query how many stars to draw
b.addEventListener(MouseEvent.CLICK,buttonPressed); // listen for mouse
buttons.push(b);
}
}
private function buttonPressed(e:MouseEvent):void {
var level:int=buttons.indexOf(e.target);
var b:LevelButton=e.target; // if need to do something with the button
// query correctness and navigate to level screen
}
}

It sounds like you need to break the problem down into smaller steps. I'm not sure if you're using the Flash timeline or external .as Classes. I'd recommend using Classes as you can be much more flexible about what you display on screen. If you're not used to using Classes, the following probably won't make much sense...
In your main Document.as Class you could keep track of which levels the player has completed (perhaps in an Array of Boolean values corresponding to the level numbers). When a LevelSelect page is needed, make a new LevelSelect page and pass the _levelsCompleted Array as a parameter. The passed array can be used by the LevelSelect Class instance to determine how many LevelButtons are needed. Loop through the passed Boolean array and if an index value is true, add a LevelButton. Each LevelButton could be passed its level number (the loop counter) which could be used in its TextField to identify it (remember Array indexes are zero indexed, so level '1' might actually be '0').
If this doesn't make any sense, let me know.

Related

Cocos2d-x 3 - Disable collision between two bodies and detect when them separate each other

I'm developing a cocos2d-x game (version 3.8). My game uses chipmunk physics and it has a static body that works like an interruptor. This interruptor is enabled when another body is over it. The interruptor is disabled when bodies separate each other.
I want to:
Moving body don't collision with interruptor. It has to cross interruptor with no bounce
I want to detect when moving body separates the interruptor
My first approach was implementing onContactBegin method. I return false when those two bodies get in touch. This way the body crosses the interruptor and does not bounce.
The problem is onContactSeparate method is not called, because contact did not happen.
If I return true in onContactBegin method, onContactSeparate is called and I can detect it. The problem is the body does not cross the interruptor, it bounces.
[EDIT] More info
This is the scenario where two sprites are separated. The ball can move and interruptor is a static body. Ball could be over the interruptor.
This is the scenario where two sprites are in contact and object1 (the ball) is over the interruptor. I want to detect where two sprites separate each other.
Any help would be appreciated!
It seems to me like you are using Box2D within cocos, so I'll answer with that as my base assumption.
This is what i would do.
My interrupter would be a b2Body* with no BodyDef dimensions defined or just a 0x0 dimension def.
I would set the user data for the bodyDef to a rectangle that describes my interruption area. This way you can always have your interruption area represented, but will not collide with anything.
(Optional) If you want the interruption area to move around based on the fake body you assigned to it, you can updated it just after the step function using something like below.
world->Step(delta, 10, 10);
for (auto physicsBody = _world->GetBodyList(); physicsBody; physicsBody = physicsBody->GetNext())
{
auto userData = static_cast<Node*>(physicsBody->GetUserData());
if(userData != NULL)
{
// Set interruptor area rectangle = physicsBody->GetPosition();
}
}
To let the rest of the system know when I have left the interrupter I would store a function pointer to the function I want to call when this happens, When a object enters the interruption area I would flag it saying "I'm in the area" after that, the first update step you get when it's not in the area anymore I would fire the callback and reset the flags I used to get to that point.
I hope this helps. You are not giving a lot of context for what you want to do, an image would be helpful. Especially when it comes to looking for help with code that has a visual representation as well.
[EDIT]
Based on the behaviour you want this is the way I did this. The first thing to know is that you don't need physics collisions for the behaviour you want. You can do this by using bounding box intersection tests and use flags and callbacks to figure out the rest.
I have an object that knows about both the ball and my interrupter nodes. In the update loop of this object I check if the two intersects. I set a flag indicating "I am in the interrupter", the next frame that I am not in the interrupter and my flag is still true I call the function that I assigned with my "leaving logic" in it, and set then flag back to false.

Make a turn based system like final fantasy tactics AS3

i wanted to make a turn based system like final fantasy tactics. I already created the map, which is 5x5 tiles grid and the characters which is each character places in the end of the tiles. I have 2 teams, which are named Red and Yellow.
------Red-------:
First character is at 0,0. Second character is at 0,1. Third character is at0.2, fourth character is at0.3, and the last one is at0.4`.
-----Yellow------:
First character is at 5.0. Second character is at 5.1. Third character is at 5.2, fourth character is at 5.3, and the last one is at 5.4.
I wanted Red team are moving first and make a decision (whether it is attack or wait), and after 5 characters of the Red team is already made a decision, the Yellow team is the one that make a decision (Yellow team is an AI)
But, i don't know how to move my characters into the next grid (e.g: from 0,0 to 0,1) by clicking the left mouse button and also how do i display a grid (when select a move selection) that shows how many tiles that the character able to move.
Anyone know about this? or how should i know more about this? is there any recommendations books or webs?
You have your basic data structures set up, but now you need to get some higher level code to manipulate that data.
First of all, I think you should work on selecting locations on the grid with the mouse. Once you can click and get that grid coordinate saved to a variable, you need to set up a function to move your characters. After the first click (on a character), you need to check the valid moves, and for each valid move, you need to render an image on the grid square (or highlight the square's texture).
Secondly, you need a function which iterates through all the characters in each team, according to who moves next. When you have gone through Red.length (red is an array consisting of each player), then you switch to counting through Yellow.length, and running the AI for each character. If you are trying to make a two player game, you instead ask for user input a second time for the yellow team.
I recommend that you learn about how to display your grid and set up a simple way to highlight squares on the grid. After that, you need to convert mouse coordinates into grid coordinates. Your teams should each be an array of characters. I'm not familiar with actionscript, but in the languages I know, they would look like this:
team[6] = {Character1, Character2, Character3... }
Character1.position = {x, y}
running a turn would be something like this:
while battle == not finished {
for (i = 0; i < red.length; i++) {
getInput();
move(red[i], newX, newY); //red[i].position = {newX, newY}
}
for (i = 0; i < yellow.length; i++) {
runAI();
move(yellow[i], newX, newY);
}
}
The hardest part will be the mouse selection and drawing the grid/characters. Graphics are always a nuisance. The data itself just takes a bit of thinking. Your question in particular seems to be about game programming. My advice is to make the grid, then figure out how to display the grid. Then get mouse input. Finally, worry about moving the characters and highlighting squares.

Bring an object to the front, while keeping same child indexes on the parent. AS3/FLEX

When we click on an image it should come in front as the selected image, but I dont want to change the index value of that image
canvas1.setChilIndex(Image(event.target), numChildern-1)
The above line is changing the index value of the selected image and setting it to maximum-1 (for ex: 5-1 = 4 as index value). I Need alternate for above line that keeps the same index for the image.
Any help is appreciated.
What you can do, is in your click handler store the index of the item clicked, then on the next click (or whenever you want), send the item back to its previous index:
var previousImg:Image;
var previousIndex:int;
function selectImage(img:Image):void {
deselectImage(); //if there is already a selected image, put it back before moving this new one to the top
previousImg = img;
previousIndex = canvas1.getChildIndex(img);
canvas1.addChild(img); //brings it to the front
}
function deselectImage():void {
if(previousImg){
canvas1.setChildIndex(previousImage, previousIndex);
previousImg = null; //null the var in case you call this method manually
}
}
so in your click handler, do this instead of the line you have in your question:
selectImage(Image(event.target));
With this method, anytime you call selectImage, it will put the last click one back where it belongs. You could also call deselectImage manually if you so desired.
It is impossible, because in flash child index is the only criterion of drawing order.
If you want to hold the order of adding images, you can store images, for example, in array, then every next item will have index in order of adding.
When I see your question, I have the same ideas that LondonDrugs and Roman suggested above. However, your question is quite simple, so the answer is not possible.
The situation is quite complicated if I don't know the flow of the application.
For example, if you will add image to your canvas at the run time after you selected an image then which order of index you would like to roll back?
My suggestion:
You can set a cut point that you want to keep the order of index, then use a loop to find the index of all the image and keep it in an array. When the user finished playing, roll the index back to the cut point.

Generalizing instance name in ActionScript3

Imagine there is a situation : I have 100 movieclips with instance names : MC1a, MC2a, MC3a .. MC100a
and i want all of them to be invisible is there any other way than :
MC1a.visible = false; ... MC100a.visible = false;
because in this way the code gets very heavy and i thinks it's not the right way. so i was thinking is there any possible way to be something like that :
MC*a.visible = false;
all the movieclips that contains 'MC' in the begging and 'a' and the ending to disappear ? maybe something with array ?
If the parent of all these movieclips is called container you can do :
container["MC"+i+"a"].visible=false
This is due to the script nature of ActionScript.
For your particular case you can do
for(i=0;i<100;i++){
container["MC"+i+"a"].visible=false;
}
If you don't have all number between 0 and 100 you can do something like this :
for each(MovieClip mc in container){
name=mc.name;
if(name.substring(0,2)=="MC" && name.substring(-1)=="a"){
mc.visible=false;
}
}
(This is non tested pseudocode written on the fly)
There are several ways you can achieve this. First - make a Sprite container, which will be their common parent, then alter its visibility. This is not a flexible way, for example, if your movie clips are located on two different areas of stage, and need to interact somehow, you might be unable to put them all under a single parent in your display list. The second way is to make an array out of those 100 movie clips at the time of their instantiation (if possible, of course), then you iterate through the array and assign their visibility in a loop.
Basically, if you have some objects that should form a structure, consider linking them somehow first, then altering their visibility or other parameters all together. Should you need to move them all at once, or hide, the container approach will be better. Should you need them to perform similar, but not exactly same actions (say you have monsters as movie clips, and you need them to move together, but each with their own direction and speed), you should have an array.
Another thing to consider, if there is a movie clip that has a name like "MCbig_a", that is, complies with your condition, but does not exactly belong to the group of MCs you desire to make invisible, you will have to take precautions about such occurrences.
Assuming that al children are added in the same container called myContainer
var container:MovieClip = myContainer;
var i:uint = container.numChildren;
while (i--)
{
var child:* = container.getChildAt(i);
child.visible = false;
}

AdvancedDataGrid : Conditionally change the icon of the leaf node

Introduction: I have a flat ArrayCollection of object's, which i group to create the dataProvider for an AdvancedDataGrid. In this AdvancedDataGrid i have different branches representing different type of tasks. I want to conditionally change the icon for the leaf nodes in the AdvancedDataGrid based on a date field stored in each object.
For this purpose lets say each Task object contains an id and an updatedDate (Representing when the task was last updated). If the task has not been updated in the last five days (updatedDate+5 < today) the icon of that leaf node(Task) should be red, in constrast to the opposite the leaf icon in the AdvancedDatagrid should be green, e.g. like the image below. In this case task 35 has not been updated in the last 5 days, while 13 and 39 have.
Question: How do i change the leaf icons in the ADG based on the updatedDate of the underlying object? I would think that i have to extend AdvancedDataGrid and override some method, but which and how? Any type of guidance for achieving this particular task is much appriciated!
I have seen easy ways of changing the open and closed icons on the web, but no way of conditionally changing an open node's icon :)
Update: After applying #takteek groupIconFunction solution which always returned the same icon:
The problem is that I need the leaf node's icons changed, and not the branches.
SOLVED: Used #takteek's answer, with the exception of using iconFunction instead of groupIconFunction, because i wanted to change the leaf node's icons, and not the groupIcons :)
Your two options are:
Specify agroupIconFunction for the data grid. This gets passed the current item and you return which icon to use, or null to use the default.
Create a subclass of AdvancedDataGrid and override makeListData. This function is responsible for creating the AdvancedDataGridListData object that gets passed to the renderers. You can change the icon and disclosureIcon properties on the list data to what you want. This is probably unnecessary unless you need more control.
Create your own item renderer based on AdvancedDataGridGroupItemRenderer.