Making objects snap to a grid
In this tutorial you will learn how to make MC’s (movie clips) snap to a grid through actionscript using some basic math. I am using Adobe Flash CS3, but Flash 8 and Flash MX 2004 will work fine as well. If you are using CS3 just make sure you select an AS (Actionscript) 2.0 file.
Here is what we will be making:
Draw a 10×10 circle on the stage. Make it a MC (F8), set its registration to the center. Before you click OK, hit the button that reads ‘advanced’ if it hasn’t already been pressed. Tick the checkbox that labeled ‘Export for ActionScript’. In the ‘identifier’ text box enter ‘ball’.
Now draw a 1px line horizontally across the stage (make sure it is wider than the stage). Select it and hit F8 to convert it to a MC. Make its registration point on the middle left. Tick ‘Export for ActionScript’ and give it an identifier of ‘length’.
Draw another 1px line but make this one vertical (make sure it is higher than the stage). Select it and hit F8 to convert it to a MC. Make its registration point the top middle. Tick ‘Export for ActionScript’ and give it an identifier of ‘height’.
Theses last two MC’s have been so we can draw the grid through actionscript, and resize the grid by changing the value of a single variable.
Delete all of the MC’s that are on the stage (do not delete them from the library though!) and select the frame. Open the actions panel (F9) and enter this code.
var i:Number;
var h:Number;
var grid:Number = 25;
for (i=0; (i*grid)<Stage.height; i++) {
attachMovie("length","l"+i,getNextHighestDepth());
_root["l"+i]._y = i*grid;
}
for (h=0; (h*grid)<Stage.width; h++) {
attachMovie("height","h"+h,getNextHighestDepth());
_root["h"+h]._x = h*grid;
}
attachMovie("ball","ball",getNextHighestDepth());
ball._x = grid+(random(Stage.width)-(grid*2));
ball._y = grid+(random(Stage.height)-(grid*2));
ball.onPress = function() {
drag = true;
startDrag(this);
};
ball.onRelease = function() {
drag = false;
stopDrag();
};
onEnterFrame = function () {
if (!drag) {
if (Math.abs(Math.floor(ball._x/grid)-(ball._x/grid))<Math.abs(Math.ceil(ball._x/grid)-(ball._x/grid))) {
ball._x = Math.floor((ball._x/grid))*grid;
}else{
ball._x = Math.ceil((ball._x/grid))*grid;
}
if (Math.abs(Math.floor(ball._y/grid)-(ball._y/grid))<Math.abs(Math.ceil(ball._y/grid)-(ball._y/grid))) {
ball._y = Math.floor((ball._y/grid))*grid;
}else{
ball._y = Math.ceil((ball._y/grid))*grid;
}
}
};
The first 4 lines are just declaring variables. Drag is a boolean variable that tells us if the ball if being dragged or not. ‘i’ and ‘h’ are numbers for the for statements that make that grid. Gird is just the size of the grid. Once you have all the code in try changing the value of grid and see what happens.
Lines 6-13 are what make the grid. There are 2 for statements that attach the horizontal and vertical lines onto the stage. How many there are and how far away they are spaced depends on the grid variable.
Lines 14-16 are attaching the ball to the stage and placing it randomly on the stage. It makes sure it is placed the distance of ‘grid’ away from the edges, so that it won’t appear off the screen.
Lines 18-25 are so you can drag the ball. If you are dragging the drag variable is true. If you aren’t it is false.
What that does is it divides the ball’s x by the grid variable, leaving a number which will most likely have a decimal (if not it doesn’t matter. It then rounds it down to the nearest whole number (Math.floor()). It then subtracts the original number (ball._x/grid) from the newely rounded number, and then turns it into a positive number (Math.abs()). It then does the same thing, but instead of rounding down the number it rounds the number up, and then checks which of the results were greater. If the second one is, it runs the script that will snap the ball to the nearest grid line on the right, if the first on is it will snap to the left. There is probably an easier way to do this, but this makes sense to me. If you need help understanding it just post below.
ball._x = Math.floor((ball._x/grid))*grid;
So if the ball needs to be snapped to the left, this script will run. What it does is makes ball’s x equal to Math.floor((ball._x/grid))*grid. That divides the balls x by the value of grid, and then rounds that down. It then multiplies that number by the value of gird. That number will be equal to the nearest grid line on the left.
ball._x = Math.ceil((ball._x/grid))*grid;
This script runs if the ball needs to snap to the right. It is exactly the same as the script above, except the rounds the number up, therefore resulting in the x coordinate of the nearest grid line on the right.
The rest of the code is exactly the same as the last bits of code I just explained, but they snap the ball up and down.
Click here to see the final product.















i have been looking for a tut like this thanks
Jesus Awesty, It’s been what? 3 weeks since your last post? I was starting to think you were dead! Nice code btw
Yea. I had started learning C++ and started trying to make a vehicle physics engine in flash, and I was starting to play guitar heaps AND it was the last week of school so I had heaps of work to finish.
But, 2 weeks holiday now so I should be able to post every few days.
Jesus school goes late in Australia! Wait two weeks holiday? You taking summer school too?
No, it is different here.
We have 4 terms in a school year (which each go for about 9-11 weeks) and they are all separated by 2 week holidays.
Then after the 4th term we have Christmas holidays which go for 6 weeks.
So we have 3 lots of 2 weeks breaks a 6 week break at the end, instead of one big break over Summer. It still works out the same though.
happy holidays Awesty!
wondering if you could do a tute on “general optimisation” (and not just for tile games :P)
eg: what are some ways to speed up your game etc… when to use Mr.vector and Mrs.Bitmap,effecient loops etc…
Ta :)~
Okay, although I’m probably not the best person to ask about optimized code.
If you really want your game to be fast learn AS3, it is roughly 10 times faster than AS2 and it is setup so you practically have to optimize.
This is amazing i mean how its possible ohh i dont know much scripting but wow!!!
This is waaaaay too complicated.
This code works even better if you just put it into the script of your movie clip:
onClipEvent(enterFrame) {
this.onPress=function() {
Mouse.hide();
this._alpha=40;
this._x=_root._xmouse;
this._y=_root._ymouse;
startDrag(this);
}
this.onRelease=function() {
Mouse.show();
this._alpha=100;
this._x=(Math.round(_root._xmouse/25))*25;
this._y=(Math.round(_root._ymouse/25))*25;
stopDrag();
}
}
Just replace 25 with your grid size and this code will work perfect.
Its also AS 2.
This is good code but if there is more object everyone with this script code doesn’t working is there any sugestion?
If you want the code to work with multiple objects, you simply have to define names for the functions. So the first object might have this code:
And then the second might say:
And so on, for each new object.
Here is how to do it in AS3 which runs WAY faster then AS2,
everyone should learn to use AS3 and get rid of AS2 like we did with AS1.
This is with a separate document class NOT on the main timeline because it is a bad habit for AS3.
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class Main extends
MovieClip
{
var box:Sprite = new Sprite ();
var Click:Boolean = new Boolean (false);
var gridSize:int = 10;
var i:int = gridSize;
public function Main ()
{
this.addEventListener (Event.ENTER_FRAME, EF);
box.graphics.lineStyle (1, 0×000000);
box.graphics.beginFill (0×000000);
box.graphics.drawRect (0, 0, gridSize, gridSize);
box.graphics.endFill();
this.addChild (box);
box.addEventListener (MouseEvent.CLICK, MC);
}
private function MC (e:MouseEvent)
{
if (!Click)
{
box.startDrag(false);
Click = true;
}
else if (Click)
{
box.stopDrag();
Click = false;
}
}
private function EF (e:Event)
{
if (Click)
{
while (1)
{
if(mouseX {
box.x = (i - gridSize);
i = gridSize;
break;
}
i = gridSize;
}
while (1)
{
if (mouseY < i)
{
box.y = (i - gridSize);
i = gridSize;
break;
}
i = gridSize;
}
}
}
}
}