HTML5 Canvas -- Drawing a game level, overlapping previously drawn rectangles - arrays

I've been hacking away at this problem for the past three hours and cannot figure out where I went wrong. Basically, I'm trying to draw a tile-based "level" for a little game. As I understand it, the canvas should draw new rectangles on rectangles that have already been drawn.
I want to set it up so that there is one function that basically draws the background, and another function that draws the highlights on top of it. The "highlights" are the top of a wall, and the background shows the side of it. I want to draw the highlights on top because ideally I'd eventually like to draw a character in between them so the highlights would be on top of the character (as though it is behind the wall) while the background would be behind the character.
The background and shape of the level (without the highlight layer) looks like this: http://howtivity.com/leveldrawing
For some reason, I run into a lot of trouble trying to draw the highlights layer. I want to offset the layer 50px above the background layer to give the impression of a three dimension wall, and I want any blank spaces where there is no wall to be transparent so the background still shows. When I try drawing the layer with an almost identical function whose only difference is offsetting the layer 50px upward and set the no-wall fillStyle to transparent, it looks like this: http://howtivity.com/leveldrawing/highlight.html
I've set it up to print text so I could diagnose where it might be wrong, but the text has shown up correctly. I feel like I either misunderstood something about how the canvas is drawn, or have made some kind of error that I'm just not seeing.
<canvas height="600" width="1000" style="position: absolute; z-index: 0; background: transparent;" id="background">
</canvas>
<script>
var level =
[
[1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,1,0,0],
[1,0,1,0,1,1,0,1,0,1],
[0,0,0,0,0,1,0,0,0,1],
[1,0,0,0,0,0,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1]
];
var bg = document.getElementById("background");
var bgContext = bg.getContext("2d");
var drawLevel = function() {
var levelDrawX = 0;
var levelDrawY = 0;
for (levelRow = 0; levelRow < 6; levelRow++)
{
for (levelCol = 0; levelCol < 10; levelCol++)
{
levelDrawX = (100 * levelCol);
if (level[levelRow][levelCol]==1)
{
bgContext.fillStyle = "#ffe680";
bgContext.fillRect(levelDrawX, levelDrawY, levelDrawX + 100, levelDrawY + 100);
} else {
bgContext.fillStyle = "#8dd35f";
bgContext.fillRect(levelDrawX, levelDrawY, levelDrawX + 100, levelDrawY + 100);
}
}
levelDrawY += 100;
}
};
var drawHighlights = function() {
var levelDrawX = 0;
var levelDrawY = 0;
for (levelRow = 0; levelRow < 6; levelRow++)
{
for (levelCol = 0; levelCol < 10; levelCol++)
{
levelDrawX = (100 * levelCol);
if (level[levelRow][levelCol]==1)
{
bgContext.fillStyle = "#000";
} else {
bgContext.fillStyle = "transparent";
}
bgContext.fillRect(levelDrawX, levelDrawY-50, levelDrawX+100, levelDrawY+50);
}
levelDrawY += 100;
}
};
drawLevel();
drawHighlights();
Any help would be really appreciated! Thank you!

I admit to being a bit confused about what you want in your finished design.
Do you want your drawHighlights() to add a semi-transparent "shadows" to your drawLevel()?
If so, you can do that by setting the context's globalAlpha which is the level of opacity.
var drawHighlights = function() {
var levelDrawX = 0;
var levelDrawY = 0;
bgContext.globalAlpha=0.8;
for (levelRow = 0; levelRow < 6; levelRow++)
{
for (levelCol = 0; levelCol < 10; levelCol++)
{
levelDrawX = (100 * levelCol);
if (level[levelRow][levelCol]==1)
{
bgContext.fillStyle = "#777";
} else {
bgContext.fillStyle = "transparent";
}
//bgContext.fillText(levelCol, levelCol*100, 10+levelRow*100);
bgContext.fillRect(levelDrawX, levelDrawY-50, levelDrawX+100, levelDrawY+50);
}
levelDrawY += 100;
}
bgContext.globalAlpha=1.0;
};

My mistake was with the values required by fillRect.
I had typed them as if they were:
fillRect(startX, startY, endX, endY);
when actually they are:
fillRect(startx, starty, width, height);

Related

AS3 Accessing elements in an array once only

