Background color in flex DataChooser - actionscript-3

I'm trying to change the background color for specific dates in DataChooser. More specifically , 10 and 20 must have a different color. Here is my code, that I took this question (I cannot add comments there still):
public class FancyDateChooser extends DateChooser {
public var highlightColor : Number = 0xff0000;
public var highlightDate : Array = ["10","20"];
public function FancyDateChooser() {
super();
}
protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
var dateGrid : UIComponent = mx_internal::dateGrid;
for ( var i: int = 0; i < dateGrid.numChildren; i++ ) {
if (dateGrid.getChildAt( i ) is IUITextField) {
var textField:UITextField = dateGrid.getChildAt(i) as UITextField;
for (var j:int = 0; j<highlightDate.length; j++) {
if ( textField.text == highlightDate[j] ) {
textField.backgroundColor = highlightColor;
}
}
}
}
}
}
It is entering the updateDisplayList method perfectly , but the background color does not change.
I have to use the updateDisplayList or invalidateDisplayList parent methods to work? I do not know how to use these methods .
Thank you.

Related

Removing an Object when it hits another object AS3

Beginner here. I have a symbol on the timeline with an instance name of 'island', so basically I want to remove the cells that hits the 'island'
if (cell.hitTestObject (island)) {
if(stage.contains(cell))
removeChild (cell);
}
I tried this one under the moveCell function but it only removes one cell instead of every cell that hits the island. Thanks everyone!
Here's my code so far:
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Main extends MovieClip {
public var cell:Cell;
public var group:Array;
public var gameTimer:Timer;
public function Main() {
cell = new Cell (400, -15);
addChild (cell);
group = new Array();
var newCell = new Cell (100, -15);
group.push ( newCell);
addChild(newCell);
gameTimer = new Timer (25);
gameTimer.addEventListener(TimerEvent.TIMER,moveCell);
gameTimer.start();
}
public function moveCell (timerEvent:TimerEvent):void {
if (Math.random() < 0.01) {
var randomX:Number = Math.random() * 700;
var newCell:Cell = new Cell (randomX, -15);
group.push (newCell);
addChild(newCell);
}
for each(var i:MovieClip in group) {
if (i.hitTestObject(island)) {
i.visible = false;
//i.parent.removeChild(i);
var score:int = 0;
score ++;
scoreOutPut.text = score.toString();
}
}
}
}
}`
You got the "Cannot access a property or method of a null object reference" because you've removed the Cell object from the DisplayObjectContainer (its parent) but not from the group array, so in the next iteration of your for loop, that object didn't exist anymore and that error will be fired.
To avoid that you can do like this :
for(var i:int = 0; i < group.length; i++)
{
var cell:Cell = Cell(group[i]);
if (cell.hitTestObject(island))
{
cell.parent.removeChild(cell);
group.splice(i, 1);
score++;
}
}
For the score, it should be a global property for all your class to get updated every time.
Also, for your code to be more organised and clearer, it's better to put every task in a single method.
For example, for creating cells, you can use a createCell() method :
// 0 is the default value of __x and -15 is the default one of __y
private function createCell(__x:Number = 0, __y:Number = -15): void
{
var cell:Cell = new Cell(__x, __y);
group.push(cell);
addChild(cell);
}
Then you can use it in any place in your code, for example, for your two first cells that you create in the constructor :
public function Main()
{
// ..
createCell(400);
createCell(100);
// ...
}
Or inside the moveCell() method :
if (Math.random() < 0.01)
{
var randomX:Number = Math.random() * 700;
createCell(randomX);
}
Also, if you don't really need that a property or a method to be public, don't put it as public.
...
Hope that can help.

How to create a table of elements with different content

How do i create a 3x3 table (in tabular form) and every cell has a different image.
But i want to create the cell and then in it add the picture of the icon, not make the icon an movieClip and directly adding it after that.
I`m trying to have 3 rows :
1st row will be Time1 ,Time2 ,Time3.
2nd row Turbo1 ,Turbo2 ,Turbo3
3rd row will be something like Speed1, Speed2, Speed3 .
Something like the picture below.
(in blue are the names of the bitmaps/movieClips/names of the pictures I am using for every icon)
i was thinking of doing it like this
private var testArr:Array = new Array();
public function MainClass()
{
for(var i:int=0; i<3; i++)
{
testArr[i]= new Array();
for(var j:int = 0 ; j<3 ; j++)
{
testArr[i][j] = new IconClass();
this.addChild(testArr[i][j]);
testArr[i][j].x=testArr[i][j].width*j + j*10;
testArr[i][j].y=testArr[i][j].height*i + i*10;
testArr[i][j].addEventListener(MouseEvent.CLICK, somethingFancy );
}
}
}
and on new IconClass(); i would pass the image that it needs to have. But! how would it be done ??
So as discussed there are a couple of useful designs. For handling the different images for different states I would create an Icon class that is a display object that handles what images to load for the different states.
That would look something like:
package
{
import flash.display.Sprite;
public class icon extends Sprite
{
private var _images:Vector.<Object>;
public var isEnabled:Boolean;
public function icon() {
_images = new Vector.<Object>();
}
//in this functions all the images you need for different states
private function addImage( state:String, bitmap:Bitmap ):void {
_images.push( { state:state, image:bitmap } );
}
//change the image of the sprite, based on the state ( i.e. - mouseOver, mouseOut )
public function changeState( state:String ):void {
var i:int;
state = isActive ? "enabled" + state : "disabled" + state;
for ( ; i < _images.length; i++ ) {
if ( _images[i].state == state ) {
updateImage( _images[i].image );
}
}
}
private function updateImage( bitmap:Bitmap ):void {
//do image changing here to new bitmap
}
}
}
And what is happening here is the icon class will have a vector of objects that associate the correct bitmap to the correct state. Now how that would be setup in your table might look something like this:
private var _iconList:Vector.<icon>;
public function MainClass():void {
createSprites();
_iconList = new Vector.<icon>();
var rows :int = 3,
columns :int = 3,
startX :int = 0, //set to some x coordinate
startY :int = 0, //set to some y coordinate
padding :int = 5,
i :int,
j :int,
currentIndex:int;
for ( i = 0; i < rows; i++ ) {
for ( j = 0; j < columns; j++ ) {
_iconList[currentIndex].x = startX + i * ( _iconList[currentIndex].width + padding );
_iconList[currentIndex].y = startY + j * ( _iconList[currentIndex].height + padding );
_iconList[currentIndex].addEventListener( MouseEvent.MOUSE_OVER, onMouseOver );
_iconList[currentIndex].addEventListener( MouseEvent.MOUSE_OUT, onMouseOut );
addChild( _iconList[currentIndex] );
currentIndex++;
}
}
}
private function createIcons():void {
var i:int;
for ( ; i < 9; i++ ) {
var ic:icon = new icon();
ic.addImage( "disabledMouseOver", "yourImageGetter()" ); //you're using a getAtlas() to a bitmap
ic.addImage( "disabledMouseOut", "yourImageGetter()" );
ic.addImage( "enabledMouseOver", "yourImageGetter()" );
ic.addImage( "enabledMouseOut", "yourImageGetter()" );
_iconList.push( ic );
}
}
private function onMouseOver( e:MouseEvent ):void {
var ic:icon = e.target as icon;
ic.changeState( "MouseOver" );
}
private function onMouseOut( e:MouseEvent ):void {
var ic:icon = e.target as icon;
ic.changeState( "MouseOut" );
}
So what's happening here:
We create an icon class that has storage for the different bitmap images and different states to associate them with
In our main class, we do createIcons() which makes new icons and adds the different images for the different states
Then we create our table with the list of icons in _iconList and add the mouse event listeners to each of them.
The listeners onMouseOver and onMouseOut call the targeted icon changeState() which will then handle the correct image to switch between.
Edit:
The isEnabled boolean is going to be used at your discretion ( as discussed in chat ) from another view to control icons that are enabled for the user and which MOUSE_OVER and MOUSE_OUT states to use.
private var iconArr:Array = new Array();
private var testArr:Array = new Array();
public function MainClass()
{
iconArr.push(
[
"time1",
"time2",
"time3"
],
[
"turbo1",
"turbo2",
"turbo3"
],
[
"speed1",
"speed2",
"speed3"
]
);
for(var i:int=0; i<3; i++)
{
testArr[i]= new Array();
for(var j:int = 0 ; j<3 ; j++)
{
//pass in a string, the icon will change depending on that string
testArr[i][j] = new IconClass(iconArr[i][j]);
this.addChild(testArr[i][j]);
testArr[i][j].x=testArr[i][j].width*j + j*10;
testArr[i][j].y=testArr[i][j].height*i + i*10;
testArr[i][j].addEventListener(MouseEvent.CLICK, somethingFancy );
}
}
}
May not fit your needs, in which case you should edit it.

