(Actionscript 3.0) Collision detection for draggable objects? - actionscript-3

I am currently working on a new Flash Game that is a sliding puzzle game. However, most of the pieces are not shaped like squares as in a standard sliding puzzle game, which makes the collision detection between the pieces much harder. I decided to try to program the collision detection between the Yellow L and the White L piece, each of which are a 100X100 squares with a 50X50 square cut off of the corner. Is there anyway to give them collision detection so that they cannot overlap each other?
var YellowLClicked: Boolean=false;
addEventListener(Event.ENTER_FRAME,onEnterFrameHandler);
YellowL.addEventListener(MouseEvent.MOUSE_DOWN, dragYellowL);
YellowL.addEventListener(MouseEvent.MOUSE_UP, DoNotdragYellowL);
YellowL.addEventListener(MouseEvent.ROLL_OUT, DoNotdragYellowL);
function dragYellowL(e:MouseEvent): void{
YellowLClicked=true;
}
function DoNotdragYellowL(e:MouseEvent): void{
YellowLClicked=false;
}
function onEnterFrameHandler(e:Event): void{
if(YellowLClicked){
YellowL.startDrag();
} else YellowL.stopDrag();
//Can you help with this code here?
if(YellowL.hitTestObject(WhiteL)) trace("true"); else trace(false);
}

This is the collision check I use in my tetris-style game. It is in my Main.as file.
private function checkCollision(f:GameField):Boolean{
var p:Piece = f.activePiece;
var a:Array = f.blockArray;
for (var j:int = 0; j < p.numChildren; j++){
var b:Block = p.getChildAt(j) as Block;
// check walls, your will probably have four instead of 3
if (b.hitTestObject(f.leftWall) || b.hitTestObject(f.rightWall) || b.row + b.rowLocal >= f._rows){
return true;
}
}
// check all the blocks in f.blockArray
for (var i:int = 0; i < a.length; i++){
// check the moving PIECE against all other BLOCKS
if (p.hitTestObject(a[i])){
// check every child of the PIECE (these will be the blocks)
for (var j:int = 0; j < p.numChildren; j++){
// excluding the BLOCKS in the moving PIECE
if (p.getChildAt(j).parent != a[i].parent){
var b:Block = p.getChildAt(j) as Block;
// finally, BLOCK vs BLOCK collision check
if (b.hitTestObject(a[i])){
return true;
}
}
}
}
}
return false;
}
This is the constructor for my Piece class:
public function Piece(f:GameField,shape:Array,color:uint)
{
makeGrid();
f.addChild(this);
// the shape array passed to this constructor is shown at the end of my post
_shape = shape;
addBlocks(f,shape,color);
}
private function addBlocks(f:GameField, shape:Array, color:uint):void{
_shape = shape;
for (var i:int = 0; i < shape.length; i++){
var b:Block = new Block(color);
// this uses the Array passed as var "shape" to tell where the block will be in relation to the center of rotation of the Piece instance
b.rowLocal = shape[i].y+2;
b.columnLocal = shape[i].x+2;
// this tells the brick its starting column and row are
b.row = -2;
b.column = 3;
// this is the sum of the local and global coordinates
b.y = (b.rowLocal + b.row) * Main.UNIT_SIZE;
b.x = (b.columnLocal + b.column) * Main.UNIT_SIZE;
// put the block on the display list
addChild(b);
// add the block to the array to use for collision checks in the Main doc
f.blockArray.push(b);
}
}
And the Block class just extends sprite and draws a square (mine has some goodies that don't need to be applied here, so I won't post it).
And finally the calling of the Piece constructor and an example of the shape array that gets passed to it.
var newP:Piece = new Piece(f, arr, color);
and the shape Array:
_shapeArray = [
{shape:new Array(new Point (-2, 0), new Point (-1, 0), new Point (0, 0), new Point (1, 0)),color:_colorArray[0]}, // I
{shape:new Array(new Point (-1, -1), new Point (-1, 0), new Point (0, 0), new Point (0, -1)),color:_colorArray[1]}, // O
{shape:new Array(new Point (-2, -1), new Point (-1, -1), new Point (-1, 0), new Point (0, 0)),color:_colorArray[2]}, // Z
{shape:new Array(new Point (-2, 0), new Point (-1, 0), new Point (-1, -1), new Point (0, -1)),color:_colorArray[3]}, // S
{shape:new Array(new Point (-2, 0), new Point (-1, 0), new Point (0, 0), new Point (-2, -1)),color:_colorArray[4]}, // J
{shape:new Array(new Point (-2, 0), new Point (-1, 0), new Point (0, 0), new Point (0, -1)),color:_colorArray[5]}, // L
{shape:new Array(new Point (-2, 0), new Point (-1, 0), new Point (0, 0), new Point (-1, -1)),color:_colorArray[6]} // T
];
To summarize:
Make a Block class that extends Sprite
Make a Piece class that contains Block instances arranged in a shape that you choose.
Run a collision check between pertinent Block pieces.
edit
This looks like it could work. However, I have one more question: checkCollision() returns a boolean but what I do with that boolean? If the boolean is true, how do I make the objects unable to cross?
This is how I implemented that. Allow the objects to cross each other and then call
if (checkCollision(f)) {
// check collision returned true
// so reverse the last move
// before finishing this game loop
}