I have an array like so...
var pointsArray:Array = [100, 200, 250, 1000, 1500];
a for loop ...
for(var i:int = 0; i<27; i+=1)
{
ach.scrollp.content["ach"+i].text = "Locked";
ach.scrollp.content["ach"+i].textColor = 0x666699;
}
and an achievements function ...
if (TotalScore >= pointscollectedArray[0])
{
ach.scrollp.content.ach0.text = "Unlocked";
ach.scrollp.content.ach0.textColor = 0xFF9900;
}
etc etc
No issues at all with the data displaying in an achievements interface. But what I am trying to do is display a movie clip during the actual game that tells the player when they have unlocked an achievement. The problem is I don't know how to display the movieclip once only per unlocked achievement ie the movieclip doesn't display again until the next achievement is unlocked.
I have no idea how to access the elements in an array only once.
I'm a noob at AS3 so I hope I've explained everything properly.
Cheers
It would be best if you redesigned your achievement architecture. But for a simple fix, something like this:
if (TotalScore >= pointscollectedArray[0] &&
ach.scrollp.content.ach0.text != "Unlocked")
{
ach.scrollp.content.ach0.text = "Unlocked";
ach.scrollp.content.ach0.textColor = 0xFF9900;
// play movie
}
It is better to redesign your code. I can suggest you something like this:
var iLevel: int = 0; // This is the achievement that is reached. Player starts from 0 but if your game support save, iLevel can be different;
var nTotalLevels: int = 27; // This is total amount of achievements you have
for ( var i:int = 0; i < iLevel; ++i )
{
//This code show unlocked achievements
ach.scrollp.content["ach"+i].text = "Unlocked";
ach.scrollp.content["ach"+i].textColor = 0xFF9900;
}
for ( var k:int = iLevel; k < nTotalLevels; ++k )
{
// This code show locked achievements;
ach.scrollp.content["ach"+k].text = "Locked";
ach.scrollp.content["ach"+k].textColor = 0x666699;
}
so in this case when the player receive new achievement, you can show it like this
if ( TotalScore >= pointscollectedArray[0] )
{
++iLevel;
ach.scrollp.content["ach"+iLevel].text = "Unlocked";
ach.scrollp.content["ach"+iLevel].textColor = 0xFF9900;
// play movie
}
I hope that I understand right what you need;

Remove Array and its contents with mouse click AS3 Flash CS5.5

