Dragging and placing movieclips - actionscript-3

I'm trying to make an animation using AS3 which consists of dragging and placing movieclips (small images) inside some rectangles (bitmaps) and then presenting the images (big images) corresponding to the movieclips by the same order as they were placed along the rectangles.
However, there is a little trick with which I'm having a few difficulties. When a movieclip is placed inside a rectangle and I try to drag another movieclip to the same rectangle, the one that I'm dragging should return to the initial position. The code I have is working sometimes, but others, it doesn't (still possible to place the movieclip above or under the other).
Another question is: How can I make for the movieclip that I'm dragging to always go above another movieclip and not under? (sometimes they go above, anothers they go under).
Thanks in advance. Best regards.
Here is my code:
function returnToInitial(k:int){
this["foto"+String(k)+"_mc"].x = this["foto"+String(k)+"_mc"].iniX;
this["foto"+String(k)+"_mc"].y = this["foto"+String(k)+"_mc"].iniY;}
for(i=1; i<7; i++){
this["foto"+String(i)+"_mc"].addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
this["foto"+String(i)+"_mc"].num = i;
if(i <= 3){
this["foto"+String(i)+"_mc"].iniX = (160*i)+(i-1)*100;
this["foto"+String(i)+"_mc"].iniY = 100;
}else if(i > 3){
this["foto"+String(i)+"_mc"].iniX = (160*(i-3))+((i-3)-1)*100;;
this["foto"+String(i)+"_mc"].iniY = 260;
}
}
function startDragging(me:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
MovieClip(me.currentTarget).startDrag(true);
currentDragged = MovieClip(me.currentTarget);}
function stopDragging(evt:Event):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, stopDragging);
stopDrag();
checkPosition(currentDragged);}
function firstCheck(mcR:MovieClip){
for(q = 0; q < icons.length; q++){
if(this[icons[q]].y == 455){
posX = Math.abs(mcR.x - this[icons[q]].x);
if(posX < 10){
returnToInitial(mcR.num);
}
}
}
}
function checkPosition(mc:MovieClip){
firstCheck(mc);
if(mc.y > 420 && mc.y < 490){
mc.y = 455;
for(k=0; k<6; k++){
if(mc.x > 60+(k*135) && mc.x < 120+(k*135)){
mc.x = 90+(k*135);
array[k] = mc.num;
}
}
}
}

For making the movieclip you are dragging appear on top of everything else, add this to startDragging:
setChildIndex(MovieClip(me.currentTarget), this.numChildren-1);

Related

Program help needed in Actionscript 3 game

