Create a Dynamic Grid of Animated Buttons in AS3 [closed] - arrays

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm new to Flash and intermediate in HTML/CSS. I would like to create a grid of buttons that when you hover over them, they change color and show a linkable caption/tooltip on hover. I would also like this to be dynamic as possible as I will need a grid of 2000+ buttons/squares that may have to be updated from time to time.
Here is an example created with HTML/CSS and some JS
//<![CDATA[
$(window).load(function(){
// Create the tooltips only when document ready
$(document).ready(function () {
// This will automatically grab the 'title' attribute and replace
// the regular browser tooltips for all <a> elements with a title attribute!
$('a[title]').qtip();
});
});//]]>
I need to know the best way to build this in flash, and would really appreciate a barebones breakdown of the code/AS. I am somewhat new to flash and this is just way above my head.
Thanks in advance.

Ok, so you want grid of small bitmaps/shapes on stage. I would recommend bitmaps since they work better when you want to transform something - but if the grid will be standing still, then you can use Sprite filled with color. Below you can find a snippet complete example. You can compile it using mxmlc compiler or using Flash Develop||FDT, or connecting this file as a document class in Flash IDE.
It's the most efficient way I can imagine. We have only one Sprite and we color some parts of it depending on where our mouse is. Hope this helps.
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
/**
* ...
* #author
*/
public class Main extends Sprite
{
private var color:int = 0xf2f2f2;
private var color1:int = 0xff000;//colors definition
private var size:int = 12;//size of our square
private var container:Sprite;//container definition
private var rows:int = 48;//number of rows
private var margin:int = 2;//margin on each side
private var count:int = 2000;//number of elements
private var totalspace:int = size + margin;
private var currentPoint:Point = new Point();
private var lastPoint:Point = null;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
container = new Sprite();//define squares container;
container.graphics.beginFill(color);//define fill color;
var posX:int;
var posY:int;
for ( var i:int = 0; i < count; i++) {
posX = int(i % rows) * totalspace;//calculate x axis position based on modulo
posY = int(i / rows) * totalspace;//calculate y axis position
container.graphics.drawRect( posX, posY, size, size );//call drawRect method on graphics object.
}
addChild(container);//add container to stage - meaning it will be visible, because flash is rendering it.
container.buttonMode = true;//set mouse to button mode
container.addEventListener( MouseEvent.MOUSE_MOVE, onMM );
container.addEventListener( MouseEvent.ROLL_OUT, onMO );
//add eventListener for mouse move - so each time you move a mouse over container object it will trigger an event.
}
private function onMO(e:MouseEvent):void
{
currentPoint = null;
}
private function onMM(e:MouseEvent):void
{
if ( lastPoint == currentPoint ) {
//if moouse is on the same square exit this function
return;
}
//calculate x and y position of square we need to color
currentPoint = new Point( int( container.mouseX/totalspace ) * totalspace, int(container.mouseY/totalspace) * totalspace );
container.graphics.beginFill( color1 );
container.graphics.drawRect( currentPoint.x, currentPoint.y, size, size );
if ( lastPoint ) {
//if last point is present, make it grey, as for roll out
container.graphics.beginFill( color );
container.graphics.drawRect( lastPoint.x, lastPoint.y, size, size );
}
lastPoint = currentPoint;
}
}
}

Related

Winforms pie chart legend text length affects label and chartarea size