Related

can you explain me as3 randomly swap shapes' positions

I copy some code and want to use it but I don't understand. this code is about How to randomly swap shapes' positions in specific locations. anyone can explain in simple how this code works?
function randomSort(a:*, b:*):Number
{
if (Math.random() < 0.5) return -1;
else return 1;
}
// Push 12 positions as new Point() in an array.
var positions:Array = [ new Point(12, 42), new Point(43, 56), new Point(43,87) ]; // ...add 12 positions
var mcs:Array = [mc1, mc2, mc3]; // ...add 12 mcs
positions.sort(randomSort);
// link randomized position to MovieClips:
for (var i:int = 0, l:int = positions.length; i < l, i++ ) {
var mc:MovieClip = mcs[i];
var point:Point = positions[i];
mc.x = point.x;
mc.y = point.y;
}
There are two lists: MovieClips and Points. The provided script randomizes one of the lists, so each MovieClip get a random Point out of the given ones.
The idea of random-sorting could be confusing a bit. The Array.sort() method is intended to organize Array's elements on given criteria, but if you give a random-based criteria instead, the elements are mixed with no predefined order.
The other (and probably more understandable) way to do the thing is to match a fixed MovieClip to a random Point, then remove matched pair from the respective lists, then proceed until there are items left.
var P:Array = [new Point(12, 42), new Point(43, 56), new Point(43,87)];
var M:Array = [mc1, mc2, mc3];
// Do while there are items to process.
while (M.length)
{
// Get the last MovieClip and remove it from the list.
var aMC:MovieClip = M.pop();
// Produce a random Point.
var anIndex:int = Math.random() * P.length;
var aPo:Point = P[anIndex];
// Remove the selected Point from its list.
P.splice(anIndex, 1);
// Move the selected MovieClip to the selected Point coordinates.
aMC.x = aPo.x;
aMC.y = aPo.y;
}

Dynamically generated display object as a gradient mask

I just want to create a gradient mask –which is generated dynamically through AS3 code– for an object (a pentagon in my following example,) and I simply, cannot! [The SWF file of what I've tried.]
The code works just fine unless it ignores the alpha gradient of the dynamically created Sprite for being used as a gradient mask (it's being treated as a solid mask), while the exact code acknowledges the "on-stage" created object (through the user interface) for being a gradient mask!
I think the runtime just cannot cache the object as bitmap and hence the ignorance! However, I'm stuck at making that happen! So please, shed some lights on this, any help is greatly appreciated in advance :)
var X:Number = 100, Y:Number = 35, W:Number = 350, H:Number = 150;
var mat:Matrix = new Matrix();
mat.createGradientBox(W, H, 0, X, Y);
var gradientMask:Sprite = new Sprite();
gradientMask.graphics.beginGradientFill(GradientType.LINEAR, [0, 0], [1, 0], [0, 255], mat);
gradientMask.graphics.drawRect(X, Y, W, H);
gradientMask.graphics.endFill();
pentagon1.cacheAsBitmap = true;
pentagon2.cacheAsBitmap = true;
onStageGradient.cacheAsBitmap = true;
gradientMask.cacheAsBitmap = true;
pentagon1.mask = gradientMask;
pentagon2.mask = onStageGradient;
stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
function _onEnterFrame(e:Event):void {
pentagon1.x += 7;
pentagon2.x += 7;
if (pentagon1.x > 500) {
pentagon1.x = 0;
pentagon2.x = 0;
}
}
You have to add the gradientMask to the display list to have it in effect.
pentagon1.parent.addChild(gradientMask);

Flex/AS Component

Hi i want to make a component to draw a Graph like this:
However, the Area under the Graph should be filled with red color. I have 2 different types of values i use on x value i want to use time and on the y i want to use money value both ints but how should i start? My Idea on start was to draw Sprites with Vector but that dont work, because he starts on top left regular zero point and i cant fill the complete area under the graph.
package
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Point;
[SWF(backgroundColor="0xFFFFFF" , width="500" , height="500")]
public class Highprofil extends Sprite
{
public function Highprofil()
{
var drawSprite:Sprite = new Sprite();
var localPoint:Point = drawSprite.localToGlobal(new Point(0,999));
var money:Array = new Array(1,2,10,20,10,2,1);
var time:Array = new Array(12,58,52,41,66,98,3);
var geo:Shape=new Shape();
var testdata:Vector.<Number>=new Vector.<Number>;
for(var i:int=0;i<money.length;i++){
testdata.push(money[i]);
testdata.push(time[i]);
}
var commands:Vector.<int> = new Vector.<int>();
for(var j:int=0;j<money.length;j++){
commands.push(j);
}
drawSprite.graphics.beginFill(0xFFFF0000); // Color Red
drawSprite.graphics.drawPath(commands, testdata); // Draw the path
drawSprite.graphics.endFill();
addChild(drawSprite);
}
}
}
This will be a Uicomponent dont know if its easier to realize in flex component, but actually it doesnt even look close like a graph.
The code you have there misses some points clearly stated in the docs of Graphics.drawPath() and has some indentation issues ;) .
The most important part is, that the commands Vector should contain values from GraphicsPathCommand, in your case 2 for LINE_TO to draw lines between the coordinates.
Then to get the desired graph, you need to order the X values (and the Y values accordingly). I ordered those values manually in the code and made up my own Y values for testing.
Then in your loop you first added the Y values and then the X values to testdata, but it needs to be the other way around [x, y, x, y, x, y,...].
Only doing this gave me a great graph that pointed downwards. So I continued with tweaking the code a little bit (see comments)and came up with this:
http://wonderfl.net/c/6BrY
(there you can fork it and play with it seeing the result instantly)
for direct/later reference here is the code only:
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.GraphicsPathCommand;
public class FlashTest extends Sprite {
public function FlashTest() {
var drawSprite:Sprite = new Sprite();
//the values for the X axis need to be sorted!
var time:Array = new Array( 3, 12, 41, 52, 58, 66, 98);
var money:Array = new Array( 4, 3, 9, 20, 10, 8, 15);
var testdata:Vector.<Number>=new Vector.<Number>();
var commands:Vector.<int> = new Vector.<int>();
var currentY:Number, maxY:Number = 0;
//some "scaling" for the values, otherwise those are pixels
const scaleX:int = 3, scaleY:int = 10;
for(var i:int=0;i<money.length;i++){
//first X values!
testdata.push(time[i]*scaleX);
//then Y values
currentY = money[i]*scaleY;
testdata.push(-currentY);//adding negative values so the graph goes upwards
if(currentY > maxY){
maxY = currentY;//keep track of highest point in graph
}
commands.push(GraphicsPathCommand.LINE_TO);
}
//get the graph back to zero maxX/0 so it gets filled correctly (independent of last X value)
testdata.push(time[time.length-1]*scaleX, 0);
commands.push(GraphicsPathCommand.LINE_TO);
drawSprite.graphics.beginFill(0xFFFF0000);
drawSprite.graphics.drawPath(commands, testdata);
drawSprite.graphics.endFill();
addChild(drawSprite);
drawSprite.y = maxY + 10;//moving the sprite down so the graph is completely visible (+10 pixel padding)
drawSprite.x = 10;//(+10 pixel padding)
}
}
}

Render to texture not functioning

I'm trying to test Stage3D's setRenderToTexture function, but my test code is not providing any output. I was hoping someone could tell me why - I've tried practically everything to get this working. The code I've created is below:
import flash.events.Event;
import flash.display.*;
import flash.display3D.*;
import flash.display3D.textures.Texture;
import AGALMiniAssembler;
//using stage size in several locations for simplicity - needs to be square, 2^n
[SWF(width='512', height='512', backgroundColor='0x000000', frameRate='60')]
//vars
var context0:Context3D;
var vBuff:VertexBuffer3D;
var iBuff:IndexBuffer3D;
var tex0:Texture;
var tex1:Texture;
var vShader:AGALMiniAssembler = new AGALMiniAssembler();
var fShader:AGALMiniAssembler = new AGALMiniAssembler();
var program:Program3D;
//create a square
var square:Shape = new Shape();
square.graphics.beginFill(0xaa00ff,1);
square.graphics.drawRect(10, 10, stage.stageWidth - 20, stage.stageHeight - 20);
//draw square to bitmapdata and create one blank bitmapdata
var tex0data:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0);
tex0data.draw(square);
var tex1data:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0);
//initialize stage3d
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, initStage3D);
stage.stage3Ds[0].requestContext3D();
function initStage3D(e:Event):void {
context0 = stage.stage3Ds[0].context3D;
context0.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0);
//create buffers - simple quad
var vBuff_vec:Vector.<Number> = new <Number>[-1, -1, 0, 0, 1,
-1, 1, 0, 0, 0,
1, 1, 0, 1, 0,
1, -1, 0, 1, 1];
var iBuff_vec:Vector.<uint> = new <uint>[0, 1, 2, 0, 2, 3]
vBuff = context0.createVertexBuffer(4, 5);
vBuff.uploadFromVector(vBuff_vec, 0, 4);
iBuff = context0.createIndexBuffer(6);
iBuff.uploadFromVector(iBuff_vec, 0, 6);
//load bitmapdata into textures - square to tex0 and blank to tex1
tex0 = context0.createTexture(tex0data.width,tex0data.height,'bgra',false);
tex0.uploadFromBitmapData(tex0data);
tex1 = context0.createTexture(tex1data.width, tex1data.height,'bgra',true);
tex1.uploadFromBitmapData(tex1data);
//create and upload simple shader program
vShader.assemble('vertex', 'mov v0, va1 \n'+ //uv coords to v0
'mov op, va0'); //output xyz coords
fShader.assemble('fragment', 'tex oc, v0, fs0 <2d, linear, nomip>'); //output texture at fs0
program = context0.createProgram();
program.upload(vShader.agalcode, fShader.agalcode);
context0.setProgram(program);
//set buffers
context0.setVertexBufferAt(0, vBuff, 0, 'float3');
context0.setVertexBufferAt(1, vBuff, 3, 'float2');
//prep rendering
addEventListener(Event.ENTER_FRAME, render);
}
function render(e:Event):void {
context0.clear();
//render tex0 onto tex1
context0.setRenderToTexture(tex1);
context0.setTextureAt(0, tex0);
context0.drawTriangles(iBuff);
//render tex1 to back buffer and present
context0.setTextureAt(0, tex1);
context0.setRenderToBackBuffer();
context0.drawTriangles(iBuff);
context0.present();
}
EDIT: I have noticed that changing the color of the blank bitmap does change the color of the final output - it's being displayed, but the square isn't being rendered to it.
FINALLY figured this out! There is a subtle, but important, step that must be taken before a texture is viable as a render target - it must be cleared after the render target is switched. Revising the render function as follows causes the program to function as expected:
function render(e:Event):void {
//render tex0 onto tex1
context0.setRenderToTexture(tex1);
context0.clear();
context0.setTextureAt(0, tex0);
context0.drawTriangles(iBuff);
//render tex1 to back buffer and present
context0.setTextureAt(0, tex1);
context0.setRenderToBackBuffer();
context0.clear();
context0.drawTriangles(iBuff);
context0.present();
}

Converting bitmap to vector in as3

