AS3 Bitmaps are too large and improperly placed - actionscript-3

Alright I'm programming in actionscript 3, using flex as a compiler. I have an 16x16 large PNG file that is basically a square outline like this:
http://wiki.urbandead.com/images/1/1c/Square.gif
But in more noticeable colors.
I want to draw an 11x11 grid of these squares, so I use these for loops:
for (i1 = 0; i1 < 11; i1 ++)
{
for (i2 = 0; i2 < 11; i2 ++)
{
new OBJECT_tile().CREATE(CONTAINER,32 + 16*i1,32 + 16*i2);
}
}
Where the CREATE() function makes a new tile object with the container CONTAINER with the given x and y coordinates.
public class OBJECT_tile extends Sprite
{
public var X:Number; public var Y:Number;
public var DEPTH:int = 10 ;
public var SPRITE:Sprite = new Sprite();
public var BITMAP:Bitmap;
public var CONTAINER:Sprite = new Sprite();
[Embed(source = 'TILE.png')]
private var CLASS_IMAGE:Class;
private var IMAGE:Bitmap = new CLASS_IMAGE();
public function CREATE(CONTAINER:Sprite,X:Number,Y:Number):void
{
var DATA:BitmapData = new BitmapData(16,16,true,0);
DATA.draw(IMAGE);
BITMAP = new Bitmap(DATA);
BITMAP.smoothing = false;
addChild(BITMAP);
this.CONTAINER = CONTAINER;
(CONTAINER as MAIN).INSTANCE_LIST[(CONTAINER as MAIN).INSTANCE_LIST.length] = this;
this.X = X; BITMAP.x = this.X;
this.Y = Y; BITMAP.y = this.Y;
DRAW();
}}
However for some reason the tiles are drawn to twice their size (32x32 instead of 16x16) and tend to bunch up or spread out depending on how many tabs I have open in my browser. The bunching up isn't consistent either, for instance the tiles might for a 3x3 group that's perfectly fine but then there will just be a line of messed up tiles next to that group (really hard to describe). Why is this happening?

Okay I figured it out. It turns out as3 will try to scale things behind your back, I'm guessing this is some kind of holdout from Adobe's ide (I detest the thing and program in notepad++). Anyways if you stick this:
stage.scaleMode = StageScaleMode.NO_SCALE;
In your main function it will stop it from scaling unless you say otherwise.

Related

Revmob ads showing in the middle of the screen

I have developed a game in starling and after fixing multi resolution issue , i stuck into another one
when I try implementing Revmob banner ads on bottom it shows in the middle of the screen on samsung note - but on samsung galaxy S2 , it show on the bottom which is perfect.
I don't know how to fix this problem
here is two ways i am trying to implement revmob banner ad
Game.revmob.showBanner(0 , stage.stageHeight);
OR
Game.revmob.showBanner();
here is the code for multi resolution
public class FTC extends MovieClip
{
public static var star:Starling;
public static var debugSprite:flash.display.Sprite;
public static var _baseWidth:Number = 480;
private static const STAGE_WIDTH:int = 320;
private static const STAGE_HEIGHT:int = 480;
public static var DIMX:Number;
public static var DIMY:Number;
/**
* The height that the app is based on, this should be the lowest height such as 480 (iphone) or 512 (ipad)
*/
public static var _baseHeight:Number = 800;
public function FTC()
{
this.stage.align = StageAlign.TOP_LEFT;
this.stage.scaleMode = StageScaleMode.NO_SCALE;
Starling.handleLostContext = true;
// Get the preferred stage size based on our smallest target resolution
var stageArea:Rectangle = new Rectangle(0, 0, STAGE_WIDTH, STAGE_HEIGHT);
// Get the fullscreen size available
var fullscreenArea:Rectangle = new Rectangle(0, 0, stage.fullScreenWidth, stage.fullScreenHeight);
// Fit the stage to the full screen. ScaleMode.SHOW_ALL ensures that everything will be visible (not croping will occur).
var viewport:Rectangle = RectangleUtil.fit(stageArea, fullscreenArea, ScaleMode.SHOW_ALL);
// Create a new instance and pass our class, the stage and the wished viewport
star= new Starling(Game, stage, viewport);
// Show debug stats
// star.showStats = true;
// Define level of antialiasing,
star.antiAliasing = 1;
// Set to our preferred stage size
star.stage.stageWidth = STAGE_WIDTH;
star.stage.stageHeight = STAGE_HEIGHT;
star.start();
}
private function onResized(e:Event):void
{
var viewPort:Rectangle = star.viewPort;
viewPort.width = this.stage.stageWidth;
viewPort.height = this.stage.stageHeight;
star.viewPort = viewPort;
star.stage.stageWidth = stage.stageWidth;
star.stage.stageHeight = stage.stageHeight;
}
}
Try to check if the "onResized" Method has been called or maybe you can force a call to it by placing a onResized(null); after the star.start(); call.

Loading images does not load them into memory

I am loading a batch of 150 HD images into my app - it is basically a 3D view of an object. Once I load the image files using Loader instances I store the loaders' first child's bitmapdata in a Vector. When all of the loaded, I want to begin to "rotate" the object = meaning I am simply swapping the images. I take the Vector where I have the bitmapdatas and draw them onto a canvas bitmapdata one after the other. No science there, it all works as intended.
The problem is that once all the images are loaded and stored in a vector and BEFORE they are drawn to the canvas, they are not in the memory. That means that the first rotation of my 3D object (-> all 150 images drawn) is really slow. After the first rotation there is no problem and all is fluid. My question is: is there a way to force the images to get loaded into the memory without drawing them onto the stage? I expected that they would simply get loaded to memory once they are loaded to the app (Wrong!).
I tried to use addChild() instead of drawing them to a canvas bitmap, same result. I don't think the code is necessary but just in case:
private var _loaders:Vector.<Loader>;
private static const NAME:String = "img_00";
private static const MIN:uint = 0;
private static const MAX:uint = 150;
private var _loaded:uint = 0;
private var _currentFrameIndex:uint = 0;
private var _canvas:Bitmap;
private var _bitmaps:Vector.<BitmapData>;
private var _destPoint:Point;
public function loadImages():void {
var s:String;
for(var i:int=MIN; i<=MAX; i++) {
if(i < 10) s = "00" + i;
else if(i < 100) s = "0" + i;
else s = i.toString();
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loadHandler);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loadHandler);
loader.load(new URLRequest("images/JPEG/"+ NAME + s + ".jpg"));
_loaders.push(loader);
}
}
private function loadHandler(e:Event):void {
_loaded++;
if(_loaded > (MAX - MIN)) {
_bitmaps = new Vector.<BitmapData>(_loaders.length);
for(var i:int=0; i<_loaders.length; i++) {
var loader:Loader = _loaders[i];
_bitmaps[i] = Bitmap(loader.getChildAt(0)).bitmapData;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, loadHandler);
loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, loadHandler);
}
setFrame(0);
dispatchEvent(new Event(LOAD_COMPLETE));
}
}
public function setFrame(frame:uint):void {
if(frame >= 0 && frame < _bitmaps.length) {
_currentFrameIndex = frame;
var bmpData:BitmapData = _bitmaps[_currentFrameIndex];
_canvas.bitmapData.copyPixels(bmpData, bmpData.rect, _destPoint);
}
}
"Not in the memory" means that the images are loaded, but not yet decoded, and this decode is done on the fly, and this takes the time you observe as slowness. You can attempt to "virtually" rotate the image by having a bitmap that's not yet added to stage to be the reference to each of the bitmapDatas of your vector. Make a progress bar that shows how much of the vector has already been decoded, and once this happens, display the bitmap and give the user smooth rotation.
addEventListener(Event.ENTER_FRAME,prerender);
var b:Bitmap=new Bitmap();
/* optional
b.x=stage.stageWidth;
b.y=stage.stageHeight;
addChild(b);
*/
var vi:int=0;
var sh:Shape=new Shape();
sh.graphics.lineStyle(4,0,1); // a simple progress bar
sh.graphics.moveTo(0,0);
sh.graphics.lineTo(100,0);
sh.scaleX=0;
sh.x=stage.stageWidth/2-50; // centered by X
sh.y=stage.stageHeight/2;
addChild(sh);
function prerender(e:Event):void {
if (vi==_bitmaps.length) {
// finished prerender
removeEventListener(Event.ENTER_FRAME, prerender);
removeChild(sh);
// removeChild(b); if optional enabled
setFrame(0);
return;
}
b.bitmapData=_bitmaps[vi];
vi++;
}
Also, it's always better to assign the bitmapData property to a Bitmap object if you don't plan to have that bitmapdata changed. So, instead of your _canvas.bitmapData.copyPixels(bmpData, bmpData.rect, _destPoint); you just do _canvas.bitmapData = bmpData; and it'll work.
UPDATE: Your issue might as well nail to the last point, that is assigning instead of copying. If your destPoint is something else than (0,0), you just make another Bitmap object on top of your _canvas with desired offset, and assign bitmapdatas in there. I have remembered that when I first made multiple animated objects based on a single Vector.<BitmapData> like yours, and tried doing copyPixels(), my animations were jittering and not displaying proper frames, but once I did _bitmap.bitmapData=_bitmaps[currentFrame] everything went as smooth as it should be.

trouble resetting a flash game

I'm trying to build a simple flash game in which I need to be able to restart the game if the user dies. However resetting all of the variables doesn't seem to be accomplishing anything. All of my game elements are stored in arrays and I thought that maybe setting each of them to the array constructor wasn't deleting the objects that they were pointing to and that they were left on the screen as a result. Does anyone know of a way to delete those elements (since I can't iterate over the list to delete them for obvious reasons) or does anyone know of a better way to reset a game in flash? For reference, here's the init function and the variable declarations at the top of my program that are supposed to start/reset the game.
public class Main extends MovieClip {
//put field variables here
static var hudLayer:Sprite; //layer used to represent HUD elements
static var gameLayer:Sprite; //layer used to represent objects in the game space
static var uiTextLayer:Sprite; //layer used to represent text that should appear ON TOP of the HUD
static var backgroundLayer:Sprite; //layer used to display the background image
static var players: Array; //array of all the player objects for reference
static var backgrounds:Array; //array of all the background objects
static var lines: Array; //array of all the lines
static var powerUps:Array; //array of all the powerups
static var enemies:Array; //array of all the enemies
static var miscellaneousObjects:Array; //array of miscellaneous objects that I'd like to be able to keep track of
var xCoords:Array, yCoords:Array; //Used to temporarily hold x and y coordinates when making new drawings
static var grav:Number; //coefficient representing the force of gravity
static var isPaused:Boolean; //manages pausing mechanic
static var timer:Timer; //used for time delayed updating of game elements
var pt:Point; //variable used by collision detection
var asteroidTiming:Number; //used to properly delay creating of asteroids on the screen
static var asteroidDelay:Number; //current delay between when asteroids are deployed, changes over course of execution
static var score:Number; //this should be self-explanatory
var scoreField:TextField; //used to display the score
static var myTextFormat:TextFormat; //used to format the text in the scoreField
static var inGameOver:Boolean; //used to determine if we're at the game over screen
[Frame(factoryClass="Preloader")]
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//set up the Sprite Layers
backgroundLayer = new Sprite();
gameLayer = new Sprite();
hudLayer = new Sprite();
uiTextLayer = new Sprite();
addChild(backgroundLayer);
addChild(gameLayer);
addChild(hudLayer);
addChild(uiTextLayer);
//instantiate important variables
xCoords = new Array();
yCoords = new Array();
players = new Array();
backgrounds = new Array();
enemies = new Array();
powerUps = new Array();
miscellaneousObjects = new Array();
grav = .04;
addBackGround();
addPlayer(400, 50);
isPaused = false;
lines = new Array();
score = 0;
inGameOver = false;
//instantiate text fields
scoreField = new TextField();
scoreField.text = "Score: " + score;
hudLayer.addChild(scoreField);
scoreField.x = 20;
scoreField.y = 20;
scoreField.textColor = 0xFFFFFF;
myTextFormat = new TextFormat();
myTextFormat.size = 15;
scoreField.setTextFormat(myTextFormat);
//set up timer
timer = new Timer(5);
timer.addEventListener(TimerEvent.TIMER, function():void { update()});
timer.start()
asteroidTiming = 0;
asteroidDelay = 150;
//set up mouse listener
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEvent);
//set up key listener
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyEvent);
//tests
}
Since I can't see all your code, I will guess that you are not using removechild() to get rid of display objects off the stage.
To create a object:
var object:DisplayObject = new DisplayObject();
To make it visible on the display list:
parent.addChild(object);
To remove it from the display list:
parent.removeChild(object);
To erase its memory:
object=null;
(These four things must be done in this order, for this to work properly. IF you make something null without removing it from the display list, you leave it there, still visible, with no way of referencing it. It like lost in your application.
You have to make sure you always use removeChild() before making a variable null, or overwriting the variable.

how to use a scaled object(MC) to fill the background with the new properties

I have a stage 300 to 200 and all object that i have are for this dimensions.Also have an pattern function that fills the background.
But the user is thinking of resizing the stage to lets say 1024 to 480 (he switched from a phone to a tablet).And now the scale of the objects in the tablet screen are more than 3times before(when seen on the Phone)
How do i save the current new size object and use it in the creation of the new background (the 1024x480).
i have this code
public static const GAME_ORG_WIDTH:uint = 300;
public static const GAME_ORG_HEIGHT:uint = 200;
private var myC:MyClip = new MyClip();
public function MainClass_road() {
addEventListener(Event.ADDED, init);
}
public function init(e:Event):void{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener(Event.RESIZE, setUpScreen);
}
public function setUpScreen(ev:Event):void{
stage.removeEventListener(Event.RESIZE, setUpScreen);
if(stage.fullScreenHeight > stage.fullScreenWidth){
gameStageWidth = stage.fullScreenWidth;
gameStageHeight = stage.fullScreenHeight;
}else {
gameStageWidth = stage.fullScreenHeight; // 480
gameStageHeight = stage.fullScreenWidth; //1024
}
rescaleRatio = gameStageWidth / GAME_ORG_WIDTH;
//rescale every object, ie:
myC.scaleX = myC.scaleY = rescaleRatio;
//start filling the Background with the pattern
tileBgF();
}
so before the tileBgF() how do i save the new dimensions of the object and use them(the new values)to fill the screen with this function .cause right now im just using the old object properties (sizes), not the updated one.
public function tileBgF(e:Event=null):void {
var bgClip:MovieClip = new myC();
var i:int = 0;
var j:int = 0;
while (bgClip.x < gameStageWidth - bgClip.width) {
bgClip = MyC;
while (bgClip.y < gameStageHeight - bgClip.height) {
bgClip = MyC;
tileLayer.addChild(bgClip);
bgClip.x = bgClip.width * i;
bgClip.y = bgClip.height * j;
j++;
}
j = 0;
i++;
}
addChildAt(tileLayer,0);
}
and if i decide in the future to use the background again (so i have 2 backgrounds at the same time on the stage) is it enough just to make another tileLayer and add it again or i need to do something more ?
bgClip = new MyClip();
bgClip.scaleX = bgClip.scaleY = scaleRatio
tileLayer.addChild(bgClip);
bgClip.x = bgClip.width * i;
bgClip.y = bgClip.height * j;

Draw a Sine Wave Between Two Arbitrary Points in Actionscript 3

Drawing "flat" waves is easy, but I want to draw the wave between two points x1,y1 x2,y2
Here is the "flat" code:
package display
{
import flash.display.Sprite;
import flash.events.Event;
public class SineWave extends Sprite
{
private var angle:Number = 0;
private var centerY:Number = 200;
private var range:Number = 50;
private var xspeed:Number = 2;
private var yspeed:Number = .1;
private var xpos:Number
private var ypos:Number
public function SineWave()
{
init()
}
protected function init():void
{
var sinWavePosition = 100;
var cosWavePosition = 200;
var sinWaveColor:uint = 0xFF0000;
var cosWaveColor:uint = 0x00FF00;
var waveMultiplier:Number = 10;
var waveStretcher:Number = 5;
var i:uint;
for(i = 1; i < 500; i++)
{
var sinPosY:Number = Math.sin(i / waveStretcher) * waveMultiplier;
var cosPosY:Number = Math.cos(i / waveStretcher) * waveMultiplier;
graphics.beginFill(sinWaveColor);
graphics.drawRect(i, sinWavePosition + sinPosY, 2, 2);
graphics.beginFill(cosWaveColor);
graphics.drawRect(i, cosWavePosition + cosPosY, 2, 2);
}
}
}
}
What about a bezier curve? This isn't a sine wave per se. But the effect is similar. With proper control points you should be able to make it look just like a sine wave.
Well quick cheat would be to get the distance between the points, draw the graphic onto a separate sprite, then just work out the angle between the two points and rotate the graphic to that angle.
Not the most 'perfect' solution, but should do the trick, otherwise I can imagine, working out the angle between the two points and then adding this as an increment to the existing values.
Hope this hack helps.
I believe this will work, it's basically a rotationmatrix that is applied to every point on the line.
There might be some errors with the order and signs of the multiplications and the parameters to atan2 but otherwhise i think this will work.
float v = Atan2(y2-y1, x2-x1);
for(blabla)
{
calculate sinPosY from i
newSinPosY = i*Cos(v) + sinPosY*Sin(v);
sinPosX = i*-Sin(v) + sinPosY*Cos(v));
add offset
render
}