1

i have a darkBlueRect rectangle sprite and a copy of the same sprite with a larger scale and a lighter color - lightBlueRect.

i'm attempting to shift the location of the lightBlueRect according to the mouse.x location when the mouse is moving over the darkBlueRect. this way if the mouse is on the right of the darkBlueRect than the location of the scaled up lightBlueRect will be on the opposite side and shifted towards the left proportionate to the mouse position and scale. in addition, the lightBlueRect must appear "locked" to the darkBlueRect so lightBlueRect.x must never be more than darkBlueRect.x and lightBlueRect.x + lightBlueRect.width must never be less than darkBlueRect.x + darkBlueRect.width.

the image below depicts 3 states of what i'm attempting to accomplish:

  1. State A: mouse.x is over darkBlueRect.x = 1 and both sprites are aligned to the left.
  2. State B: mouse.x is in the middle of darkBlueRect and both sprites are aligned to the middle.
  3. State C: mouse.x is on the last pixel of darkBlueRect and both sprites are aligned to the right.

enter image description here

for this example, the darkBlueRect.width is equal to 170 and the lightBlueRect.width is equal to 320, or a scale of 1.89.

each time the mouse changes it's x position over darkBlueRect the following is called. however, while my current code works for the most part, it's not exactly correct. when the mouse.x is over darkBlueRect.x = 1, as shown in State A, the lightBlueRect.x is not property aligned with darkBlueRect and appears less than darkBlueRect.x.

var scale:Number = 1.89;

lightBlueRect.x = darkBlueRect.x - Math.round((mouse.x * scale) / darkBlueRect.width * (lightBlueRect.width - darkBlueRect.width));

what equation can i use so that no matter the scale of the lightBlueRect it's first position (mouse over first pixel) and last position (mouse over last pixel) will result in the 2 sprites being aligned as well as property proportionate positioning in between?


[EDIT] the coordinates of the darkBlueRect is {0, 0}, so when the lightBlueRect moves towards the left it is moving into the negative. i could have simply written my code (what doesn't work) like this instead:

var scale:Number = 1.89;

lightBlueRect.x = 0 - Math.round((mouse.x * scale) / darkBlueRect.width * (lightBlueRect.width - darkBlueRect.width));

[EDIT 2] when the display objects are small, the problem is difficult to notice. however, when they are large the problem becomes move obvious. the problem, here, being that the objects on the left side are misaligned.

also the problem is probably exasperated by the fact that both the lightBlueRect and darkBlueRect are scalable. darkBlueRect is scaled down and lightBlueRect is scaled up.

here is a link to the test displaying the problem. mousing over the shape quickly will obviously result in inaccurate alignment since it's based on frame rate speed, but this is not my concern. still, when you slowly mouse over the shape it will not align correctly on the left side when the mouse is over the first pixel of darkBlueRect: http://www.geoffreymattie.com/test/test.html

[SWF(width = "1000", height = "600", backgroundColor = "0xCCCCCC")]

import flash.display.Sprite;
import flash.events.MouseEvent;

var downScale:Number = 0.48;
var upScale:Number = 2.64;

var darkBlueRect:Sprite = createSprite();
darkBlueRect.scaleX = darkBlueRect.scaleY = downScale;
darkBlueRect.x = stage.stageWidth / 2 - darkBlueRect.width / 2;
darkBlueRect.y = stage.stageHeight / 2 - darkBlueRect.height / 2;
addChild(darkBlueRect);

var lightBlueRect:Sprite = createSprite();
lightBlueRect.scaleX = lightBlueRect.scaleY = upScale;
lightBlueRect.y = stage.stageHeight / 2 - lightBlueRect.height / 2;
lightBlueRect.x = stage.stageWidth;
lightBlueRect.mouseEnabled = false;
addChild(lightBlueRect);

darkBlueRect.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);

function mouseMoveEventHandler(evt:MouseEvent):void
{
    lightBlueRect.x = darkBlueRect.x + Math.max(0.0, Math.min(darkBlueRect.mouseX / darkBlueRect.width * downScale, 1.0)) * (darkBlueRect.width - lightBlueRect.width);
}

function createSprite():Sprite
{
    var result:Sprite = new Sprite();
    result.graphics.beginFill(0x0000FF, 0.5);
    result.graphics.drawRect(0, 0, 700, 200);
    result.graphics.endFill();

    return result;
}

i believe the problem is that the scaling of the shapes.

Cyril Gandon
  • 16,830
  • 14
  • 78
  • 122
Chunky Chunk
  • 16,553
  • 15
  • 84
  • 162

1 Answers1

1

Assuming you have a Clamp function handy, and that width is floating-point so that division works as expected:

lBR.x = dBR.x + Clamp((mouse.x - dBR.x) / dBR.width, 0, 1) * (dBR.width - lBR.width);

(You can define Clamp(x, m, M) = min(max(x, m), M) if you don't have one.)

Gareth Rees
  • 64,967
  • 9
  • 133
  • 163
  • hi Gareth. this didn't work for me. first the lightBlueRect is much further to the left when the mouse is over the first pixel of the darkBlueRect and secondly the image moves too fast and finishes aligning on the right side when the mouse.x hasn't even reached the middle. i should have made it more clear that the darkBlueRect's coordinates are {0, 0} so when the ligthBlueRect moves towards the left it's moving into negative. – Chunky Chunk Jul 28 '11 at 13:03
  • since the coordinates are at `{0, 0}` i've removed `dBR.x` from your code (since it's simply zero) and now have this, but it doesn't work: `lBR.x = Math.max(0.0, Math.min(mouse.x / dBR.width, 1.0)) * (dBR.width - lBR.width);` – Chunky Chunk Jul 28 '11 at 13:09
  • also, i'm not exactly sure i follow you when you say the width must be floating-point. it's width is based on pixels so it's an unsigned integer, in this case the width of dBR is 170. – Chunky Chunk Jul 28 '11 at 13:52
  • In answer to your last question: you originally didn't say which language you were programming this in. In some languages (for example, C, or Python 2) the operator `/` truncates the result if both operands are integers. However, now that you've added the `actionscript-3` tag I can see that this is not a concern, because in ActionScript the division operator always produces a floating-point result. – Gareth Rees Jul 28 '11 at 15:54
  • ah, ok now i understand. however, i still can't get it to work using your solution. – Chunky Chunk Jul 28 '11 at 16:17
  • It looks fine to me from here: according to my function, when `mouse.x` is 0, then so is `lBR.x`, and when `mouse.x` is `dBR.width`, then `lBR.x` is `dBR.width - lBR.width` (with linear interpolation in between). So there is something going on that I don't understand. Maybe some actual numbers would help. – Gareth Rees Jul 28 '11 at 16:30
  • i've edited my question again showing code and a working example of the problem. – Chunky Chunk Jul 29 '11 at 03:19
  • i trust your math so i'm going to mark this as correct, even though my problem isn't solved. but i believe the problem i'm having is caused by a Flash Player bug: http://stackoverflow.com/questions/6871208/actionscript-inaccurate-mouse-coordinates – Chunky Chunk Jul 29 '11 at 10:19