I have the following ChartArea Annotation settings set up:
private void chart1_PrePaint(object sender, ChartPaintEventArgs e)
{
if (e.ChartElement is ChartArea)
{
var ta = new TextAnnotation();
ta.IsMultiline = true;
ta.Text = "Results of Calculation\n%";
ta.Width = e.Position.Width;
ta.Height = e.Position.Height;
ta.X = e.Position.X;
ta.Y = e.Position.Y;
ta.Font = new Font("Candara", e.Position.Height / 10, FontStyle.Regular);
chart1.Annotations.Add(ta);
}
}
A few issues with this, and with the Legend in relation to my other posted question:
My other Pie Chart Legend/ChartArea question
With this PrePaint setup, I'm not sure if my position is correct for the TextAnnotation. I'm using the e.Position but it's coming out not "exactly" centered in the middle of the doughnut of the pie chart area. I'd like it to be centered perfectly. Not sure what other property to use here.
A second issue is that when Legend text length changes, it "pushes" and makes the ChartArea itself smaller so the pie chart gets smaller. I'd like it to be the other way around, where the ChartArea pie chart stays the same size but the Legend gets pushes aside.
Is this possible?
The following is the position setup of the pie chart:
Thanks
I'm sorry I couldn't help more, last time. I tested the centering of the TextAnnotation and in fact it has problems when the InnerPlotPosition is set to auto. Moreover, the answer found at link creates a new instance of the TextAnnotation at every PrePaint, causing the overlapping of TextAnnotations and the blurrying of the centered text.
I couldn't find a way to avoid the resizing of the doughnut (I'm not sure it's even possible, at this point...I'll wait for some other answers) but maybe this can work out as a workaround.
First I created a dictionary to store the centered TextAnnotations references (the key is the graph name, in case you have more than one), then in the PrePaint event I get the correct reference of the TextAnnotation used in the graph and update the coordinates of that one.
Second, I set the InnerPlotPosition manually, this seems to solve the problem of the centering of the TextAnnotation. Of course, you need to specify coordinates and size for the InnerPlot like I did with the line:
chart1.ChartAreas[0].InnerPlotPosition = new ElementPosition(0, 0, 60.65f, 94.99f);
Lastly, I set the position and the size of the legend manually and, with the extension method WrapAt I set a "line break" every _maxLegendTextBeforeWrap in the legend items text. Couldn't find a way to make it dynamically change with the width of the legend area, so it has to be set manually.
Below there's a GIF of the resulting effect. Don't know if this suits you as a solution (too much tweaking and code, for my taste), but anyway. Maybe this can trigger some new ideas on how to solve.
To do so I created these global variables:
/// <summary>
/// Saves the currently doughnut centered annotations per graph.
/// </summary>
private IDictionary<string, TextAnnotation> _annotationsByGraph;
/// <summary>
/// Number of characters
/// </summary>
private int _maxLegendTextBeforeWrap = 10;
/// <summary>
/// Legend area width.
/// </summary>
private int _legendWidth = 20;
/// <summary>
/// Legend area height.
/// </summary>
private int _legendHeight = 90;
This is the handler of the Load event:
private void ChartTest_Load(object sender, EventArgs e)
{
// ** Start of test data **
chart1.Series["Series1"].Points.AddXY("A", 33);
chart1.Series["Series1"].Points[0].LegendText = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
chart1.Series["Series1"].Points.AddXY("B", 33);
chart1.Series["Series1"].Points[1].LegendText = "BBBBBBBBBBBBBBBBBBBB";
chart1.Series["Series1"].Points.AddXY("C", 34);
chart1.Series["Series1"].Points[2].LegendText = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
// ** End of test data **
// Creates a new instance of the dictionary storing the references to the annotations.
_annotationsByGraph = new Dictionary<string, TextAnnotation>();
// Createa a new instance of an annotation for the chart1 graph.
_annotationsByGraph.Add(chart1.Name, new TextAnnotation());
// Manually setting the position of the chart area prevents the imperfect positioning of the
// TextAnnotation at the center of the doughnut.
chart1.ChartAreas[0].Position.Auto = true;
// Manually set the position of the InnerPlotPosition area prevents the imperfect positioning of the
// TextAnnotation at the center of the doughnut.
chart1.ChartAreas[0].InnerPlotPosition.Auto = false;
chart1.ChartAreas[0].InnerPlotPosition = new ElementPosition(0, 0, 60.65f, 94.99f);
// Minimum size for the legend font.
chart1.Legends[0].AutoFitMinFontSize = 5;
// Set the legend style as column.
chart1.Legends[0].LegendStyle = LegendStyle.Column;
// Splits the legend texts with the space char every _maxLegendTextBeforeWrap characters.
chart1.Series["Series1"].Points.ToList().ForEach(p => p.LegendText = p.LegendText.WrapAt(_maxLegendTextBeforeWrap));
}
This is the handler of the PrePaint event:
private void chart1_PrePaint(object sender, ChartPaintEventArgs e)
{
if (e.ChartElement is ChartArea)
{
// Get the reference to the corresponding text annotation for this chart.
// We need this, otherwise we are creating and painting a new instance of a TextAnnotation
// at every PrePaint, with the resulting blurrying effect caused by the overlapping of the text.
var ta = _annotationsByGraph[e.Chart.Name];
// Check if the annotation has already been added to the chart.
if (!e.Chart.Annotations.Contains(ta))
e.Chart.Annotations.Add(ta);
// Set the properties of the centered TextAnnotation.
ta.IsMultiline = true;
ta.Text = "Results of Calculation\nx%";
ta.Font = new Font("Candara", e.Position.Height / 10, FontStyle.Regular);
ta.Width = e.Position.Width;
ta.Height = e.Position.Height;
ta.X = e.Position.X;
ta.Y = e.Position.Y;
// Move the legend manually to the right of the doughnut.
e.Chart.Legends[0].Position = new ElementPosition(e.Position.X + e.Position.Width, e.Position.Y, _legendWidth, _legendHeight);
}
}
This is what the button does:
private void BtnChangeLegendItemLength_Click(object sender, EventArgs e)
{
if (chart1.Series["Series1"].Points[1].LegendText.StartsWith("DD"))
chart1.Series["Series1"].Points[1].LegendText = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB".WrapAt(_maxLegendTextBeforeWrap);
else
chart1.Series["Series1"].Points[1].LegendText = "DDDDDD".WrapAt(_maxLegendTextBeforeWrap);
}
This is the extension method definition:
internal static class ExtensionMethods
{
public static string WrapAt(this string legendText, int maxLengthBeforeWrap)
{
if (legendText.Length <= maxLengthBeforeWrap)
return legendText;
// Integer division to get how many times we have to insert a space.
var times = legendText.Length / maxLengthBeforeWrap;
// Counter of added spaces.
var spacesAdded = 0;
// Iterate for each space char needed.
for (var i = 1; i <= times; i++)
{
// Insert a space char every maxLengthBeforeWrap positions.
legendText = legendText.Insert(maxLengthBeforeWrap * i + spacesAdded, new string(' ', 1));
spacesAdded++;
}
return legendText;
}
}