I have been making this game in AS3 and the basics work. The thing i am having trouble with is making a 'start' menu appear when the game starts but also when the player dies. I have been trying the .visible code but that didn't seem to work.
Question: What code do i add to my game that makes the start button appear when the game starts but also when the player dies. Code:
package{
import flash.display.MovieClip;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.events.Event; //used for ENTER_FRAME event
public class Main extends MovieClip{
//constants
const gravity:Number = 1.5; //gravity of the game
const dist_btw_obstacles:Number = 300; //distance between two obstacles
const ob_speed:Number = 8; //speed of the obstacle
const jump_force:Number = 15; //force with which it jumps
//variables
var player:Player = new Player();
var lastob:Obstacle = new Obstacle(); //varible to store the last obstacle in the obstacle array
var obstacles:Array = new Array(); //an array to store all the obstacles
var yspeed:Number = 0; //A variable representing the vertical speed of the bird
var score:Number = 0; //A variable representing the score
public function Main(){
init();
}
function init():void {
//initialize all the variables
player = new Player();
lastob = new Obstacle();
obstacles = new Array();
yspeed = 0;
score = 0;
//add player to center of the stage the stage
player.x = stage.stageWidth/2;
player.y = stage.stageHeight/2;
addChild(player);
//create 3 obstacles ()
createObstacle();
createObstacle();
createObstacle();
//Add EnterFrame EventListeners (which is called every frame) and KeyBoard EventListeners
addEventListener(Event.ENTER_FRAME,onEnterFrameHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, key_up);
}
private function key_up(event:KeyboardEvent){
if(event.keyCode == Keyboard.SPACE){
//If space is pressed then make the bird
yspeed = -jump_force;
}
}
function restart(){
if(contains(player))
removeChild(player);
for(var i:int = 0; i < obstacles.length; ++i){
if(contains(obstacles[i]) && obstacles[i] != null)
removeChild(obstacles[i]);
obstacles[i] = null;
}
obstacles.slice(0);
init();
}
function onEnterFrameHandler(event:Event){
//update player
yspeed += gravity;
player.y += yspeed;
//restart if the player touches the ground
if(player.y + player.height/2 > stage.stageHeight){
restart();
}
//Don't allow the bird to go above the screen
if(player.y - player.height/2 < 0){
player.y = player.height/2;
}
//update obstacles
for(var i:int = 0;i<obstacles.length;++i){
updateObstacle(i);
}
//display the score
scoretxt.text = String(score);
}
//This functions update the obstacle
function updateObstacle(i:int){
var ob:Obstacle = obstacles[i];
if(ob == null)
return;
ob.x -= ob_speed;
if(ob.x < -ob.width){
//if an obstacle reaches left of the stage then change its position to the back of the last obstacle
changeObstacle(ob);
}
//If the bird hits an obstacle then restart the game
if(ob.hitTestPoint(player.x + player.width/2,player.y + player.height/2,true)
|| ob.hitTestPoint(player.x + player.width/2,player.y - player.height/2,true)
|| ob.hitTestPoint(player.x - player.width/2,player.y + player.height/2,true)
|| ob.hitTestPoint(player.x - player.width/2,player.y - player.height/2,true)){
restart();
}
//If the bird got through the obstacle without hitting it then increase the score
if((player.x - player.width/2 > ob.x + ob.width/2) && !ob.covered){
++score;
ob.covered = true;
}
}
//This function changes the position of the obstacle such that it will be the last obstacle and it also randomizes its y position
function changeObstacle(ob:Obstacle){
ob.x = lastob.x + dist_btw_obstacles;
ob.y = 100+Math.random()*(stage.stageHeight-200);
lastob = ob;
ob.covered = false;
}
//this function creates an obstacle
function createObstacle(){
var ob:Obstacle = new Obstacle();
if(lastob.x == 0)
ob.x = 800;
else
ob.x = lastob.x + dist_btw_obstacles;
ob.y = 100+Math.random()*(stage.stageHeight-200);
addChild(ob);
obstacles.push(ob);
lastob = ob;
}
}
}
Thanks in advance!
Draw a Box (with colour fill but no outline). Convert to MovieClip type. Give a name eg: "Menu"
It will be
a container for your menu. Add content by double-clicking it, to add
graphics & text on new layers. Or if you have already have content on some other frames, then just "cut frames" and later do a "paste frames" inside the timeline of this new movieClip.
When you converted, it was added to the Library section
(ctrl + L). Find it ("Menu") in the library and right-click then choose "properties". In
linkage section click "export for actionscript". The Class name should become "Menu" automatically. Now just click "OK".
Example usage in game code.. (ie: To add to screen or remove etc)
//# load the movieClip...
var Menu_Screen : Menu = new Menu(); //# Menu is linkage name given in Library
//# Adding to screen...
gameContainer_MC.addChild( Menu_Screen );
gameCcontainer_MC.removeChild( Menu_Screen );
//# Controlling the movieClip...
Menu_Screen.x = 50;
gameContainer_MC.Menu_Screen.x = 50;

AS3 move towards mouse click