I have been trying to convert a bitmap I've captured from a camera input into a vector to then convert the vectors points into an array for use later.
However I can not find any such functionality within Flash and so I've been trying to use 'Vectorization Package' created by Corey O'Neil. This seems to work but fails to remove the white background on my bitmap (I am capturing a picture of paper with a line on it). Even manually doing this and making the background transparent still yields no results.
Here is my code:
public class DocumentRich extends MovieClip{
public var initBox2D:Main;
var cam:Camera = Camera.getCamera();
var vid:Video = new Video(420, 300);
var myVector:Vectorize;
public function DocumentRich()
{
if(stage){
initBox2D = new Main();
addChild(initBox2D);
//addChild(new movieMonitor());
}
addEventListener(MouseEvent.CLICK, clickHandler, false, 0, true);
StartAnim();
}
function StartAnim():void
{
//SET UP WORLD
initBox2D.isDebugMode(false);
initBox2D.mouseDragEnabled(true);
Main.world.SetGravity(new b2Vec2(0,0));
cam.setQuality(0, 100);
cam.setMode(420, 300, 30, true);
trace(cam.height);
vid.attachCamera(cam);
addChild(vid);
addChild(go);
}
function clickHandler(m:MouseEvent){
trace(m.target.name);
switch(m.target.name){
case 'go':
goButtonFun();
break;
}
}
function goButtonFun():void{
var screenShot:BitmapData = new BitmapData(cam.width, cam.height);
var screenShot_image:Bitmap=new Bitmap(screenShot);
screenShot.draw(vid) ;
ReduceColors.reduceColors(screenShot, 0, true, false);
screenShot.colorTransform(new Rectangle(0, 0, screenShot.width, screenShot.height), new ColorTransform(2,2,2,1) );
///// --------- MAY NOT NEED THIS ----------- ////////////
for(var i:int = 0; i<screenShot.width; i++)
{
for(var j:int = 0; j<screenShot.height; j++)
{
if(screenShot.getPixel(i,j) == 0xffffff)
{
var transparent:uint = 0x00000000;
screenShot.setPixel32(i, j, transparent);
}
}
}
myVector = new Vectorize(screenShot_image, 23, 2, 1, 3, 0xFFFFFF);
myVector.addEventListener(Vectorize.INIT, traceStatus);
myVector.addEventListener(Vectorize.DESPECKLE_START, traceStatus);
myVector.addEventListener(Vectorize.DESPECKLE_COMPLETE, traceStatus);
myVector.addEventListener(Vectorize.GROUPING_START, traceStatus);
myVector.addEventListener(Vectorize.GROUPING_COMPLETE, traceStatus);
myVector.addEventListener(Vectorize.EDGING_START, traceStatus);
myVector.addEventListener(Vectorize.EDGING_COMPLETE, traceStatus);
myVector.addEventListener(Vectorize.DESPECKLE_PROGRESS, traceProgress);
myVector.addEventListener(Vectorize.GROUPING_PROGRESS, traceProgress);
myVector.addEventListener(Vectorize.EDGING_PROGRESS, traceProgress);
myVector.addEventListener(Vectorize.COMPLETE, showVector);
myVector.vectorize();
//addChild(screenShot_image);
addChild(go);
removeChild(vid);
cam = null;
vid.attachCamera(null);
vid = null;
}
function traceStatus(event:Event):void
{
trace(event.type);
}
function traceProgress(event:Event):void
{
var progress:int = event.target.percentDone * 100;
trace(event.type + ": " + progress + "%");
}
function showVector(event:Event):void
{
trace(event.type);
addChild(myVector);
}
}
Any suggestions?
Thanks.
UPDATE:
Sorry for any confusion, basically I would like a way to trace a transparent bitmap, and get an array of the points of the shape in said bitmap. An array of pixel data is simply too large... I'd like 4 points for a rectangle, regardless of it's size...
Apparently you are looking for BitmapData.getVector(). It's available from Flash player 10, so you should have it at your disposal.
EDIT: After I've reread your question, I understand you want your bitmap to be parsed into a vector - and a vector isn't an array of pixels, but instead a start and end of a certain line. Then yes, if you are capable of calling a threshold() so that the line's pixels will be of one color, and the background of another, you then can call getColorBoundsRect() and query all 4 corners of the rectangle. The ones which have the color of the line are your start and end coordinates, store these.