Positioning Array Content (Sprites)

I have Pictures with Numbers on it (I mean Sprites).
I got them on an Empty GameObject, I mean [SerializeField] and added through the script (C# Ofcourse), So the Objects are not really there they are being Generated when the Game begins.
So as you can see in the Code that I can set Row and Columns Amount and with Offset also distances in X and Y Axis. But I cannot re-position it. It seems that the first one being generated is locked to the middle of the project (the first one up-Left)So I tried to move the gizmo of the empty gameobject but the sprites are still on the spot even if I use the Inspector Instead. It seems that it would need to be positioned it in the script, But How?
Please give me enough Examples witch will work with Unity?
What I tried is to position it in Unity as I already mentioned with moving the Gizmo of the Gameobject and also in the Inspector It really seems that it can only be done on the script (I might be wrong but I tried everything).
public class Controll : MonoBehaviour
{
public const int gridRows = 6;
public const int gridCols = 6;
public const float offsetX = 0.65f;
public const float offsetY = 0.97f;
[SerializeField] private GameObject[] cardBack;
// Use this for initialization
void Start ()
{
for (int i = 0; i < gridRows; i++)
{
for (int j = 0; j < gridCols; j++)
{
Instantiate(cardBack[i], new Vector3(offsetY*j, offsetX* i *-1 , -0.1f), Quaternion.identity);
}
}
}
You are instantiating all objects into the Scene root level. They are in no way related to the GameObject which was originally responsible for the instantiation.
If you rather want them to be positioned relative to the spawning GameObject then use
var position = transform.position + new Vector3(offsetY * j, offsetX * i * -1, -0.1f);
Instantiate(cardBack[i], position, Quaternion.Identity, transform);
in order to instantiate them as child objects of the GameObject this Controll script is attched to.
Now if you translate, rotate or scale that parent object all instantiated objects are transformed along with it.

Place an Image scaled at the width available space

I created a code that works, but I'm not sure that it's the best way to place an Image scaled automatically to the available width space. I need to put some content over that image, so I have a LayeredLayout: in the first layer there is the Label created with the following code, on the second layer there is a BorderLayout that has the same size of the Image.
Is the following code fine or is it possible to do better?
Label background = new Label(" ", "NoMarginNoPadding") {
boolean onlyOneTime = false;
#Override
public void paint(Graphics g) {
int labelWidth = this.getWidth();
int labelHeight = labelWidth * bgImage.getHeight() / bgImage.getWidth();
this.setPreferredH(labelHeight);
if (!onlyOneTime) {
onlyOneTime = true;
this.getParent().revalidate();
}
super.paint(g);
}
};
background.getAllStyles().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
background.getAllStyles().setBgImage(bgImage);
Shorter code:
ScaleImageLabel sl = new ScaleImageLabel(bgImage);
sl.setUIID("Container");
You shouldn't override paint to set the preferred size. You should have overriden calcPreferredSize(). For ScaleImageLabel it's already set to the natural size of the image which should be pretty big.

how to show images from texture array like slide shows in unity

i have a scene in which after a particular time the slide show of
images should start.
i have created the texture array and loaded the images to array in
inspector.
now i need to slide each image after every two seconds.
this is the code i have done but it is error
public Texture[] Images;
void ChangeImage()
{
for(int i=1;i<Imagez.Length;i++)
{
print (Imagez [i].ToString());
Imag =Imagez [i];
}
}
i try to load each image from the array, but i know that its not the proper way..can any one please help
Add a scroll rect then add a panel for container and make that panel the scroll rect to control.
Then the container gets a Horizontal/VerticalLayoutGroup. Add all of your images and set the container size so they show properly.
Run the game, you should be able to scroll them appropriately (make sure you constrain the movement hor/vert so it moves correctly).
private int currentIndex = 0;
[SerializeField] private float imageSize;
[SerializeField] private RectTransform panel;
[SerializeField] private float frequency;
void Start()
{
InvokeRepeating("IncreaseCurrentIndex", frequency,frequency);
}
private void IncreaseCurrentIndex()
{
if(++this.currentIndex >= this.imageCount){ this.currentIndex = 0; }
}
void MoveToNextItem()
{
float targetX = (float)this.currentIndex * this.imageSize;
Vector2 delta = this.panel.anchoredPosition;
delta.x = Mathf.MoveTowards(delta.x, targetX, Time.deltaTime * speed);
this.panel.anchoredPosition = delta;
}
First you give the size of the image in the inspector. The panel is the container for all the images. I guess the rest is self explanatory.
The code is as simple as possible, it could benefit more flexibility but at least it should go as is.
NOTE: This is meant to be for horizontal scrolling. You would change the x for y in the update for vertical scrolling. Also, it uses Mathf.MoveTowards, you could use lerp instead of the velocity of scroll rect.

AS3- how to addchild this array(john) correctly

I do not know how to add the john array and make a hittestobject with it.
Bal is a different class non relevant to this problem.
I've tried to do john[new Bal]
tried john[ k ]
tried z and to specify z as a for-loop but then i would just get Z balls place.
This is supposed to become a space-invader type of game. I'm trying to make a hit test object between HENK and the 'falling balls' (JOHN). I do not know how to work with arrays especially given the fact that is should be timer-triggered.
Thanks
public class Main extends Sprite
{
public var henk:Sprite = new Sprite();
public var level:Timer = new Timer (2000, 0);
public var valTijd:Number = new Number
public var i:Number = 2000;
public var john:Array = new Array();
public var k:Number = 9000;
public function Main():void
{
henk.graphics.beginFill(0xFF00FF);
henk.graphics.drawCircle(0, 500, 20);
henk.graphics.endFill();
addChild(henk);
level.addEventListener(TimerEvent.TIMER, up);
level.start();
henk.addEventListener(Event.ENTER_FRAME, muis);
henk.addEventListener(Event.ENTER_FRAME, hit);
}
public function up(e:TimerEvent):void
{
var tijdje:Timer = new Timer( i, 0)
tijdje.addEventListener(TimerEvent.TIMER, tijdLuisteraar);
tijdje.start();
i = i - 250;
}
public function muis (e:Event):void
{
henk.x = mouseX;
}
public function hit (e:Event): void
{
if ( henk.hitTestObject(john [k] ))
{
if (contains(john[k] ))
{
removeChild(henk);
}
}
}
public function tijdLuisteraar(e:TimerEvent):void
{
john.push(new Bal);
addChild(john[k]);
}
}
}
welcome to stackoverflow!
This problem is actually fairly simple, I will describe how you will probably want to use an array in the case you described.
At the part where you create new Balls you want to append them to an array, which will be something like the following:
var ball = new Bal();
john.push(ball);
addChild(ball);
This will go inside your timer-triggered function, obviously.
Secondly, you want to have a hitTestObject with henk and all of the balls stored in the john array.
for(var i = 0; i < john.length; i++) {
if (henk.hitTestObject(john[i])) {
// well, that's a bummer for your player, henk hit one of the balls in the john array
// display something like a message here
}
}
This will automatically detect the size of the array, so all elements are tested. Be careful with hitTestObject when you have a lot of elements in the john-array, this can slow down your game drastically.
Furthermore, reflecting your code I suggest the following:
remove public var i:Number = 2000; and public var k:Number = 9000;, these have no meaning anymore
use a mouse event to move your henk object, not an ENTER_FRAME. I guess you will be able to find how this works. This will only trigger the function when it has to do something, resulting in less CPU-power needed and a cleaner code.
if you want to make the game even cooler, you could add the support for using the arrow keys

Resources