I have been trying to do this for two nights now and haven't had any joy, please help if you can...
Simple throwing game with darts and other weapons, what I am trying to do is
Remove an array and all of its Children when I change weapon,
I feel sure there is a simple snippet of code that will remove all the children and array with no hassle but I haven't yet figured it out, if you know or could suggest anything, I would really appreciate it.
something like "removeArrayAndAllInstances(balls);" if only...
at the moment I have....(balls is the array in question)
for(var inter:int = balls.length - 1; inter > -1; inter--)
{
balls.splice(1);
balls.splice(1, balls.length);
}
but this docent work for some reason, the array and all of its children are all still on the stage.
I also tried
balls[];
No luck...
Please don't judge my code I am a novice as I am sure was evident and I know its a disgusting mess, sorry (Its the only way it makes sense to me).
I have tried numerous things, hope someone can help
Thanks in advance.....
var mouseTarget:MovieClip;
var balls:Array = new Array();
var ball:MovieClip = new dart();
var hammers:MovieClip = new hammer();
ball.x = 150;
ball.y = 50;
hammer_btn.addEventListener(MouseEvent.MOUSE_DOWN, hammerweapon);
dart_btn.addEventListener(MouseEvent.MOUSE_DOWN, dartweapon);
function removealldartsfromstage(e:MouseEvent):void
{
for(var inter:int = balls.length - 1; inter > -1; inter--)
{
balls.splice(1);
balls.splice(1, balls.length);
}
stage.removeEventListener(MouseEvent.MOUSE_UP, addDart);
}
function dartweapon(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, addHammer);
dart_btn.removeEventListener(MouseEvent.CLICK, dartweapon);
stage.addEventListener(MouseEvent.MOUSE_UP, addDart);
//removeChild(balls);
}
function hammerweapon(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, addDart);
dart_btn.addEventListener(MouseEvent.MOUSE_DOWN, dartweapon);
//stage.addEventListener(MouseEvent.MOUSE_UP, addDart);
stage.addEventListener(MouseEvent.MOUSE_UP, addHammer);
}
function addHammer(e:MouseEvent):void
{
var hammers = new hammer();
addChild(hammers);
removeChild(dart_btn);
addChild(dart_btn);
dart_btn.addEventListener(MouseEvent.CLICK, dartweapon);
balls.splice(10);
}
function addDart(e:MouseEvent):void
{
str.alpha = 0;
var ball = new dart();
addChild(ball);
removeChild(hammer_btn);
addChild(hammer_btn);
ball.x = 150;
ball.y = 50;
balls.push(ball);
trace(balls);
addEventListener(Event.ENTER_FRAME, checkIfHitTest);
hammer_btn.addEventListener(MouseEvent.MOUSE_DOWN, removealldartsfromstage);
function checkIfHitTest(Event)
{
for (var i:int = 0; i<balls.length; i++)
{
if (balls[i].dart_point.hitTestObject(eyeleft))
{
trace("hitleftbullseye");
ball.gotoAndStop("hitlefteyeframe");
Event.currentTarget.removeEventListener(Event.type, checkIfHitTest);
balls.splice(i, 1);
}
}
}
}
The balls array is just a storage for ball references. It bears no relation to the stage or the DisplayObjectContainer which they have been added at all. So you have to remove them individually.
This is what I'd do:
while(balls.length > 0)
{
var ball:MovieClip = balls.pop();
if (ball.parent) // Just to make sure you are referencing the correct container.
{
ball.parent.removeChild(ball);
}
}
I can't follow the logic of your game very well. That said, you'd do well to create conatiners for separate group of clips in order to make managing them easier. For example, in the creation stage:
var ballContainer:Sprite = new Sprite();
addChild(ballContainer);
for (var i:int = 0; i < ballLimit; i++)
{
var ball:Dart = new Dart();
ballContainer.addChild(ball);
}
This way, you can clear them of children all at once:
function removeAllChildren(container:Sprite) // Or just DisplayObjectContainer
{
while(container.numChildren > 0)
{
container.removeChild(container.getChildAt(0));
}
}

horizontal scroller on tree panel

does any body know how to show the horizontal scroller on tree panel...
since it describe here, the bugs will be fix in 4.1.x version,...
cause i'm not satisfied, i try to googling to find the hot fix,.
and i got this, Mr. Edspencer suggest to using ext 4.0.6....
but, it still not working,. (tested version 4.0.7)
anybody know how to fix this???
I have some workaround. See code below.
afterrender: function() {
var view = this.getView();
var c = view.container;
var e = view.el;
var max = 0;
Ext.each(e.query('.x-grid-cell-inner'), function(el) {
el = Ext.get(el);
var size = el.getPadding('lr');
Ext.each(el.dom.childNodes, function(el2){
if (el2.nodeType == 3) {
size += 6 + el.getTextWidth(el2.nodeValue);
} else {
size += Ext.get(el2).getWidth();
}
});
max = Math.max(max, size);
});
max += c.getPadding('lr');
if (c.getWidth() < max) {
c.dom.style.overflowX = 'scroll';
e.setWidth(max);
e.down('table').setWidth(max);
}
}
You only need to add this listener to your TreePanel. Basically it finds width of wider element and extend width of table, switch overflow on container.
Working sample: http://jsfiddle.net/Uf7yy/2/

How can I prevent this arbitrary text truncation in AS3