getChildByName loop inside mc

I'm trying to get the getChildByName work by loop inside movieclip.
On library i have a movieclip called PlayScreen, inside PlayScreen i have another movieclip called Bg. PlayScreen is put on stage by MainClass (class document) and PlayScreen is link to MainRun class. Bg movieclip is manually added to the PlayScreen by dragging it in from the library.
here is my MainRun class.
public class MainRun extends MovieClip
{
public var flyClone:Array;
public var newFly:Fly_MC;
public var spX:Number = 550;
public var spY:Number = 400;
public function MainRun()
{
flyClone = new Array();
for(var i:int=0; i<10; i++)
{
newFly = new Fly_MC(Math.random()* spX, Math.random()* spY);
flyClone.push(newFly);
addChild(newFly);
newFly.name = "fly_" + i;
}
//...
bla();
}
and here i couldn't make the getChildByName work properly, and it return; Error #1009: Cannot access a property or method of a null object reference.
at MainRun/bla()
public function bla():void
{
for(var j:int=0; j< numChildren; j++)
{
getChildByName("fly_" + j).addEventListener(Event.ENTER_FRAME, randomMove);
//...
}
}
any suggestion?
name property of your MovieClip object must is a String value, but you are putting an int there.
Try adding String(j);
It's better to use your flyClone array instead of just getting objects by it's name.
Image what will happen if you add anything else to the DisplayList (addChild).
for(var j:int=0; j< flyClone.length; j++)
{
flyClone[j].addEventListener(...);
}
I am almost positive you have a child that is not a fly.
public function bla():void
{
for(var j:int=0; j< numChildren; j++)
{
var fly : Fly_MC = getChildByName("fly_" + j) as Fly_MC;
if( fly )
{
fly.addEventListener(Event.ENTER_FRAME, randomMove);
}
}
}
Why don't you just:
for each( var fly : Fly_MC in flyClone )
{
fly.addEventListener(Event.ENTER_FRAME, randomMove);
}
or better
addEventListener(Event.ENTER_FRAME, randomMoveFlies);
public function randomMoveFlies( e:Event ):void
{
for each( var fly : Fly_MC in flyClone )
{
//move flies;
}
}
for(var j:int=0; j< flyClone.length; j++)
{
(flyClone[j] as MovieClip).addEventListener(Event.ENTER_FRAME, randomMove);
}

How to make new bubbles stack in my Bubble Shooter game?

I'm making a Bubble Shooter game, and I'm trying to make the bubble I'm fireing to stack and then be at the right place in the column. The bubbles I've placed on the board looks like this:
000000000000000
000000000000000
000000000000000
000000000000000
There's 4 rows with 15 bubbles. This is the code I have written so far:
Main
package {
import flash.display.Sprite;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.display.SpreadMethod;
public class Main extends Sprite {
private const ROT_SPEED:uint=2;
private const R:uint=18;
private const DEG_TO_RAD:Number=0.0174532925;
private const BUBBLE_SPEED:uint=10;
private var bubbleArr:Array=new Array();
private var loadArr:Array=new Array();
private var cannon:cannon_mc;
private var bubble:bubble_mc;
private var row:uint=0;
private var col:uint=0;
private var left:Boolean=false;
private var right:Boolean=false;
public var bubCont:Sprite;
private var loadCont:Sprite;
private var fire:Boolean=false;
private var vx,vy:Number;
public function Main() {
placeContainer();
placeCannon();
loadBubble();
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKDown);
stage.addEventListener(KeyboardEvent.KEY_UP,onKUp);
addEventListener(Event.ENTER_FRAME,onEFrame);
trace("row= "+row+" , col= "+col);
}
private function placeCannon():void {
cannon=new cannon_mc();
addChild(cannon);
cannon.y=385.5;
cannon.x=320;
}
private function onKDown(e:KeyboardEvent):void {
switch(e.keyCode) {
case 37 :
left=true;
break;
case 39 :
right=true;
break;
case 38 :
if (! fire) {
fire=true;
var radians=(cannon.rotation-90)*DEG_TO_RAD;
vx=BUBBLE_SPEED*Math.cos(radians);
vy=BUBBLE_SPEED*Math.sin(radians);
}
break;
}
}
private function onKUp(e:KeyboardEvent):void {
switch(e.keyCode) {
case 37 :
left=false;
break;
case 39 :
right=false;
break;
}
}
private function onEFrame(e:Event):void {
if (left) {
cannon.rotation-=ROT_SPEED;
}
if (right) {
cannon.rotation+=ROT_SPEED;
}
if (fire) {
bubble.x+=vx;
bubble.y+=vy;
if (bubble.x<59) {
bubble.x=59;
vx*=-1;
}
if (bubble.x>(59+R*R)) {
bubble.x=59+R*R;
vx*=-1;
}
if (bubble.y<(40)) {
bubble.y=40;
}
}
}
public function placeContainer():void {
var iRow:Boolean=false;
bubCont=new Sprite();
addChild(bubCont);
for (var i:uint=0; i<4; i++) {
if (! iRow) {
for (var j:uint=0; j<15; j++) {
bubbleArr[i]=new Array();
bubbleArr[i][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i][j],i,j);
bubCont.addChild(bubble);
iRow=true;
row++;
col++;
}
} else {
for (j=0; j<15; j++) {
bubbleArr[i]=new Array();
bubbleArr[i][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i][j],i,j);
bubble.x=77+j*2*R;
bubCont.addChild(bubble);
iRow=false;
row++;
col++;
}
}
}
}
private function loadBubble():void {
addChild(bubble);
bubble.gotoAndStop(Math.floor(Math.random()*6))+1;
bubble.x=320;
bubble.y=410;
}
}
bubble_mc class:
package {
import flash.display.MovieClip;
public class bubble_mc extends MovieClip {
public function bubble_mc(val:uint,row:uint,col:uint) {
gotoAndStop(val+1);
name=row+"_"+col;
x=59+col*36;
y=40+row*32;
}
}
I have absolutley no idea how to make the bubbles stack together.. I have tried using hitTestObject-function and I have tried to write my own function that checks for collision and then calls a function that is supposed to place the bubble in the right place, but it doesn't work and I dont know why. I'm getting a error called TypeError: Error #1010.
Here is the collision function and the parkBubble function- which is supposed to place the bubbles in the right place:
private function parkBubble(bubble:bubble_mc,row:int,col:int):void {
var iRow:Boolean=false;
for (var j:uint=0; j<col; j++) {
trace("first for loop ");
for (var i:uint=row; i>0; i--) {
trace("second for loop ");
if (bubbleArr[i][j]!=null) {
trace("first if loop ");
if (! iRow) {
trace("second if loop ");
bubbleArr[i+1]=new Array();
bubbleArr[i+1][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i+1][j],(i+1),j);
bubCont.addChild(bubble);
iRow=true;
row++;
col++;
} else {
trace("first for loop after else ");
bubbleArr[i+1]=new Array();
bubbleArr[i+1][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i+1][j],(i+1),j);
bubble.x=77+j*2*R;
bubCont.addChild(bubble);
iRow=false;
row++;
col++;
}
}
}
}
removeChild(bubble);
fire=false;
loadBubble();
trace("slutet av parkBubble ");
}
private function collide(bub:bubble_mc):Boolean {
var dist_x:Number=bub.x-bubble.x;
var dist_y:Number=bub.y-bubble.y;
return Math.sqrt(dist_x*dist_x+dist_y*dist_y)<=2*R-4;
}
Was the TypeError on this line?
var placed_bubble:bubble_mc=new bubble_mc([row][col],row,col);
The [row] is an array, and [col] is an array. But the constructor expects an unsigned integer:
public function bubble_mc(val:uint,row:uint,col:uint) {
In order to copy the bubble to the bubble container, pass the frame number:
var placed_bubble:bubble_mc=new bubble_mc(bubble.currentFrame-1, row, col);
This might not be the only problem. TypeError often results from a variable not being defined, which could be from some other code that modifies the variable "bubble". For example, placeContainer assigns the bubbles in the container to the variable "bubble".
The function parkBubble always sets "iRow" to false, but if the bubble collides with a row above it that is odd you want iRow to be true.
var row:uint=Math.floor(bubble.y/(40+R*Math.sqrt(3)));
var iRow:Boolean= row % 2 == 1 ? true : false;
After it is at least compiling, you'll have less problems if you go back and simplify and optimize the math with some constant names. Then you'll more easily see the above code for calculating the row is not quite right. It should subtract the top margin (40). That is obvious with named constants:
private const Y_PER_ROW:int = int(R * Math.sqrt(3));
private const TOP:int = 40;
...
var row:uint = int((bubble.y - TOP) / Y_PER_ROW);
I would double-check your other calculations, too. Puzzle Bobble games usually set the odd rows to horizontally offset at radius, not at 2 radius (2 * R). So they fit together like hexagons.
The placeContainer function could be simplified. Most of the code in even or odd rows is the same, so could be taken out of the if block. And in this code you posted, I don't see why you need "row++" and "col++" in placeContainer. This is equivalent and easier to read:
for (var i:uint=0; i<4; i++) {
var xOffset:int = (i % 2) * 2 * R;
for (var j:uint=0; j<15; j++) {
bubbleArr[i] = new Array();
bubbleArr[i][j] = int(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i][j], i, j);
bubble.x += xOffset;
bubCont.addChild(bubble);
row++;
col++;
}
}
Then, the collision detection code could be simplified and optimized to avoid calculations when the bubble is far away and avoid the expensive square-root calculation:
Circle Collision Detection HTML5 Canvas
http://cgp.wikidot.com/circle-to-circle-collision-detection

