This may sound like a duplicate, but please hear me out as I need a specific answer.
I am creating UI that needs to visually change while the user is dragging - not on complete. I've discovered how to determine if we've moved left or right based upon a selected item offset left position in an array and how to determine the position of the pointer while moving right from that position and am able the give visual feedback just fine. Now that I also know how to determine if we're moving left from the selected item offset left position in the array, how do I determine how far left I'm moving the pointer? I've been struggling with this for hours.
Here's a summary of what I have so far:
var ActiveElement = null;
function init() {
touchElement.msg = new MSGesture();
touchElement.msg.target = touchElement;
touchElement.addEventListener("MSGestureStart", te_gs, false);
touchElement.addEventListener("MSGestureChange", te_gc, false);
touchElement.addEventListener("MSGestureEnd", te_ge, false);
touchElement.addEventListener("MSInertiaStart", te_is, false);
touchElement.addEventListener("MSPointerDown", te_pd, false);
touchElement.addEventListener("MSPointerUp", te_pu, false);
touchElement.addEventListener("MSGestureTap", te_click, false);
};
//************************************************************************************************************************
// POINTER DOWN
//************************************************************************************************************************
function te_pd(e) {
//get activeel pos
ActiveElement.pos = getElPos(ActiveElement);
var touchE = e.currentTarget;
touchE.msg.addPointer(e.pointerId);
}
//************************************************************************************************************************
// GESTURE START
//************************************************************************************************************************
function te_gs(e) {
// set touchElement to the widget
var touchE = e.currentTarget;
// track the location from the start
touchE.diffx = ActiveElement.offsetLeft - e.clientX;
}
//************************************************************************************************************************
// GESTURE CHANGE
//************************************************************************************************************************
function te_gc(e) {
var touchE = e.currentTarget;
var activeElementLeftEdge = listArray[ActiveElement.pos].offsetLeft - listArray[ActiveElement.pos - 1].offsetLeft;
var dragRight = e.translationX > ActiveElement.offsetLeft - e.clientX;
var dragLeft = e.translationX < ActiveElement.offsetLeft - e.clientX;
if (dragRight) {
// I'm doing stuff to the right here where activeElementLeftEdge helps me determine the current location of the pointer going to the right
// my problem is that I don't know how to determine the equivalent when moving left
if (activeElementLeftEdge > listArray[ActiveElement.pos - 1].offsetLeft * 0) {
// show state
} else if (activeElementLeftEdge < 100) {
// hide state
}
if (activeElementLeftEdge > 200) {
// show next state
} else if (activeElementLeftEdge < 200) {
// hide state
}
}
if (dragLeft) {
// How do I determine the x position of the pointer here?
}
}
//************************************************************************************************************************
// GESTURE END
//************************************************************************************************************************
function te_ge(e) {
}
//************************************************************************************************************************
// POINTER UP
//************************************************************************************************************************
function te_pu(e) {
}
//************************************************************************************************************************
// INERTIA STARTING
//************************************************************************************************************************
function te_is(e) {
}
//************************************************************************************************************************
// CLICKED
//************************************************************************************************************************
function te_click(e) {
}
//************************************************************************************************************************
//returns the element position in the listArray
//************************************************************************************************************************
function getElPos(element) {
//loop through the array
for (i = 0; i < listArray.length; i++) {
if (listArray[i].id == element.id) {
return (i);
}
}
}
Related
I am creating a drag and drop the game for kids and I realized that when the kid drags a movie clip by mistake outside the stage the movie clip hangs where it is dragged onto and doesn't return back to its original position or it overlaps over other movie clips.
Thanks in advance
the code I am basically using is:
* square_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp2);
square_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt2);
function pickUp2(event: MouseEvent): void {
square_mc.startDrag(true);
event.target.parent.addChild(event.target);
startX = event.currentTarget.x;
startY = event.currentTarget.y;
}
function dropIt2(event: MouseEvent): void {
square_mc.stopDrag();
var myTargetName:String = "target" + event.target.name;
var myTarget:DisplayObject = getChildByName(myTargetName);
if (event.target.dropTarget != null && event.target.dropTarget.parent ==
myTarget){
event.target.removeEventListener(MouseEvent.MOUSE_DOWN, pickUp2);
event.target.removeEventListener(MouseEvent.MOUSE_UP, dropIt2);
event.target.buttonMode = false;
event.target.x = myTarget.x;
event.target.y = myTarget.y
} else {
event.target.x = startX;
event.target.y = startY;
}
}*
What you need to do is to preserve the initial position of the clip somewhere and then use it.
Basic algorithm I can think of can look as follows: 1 - player starts dragging a clip, init position is saved 2 - player releases the clip.
Two outcomes are possible: (a): the clip is on the right position or (b): it is misplaced. In case (b) you just need to assign initial coordinates back to the clip.
Very simple example:
private const initialCoords: Dictionary = new Dictionary();
private function saveInitialCoords(clip: DisplayObject): void {
initialCoords[clip] = new Point(clip.x, clip.y);
}
private funciton retreiveInitialCoords(clip: DisplayObject): Point {
return initialCoords[clip]; // it would return null if there is no coords
}
UPD: As it was pointed by #kaarto my answer might be irrelevant. If the issue is to keep the dragging movieclip
within some bounds I usually use something like this:
private var currentTarget: DisplayObject; // clip we're dragging currently
private var areaBounds: Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight); // you might want to ensure stage is not null.
private function startDrag(e: MouseEvent): void {
// I'll drop all checks here. Normally you want to ensure that currentTarget is null or return it to initial position otherwise
currentTarget = e.currentTarget as DisplayObject;
saveInitialCoords(currentTarget);
addEventListener(MouseEvent.MOUSE_MOVE, checkAreaBounds);
}
private funciton stopDrag(e: MouseEvent): void {
// some checks were dropped.
if (clipIsOnDesiredPlace(currentTarget)) {
// do something
} else {
const initialCoords: Point = retreiveInitialCoords(currentTarget);
currentTarget.x = initialCoords.x;
currentTarget.y = initialCoords.y;
}
currentTarget = null;
removeEventListener(MouseEvent.MOUSE_MOVE, checkAreaBounds);
}
private funciton checkAreaBounds(e: MouseEvent): void {
// you might need to convert your coords localToGlobal depending on your hierarchy
// this function gets called constantly while mouse is moving. So your clip won't leave areaBounds
var newX: Number = e.stageX;
var newY: Number = e.stageY;
if (currentTarget) {
if (newX < areaBounds.x) newX = areaBounds.x;
if (newY < areaBounds.y) newY = areaBounds.y;
if (newX + currentTarget.width > areaBounds.x + areaBounds.width) newX = areaBounds.x + areaBounds.width - currentTarget.width;
if (newY + currentTarget.height > areaBounds.y + areaBounds.heght) newY = areaBounds.y + areaBounds.height - currentTarget.height;
currentTarget.x = newX;
currentTarget.y = newY;
}
}
... somewhere ...
// for each clip you're going to interact with:
for each (var c: DisplayObject in myDraggableClips) {
c.addEventListener(MouseEvent.MOUSE_DOWN, startDrag);
c.addEventListener(MouseEvent.MOUSE_UP, stopDrag);
}
Another option (if you don't want to limit the area with some bounds) is to use MouseEvent.RELEASE_OUTSIDE event and return a clip to it's initial position once it gets released:
stage.addEventListener(MouseEvent.RELEASE_OUTSIDE, onMouseReleaseOutside);
private function onMouseReleaseOutside(e:MouseEvent):void {
// return clip to it's position.
}
More info you can find in documentation: https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/MouseEvent.html#RELEASE_OUTSIDE
I have an array with six buttons called "sostaletters" and an array with six elements called "addedletters". What I want is every time a button is been clicked a new movieclip from the array "addedletters" to be added on stage. For example if the third element of the array "sostaletters" is been clicked then the third element of the array "addedletters" to be added on stage. How i can do that?
This is what i have done for my array "sostaletters"
var sostaletters:Array = [a7,a17,a24,a1,a18]
for each (var letter:MovieClip in sostaletters) {
letter.buttonMode = true;
letter.isClicked = false;
letter.addEventListener(MouseEvent.CLICK, kanoklick2);
function kanoklick2(event:MouseEvent):void
{
event.target.alpha = 0.5;
if(event.currentTarget.isClicked == false){
clickCount2 ++;
event.currentTarget.isClicked = true;
sostaletters[i].x = positionsArray[i].xPos;
sostaletters[i].y = positionsArray[i].yPos;
setChildIndex(MovieClip(e.currentTarget), numChildren - 1);
}
if(clickCount2 == sostaletters.length){
addChild(welldoneman);
myTimer.start();
if (contains(kremmala)) {
removeChild(kremmala)
}
for (var i:int= 0; i< wrongletters.length; i++)
{
wrongletters[i].removeEventListener(MouseEvent.CLICK, kanoklick);
}
for (var o:int= 0; o< sostaletters.length; o++)
{
sostaletters[o].removeEventListener(MouseEvent.CLICK, kanoklick2);
}
trace("All buttons have been clicked");
}
}
}
Neal Davis has already gave a right answer. But I shall make a code review for more clarity. See my comments in the code.
var sostaletters:Array = [a7,a17,a24,a1,a18]
// "sostaletters" is an Array. So it is better to use iteration by index
for each (var letter:MovieClip in sostaletters) {
letter.buttonMode = true;
letter.isClicked = false;
letter.addEventListener(MouseEvent.CLICK, kanoklick2);
// You will create "kanoklick2" function at each iteration.
// Move this declaration from this loop
function kanoklick2(event:MouseEvent):void {
event.target.alpha = 0.5;
// There is no need to compare a boolean property with "false" or "true"
// You can write "if(event.currentTarget.isClicked)"
if(event.currentTarget.isClicked == false) {
clickCount2 ++;
event.currentTarget.isClicked = true;
// You declare an "i" variable below.
// So the compiler will not fire en error.
// But you will not get an index of the current letter.
sostaletters[i].x = positionsArray[i].xPos;
sostaletters[i].y = positionsArray[i].yPos;
setChildIndex(MovieClip(e.currentTarget), numChildren - 1);
}
// If number of "sostaletters" are not changed
// you can save its value in a variable for an example "sostalettersNum"
if (clickCount2 == sostaletters.length) {
addChild(welldoneman);
myTimer.start();
if (contains(kremmala)) {
removeChild(kremmala)
}
// You declare an "i" variable. And use it above to get a current letter.
// But an "i" will not contain its index.
// It will be equal to "wrongletters.length"
for (var i:int= 0; i
I'm making a "spit" card game and I'm trying to be able to have 3 cards on the stage at once to be able to drag to the pile. So my question is how do I have multiple instances of the same object on the stage, but be able to assign each card different frames, etc. Here is the code to understand the context of it.
"cardArray" has 53 frames, 52 of which have a card face, 53rd is a "deck" picture.
//variables, constants
var cardDeck:Array = new Array();
var timer:Timer = new Timer(2000);
var j:int = 0;
var card:MovieClip = new CardArray();
var cardInDeck:Boolean;
const deckSize:int = 52;
//events:
card.addEventListener(MouseEvent.MOUSE_DOWN,fDown);
card.addEventListener(MouseEvent.MOUSE_UP,fUp);
startRandomise();
//This is where the unshuffled "deck" is created - values loaded into the array.
function createDeck():void
{
var i:int;
for(i =0; i<deckSize; i++)
{
cardDeck[i] = i+1;
}
}
function randomizeDeck( a : *, b : * ):int
{
return (Math.random()>.5) ? 1 : -1;
}
//Grab the value from the (presumably) current frame of the card
function convertCard(cardNo:int):int
{
var deckPos:int;
if (cardNo <= deckSize/4)
{
deckPos = cardNo;
}
else if (cardNo > deckSize/4 && cardNo <= deckSize/2)
{
deckPos = cardNo -13;
}
else if (cardNo > deckSize/2 && cardNo <=deckSize*3/4)
{
deckPos = cardNo -deckSize/2;
}
else if (cardNo >39)
{
deckPos = cardNo -39;
}
return deckPos;
}
btn.addEventListener(MouseEvent.MOUSE_UP,showArray);
function showArray(event:MouseEvent):void
{
if(j<deckSize /2)
{
addChild(card);
card.gotoAndStop(cardDeck[j]);
trace(cardDeck[j]+","+deckCompare[j]);
j++;
}
if(cardInDeck)
{
card.x = 200;
card.y = 200;
cardInDeck+false;
}
}
function fDown(evt:MouseEvent)
{
card.startDrag();
}
function fUp(evt:MouseEvent)
{
stopDrag();
if(card.hitTestObject(deck))
{
trace("deck: "+convertCard(deck.currentFrame));
trace("card: "+convertCard(card.currentFrame));
if(convertCard(card.currentFrame) == convertCard(deck.currentFrame)+1 || convertCard(card.currentFrame) == convertCard(deck.currentFrame)-1 || convertCard(card.currentFrame) == 13 && convertCard(deck.currentFrame) == 1 || convertCard(card.currentFrame) == 1 && convertCard(deck.currentFrame) == 13 || convertCard(deck.currentFrame) == 14)
{
deck.gotoAndStop(card.currentFrame);
removeChild(card);
cardInDeck=true;
}
else
{
card.x = 200;
card.y = 200;
}
}
else
{
card.x = 200;
card.y = 200;
}
}
function startRandomise():void
{
createDeck();
cardDeck.sort(randomizeDeck);
cardDeck.sort(randomizeDeck);
trace("random: "+cardDeck);
trace("deckCompare: "+deckCompare);
card.x = 200;
card.y = 200;
deck.gotoAndStop(53);
}
To have multiple cards, you need to instantiate more than one card. I don't know anything about the card game spit and don't understand the purpose of many of your functions, but you'll want to do something along these lines:
Create a function that generates (instantiates) a new card:
function createCard(faceFrame):MovieClip {
var tmpCard:MovieClip = new CardArray(); //this creates a new instance of a card
tmpCard.addEventListener(MouseEvent.MOUSE_DOWN, cardMouseDown); //make the card call the mouse down function when that event is triggered
tmpCard.gotoAndStop(faceFrame); //assign the card it's face (frame)
addChild(tmpCard); //add the card to the screen
return tmpCard;
}
Then, in your mouse down handler (I renamed it to be more clear what is is), you can do the following to card that was mouse downed:
function cardMouseDown(evt:MouseEvent) {
//the events currentTarget property is reference to the item that you attached the listener to, so in this case the card who triggered the mouse down
card = evt.currentTarget as MovieClip; //assign the current clicked card to the global card variable (so we can access it in the mouse up function)
card.startDrag();
//add the mouse up listener on the stage, since there are cases where you can drag so fast that the mouse isn't over the item it's dragging (and then if you were to release the mouse at that moment it wouldn't dispatch the event)
stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
}
Then your mouse up function would look something like this:
function stageMouseUp(evt:MouseEvent) {
//remove the mouse up listener from the stage
stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
card.stopDrag();
if(card.hitTestObject(deck))
{
......//rest if the code
Seems like you would want to generate a new card in the showArray function you have? So something like this:
function showArray(event:MouseEvent):void
{
var newCard:MovieClip = createCard(cardDeck[j]);
j++
newCard.y = newCard.x = 200;
trace(cardDeck[j]+","+deckCompare[j]);
}
As an aside, you should consider calling your Card object something more sensible, like Card instead of CardArray, as it's not an array...
Script problem is that every movieclip dispatch down and up mouse event but mouse move event is not dispatching by some movieclips, which is an unexpected behaviour while I have traced the down event and it trace successfully on every object
also recommend your feedback on my code, thanks.
private function loadPurchasedClip(){
var decorationItem:String;
var lastItemIndex:uint = this.getChildIndex(tree1);
var item:Sprite;
for(var a in purchasedItems){
for(var b in purchasedItems[a]){
if(purchasedItems[a][b].item=='shed'){
item = new shed();
} else {
var ClassDefinition:Class = loadedDecorationItem.purchaseItem(purchasedItems[a][b].item) as Class;
item = new ClassDefinition();
}
item.x = purchasedItems[a][b].posX;
item.y = purchasedItems[a][b].posY;
item.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent){
Mouse.cursor = "hand";
e.target.startDrag(false);
dusbin.visible = true;
item.addEventListener(MouseEvent.MOUSE_MOVE,trashMe);
});
item.addEventListener(MouseEvent.MOUSE_UP,function(e:MouseEvent){
Mouse.cursor = "auto";
e.target.stopDrag();
externalPhpCall(e);
dusbin.visible = false;
if(trashClip){
removeChild(trashClip);
trashClip = null;
}
});
item.mouseChildren = false;
// if item is fence or flowers then move them behind the tree
if(
String(purchasedItems[a][b].item).indexOf('fence')!=-1
||
String(purchasedItems[a][b].item).indexOf('flower')!=-1
){
addChildAt(item,lastItemIndex);
lastItemIndex++;
} else {
addChildAt(item,this.numChildren-2);
}
purchasedNameAr[getChildIndex(item)] = purchasedItems[a][b].item;
}
}
Can't be sure, but I think it's probably that you're expecting a clip to continue to dispatch MouseEvent.MOUSE_MOVE events even once the mouse has left the clip - this won't happen, it's only whilst the local mouse pointer co-ordinates (ie yourClip.mouseX/mouseY) intersect the graphics of the clip itself that it will fire - even when dragging a clip, it can't be guaranteed that it will dispatch a MOVE event.
Let's suppose your clips are all on the root, which means you have access to 'stage' - you could do this:
replace:
item.addEventListener(MouseEvent.MOUSE_MOVE,mouseMove);
with:
stage.addEventListener(MouseEvent.MOUSE_MOVE,mouseMove);
...but you should remember to remove that event when necessary (use stage again, in case mouse is not released over the clip):
stage.addEventListener(MouseEvent.MOUSE_UP,endMove);
//Don't use anon function as won't have stage reference:
function endMove(e:MouseEvent):void {
//The rest of your code, then:
stage.removeEventListener(MouseEvent.MOUSE_MOVE,mouseMove);
}
private function loadPurchasedClip(){
var decorationItem:String;
var lastItemIndex:uint = this.getChildIndex(tree1);
var item:Sprite;
var Move:Boolean
for(var a in purchasedItems){
for(var b in purchasedItems[a]){
if(purchasedItems[a][b].item=='shed'){
item = new shed();
} else {
var ClassDefinition:Class = loadedDecorationItem.purchaseItem(purchasedItems[a][b].item) as Class;
item = new ClassDefinition();
}
item.x = purchasedItems[a][b].posX;
item.y = purchasedItems[a][b].posY;
item.addEventListener(e:Event.ENTER_FRAME, onEnterFrame);
item.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent){
Mouse.cursor = "hand";
e.target.startDrag(false);
Move = true
dusbin.visible = true;
});
item.addEventListener(MouseEvent.MOUSE_UP,function(e:MouseEvent){
Mouse.cursor = "auto";
e.target.stopDrag();
externalPhpCall(e);
dusbin.visible = false;
if(trashClip){
removeChild(trashClip);
trashClip = null;
}
});
item.mouseChildren = false;
// if item is fence or flowers then move them behind the tree
if(
String(purchasedItems[a][b].item).indexOf('fence')!=-1
||
String(purchasedItems[a][b].item).indexOf('flower')!=-1
){
addChildAt(item,lastItemIndex);
lastItemIndex++;
} else {
addChildAt(item,this.numChildren-2);
}
purchasedNameAr[getChildIndex(item)] = purchasedItems[a][b].item;
}
function onEnterFrame(e:Event):void{
if(Move){
// what ever here
{
}
<script type="text/javascript">
var canvas, context, tool, e;
var varblurup=0;
var varsizeup=1;
var swtchclr;
// Keep everything in anonymous function, called on window load.
if(window.addEventListener) {
window.addEventListener('load', function () {
//check tool is pen or line or shape
var chktool="pen";
function init () {
alert("Line3");
// Find the canvas element.
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
//varblurup=10;
context.shadowColor = 'colour';
context.shadowBlur = 0;
context.lineWidth=1;
context.lineJoin = 'miter';
context.miterLimit = 4;
this.context.save();
// Pencil tool instance.
//tool = new tool_pencil();
//alert("Pen");
if(chktool=="pen")
{ tool = new tool_pencil();
alert("Pen");
}else if (chktool=="line")
{
tool2 = new tool_line();
alert("Line");
}
// Attach the mousedown, mousemove and mouseup event listeners.
canvas.addEventListener('mousedown', ev_canvas, false);
canvas.addEventListener('mousemove', ev_canvas, false);
canvas.addEventListener('mouseup', ev_canvas, false);
}
// This painting tool works like a drawing pencil which tracks the mouse
// movements.
function tool_pencil () {
var tool = this;
this.started = false;
// This is called when you start holding down the mouse button.
// This starts the pencil drawing.
this.mousedown = function (ev) {
context.beginPath();
context.moveTo(ev._x, ev._y);
tool.started = true;
};
// This function is called every time you move the mouse. Obviously, it only
// draws if the tool.started state is set to true (when you are holding down
// the mouse button).
this.mousemove = function (ev) {
if (tool.started) {
context.lineTo(ev._x, ev._y);
//this.style('stroke-opacity').value
context.stroke();
}
};
// This is called when you release the mouse button.
this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
}
};
}
// The general-purpose event handler. This function just determines the mouse
// position relative to the canvas element.
function ev_canvas (ev) {
if (ev.layerX || ev.layerX == 0) { // Firefox
ev._x = ev.layerX;
ev._y = ev.layerY;
} else if (ev.offsetX || ev.offsetX == 0) { // Opera
ev._x = ev.offsetX;
ev._y = ev.offsetY;
}
// Call the event handler of the tool.
var func = tool[ev.type];
if (func) {
func(ev);
}
}
init();
}, false); }
I found the Mozilla canvas tutorial to be a helpful guide. It covers most areas including shape drawing:
https://developer.mozilla.org/en/Canvas_tutorial
https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
It is quite an extended question so here are a couple of links about it..
HTML5 Canvas: Shape Drawing
A Quick Introduction to the HTML 5 Canvas
A Quick Introduction to the HTML 5 Canvas – Part Two