In a side-scroller type game, I want the object to move wherever I click the mouse and then stop at that location. What is the best way to accomplish this? The object can only move on the x-axis so I don't have to worry about moving on the y-axis.
What I would do is set a target x coordinate, then move towards it each frame (or timer tick) based on a constant movement speed.
const moveSpeed:Number = 5;
var targetX:Number = 0;
stage.addEventListener(MouseEvent.CLICK, click);
function click(e:MouseEvent):void {
targetX = mouseX;
addEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void {
if (Math.abs(targetX - player.x) < moveSpeed) {
// reached target
player.x = targetX;
} else if (targetX > player.x) {
// move right
player.x += moveSpeed;
} else {
// move left
player.x -= moveSpeed;
}
}
Use tweener:
http://hosted.zeh.com.br/tweener/docs/en-us/
And apply a tween like this:
Tweener.addTween(myObject, {_x:myObject.parent.mouseX, time:1, transition:"linear"});
And you can play with the time and the transition type. Good overview of transition types can be found here:
http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html

I added animation to the timeline of my movie clip, now its no longer colliding with objects as it did before

I'm working on a platform game in AS3 for Flash. There is of course a player character and enemies for him to interact with. I first made a simple placeholder graphic for the enemy while I worked on the code. I got the enemy to move back and forth between two bumpers with code. He also collides with the player, sending them back to the start screen. Now that I got the code working, I wanted to add some animations to the enemies so they walk instead of just skate across the ground. I added the animations to the timeline of the enemy movie clip. Now when I test the game, the animations play fine and the enemy begins to move, but he passes through the first bumper and doesn't collide with the player at all. If I force the movie clip to stop and not play the collision starts to work again. What would be causing this?
This is the code within the main timeline of the .fla file.
addEnemiesToLevel1();
addBumpersToLevel1();
function addEnemiesToLevel1():void
{
addEnemy(700, -54);
addEnemy(1341, -54);
addEnemy(2187, -54);
}
function addBumpersToLevel1():void
{
addBumper(900, -80);
addBumper(644, -80);
addBumper(1135, -90);
addBumper(1380, -90);
addBumper(2053, -90);
addBumper(2226, -90);
}
function addEnemy(xLocation:int, yLocation:int):void
{
var enemy:Enemy = new Enemy(xLocation, yLocation);
back.addChild(enemy);
enemy.addEventListener(Event.REMOVED, enemyRemoved);
enemyList.push(enemy);
}
function addBumper(xLocation:int, yLocation:int):void
{
var bumper:Bumper = new Bumper(xLocation, yLocation);
back.addChild(bumper);
bumper.visible = false;
bumperList.push(bumper);
}
//corralling the bad guys with bumpers
if (enemyList.length > 0){ //enemies left in the enemyList?
for (var k:int = 0; k < enemyList.length; k++){ // for each enemy in the enemyList
if (bumperList.length > 0){
for (var h:int = 0; h < bumperList.length; h++){ // for each bumper in the List
if ( enemyList[k].hitTestObject(bumperList[h]) ){
enemyList[k].changeDirection();
}
}
}
}
}
//player and enemy collisions
if (enemyList.length > 0){ //enemies left?
for (var m:int = 0; m < enemyList.length; m++){ // for each enemy in the enemyList
if ( enemyList[m].hitTestObject(player) ){
trace("player collided with enemy");
gotoAndStop(4);
enemyList[m].removeSelf();
}
}
}
}
This is the enemy class file.
package {
import flash.display.MovieClip;
import flash.events.Event;public class Enemy extends MovieClip {
private var xSpeedConst:int = 2;
private var flip:int = 1;
public function Enemy(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, loop);
}
public function loop(e:Event):void {
if ((flip%2) == 1){
x += xSpeedConst;
} else if((flip%2) == 0){
x += (-xSpeedConst);
}
}
public function removeSelf():void {
trace("remove enemy");
removeEventListener(Event.ENTER_FRAME, loop);
this.parent.removeChild(this);
}
public function changeDirection():void{
trace("x ="+x);
flip++;
this.scaleX *= -1;
}
}
}
I had a problem that was very similar to this:
2D Platform Game using hitTestPoint:glitches
My problem was that my character's hitTestPoint wouldn't work after I animated the character. However, it wasn't because of the animation, it was because of my turning code for the character. I was using scaleX to flip the character. However, this flipped the points nested within the character as well (which were used to handle my collisions). I notice that you also flipped the character's scale:
public function changeDirection():void{
trace("x ="+x);
flip++;
this.scaleX *= -1;
}
Perhaps you are having the same problem as I did. If so, try removing this line of code for now:
this.scaleX *= -1;
...and see what happens...We can figure out what to do next from there
Drake Swartzy

AS3 : How to remove movieclip properly without Error 1009 overflow?

