Copy link to clipboard
Copied
Hi,
I found an interesting tutorial (link) and created a working model, adapting it as needed.
So far, when I center the container sprite and rotate it, it appears to first rotate from a 0,0 registration point, instead of from its center. I've tried to changet he sprite's registration point, but so far this hasn't worked/helped. Nothing else has worked to fix this rotation problem.
I must be doing something wrong.
Here's the AS3 (to view, add to first frame of new FLA, 1024X768 stage, color black). Rotation segments below are commented as //ROTATION.:
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.TextField;
//import flash.geom.ColorTransform;
stop();
//public class bejewelled extends Sprite {
var gems_array:Array=new Array();
var aGem:Sprite;
var selectorBox:Sprite=new Sprite();
var selectorRow:int=-10;
var selectorColumn:int=-10;
var red:uint = 0xFF0000;
var green:uint = 0xFF00;
var blue:uint = 0xFF;
var yellow:uint = 0xFFFF00;
var cyan:uint = 0xFFFF;
var magenta:uint = 0xFF00FF;
var white:uint = 0xFFFFFF;
var colours_array:Array=new Array(red,green,blue,yellow,cyan,magenta,white);
var clickPossible:Boolean=false;
var score_txt:TextField=new TextField();
var hint_txt:TextField=new TextField();
var score:uint=0;
var inaRow:uint=0;
var match:Boolean = true;
var gemSize:uint = 96;
var format:TextFormat = new TextFormat();
var rotate:Boolean=false;
var container:Sprite = new Sprite(); // Create the container sprite
//var newColorTransform:ColorTransform = exitBtn.transform.colorTransform;
//newColorTransform.color = 0xff0000;
//exitBtn.transform.colorTransform = newColorTransform;
function bejewelled() {
// Game initiation
format.size = 40;
format.font = 'Arial';
// Create and style score text
addChild(score_txt);
score_txt.textColor=0xFFFFFF;
score_txt.x=gemSize*9.6;
score_txt.autoSize = TextFieldAutoSize.LEFT;
score_txt.defaultTextFormat = format;
// Create and style hint text
addChild(hint_txt);
hint_txt.textColor=0xFFFFFF;
hint_txt.x=gemSize*9.6;
hint_txt.y=gemSize;
hint_txt.autoSize = TextFieldAutoSize.LEFT;
hint_txt.defaultTextFormat = format;
// Create Gems in rows and columns
addChild(container); // Add the container to the display list (stage)
for (var i:uint=0; i<8; i++) {
gems_array=new Array();
for (var j:uint=0; j<8; j++) {
do {
gems_array
=Math.floor(Math.random()*7); }
while (rowLineLength(i,j)>2 || columnLineLength(i,j)>2);
aGem=new Sprite();
aGem.graphics.beginFill(colours_array[gems_array
]); aGem.graphics.drawCircle(gemSize/2,gemSize/2,gemSize/2.07);
aGem.graphics.endFill();
aGem.name=i+"_"+j;
aGem.x=j*gemSize;
aGem.y=i*gemSize;
container.addChild(aGem);
}
}
//Center the container sprite
container.width = container.width - 10;
container.height = container.height - 10;
container.x = (stage.stageWidth-container.width)/2;
container.y = (stage.stageHeight-container.height)/2;
// Create and style selector box
container.addChild(selectorBox);
selectorBox.graphics.lineStyle(2,red,1);
selectorBox.graphics.drawRect(0,0,gemSize,gemSize);
selectorBox.visible=false;
// Listen for user input
container.addEventListener(MouseEvent.CLICK,onClick);
addEventListener(Event.ENTER_FRAME,everyFrame);
}
// Every frame...
function everyFrame(e:Event):void {
//Assume that gems are not falling
var gemsAreFalling:Boolean=false;
// Check each gem for space below it
for (var i:int=6; i>=0; i--) {
for (var j:uint=0; j<8; j++) {
// If a spot contains a gem, and has an empty space below...
if (gems_array
!= -1 && gems_array[i+1] ==-1) { // Set gems falling
gemsAreFalling=true;
gems_array[i+1]
=gems_array ; gems_array
=-1; trace("#");
trace(i+"_"+j);
container.getChildByName(i+"_"+j).y+=gemSize;
container.getChildByName(i+"_"+j).name=(i+1)+"_"+j;
break;
}
}
// If a gem is falling
if (gemsAreFalling) {
// don't allow any more to start falling
break;
}
}
// If no gems are falling
if (! gemsAreFalling) {
// Assume no new gems are needed
var needNewGem:Boolean=false;
// but check all spaces...
for (i=7; i>=0; i--) {
for (j=0; j<8; j++) {
// and if a spot is empty
if (gems_array
==-1) { // now we know we need a new gem
needNewGem=true;
// pick a random color for the gem
gems_array[0]
=Math.floor(Math.random()*7); // create the gem
aGem=new Sprite();
aGem.graphics.beginFill(colours_array[gems_array[0]
]); aGem.graphics.drawCircle(gemSize/2,gemSize/2,gemSize/2.07);
aGem.graphics.endFill();
// ID it
aGem.name="0_"+j;
// position it
aGem.x=j*gemSize;
aGem.y=0;
// show it
container.addChild(aGem);
// stop creating new gems
break;
}
}
// if a new gem was created, stop checking
if (needNewGem) {
break;
}
}
// If no new gems were needed...
if (! needNewGem) {
// assume no more/new lines are on the board
var moreLinesAvailable:Boolean=false;
// check all gems
for (i=7; i>=0; i--) {
for (j=0; j<8; j++) {
// if a line is found
if (rowLineLength(i,j)>2 || columnLineLength(i,j)>2) {
// then we know more lines are available
moreLinesAvailable=true;
// creat a new array, set the gem type of the line, and where it is
var lineGems:Array=[i+"_"+j];
var gemType:uint=gems_array
; var linePosition:int;
// check t's a horizontal line...
if (rowLineLength(i,j)>2) {
// if so, find our how long it is and put all the line's gems into the array
linePosition=j;
while (sameGemIsHere(gemType,i,linePosition-1)) {
linePosition--;
lineGems.push(i+"_"+linePosition);
}
linePosition=j;
while (sameGemIsHere(gemType,i,linePosition+1)) {
linePosition++;
lineGems.push(i+"_"+linePosition);
}
}
// check t's a vertical line...
if (columnLineLength(i,j)>2) {
// if so, find our how long it is and put all the line's gems into the array
linePosition=i;
while (sameGemIsHere(gemType,linePosition-1,j)) {
linePosition--;
lineGems.push(linePosition+"_"+j);
}
linePosition=i;
while (sameGemIsHere(gemType,linePosition+1,j)) {
linePosition++;
lineGems.push(linePosition+"_"+j);
}
}
// for all gems in the line...
for (i=0; i<lineGems.length; i++) {
// remove it from the program
container.removeChild(container.getChildByName(lineGems));
// find where it was in the array
var cd:Array=lineGems.split("_");
// set it to an empty gem space
gems_array[cd[0]][cd[1]]=-1;
// set the new score
score+=inaRow;
// set the score setter up
inaRow++;
}
// if a row was made, stop the loop
break;
}
}
// if a line was made, stop making more lines
if (moreLinesAvailable) {
break;
}
}
// if no more lines were available...
//ROTATION
if (! moreLinesAvailable) {
if(rotate){
container.rotation+=5;
if(container.rotation%90==0){
rotate=false;
container.rotation=0;
rotateClockwise(gems_array);
while(container.numChildren>0){
container.removeChildAt(0);
}
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
aGem=new Sprite();
aGem.graphics.beginFill(colours_array[gems_array
]); aGem.graphics.drawCircle(gemSize/2,gemSize/2,gemSize/2.07);
aGem.graphics.endFill();
aGem.name=i+"_"+j;
aGem.x=j*gemSize;
aGem.y=i*gemSize;
container.addChild(aGem);
container.addChild(selectorBox);
selectorBox.graphics.lineStyle(2,red,1);
selectorBox.graphics.drawRect(0,0,gemSize,gemSize);
selectorBox.visible=false;
}
}
}
}
else{
// allow new moves to be made
clickPossible=true;
// remove score multiplier
inaRow=0;
}
}
}
}
// display new score
score_txt.text=score.toString();
}
// When the user clicks
function onClick(e:MouseEvent):void {
// If a click is allowed
if (clickPossible) {
// If the click is within the game area...
if (mouseX<container.x+gemSize*8 && mouseX>0 && mouseY<container.y+gemSize*8 && mouseY>0) {
// Find which row and column were clicked
var clickedRow:uint=Math.floor((mouseY-container.y)/gemSize);
//var clickedRow:uint=Math.floor(e.target.y/gemSize);
var clickedColumn:uint=Math.floor((mouseX-container.x)/gemSize);
//var clickedColumn:uint=Math.floor(e.target.x/gemSize);
// Check if the clicked gem is adjacent to the selector
// If not...
if (!(((clickedRow==selectorRow+1 || clickedRow==selectorRow-1)&&clickedColumn==selectorColumn)||((clickedColumn==selectorColumn+1 || clickedColumn==selectorColumn-1) && clickedRow==selectorRow))) {
// Find row and colum the selector should move to
selectorRow=clickedRow;
selectorColumn=clickedColumn;
// Move it to the chosen position
selectorBox.x=gemSize*selectorColumn;
selectorBox.y=gemSize*selectorRow;
// If hidden, show it.
selectorBox.visible=true;
}
// If it is not next to it...
else {
// Swap the gems;
swapGems(selectorRow,selectorColumn,clickedRow,clickedColumn);
// If they make a line...
if (rowLineLength(selectorRow,selectorColumn)>2 || columnLineLength(selectorRow,selectorColumn)>2||rowLineLength(clickedRow,clickedColumn)>2 || columnLineLength(clickedRow,clickedColumn)>2) {
// remove the hint text
hint_txt.text="";
// dis-allow a new move until cascade has ended (removes glitches)
clickPossible=false;
// move and rename the gems
container.getChildByName(selectorRow+"_"+selectorColumn).x=e.target.x;//clickedColumn*gemSize;
container.getChildByName(selectorRow+"_"+selectorColumn).y=e.target.y;//clickedRow*gemSize;
container.getChildByName(selectorRow+"_"+selectorColumn).name="t";
container.getChildByName(clickedRow+"_"+clickedColumn).x=selectorColumn*gemSize;
container.getChildByName(clickedRow+"_"+clickedColumn).y=selectorRow*gemSize;
container.getChildByName(clickedRow+"_"+clickedColumn).name=selectorRow+"_"+selectorColumn;
container.getChildByName("t").name=clickedRow+"_"+clickedColumn;
match = true;
rotate = true;
}
// If not...
else {
// Switch them back
swapGems(selectorRow,selectorColumn,clickedRow,clickedColumn);
match = false;
}
if (match) {
// Move the selector position to default
selectorRow=-10;
selectorColumn=-10;
// and hide it
selectorBox.visible=false;
}
else {
// Set the selector position
selectorRow=clickedRow;
selectorColumn=clickedColumn;
// Move the box into position
selectorBox.x=gemSize*selectorColumn;
selectorBox.y=gemSize*selectorRow;
match = false;
// If hidden, show it.
selectorBox.visible=true;
}
}
}
// If the click is outside the game area
else {
// For gems in all rows...
for (var i:uint=0; i<8; i++) {
// and columns...
for (var j:uint=0; j<8; j++) {
// if they're not too close to the side...
if (i<7) {
// swap them horizontally
swapGems(i,j,i+1,j);
// check if they form a line
if ((rowLineLength(i,j)>2||columnLineLength(i,j)>2||rowLineLength(i+1,j)>2||columnLineLength(i+1,j)>2)) {
// if so, name the move made
selectorBox.x = j*gemSize;
selectorBox.y = i*gemSize;
selectorBox.visible = true;
hint_txt.text = (i+1).toString()+","+(j+1).toString()+"->"+(i+2).toString()+","+(j+1).toString();
}
// swap the gems back
swapGems(i,j,i+1,j);
}
// then if they're not to close to the bottom...
if (j<7) {
// swap it vertically
swapGems(i,j,i,j+1);
// check if it forms a line
if ((rowLineLength(i,j)>2||columnLineLength(i,j)>2||rowLineLength(i,j+1)>2||columnLineLength(i,j+1)>2) ) {
// if so, name it
selectorBox.x = j*gemSize;
selectorBox.y = i*gemSize;
selectorBox.visible = true;
hint_txt.text = (i+1).toString()+","+(j+1).toString()+"->"+(i+1).toString()+","+(j+2).toString();
}
// swap the gems back
swapGems(i,j,i,j+1);
}
}
}
}
}
}
//Swap given gems
function swapGems(fromRow:uint,fromColumn:uint,toRow:uint,toColumn:uint):void {
//Save the original position
var originalPosition:uint=gems_array[fromRow][fromColumn];
//Move original gem to new position
gems_array[fromRow][fromColumn]=gems_array[toRow][toColumn];
//move second gem to saved, original gem's position
gems_array[toRow][toColumn]=originalPosition;
}
//Find out if there us a horizontal line
function rowLineLength(row:uint,column:uint):uint {
var gemType:uint=gems_array[row][column];
var lineLength:uint=1;
var checkColumn:int=column;
//check how far left it extends
while (sameGemIsHere(gemType,row,checkColumn-1)) {
checkColumn--;
lineLength++;
}
checkColumn=column;
//check how far right it extends
while (sameGemIsHere(gemType,row,checkColumn+1)) {
checkColumn++;
lineLength++;
}
// return total line length
return (lineLength);
}
//Find out if there us a vertical line
function columnLineLength(row:uint,column:uint):uint {
var gemType:uint=gems_array[row][column];
var lineLength:uint=1;
var checkRow:int=row;
//check how low it extends
while (sameGemIsHere(gemType,checkRow-1,column)) {
checkRow--;
lineLength++;
}
//check how high it extends
checkRow=row;
while (sameGemIsHere(gemType,checkRow+1,column)) {
checkRow++;
lineLength++;
}
// return total line length
return (lineLength);
}
function sameGemIsHere(gemType:uint,row:int,column:int):Boolean {
//Check there are gems in the chosen row
if (gems_array[row]==null) {
return false;
}
//If there are, check if there is a gem in the chosen slot
if (gems_array[row][column]==null) {
return false;
}
//If there is, check if it's the same as the chosen gem type
return gemType==gems_array[row][column];
}
//ROTATION
function rotateClockwise(a:Array):void {
var n:int=a.length;
for (var i:int=0; i<n/2; i++) {
for (var j:int=i; j<n-i-1; j++) {
var tmp:String=a
; a
=a[n-j-1]; a[n-j-1]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a
[n-i-1]; a
[n-i-1]=tmp; }
}
}
bejewelled();
Any help appreciated.
Copy link to clipboard
Copied
You can't programmatically move a registration point but what you usually do is move the contents of the clip into negative space.
e.g. a 100px X 100px box, move the position to -50x by -50x. Then the registration is in the center.
Copy link to clipboard
Copied
Actually you sort of can change the reg point. Using a similar example as I posted above:
var a:MovieClip = new car(); //library clip
addChild(a);
a.x = 50; a.y = 50;
changeRegPt(a, a.width/2, a.height/2);
function changeRegPt(dobj:DisplayObjectContainer,x:Number,y:Number){
var r:Rectangle = dobj.getBounds(dobj);
for(var i:uint=0;i<dobj.numChildren;i++){
dobj.getChildAt(i).x -= r.x+x;
dobj.getChildAt(i).y -= r.y+y;
}
dobj.x += r.x+x;
dobj.y += r.y+y;
}
addEventListener(Event.ENTER_FRAME, up);
function up(e:Event):void
{
a.rotation += 1;
}
So, instead of sticking the car in a container, you just call changeRegPoint first and then rotate as normal... If you wanted it to rotate about the front center of the hood you'd just do:
changeRegPt(a, a.width, a.height/2);
Copy link to clipboard
Copied
Bounds are determined at the current frame. If the user has a clip that animates, causing it to expand or collapse, your changeRegPt() method won't work. At the point an ENTER_FRAME would need to continuously re-echeck the bounds and that's extremely expensive. Also, custom objects don't always have an x/y property or aren't on the display list, like StageWebView. More logic is needed, there is no magic bullet here.
Copy link to clipboard
Copied
Hi Sinious and dmeN,
Thank you for these suggestions and better understanding. I think one challenge is that the export will run full screen on different devices. So, I am not sure that a fix that changes X and Y by a fixed amount, like -100, can work.
Interestingly, in the original script in the tutorial (see link) the sprite rotates OK in a 640X480 stage, but looks like it is set at 0,0 (top left), not centered.
I am guessing from your replies that there is no easy way to simply center that spite? (I've tried the registration point change-found it in this forum, posted by kglad- but in this situation, as you have noted, it will not produce a center rotation.)
So, it appears that without a complete re-write (unfortunately, beyond my ability), no easy way to accomplish a center rotation?
saratogacoach
Copy link to clipboard
Copied
You can't shift a registration point. Boy, it'd be a great feature, but you can't. Your job is to move "everything that clip controls" into the center of that point. Components, AIR native bindings (StageWebView), GPU elements (StageVideo), you name it. You must, as always, measure twice, cut once. If you didn't pre-plan all your work for immutable center point registration, you need to do the work of moving those elements (whatever they are, in their respective manner) to your central registration point yourself.
Next project you'll do I bet you won't forget it
.
Copy link to clipboard
Copied
Hi sinious,
Yes, true. A good learning experience.
The link in the postings above is not connecting. Here it is: http://www.emanueleferonato.com/2012/11/09/bejeweled-as3-engine-with-array-rotation/
Best Wishes,
Copy link to clipboard
Copied
OK, way too much code. By default, everything will rotate from top left. If you want to change that you need to change the positions of the content within the container, not the container itself.
For example if you do something like this:
var a:Sprite = new Sprite(); //container
addChild(a);
a.x = 100; a.y = 100;
var b:MovieClip = new car(); //clip from library
a.addChild(b);
addEventListener(Event.ENTER_FRAME, up);
function up(e:Event):void
{
a.rotation += 1;
}
The car added to the container will rotate about it's top left point... because that's where the container rotates about. To fix, move the car so the containers top/left is at the car's center like so:
var a:Sprite = new Sprite();
addChild(a);
a.x = 100; a.y = 100;
var b:MovieClip = new car();
a.addChild(b);
b.x -= b.width / 2;
b.y -= b.height / 2;
addEventListener(Event.ENTER_FRAME, up);
function up(e:Event):void
{
a.rotation += 1;
}
You'll notice all that changed is moving the car 1/2 it's width and height.
HTH
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more