AS3 hitTestPoint always returns false for one function

I have a movieclip I drawn, called Map. It has a child with the name Wall. I'm trying to make a function that returns a 2d tile array of if there is something in that tile or not, for pathfinding.
The problem is, levelGrid is entirely false. I'm not sure what I am doing wrong.
I have filled the whole movieclip (Wall) with bright red, and yes it still returns false.
The x and y of both Map and Wall is 0, so I don't think there should be issues with hitTestPoint accepting global x / y.
They are added to a display list.
My other movement hittest works fine.
My code:
public function levelMap() {
for (var i = 0; i < height / 25; i++) {
levelGrid[i] = [];
for (var j = 0; j < width / 25; j++) {
levelGrid[i][j] = this.getChildByName("Wall").hitTestPoint(j*25,i*25,true);
}
}
trace(levelGrid);
}
Thanks in advance (levelGrid is a class variable)
I made a visual test out of your code. I did not change any functionality though so I think your problem is your graphics. Check the width, height och positions of the graphics. If you dont get anything in the Array, then maybe those values are not set correctly.
Each dot represent a hitTestPoint in this test. If its green you have a hit (true return value). Red means no hit. Hope this helps.
TestHitPoint.as
package
{
import flash.display.Sprite;
public class TestHitPoint extends Sprite
{
private static const TILE_SIZE : int = 25;
private var levelGrid : Array;
public function TestHitPoint()
{
// add graphics to test
addChild( new WallGraphics() );
// fix array
levelGrid = new Array();
// loop
for (var i : int = 0; i < height / TILE_SIZE; i++)
{
levelGrid[i] = [];
for (var j : int = 0; j < width / TILE_SIZE; j++)
{
var success : Boolean = this.getChildByName("Wall").hitTestPoint(j*TILE_SIZE, i*TILE_SIZE, true);
levelGrid[i][j] = success;
addChild( new PositionMarker(j*TILE_SIZE, i*TILE_SIZE, success) );
}
}
}
public function levelMap() : void
{
}
}
}
import flash.display.Sprite;
internal class WallGraphics extends Sprite
{
public function WallGraphics()
{
name = "Wall";
with(graphics)
{
beginFill(0x0000FF, 1);
drawRect(100, 50, 60, 200);
drawRect(50, 100, 200, 50);
endFill();
}
}
}
internal class PositionMarker extends Sprite
{
public function PositionMarker(posX : Number, posY : Number, success : Boolean)
{
with(graphics)
{
beginFill((success) ? 0x00FF00 : 0xFF0000, 1);
drawCircle(posX, posY, 4);
endFill();
}
}
}
Output: