HitTestObject distance bug between two object - actionscript-3

I have a car game which is drive reverse.The game over when enemy and car hit each other.I have problem with collision.
Car and enemy hit when they get close each other,but they have still big space in there.
Please check this image.
https://s8.postimg.cc/p85w0wm2t/image.gif
I use this code.
if(dubageri1.hitTestObject(carMC)){
dubageri1.gotoAndPlay(2);
geribas.gericarpti = true;
stage.removeEventListener(Event.ENTER_FRAME,engeller1geri1lev1)
}
Also I tried something like this.But this time collision has late.
var nDistX:Number = Math.abs ( carMC.x - dubageri1.x );
var nDistY:Number = Math.abs ( carMC.y - dubageri1.y );
var nDistance:Number = Math.sqrt ( nDistX * nDistX + nDistY * nDistY );
var sDistx:Number = Math.abs ( carMC.x - dubageri1.x );
var sDisty:Number = Math.abs ( carMC.y - dubageri1.y );
var nsistance:Number = Math.sqrt ( sDistx * sDistx + sDisty * sDisty );
collect.text=String(nDistance);
if ( nDistance < 120 )
{
trace("aha");
dubageri1.gotoAndPlay(2);
stage.removeEventListener(Event.ENTER_FRAME,dsaa);
}
Note:My objects was made as vector.
Does anybody tell me what im doing wrong ?
UPDATE
var aPoint:Point = new Point();
aPoint = carMC.localToGlobal(aPoint);
var bPoint:Point = new Point();
bPoint = dubageri1.localToGlobal(bPoint);
stage.addEventListener(Event.ENTER_FRAME,ilkcikis);
function ilkcikis(event:Event) {
bPoint = root.globalToLocal(bPoint);
var zHit:Boolean = carMC.hitTestPoint(bPoint.x, bPoint.y, true);
textbaba.text = zHit? "! HIT !": "NO HIT";
carMC.x=mouseX;
carMC.y=mouseY;
}

Related

My game lags when I press button

I have an app that I'm developing for iOS and Android using AS3. I'm currently having several performance issues with this project. This is my very first app and game. So any type of feedback or insight is greatly appreciated. My game is a dirt bike wheelie game. It allows the user to press a button (gasPress) to wheelie upward and another button (brake) to wheelie downward. Once the "gasPress" button is pressed, a boolean "holdGas" is set to true. In my "gameLoop" (Enter_Frame event), the bike is rotated upward, IF "holdGas" is equal to true. The code for pressing the brake is the same, except it rotates the bike donward. I have buildings that slide across the screen, creating the illusion that the bike is moving. The building movie clips are cached as bitmap. I use two instances of the same building movie clip. Once the first clip slides off the stage, it's placed behind the other. In a recycling kind of mechanism lol. The problem I'm having with this is, when i press the "gasPress" button, it lags before wheelie/rotating upward. When it lags, the buildings moving in the background skips. It happens every time. So if you keep tapping the gasPress, (which is part of the gameplay) the objects on the screen keep jumping. It makes the game unplayable. I've tested the buttons by completely removing the code to move the bike upward/downward and the game still skips. I've noticed more of a skip or lag when the gas is pressed and the bike rotates upward. I currently have the frame rate set to 32, it did the same at 24.
public function TheGame() {
//Connect to tapjoy's ad network
//tjClass = new TapJoyClass();
//stage.scaleMode = StageScaleMode.NO_SCALE;
//stage.align = StageAlign.TOP_LEFT;
//Give game focus so the keyboard keys will work on computer
stage.focus = this;
globalStage = this.stage;
//Checks if ScoreData and Bike data shared object has been created, if not it creates
scoreInfo = SharedObject.getLocal ( "ScoreData" );
bikeInfo = SharedObject.getLocal ( "BikeData" );
//scoreInfo.clear ();
//bikeInfo.clear ();
mostSprocketsCollected = scoreInfo.data.mostSprocketsCollected;
//Handling background
background1 = new Background;
background2 = new Background;
addChild ( background1 );
addChild ( background2 );
background1.cacheAsBitmap = true;
background2.cacheAsBitmap = true;
background1.mouseChildren = false;
background1.mouseEnabled = false;
background2.mouseChildren = false;
background2.mouseEnabled = false;
background1.x = background1.width;
background2.x = background1.x + background2.width;
//Handling buildings
building1 = new Buildings;
building2 = new Buildings;
addChild ( building1 );
addChild ( building2 );
building1.cacheAsBitmap = true;
building2.cacheAsBitmap = true;
building1.mouseChildren = false;
building1.mouseEnabled = false;
building2.mouseChildren = false;
building2.mouseEnabled = false;
building1.x = building1.width;
building2.x = building1.x + building2.width;
//Choose which bike will be used
if( bikeInfo.data.EquippedBike == undefined ){
//Start off with original bike
whichBike = "OriginalDirtBike";
bikeInfo.data.BikeColor = "OriginalDirtBike";
}else{
whichBike = bikeInfo.data.EquippedBike;
}
if( whichBike == "Banshee" ){
//Add far wheels first
wheelClip2 = new Banshee_Far_WheelClip;
addChild ( wheelClip2 );
//wheelClip2. = 208.30;
wheelClip2.y = 350;
//Add Banshee
bitmapBike = new Banshee_Bitmap ();
bitmapBike.gotoAndStop ( bikeInfo.data.BikeColor );
addChild ( bitmapBike );
bitmapBike.y = 399.80;
bitmapBike.x = 0;
//Add frontWheels
wheelClip = new Banshee_WheelClip ();
wheelClip.backTire.frontFace.gotoAndStop ( bikeInfo.data.BikeColor );
wheelClip.frontTire.frontFace.gotoAndStop ( bikeInfo.data.BikeColor );
addChild ( wheelClip );
wheelClip.x = 187.70;
wheelClip.y = 399;
}else if( whichBike == "SupermotoDRZ400" ){
//Add Wheels
wheelClip = new WheelClip ();
wheelClip.backTire.gotoAndStop ( bikeInfo.data.BikeColor );
wheelClip.frontTire.gotoAndStop ( bikeInfo.data.BikeColor );
addChild ( wheelClip );
wheelClip.x = 0;
wheelClip.y = 409.45;
//Add bike
bitmapBike = new SuperMoto_Bitmap ();
bitmapBike.gotoAndStop ( bikeInfo.data.BikeColor );
addChild ( bitmapBike );
bitmapBike.y = 399.80;
}else if( whichBike == "OriginalDirtBike" ){
//Add wheels
wheelClip = new OriginalBike_WheelClip ();
wheelClip.backTire.gotoAndStop ( bikeInfo.data.BikeColor );
wheelClip.frontTire.gotoAndStop ( bikeInfo.data.BikeColor );
addChild ( wheelClip );
wheelClip.x = 0;
wheelClip.y = 405;
//Add Bike
bitmapBike = new OriginalBike_Bitmap ();
addChild ( bitmapBike );
bitmapBike.gotoAndStop ( bikeInfo.data.BikeColor );
bitmapBike.y = 399.80;
//Add rider
//rider = new Rider_Original_bitmap ();
//addChild ( rider );
//rider.y = 353.1
}
//bitmapBike.mouseChildren = false;
//bitmapBike.mouseEnabled = false;
//bitmapBike.cacheAsBitmapMatrix = bitmapBike.transform.concatenatedMatrix;
//bitmapBike.cacheAsBitmap = true;
//
trace ( "bitmap bike : " + getSize ( bitmapBike) );
//rider.cacheAsBitmapMatrix = rider.transform.concatenatedMatrix;
//rider.cacheAsBitmap = true;
rider.mouseChildren = false;
rider.mouseEnabled = false;
gasPress.addEventListener ( MouseEvent.MOUSE_DOWN, hitGas );
gasPress.addEventListener ( MouseEvent.MOUSE_UP, releaseGas );
brake.addEventListener ( MouseEvent.MOUSE_DOWN, hitBrake );
brake.addEventListener ( MouseEvent.MOUSE_UP, releaseBrake );
stage.addEventListener ( KeyboardEvent.KEY_DOWN, useKeyboard);
stage.addEventListener ( KeyboardEvent.KEY_UP, stopUseKeyboard);
addEventListener ( Event.ADDED_TO_STAGE, init );
ScoreBoardFormat = new TextFormat ();
ScoreBoardFormat.bold = true;
sprocketVector = new Vector.< MovieClip > ();
sprocketPool = new SprocketPool( Sprocket, pool_SprocketAmount );
stage.addEventListener ( Event.RESIZE, resizeObjects );
stage.dispatchEvent( new Event( Event.RESIZE ) );
if( Accelerometer.isSupported ){
//on mobile device
}else{
//on desktop
gravity = 15; // low values for phone
dy = 60; // low values for phone
backgroundDx = -160;
buildingDx = -300;
dx = 300; // speed and direction
}
//start bike off in a wheelie
bitmapBike.rotation = -45;
rider.rotation = -45;
wheelClip.x = -15;
rider.x = bitmapBike.x;
//Add the first sprocket
addSprocket();
}
//Following Functions are Gas and Brake related
public function hitGas (e:MouseEvent){
e.stopImmediatePropagation();
holdGas = true;
pressedBrake = "no";
}
public function hitBrake (e:MouseEvent){
e.stopImmediatePropagation();
pressedBrake = "yes";
}
public function releaseGas (e:MouseEvent){
e.stopImmediatePropagation();
holdGas = false;
}
public function releaseBrake (e:MouseEvent){
e.stopImmediatePropagation();
pressedBrake = "no";
}
//Game Loop
public function gameLoop ( e:Event ):void{
e.stopImmediatePropagation();
var timePassed:int = getTimer()-lastTime;
lastTime += timePassed;
if ( whichBike == "SupermotoDRZ400" ){
//Keep wheels in position with the bike
wheelClip.rotation = bitmapBike.rotation;
wheelClip.x = bitmapBike.x;
//make tires spin
wheelClip.frontTire.rotation += 75*timePassed/1000;
wheelClip.backTire.rotation += 75*timePassed/1000;
rider.rotation = bitmapBike.rotation - 1;
rider.x = bitmapBike.x + 25;
}else if ( whichBike == "OriginalDirtBike" ){
//Keep wheels in position with the bike
wheelClip.rotation = bitmapBike.rotation - 1.5;
wheelClip.rotation = bitmapBike.rotation;
wheelClip.x = bitmapBike.x + 16.5;
//make tires spin
wheelClip.frontTire.rotation += 75*timePassed/1000;
wheelClip.backTire.rotation += 75*timePassed/1000;
//rider
rider.x = bitmapBike.x;
rider.rotation = bitmapBike.rotation;
}else if ( whichBike == "Banshee" ){
rider.rotation = bitmapBike.rotation;
rider.x = bitmapBike.x;
//First wheels
wheelClip.x = bitmapBike.x;
wheelClip.rotation = bitmapBike.rotation;
wheelClip.frontTire.frontFace.rotation += 75*timePassed/1000;
wheelClip.frontTire.backFace.rotation += 75*timePassed/1000;
wheelClip.backTire.frontFace.rotation += 75*timePassed/1000;
wheelClip.backTire.backFace.rotation += 75*timePassed/1000;
//second wheels
wheelClip2.x = bitmapBike.x;
wheelClip2.rotation = bitmapBike.rotation;
wheelClip2.farBackTire.frontFace.rotation += 75*timePassed/1000;
wheelClip2.farFrontTire.frontFace.rotation += 75*timePassed/1000;
wheelClip2.farFrontTire.backFace.rotation += 75*timePassed/1000;
}
if( popUp != null ){
this.setChildIndex ( popUp, this.numChildren - 2 );
}
this.setChildIndex ( rider, this.numChildren - 1 );
//Stores the bikes current rotation point
var currRotation = bitmapBike.rotation;
//make shadow follow bike
var bikeX:int = bitmapBike.x;
newShadow.x = bikeX + 150; //109.8;
//ANITMATING THE DRIVER!!!!
if( currRotation <= -11 ){ //This should occur at a lower
rider.gotoAndPlay ( "sitDown" );
sitDown = true;
newShadow.gotoAndStop ( "fullShadow" );
}
if( currRotation <= -15 ){
newShadow.gotoAndStop( "three4thShadow" );
leanBack = true;
}
//just change shadow with this one
if( currRotation <= -25 ){
newShadow.gotoAndStop ( "midShadow" );
}
if( currRotation <= -30 ){
rider.gotoAndPlay ( "LeanBack" );
leanBack = true;
newShadow.gotoAndStop ( "smallShadow" );
}
if( currRotation <= -34 ){ //Highest
rider.gotoAndPlay ( "LeanBack2" );
leanBack = true;
newShadow.gotoAndStop ( "smallestShadow" );
}
if( currRotation <= -35 ){ //Highest
rider.gotoAndPlay ( "LeanBack2" );
leanBack = true;
newShadow.gotoAndStop ( "allTheWayBack" );
}
//if player holds or hit the brake
if( pressedBrake == "yes" ) { //for some reason the opposite is working right now
var currBikePosition:int;
currBikePosition = bitmapBike.rotation;
bitmapBike.rotation += 2;
currBikePosition = 0;
}
//gravity pulling bike down
bitmapBike.rotation += gravity*timePassed/1000;
bitmapBike.rotation += gravity*timePassed/1000;
//if player holding gas, do wheeliez
if( holdGas == true ){
//Make bike wheelie
bitmapBike.rotation -= dy*timePassed/1000;
rider.rotation -= dy*timePassed/1000;
}
//Move Bike to center, then move buildings
if( bitmapBike.x <=187 ){
//move bike
bitmapBike.x += dx*timePassed/1000;
}else{
//move buildings and background
building1.x += buildingDx*timePassed/1000;
building2.x += buildingDx*timePassed/1000;
//buildings
if( building1.x <= -25 ){
building1.x = building2.x + building1.width;
}else if( building2.x <= -25 ){
building2.x = building1.x + building2.width;
}
background1.x += backgroundDx*timePassed/1000;
background2.x += backgroundDx*timePassed/1000;
//background
if( background1.x <=0 ){
background1.x = background2.x + background1.width;
}else if ( background2.x <=0 ){
background2.x = background1.x + background2.width;
}
}
How are you handling the masking of "background image"? How big is the image?
Most likely the drop is due to you having to redraw EVERYTHING when your bike moves since it can no longer reuse the old values of the cached bitmap. And since your background is HUGE this causes the performance drop you notice.
As a start, you should probably define a scrollRect on the "gigantic moving background" instead of just drawing the entire background. This causes only the part of image being shown to be sent to GPU. Such as bg.scrollRect = new Rectangle(offsetX,offsetY, 1280, 1024);
read http://gskinner.com/blog/archives/2006/11/understanding_d.html for a short introduction to scrollRect.
CacheAsBitmap might not be doing what you want it to do, if you are changing the look of a displayobject over each frame, you would actually loose performance since you first have to draw the items, then put them into a bitmap, and then draw that bitmap. Then on the next frame, you would end up redoing the exact same thing (since the old cached bitmap is no longer valid). cacheAsBitmap is very useful for when you have complex vector shapes that remain the same for an amount of frames.
For a more comprehensive optimization guideline, read the following two massive pdf-files:
http://help.adobe.com/en_US/as3/mobile/flashplatform_optimizing_content.pdf
http://help.adobe.com/en_US/as3/dev/as3_devguide.pdf
in Publish setting set your Hardware acceleration to GPU, that will lean off the processor

Get the upper, bottom, rightmost and leftmost point of a pixel-perfect BitmapData collision

How can I get the upper, bottom, rightmost and leftmost point of a pixel-perfect BitmapData collision? This is my collision-detection code:
public static function checkCollision(object1:*, object2:*, debug:Boolean = false):Boolean{
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
var object1Point:Point = new Point(object1Rect.x, object1Rect.y);
var object2Point:Point = new Point(object2Rect.x, object2Rect.y);
var bitmapData1:BitmapData = new BitmapData(
object1Rect.width,
object1Rect.height,
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
object2Rect.width,
object2Rect.height,
true,
0
);
var clr:ColorTransform = new ColorTransform();
if(debug)
clr.color = 0x00ff00;
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1Rect.x, -object1Rect.y), clr);
bitmapData2.draw(object2, null, clr);
if(debug){
if(bmp1.stage)
stage.removeChild(bmp1);
bmp1 = new Bitmap(bitmapData1);
bmp1.x = object1Point.x;
bmp1.y = object1Point.y;
stage.addChild(bmp1);
if(bmp2.stage)
stage.removeChild(bmp2);
bmp2 = new Bitmap(bitmapData2);
bmp2.x = object2Point.x;
bmp2.y = object2Point.y;
stage.addChild(bmp2);
}
var bCollide:Boolean = bitmapData1.hitTest(
object1Point,
255,
bitmapData2,
object2Point,
255
);
if(!debug){
bitmapData1.dispose();
bitmapData2.dispose();
}
return bCollide;
}
And it works perfeclty fine. However, the code I use to detect the top hitpoint doesn't work properly. This is the code:
public static function getHitPoint(object1:*, object2:*):Point{
var point:Point = new Point();
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
var object1Point:Point = new Point(object1Rect.x, object1Rect.y);
var object2Point:Point = new Point(object2Rect.x, object2Rect.y);
var bitmapData1:BitmapData = new BitmapData(
object1.width,
object1.height,
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
object2.width,
object2.height,
true,
0
);
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1Rect.x, -object1Rect.y));
bitmapData2.draw(object2);
var bitmap1:Bitmap = new Bitmap(bitmapData1);
var bitmap2:Bitmap = new Bitmap(bitmapData2);
bitmap1.x = object1Point.x;
bitmap1.y = object1Point.y;
bitmap2.x = object2Point.x;
bitmap2.y = object2Point.y;
var bitmapOrigin:Point = new Point(object1Point.x, object1Point.y);
var bitmap2OriginLocal:Point = bitmap2.globalToLocal(bitmapOrigin);
var overlappingPixels:Vector.<uint> = bitmap2.bitmapData.getVector(
new Rectangle(bitmap2OriginLocal.x, bitmap2OriginLocal.y, object1Rect.width, object1Rect.height)
);
for(var i:String in overlappingPixels){
var index:uint = uint(i);
if(overlappingPixels[i] != 0){
point.x = (index % object1.width) + (bitmap2.x > bitmap1.x ? bitmap2.x : bitmap1.x);
point.y = (uint(index / bitmap1.height)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
break;
}
}
return point;
}
I've got no idea why, but the getHitPoint() function sometimes returns the wrong coordinates. Can anyone please explain why that is? And how can I detect the bottommost, the leftmost and the rightmost hitpoint?
Edit
I now know why getHitPoint() sometimes returned a wrong value: point.y = (uint(index / bitmap1.height)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y); should be point.y = (uint(index/bitmap1.width)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
Edit 2
I found out how to get the bottom hitpoint:
public static function getHitPoint(object1:*, object2:*, direction:int = 0):*{
var point:Point = new Point();
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
var object1Point:Point = new Point(object1Rect.x, object1Rect.y);
var object2Point:Point = new Point(object2Rect.x, object2Rect.y);
var bitmapData1:BitmapData = new BitmapData(
Math.round(object1Rect.width),
Math.round(object1Rect.height),
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
Math.round(object2Rect.width),
Math.round(object2Rect.height),
true,
0
);
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1Rect.x, -object1Rect.y));
bitmapData2.draw(object2);
var bitmap1:Bitmap = new Bitmap(bitmapData1);
var bitmap2:Bitmap = new Bitmap(bitmapData2);
bitmap1.x = object1Point.x;
bitmap1.y = object1Point.y;
bitmap2.x = object2Point.x;
bitmap2.y = object2Point.y;
var bitmapOrigin:Point = new Point(object1Point.x, object1Point.y);
var bitmap2OriginLocal:Point = bitmap2.globalToLocal(bitmapOrigin);
var overlappingPixels:Vector.<uint> = bitmap2.bitmapData.getVector(
new Rectangle(bitmap2OriginLocal.x, bitmap2OriginLocal.y, object1Rect.width, object1Rect.height)
);
switch(direction){
case 0: //top
for(var i:String in overlappingPixels){
var index:uint = uint(i);
if(overlappingPixels[i] != 0){
point.x = (index % bitmap1.width) + (bitmap2.x > bitmap1.x ? bitmap2.x : bitmap1.x);
point.y = (uint((index)/bitmap1.width)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
return point;
}
}
case 1: //right
// I still need this
case 2: //bottom
overlappingPixels.reverse();
for(var i:String in overlappingPixels){
var index:uint = uint(i);
if(overlappingPixels[i] != 0){
point.x = bitmap1.width - (index % bitmap1.width) + (bitmap2.x > bitmap1.x ? bitmap2.x : bitmap1.x);
point.y = (bitmap2.y + bitmap2.height > bitmap1.y + bitmap1.height ? bitmap1.y + bitmap1.height : bitmap2.y + bitmap2.height) - (uint(index/bitmap1.width));
return point;
}
}
case 3: //left
// I still need this too
}
return false;
}
I still need a way to get the left and rightmost hitpoints though
You don't need to do it like you're doing there. You can do it all within a single function, which returns everything back correctly. I've added comments to the below. Please take note of what I've changed, as when you're trying to do it as you're doing now, with the code you changed, it is impossible.
This works for any shape, any direction. It'll give you the exact X and Y of the collision.
Please do not make this into a static function. Put it into a global class and use a Singleton to manage it instead. Things start to go very badly wrong when you being using static functions and reference the stage.
Also, if you're going to be working with pixel values of less than 1 (ie 99.75), the below will need a bit of adapting to cater for that. I've assumed you're using whole pixels, given your Math.round usage.
/**
*
* #param object1
* #param object2
* #return
*/
private function getHitPoint(object1:*, object2:*):*{
var point:Point;
// X and Y where we hit
// do NOT change this to a stage location or it does NOT work
var object1Point:Point = new Point(object1.x, object1.y);
var object2Point:Point = new Point(object2.x, object2.y);
var bitmapData1:BitmapData = new BitmapData(
Math.round(object1.width),
Math.round(object1.height),
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
Math.round(object2.width),
Math.round(object2.height),
true,
0
);
// Draw
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1.x, -object1.y));
bitmapData2.draw(object2);
// Create BMP's
var bitmap1:Bitmap = new Bitmap(bitmapData1);
var bitmap2:Bitmap = new Bitmap(bitmapData2);
// Set X and Y and BMP
bitmap1.x = object1Point.x;
bitmap1.y = object1Point.y;
bitmap2.x = object2Point.x;
bitmap2.y = object2Point.y;
// BMP origin is the object1 X and Y
var bitmapOrigin:Point = new Point(object1Point.x, object1Point.y);
// Create a local version of the bitmap2 so we can see what is overlapping
var bitmap2OriginLocal:Point = bitmap2.globalToLocal(bitmapOrigin);
// Create a rectangle from what we now know
var rect:Rectangle = new Rectangle(bitmap2OriginLocal.x, bitmap2OriginLocal.y, object1.width, object1.height);
// The overlapping pixels are within the rectangle, so get them all
var overlappingPixels:Vector.<uint> = bitmap2.bitmapData.getVector(rect);
// Run through all the overlapping pixels until we find a colourful one
for (var i:uint = 0; i < overlappingPixels.length; i++ ) {
var index:uint = overlappingPixels[i];
// If the colour is not 0, we have found it
if(index != 0){
point = new Point();
// Basically, instead of using width and getting 100, we're working out how
// many pixles across the overlap is. The Vector doesn't tell us this, so we need to work it out
var overlappingWidth:uint = object1.width - Math.abs(bitmap2OriginLocal.x);
// The Y is object1.y, minus the local y, plus object1's width minus the X from the local
point.y = object1.y - bitmap2OriginLocal.y + uint(i / overlappingWidth);
// The X is the same as above, but % of the width
point.x = object1.x - bitmap2OriginLocal.x + (i % overlappingWidth);
// Found it, we're done
break;
}
}
// Only fires when you've got a collision that is less than 1 pixel from the width or height
// Just a fail safe
if (!point) {
point = new Point(object1.width, object1.height);
}
return point;
}
For context, my entire class is below which shows how I was using this function. You can copy/paste this class and it will work. It shows how you move sprites around the screen, once it finds a collision, then it works out where the collision took place.
This class is for absolute pixel perfect collision detection, including an example.
package kazo
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.Matrix;
/**
* ...
* #author KM
*/
public class TestCases2 extends Sprite
{
private var rect :Sprite;
private var circle :Sprite;
/**
*
*/
public function TestCases2()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
trace('Starting test case');
// Rectangle
rect = new Sprite();
// Circle
circle = new Sprite();
// Draw the rectangle. Center point must be TOP LEFT
// If you're using Flash Professional, place everything at 0,0 inside the MC
rect.graphics.beginFill(0xff0000);
rect.graphics.drawRect(0, 0, 100, 100);
rect.graphics.endFill();
// Draw the circle. Center point is TOP LEFT, so the X and Y of the circle need to be equal to the radius
circle.graphics.beginFill(0xffff00);
circle.graphics.drawCircle(50, 50, 50);
circle.graphics.endFill();
// Add them
addChild(rect);
addChild(circle);
// Position
rect.x = 225;
rect.y = 75;
// Position
circle.x = 225;
circle.y = 225;
// Frame loop
addEventListener(Event.ENTER_FRAME, frameFunc);
}
/**
*
* #param e
*/
private function frameFunc(e:Event):void {
// move them around
circle.y -= 2;
circle.x += 0;
rect.y += 1;
rect.x += 0;
// Check for collisions. If found, stop. Pass 'true' as the final param if you want it to draw to the screen
if (checkCollision(rect, circle)) {
var ref:Point = getHitPoint(rect, circle);
// Draws where the collision hit
var loc:Sprite = new Sprite();
loc.graphics.beginFill(0x000000);
loc.graphics.drawRect(0, 0, 10, 10);
loc.graphics.endFill();
addChild(loc);
loc.x = ref.x;
loc.y = ref.y;
trace(ref);
removeEventListener(Event.ENTER_FRAME, frameFunc);
}
}
/**
*
* #param _obj1
* #param _obj2
* #param _debug
* #return
*/
private function checkCollision(_obj1:Sprite, _obj2:Sprite, _debug:Boolean = false):Boolean {
// Draw the first item to bitmapdata
var bmd1:BitmapData = new BitmapData(_obj1.width, _obj1.height, true, 0);
// ..and the second
var bmd2:BitmapData = new BitmapData(_obj2.width, _obj2.height, true, 0);
// Now draw them
bmd1.draw(_obj1);
bmd2.draw(_obj2);
// If we're in debug, also add the bitmap to the stage so we can see where we are
if (_debug) {
var bmp:Bitmap = new Bitmap(bmd1);
bmp.x = _obj1.x;
bmp.y = _obj1.y;
addChild(bmp);
var bmp2:Bitmap = new Bitmap(bmd2);
bmp2.x = _obj2.x;
bmp2.y = _obj2.y;
addChild(bmp2);
}
// Hit test including alpha channel. Obj1 X/Y, Obj2 X/Y, alpha channel
var rtn:Boolean = bmd1.hitTest(new Point(_obj1.x, _obj1.y), 255, bmd2, new Point(_obj2.x, _obj2.y), 255);
// Dispose the bitmap data, we dont need it anymore
if (!_debug) {
bmd1.dispose();
bmd2.dispose();
}
// Return the boolean
return rtn;
}
/**
*
* #param object1
* #param object2
* #return
*/
private function getHitPoint(object1:*, object2:*):*{
var point:Point;
// X and Y where we hit
// do NOT change this to a stage location or it does NOT work
var object1Point:Point = new Point(object1.x, object1.y);
var object2Point:Point = new Point(object2.x, object2.y);
var bitmapData1:BitmapData = new BitmapData(
Math.round(object1.width),
Math.round(object1.height),
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
Math.round(object2.width),
Math.round(object2.height),
true,
0
);
// Draw
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1.x, -object1.y));
bitmapData2.draw(object2);
// Create BMP's
var bitmap1:Bitmap = new Bitmap(bitmapData1);
var bitmap2:Bitmap = new Bitmap(bitmapData2);
// Set X and Y and BMP
bitmap1.x = object1Point.x;
bitmap1.y = object1Point.y;
bitmap2.x = object2Point.x;
bitmap2.y = object2Point.y;
// BMP origin is the object1 X and Y
var bitmapOrigin:Point = new Point(object1Point.x, object1Point.y);
// Create a local version of the bitmap2 so we can see what is overlapping
var bitmap2OriginLocal:Point = bitmap2.globalToLocal(bitmapOrigin);
// Create a rectangle from what we now know
var rect:Rectangle = new Rectangle(bitmap2OriginLocal.x, bitmap2OriginLocal.y, object1.width, object1.height);
// The overlapping pixels are within the rectangle, so get them all
var overlappingPixels:Vector.<uint> = bitmap2.bitmapData.getVector(rect);
// Run through all the overlapping pixels until we find a colourful one
for (var i:uint = 0; i < overlappingPixels.length; i++ ) {
var index:uint = overlappingPixels[i];
// If the colour is not 0, we have found it
if(index != 0){
point = new Point();
// Basically, instead of using width and getting 100, we're working out how
// many pixles across the overlap is. The Vector doesn't tell us this, so we need to work it out
var overlappingWidth:uint = object1.width - Math.abs(bitmap2OriginLocal.x);
// The Y is object1.y, minus the local y, plus object1's width minus the X from the local
point.y = object1.y - bitmap2OriginLocal.y + uint(i / overlappingWidth);
// The X is the same as above, but % of the width
point.x = object1.x - bitmap2OriginLocal.x + (i % overlappingWidth);
// Found it, we're done
break;
}
}
// Only fires when you've got a collision that is less than 1 pixel from the width or height
// Just a fail safe
if (!point) {
point = new Point(object1.width, object1.height);
}
return point;
}
}
}

Increasing and decreasing the volume of a jukebox(Actionscript 3)

So I've been working on this jukebox assignment for some time now. And I've stumbled upon a problem related to changing the volume of the jukebox while playing the animation.
Here's the code I was trying to use:
var st:SoundTransform = new SoundTransform();
st.volume = 0.3;
SoundMixer.soundTransform = st;
And while this code in itself works perfectly fine, when I try to add it to my script, it has no effect on the volume level. (The code above is not added to the code below, as it didn't work)
Here is my script:
import flash.media.Sound;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.media.SoundTransform;
//Equalizer
var _sound1 :Sound = null;
var _sound2 :Sound = null;
var _sound3 :Sound = null;
var _sound4 :Sound = null;
var _sound5 :Sound = null;
var _sound6 :Sound = null;
var _sound7 :Sound = null;
var _sound8 :Sound = null;
//Volume
var _soundChannel :SoundChannel = null;
_soundChannel = new SoundChannel();
//Sanger
_sound1 = new Sound(new URLRequest("lyd1.mp3"));
_sound2 = new Sound(new URLRequest("lyd2.mp3"));
_sound3 = new Sound(new URLRequest("lyd3.mp3"));
_sound4 = new Sound(new URLRequest("lyd4.mp3"));
_sound5 = new Sound(new URLRequest("lyd5.mp3"));
_sound6 = new Sound(new URLRequest("lyd6.mp3"));
_sound7 = new Sound(new URLRequest("lyd7.mp3"));
_sound8 = new Sound(new URLRequest("lyd8.mp3"));
//Spille sanger
knapp1.addEventListener(MouseEvent.CLICK, spill1);
knapp2.addEventListener(MouseEvent.CLICK, spill2);
knapp3.addEventListener(MouseEvent.CLICK, spill3);
knapp4.addEventListener(MouseEvent.CLICK, spill4);
knapp5.addEventListener(MouseEvent.CLICK, spill5);
knapp6.addEventListener(MouseEvent.CLICK, spill6);
knapp7.addEventListener(MouseEvent.CLICK, spill7);
knapp8.addEventListener(MouseEvent.CLICK, spill8);
function spill1(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound1.play();
skjermTekst.text = "Miami Nights - Ocean Drive";
}
function spill2(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound2.play();
skjermTekst.text = "Likelike - So Electric";
}
function spill3(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound3.play();
skjermTekst.text = "LazerHawk - Disco Planet";
}
function spill4(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound4.play();
skjermTekst.text = "Garth Knight - Silent Strike";
}
function spill5(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound5.play();
skjermTekst.text = "Mitch Murder - Terminator Theme";
}
function spill6(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound6.play();
skjermTekst.text = "Dynatron - Stars of the Night";
}
function spill7(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound7.play();
skjermTekst.text = "Electric Youth - The Best Thing";
}
function spill8(event:MouseEvent)
{
SoundMixer.stopAll();
_soundChannel = _sound8.play();
skjermTekst.text = "Borgeoisie - Neon Black";
}
//Equalizer
addEventListener(Event.ENTER_FRAME, Update, false, 0, true)
function Update($e:Event):void
{
_equalizer._eq1.gotoAndStop (Math.round(_soundChannel.leftPeak * 3) );
_equalizer._eq2.gotoAndStop (Math.round(_soundChannel.rightPeak * 5) );
_equalizer._eq3.gotoAndStop (Math.round(_soundChannel.leftPeak * 7) );
_equalizer._eq4.gotoAndStop (Math.round(_soundChannel.rightPeak * 9) );
_equalizer._eq5.gotoAndStop (Math.round(_soundChannel.leftPeak * 11) );
_equalizer._eq6.gotoAndStop (Math.round(_soundChannel.rightPeak * 13) );
_equalizer._eq7.gotoAndStop (Math.round(_soundChannel.leftPeak * 15) );
_equalizer._eq8.gotoAndStop (Math.round(_soundChannel.rightPeak * 17) );
_equalizer._eq9.gotoAndStop (Math.round(_soundChannel.leftPeak * 17) );
_equalizer._eq10.gotoAndStop (Math.round(_soundChannel.rightPeak * 15) );
_equalizer._eq11.gotoAndStop (Math.round(_soundChannel.leftPeak * 13) );
_equalizer._eq12.gotoAndStop (Math.round(_soundChannel.rightPeak * 11) );
_equalizer._eq13.gotoAndStop (Math.round(_soundChannel.leftPeak * 9) );
_equalizer._eq14.gotoAndStop (Math.round(_soundChannel.rightPeak * 7) );
_equalizer._eq15.gotoAndStop (Math.round(_soundChannel.leftPeak * 5) );
_equalizer._eq16.gotoAndStop (Math.round(_soundChannel.rightPeak * 3) );
}
Now, with the volume snippet added the volume of the jukebox stays the same. Even if I change the st.volume = 0.3 to any other number between 0 and 1.
You could optimise your code greatly, and for this task you don't need SoundMixer, your sounds and SoundChannels are easily accessible. Main idea is to manage one at time SoundChannel:
const soundKey:String = "sound";
const soundNameKey:String = "soundName";
var sounds:Dictionary = new Dictionary();
var mainChannel:SoundChannel;
var volume:SoundTransform = new SoundTransform(1);
//"Bind" your buttons to the corresponding Sound description
sounds[knapp1] = {"sound": new Sound(new URLRequest("path")), "soundName": "Miami Nights - Ocean Drive"};
//Add all your sounds
//sounds[knapp8] = ...;
//Add all knapp buttons to the one container
//myKnappContainer.addChild(knapp1); ...
myKnappContainer.addEventListener(MouseEvent.CLICK, onClick);
function onClick(e:MouseEvent):void {
var soundInfo:Object = sounds[e.target];
if (soundInfo != null) {
if (mainChannel != null) {
//Stop previous sound
mainChannel.stop();
}
//Start a new
mainChannel = Sound(soundInfo[soundKey]).play();
//Apply current volume
mainChannel.soundTransform = volume;
//Display sound name
skjermTekst.text = soundInfo[soundNameKey];
}
}

Drawing an honeycomb with as3

I'm trying to create an honeycomb with as3 but I have some problem on cells positioning.
I've already created the cells (not with code) and for cycled them to a funcion and send to it the parameters which what I thought was need (the honeycomb cell is allready on a sprite container in the center of the stage).
to see the structure of the cycle and which parameters passes, please see the example below, the only thing i calculate in placeCell is the angle which I should obtain directly inside tha called function
alt text http://img293.imageshack.us/img293/1064/honeycomb.png
Note: the angle is reversed but it isn't important, and the color are useful in example only for visually divide cases.
My for cycle calls placeCell and passes cell, current_case, counter (index) and the honeycomb cell_lv (cell level).
I thought it was what i needed but I'm not skilled in geometry and trigonometry, so I don't know how to position cells correctly:
import flash.display.Sprite;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
function createHoneycomb (cells:int):void {
var honeycomb:Sprite = new Sprite ();
addChild (honeycomb);
var cell_lv:int = 1;
var increment:int = 6;
var tot_cur_cells:int = 1;
var current_case:int = 0;
var case_counter:int = 1;
var case_length:int = 1;
var max_cases:int = 6;
var nucleus:Sprite = new cell (); // hexagon from library
honeycomb.addChild (nucleus);
for (var i:int = 1; i <= cells; i ++) {
if (case_counter < case_length) {
case_counter ++;
} else {
current_case ++;
if (current_case > max_cases) current_case = 1;
case_counter = 1;
}
if (i == tot_cur_cells) { // if i reach the current level
if (i > 1) cell_lv ++;
case_length = cell_lv;
tot_cur_cells += (increment * cell_lv);
}
var current_cell:Sprite = new cell (); // hexagon from library
honeycomb.addChild (current_cell);
placeCell (current_cell, case_counter, current_case, cell_lv);
}
function centerHoneycomb (e:Event):void {
honeycomb.x = stage.stageWidth / 2
honeycomb.y = Math.round (stage.stageHeight / 2);
}
stage.addEventListener (Event.RESIZE, centerHoneycomb)
stage.dispatchEvent (new Event (Event.RESIZE));
}
function placeCell (cell:Sprite, counter:int, current_case:int, cell_lv:int):void {
var margin:int = 2;
// THIS IS MY PROBLEM
var start_degree:Number = (360 / (cell_lv * 6));
var angle:Number = (start_degree * ((current_case - 1) + counter) - start_degree);
var radius:Number = (cell.width + margin) * cell_lv;
cell.x = radius * Math.cos (angle);
cell.y = radius * Math.sin (angle);
// end of the problem
if (angle != 0) trace ("LV " + cell_lv + " current_case " + current_case + " counter " + counter + " angle " + angle + " radius " + radius);
else trace ("LV " + cell_lv + " current_case " + current_case + " counter " + counter + " angle " + angle + " radius " + radius);
}
createHoneycomb (64);
if you copy and paste this code, it works but you need to create an hexagon and call it in the actionscript library as cell
how can I do to solve it?
I've also thought to use a switch with the cases to align it, but i think is a little bit buggy doing this
Okay, I really loved this question. It was interesting, and challenging, and I got a working result. I didn’t use any of your code as the base though, but started from scratch, so depending on your final use, you might need to change a bit.
I did however created similar variables to those inside of your cells (in the picture). For each cell you have the following properties:
the iterating variable i is equally to your cell number
the radius r equals your level, and expresses the distance from the center (with 0 being the center)
the position p expresses the position in the current radius
the sector s equals your case, but starts with zero
p % r equals your index
I don’t have an angle, simply because I don’t position the individual hexagons using an angle. Instead I base the position of the (fixed) positions of the hexagons at radius 1 and calculate the missing ones in between.
The following code shows my implementation with 61 (60 + the center; but it’s configurable). You can also see the code in action on Wonderfl.
package
{
import flash.display.Sprite;
public class Comb extends Sprite
{
public function Comb ()
{
Hexagon.scale = 0.5;
this.x = stage.stageWidth / 2;
this.y = stage.stageHeight / 2;
// draw honeycomb with 60 cells
drawComb( 60 );
}
private function drawComb ( n:uint ):void
{
var colors:Array = new Array( 0x33CC33, 0x006699, 0xCC3300, 0x663399, 0xFF9900, 0x336666 );
var sectors:Array = new Array(
new Array( 2, 0 ),
new Array( 1, 1 ),
new Array( -1, 1 ),
new Array( -2, 0 ),
new Array( -1, -1 ),
new Array( 1, -1 ) );
var w:Number = 0.50 * Hexagon.hxWidth;
var h:Number = 0.75 * Hexagon.hxHeight;
var r:uint, p:uint, s:uint;
var hx:Hexagon;
for ( var i:uint = 0; i <= n; i++ )
{
r = getRadius( i );
p = getPosition( i, r );
s = getSector( i, r, p );
// create hexagon
if ( r == 0 )
hx = new Hexagon( 0xCCCCCC );
else
hx = new Hexagon( colors[s] );
hx.x = w * ( r * sectors[s][0] - ( p % r ) * ( sectors[s][0] - sectors[ ( s + 1 ) % 6 ][0] ) );
hx.y = h * ( r * sectors[s][1] - ( p % r ) * ( sectors[s][1] - sectors[ ( s + 1 ) % 6 ][1] ) );
addChild( hx );
}
}
private function getRadius ( i:uint ):uint
{
var r:uint = 0;
while ( i > r * 6 )
i -= r++ * 6;
return r;
}
private function getPosition ( i:uint, r:uint ):uint
{
if ( r == 0 )
return i;
while ( r-- > 0 )
i -= r * 6;
return i - 1;
}
private function getSector ( i:uint, r:uint, s:uint ):uint
{
return Math.floor( s / r );
}
}
}
import flash.display.Shape;
class Hexagon extends Shape
{
public static var hxWidth:Number = 90;
public static var hxHeight:Number = 100;
private static var _scale:Number = 1;
public function Hexagon ( color:uint )
{
graphics.beginFill( color );
graphics.lineStyle( 3, 0xFFFFFF );
graphics.moveTo( 0, -50 );
graphics.lineTo( 45, -25 );
graphics.lineTo( 45, 25 );
graphics.lineTo( 0, 50 ),
graphics.lineTo( -45, 25 );
graphics.lineTo( -45, -25 );
graphics.lineTo( 0, -50 );
this.scaleX = this.scaleY = _scale;
}
public static function set scale ( value:Number ):void
{
_scale = value;
hxWidth = value * 90;
hxHeight = value * 100;
}
public static function get scale ():Number
{
return _scale;
}
}

Actionscript convert background to Transparent

The purpose of the function is to covert the background to transparent and then return the bitmapdata, but it seems it do not work. The code is following:
private function transparentConverter( source:BitmapData, threshold:Number = 0.1 ):BitmapData
{
var bitmapData:BitmapData = new BitmapData( source.width, source.height, true, 0x00000000 );
bitmapData.lock();
var color:uint = source.getPixel( 0, 0 );
var x:uint, y:uint;
for ( y = 0; y < source.height; y++ )
{
for ( x = 0; x < source.width; x++ )
{
var c1:uint = source.getPixel( x, y );
var c2:uint = color;
var rx:uint = Math.abs((( c1 & 0xff0000 ) >> 16 ) - (( c2 & 0xff0000 ) >> 16 ));
var gx:uint = Math.abs((( c1 & 0xff00) >> 8 ) - (( c2 & 0xff00 ) >> 8 ));
var bx:uint = Math.abs(( c1 & 0xff ) - ( c2 & 0xff ));
var dist:uint = Math.sqrt( rx*rx + gx*gx + bx*bx );
if ( dist <= threshold )
{
bitmapData.setPixel32( x, y, 0x00000000 );
}else
{
bitmapData.setPixel32( x, y, c1 );
}
}
}
bitmapData.unlock();
return bitmapData;
}
Please advice.
Can you try this :
// This bitmapData should be defined for real, wherever you get that from ...
var source:BitmapData;
if(source == null)
trace("The source cannot be empty");
// Here you get the transformed BitmapData
var destination:bitmapData = transparentConverter( source );
// You apply it to a Bitmap in order to visualize it
var viewBitmap:Bitmap = new Bitmap(destination);
// You add the Bitmap to the stage so you can see it
addChild(viewBitmap);
Theo, thanks for your effort. I think the problem is the functions takes too long to run. After I try your script, a warning messages come out. It said the program takes more than 15 seconds to run and told me to stop running.
I think the function should be OK, but, maybe, not quite practical.
Theo, thank for your time and advice again.
I think the question can be closed.
Theo, the function seems can run, but take some time, however no bitmapdata return.
I receive the bitmpadata by the following code:
bitmapData = transparentConverter( bitmapData );
var bitmap:Bitmap = new Bitmap( bitmapData );
image1.source = bitmap;
The image do not appear.
And also, I can trace( c1 ), and I get a long list of data.
Thanks for your response.