Below is code that populates a menu. Everything seems to work great, with no errors thrown, except for one crucial part. My megaPages array has the values ["HOME","BABIES","BRIDALS","MISC","WEDDINGS","ABOUT"], but the actual text that displays on screen (which is produced by megaPages) is like this:
As you can see, some of the text is arbitrarily being truncated. I've traced the text strings as they get passed through the various functions at various stages of the menu-build, and they are always right, but somehow when each DisplayObject make it on screen, letters get ommitted (notice though that 'HOME' abd 'ABOUT' are fine). I don't even know where to start with this problem.
function buildMenu() {
var itemMCs = new Array();
for (var i = 0; i < megaPages.length; i++) {
megaPages[i] = megaPages[i].toUpperCase();
trace(megaPages[i]); // at each iteration, traces as follows "HOME","BABIES","BRIDALS","MISC","WEDDINGS","ABOUT"
var textMC = createText(megaPages[i]);
var itemMC = new MovieClip();
if (i!=0) {
var newLink = new PlateLink();
newLink.y = 0;
itemMC.addChild(newLink);
}
var newPlate = new Plate();
if (i==0) {
newPlate.y = 0;
} else {
newPlate.y = newLink.height - 2;
}
newPlate.x = 0;
newPlate.width = textMC.width + (plateMargin*2);
itemMC.addChild(newPlate);
if (i!=0) {
newLink.x = (newPlate.width/2) - (newLink.width/2);
}
textMC.x = plateMargin;
textMC.y = newPlate.y + .5;
itemMC.addChild(textMC);
itemMCs.push(itemMC);
itemMC.x = (homeplateref.x + (homeplateref.width/2)) - (itemMC.width/2);
if (i==0) {
itemMC.y = homeplateref.y;
} else {
itemMC.y = itemMCs[i-1].y + (itemMCs[i-1].height - 6);
}
menuRef.addChild(itemMC);
}
}
function createText(menuTitle) {
trace(menuTitle);
var textContainer : MovieClip = new MovieClip();
var myFont = new Font1();
var backText = instantText(menuTitle, 0x000000);
backText.x = 1;
backText.y = 1;
var frontText = instantText(menuTitle, 0xFFFFFF);
frontText.x = 0;
frontText.y = 0;
textContainer.addChild(backText);
textContainer.addChild(frontText);
return textContainer;
}
function instantText(textContent, color) {
trace(textContent); // again, traces the right text each time it is fired
var myFont = new Font1();
var myFormat:TextFormat = new TextFormat();
myFormat.size = 18;
myFormat.align = TextFormatAlign.CENTER;
myFormat.font = myFont.fontName;
var myText:TextField = new TextField();
myText.defaultTextFormat = myFormat;
myText.embedFonts = true;
myText.antiAliasType = AntiAliasType.ADVANCED;
myText.text = textContent;
myText.textColor = color;
myText.autoSize = TextFieldAutoSize.LEFT;
trace(myText.text);
return myText;
}
You need to embed all the necessary characters for the font you're using.
For textfields created in Flash:
Select the TextField, and hit the 'Embed' button in the properties panel.
For dynamically created textfields:
When you set the font to export (Font1 in your case) make sure to include all the characters you need.
You can choose to embed all uppercase characters, or just type in the ones you need for those specific menu items.

Randomly removing an array

just for the record, i'm using AS3.
I have an issue where I would like to remove a sprite randomly in AS3, I have managed to figure out how to create the sprites so that they fill as a grid, just for the life of me I can't figure out how to remove them!
Here's the code i've used to create them:
function showpixels() : void
{
for (var i:int = 0; i < 40; i++)
{
for (var j:int = 0; j < 40; j++)
{
var s:Sprite = new Sprite();
s.graphics.beginFill(0);
s.graphics.drawRect(i*10, j*10, 10, 10);
s.graphics.endFill();
addChild(s);
pixels.push(s);
}
}
}
Basically I need these to be removed randomly until what's underneath can be seen.
Any help would be good, I'm pretty new to this! Thanks!
function removeRandom():void
{
var rand:uint = Math.random()*pixels.length;
var i:Sprite = Sprite(pixels[rand]);
if(i.parent) i.parent.removeChild(i);
pixels.splice(rand, 1);
}
UPDATE: To remove at random intervals you could try something like this:
var _timer:int = 100;
addEventListener(Event.ENTER_FRAME, _handle);
function _handle(e:Event):void
{
if(pixels.length > 0) _timer --;
if(_timer < 1)
{
_timer = 10 + Math.random()*50;
removeRandom();
}
}
function removeRandom():void
{
var rand:uint = Math.random()*pixels.length;
var i:Sprite = Sprite(pixels[rand]);
if(i.parent) i.parent.removeChild(i);
pixels.splice(rand, 1);
}
Marty's idea works. Another option would be to shuffle the array first and then just pop off elements.
To shuffle an Array use pixels.sort(function (...args):int { return int(2*Math.random()-1) }).
And then you can simple remove them like this:
function remove():void {
if (pixels.length) removeChild(pixels.pop());
else clearInterval(this.id);
}
And add this line at the end of showpixels:
this.id = setInterval(remove, 500);

Resources