I have a class Catcher which lets you control a movieclip in a game. I'm trying to program the game so it finishes and you can restart. So I need to remove everything and go back to the menu. Should be a simple thing to solve but I can't seem to find out how.
So far I just have ourCatcher.parent.removeChild(ourCatcher); to remove my movieclip from the stage. And an if statement to stop one of the functions which drops things onto the stage. SoundMixer.stopAll(); to stop the music.Then I just have it going to frame 3 which is the gameover screen.
It looks fine but I get constant 1009 errors overflowing in the error console and when I restart the game, it's super slow. It seems the function for movement within Catcher is still running and creating an error because the Catcher was removed from stage and is null now.
I know I need to un-reference everything to do with the Catcher but I can't find out any documentation online to do it in my situation. Everyone seems to have different methods which I've tried and don't work.
The two functions in the Catcher class I'm using to move the character :
public function Catcher(stageRef:Stage)
{
stop();
this.stageRef = stageRef;
key = new KeyObject(stageRef);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
//movement
public function loop(e:Event):void
{
if (key.isDown(Keyboard.A))
vx -= walkSpeed;
else if (key.isDown(Keyboard.D))
vx += walkSpeed;
else
vx *= friction;
//update position
x += vx;
//speed adjustment
if (vx > maxspeed)
vx = maxspeed;
else if (vx < -maxspeed)
vx = -maxspeed;
//stay inside screen
if (x > stageRef.stageWidth)
{
x = stageRef.stageWidth;
vx = -vx
}
else if (x < 0)
{
x = 0;
vx = -vx;
}
if (key.isDown(Keyboard.A))
{
scaleX = -1;
}
else if (key.isDown(Keyboard.D))
{
scaleX = 1;
}
movement();
// Jumping
jump += gravity;
if (y > stage.stageHeight /1.5)
{
jump = 0;
canJump = true;
}
if (key.isDown(Keyboard.SPACE) && canJump)
{
jump = -10;
canJump = false;
}
y += jump;
}
The other class where I'm removing the things from the stage is called CatchingGame and it has a function which drops objects, I put the game over code there for when playerlives == 0 .
if (playerLives == 0 )
{
stop();
ourCatcher.parent.removeChild(ourCatcher);
SoundMixer.stopAll();
gotoAndStop(3);
}
I've probably made an elementary mistake since this is my first flash game. Any help is greatly appreciated as this is pretty much the last step in finishing my game.
Instead of just removing the child by referencing its parent to remove itself (I had to test to make sure this actually worked). Create a function in same place that you create/instantiate the Catcher that removes first the eventListener ENTER_FRAME, then removes the Catcher.
if (playerLives == 0 ) {
stop();
removeCatcher();
SoundMixer.stopAll();
gotoAndStop(3);
}
// new location in the main code where the catcher is created
function removeCatcher():void {
ourCatcher.cleanUp();
removeChild(ourCatcher);
}
// in the Catcher class
function cleanUp():void {
removeEventListener(Event.ENTER_FRAME, loop);
}
if (ourCatcher.parent) ourCatcher.parent.removeChild(ourCatcher);
else trace("Catcher without a parent still plays! DEBUG THIS!");
Basically, you are most likely losing control flow of your catcher, that is, it seemingly tries to remove itself from the stage twice. After it removes itself first time, its parent becomes null, hence the 1009. And, seeing as you've hit a 2028, the same reason applies, your catcher is no longer a child of anywhere.

startDrag - stop diagonal movement

Is there a way to have a MovieClip with startDrag, but to force only horizontal and vertical (i.e. not diagonal) movement?
Here is my solution. It tracks the mouseX and mouseY on click and compares it to last position. Finds out which direction the mouse is mainly moving then moves the object there. You may want to add some extra logic to lock the object to the nearest 10th unit or whatever unit size you want to form a snap grid for use in games or organized placement of the object.
Update: I went ahead and added a snapNearest function to help control the movement.
import flash.events.MouseEvent;
import flash.events.Event;
dragObj.addEventListener(MouseEvent.MOUSE_DOWN, dragIt);
var curX:Number = 0;
var curY:Number = 0;
var oldX:Number = 0;
var oldY:Number = 0;
var gridUnit:Number = 25;
function dragIt(e:MouseEvent):void
{
// set x,y on down
oldX = mouseX;
oldY = mouseY;
// add mouse up listener so you know when it is released
stage.addEventListener(MouseEvent.MOUSE_UP, dropIt);
stage.addEventListener(Event.ENTER_FRAME, moveIt);
trace("Start Drag")
}
function moveIt(e:Event):void
{
// figure out what the main drag direction is and move the object.
curX = mouseX;
curY = mouseY;
// figure out which is the larger number and subtract the smaller to get diff
var xDiff:Number = curX > oldX ? curX - oldX : oldX - curX;
var yDiff:Number = curY > oldY ? curY - oldY : oldY - curY;
if(xDiff > yDiff) {
dragObj.x = snapNearest(mouseX, gridUnit);
}else{
dragObj.y = snapNearest(mouseY, gridUnit);
}
oldX = mouseX;
oldY = mouseY;
}
function dropIt(e:MouseEvent):void
{
//remove mouse up event
stage.removeEventListener(MouseEvent.MOUSE_UP, dropIt);
stage.removeEventListener(Event.ENTER_FRAME, moveIt);
trace("Stop Drag")
}
// snap to grid
function snapNearest(n:Number, units:Number):Number
{
var num:Number = n/units ;
num = Math.round(num);
num *= units;
return num;
}
yes. there are a few options.
A. you can choose to use the startDrag() function and supply it's 2nd parameter with a bounds rectangle for your draggable object. something like;
dragSprite.startDrag(false, new Rectangle(0, 0, 20, stage.stageHeight));
B. you can set your draggable object to listen for mouse events, moving it according to the mouse movements. something like:
dragSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEventHandler);
function mouseDownEventHandler(evt:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
function mouseMoveEventHandler(evt:MouseEvent):void
{
//only move dragSprite horizontally
//dragSprite.y = evt.stageY;
dragSprite.x = evt.stageX;
}
function mouseUpEventHandler(evt:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
You could use a modifier key, for instance normal behavior would be horizontal & press down the shift key to move vertically.
function mouseMoveEventHandler(evt:MouseEvent):void
{
if(!evt.shiftKey)
dragSprite.x = evt.stageX;
else
dragSprite.y = evt.stageY;
}
You can only constrain to one axis or the other (using a constraint rectangle) But diagonal movement would be possible in the method you propose, unless you also define some other limits... for example a grid.