I'm using Greensock's TweenLite (AS3) for zooming in and out on a picture. It gets tricky when zooming out near the corners.
I am wondering if there's a way to clamp the width/height/x/y during tweening, so that it never goes out of bounds.
At the moment I have a 'fixer' method that I call when tweening is complete, but it's not ideal.
I've made a demo to show what I mean, try zooming out near a corner. (Mouse Scroll to zoom, click to pan...)
http://cloudchamber.knapnokgames.com/CCMedia/CCImageViewer/CCImageViewer.html
UPDATE: Here's the tweening code:
TweenLite.to(content, 0.3, {
width : _nativeWidth * newZoom ,
height : _nativeHeight * newZoom,
x : (((content.x - origin.x) / content.width) * (_nativeWidth * newZoom)) + origin.x,
y : (((content.y - origin.y) / content.height) * (_nativeHeight * newZoom)) + origin.y,
onComplete: ClampContentPosition});
The X and Y calculations are maybe not the best, but they work. They took me a while to figure out ;)
I would recommend running your logic BEFORE you even create the tween, thus you feed the tween the adjusted values in the first place. Or you could use an onUpdate as Neil suggested.
Related
I want to make a symbol rotate to point at the mouse. I'm using this function, but it doesn't work below the symbol's pivot. The inverse tan function has a range of 180 degrees right? So how can i get 360 degrees of movement?
Would I need to add an if statement to check the mouse position or is there a more elegant solution?
function panelTrack(){
angle = -180/Math.PI * Math.atan((mouseX - panel.x)/(mouseY - panel.y));
panel.rotation = angle;
trace(panel.rotation);
}
Math isn't my strong point - so perhaps someone else will provide a better answer, but to get all 4 quadrants, you need to use atan2.
angle = Math.atan2(mouseY - panel.y, mouseX - panel.x) * 180 / Math.PI;
I seem to recall it has to do with a check for a value of 0 (that Math.atan doesn't do).
const radiance:Number=180/Math.PI;
angle=-(Math.atan2(mouseX-panel.x, mouseY-panel.y))*radiance;
I used minus because usually the orientation is reverse when you don't add minus.
hope this helps.
In my Flash program I have a step where I want to rotate a displayObject around the center of its container.
As some of you may know, Flash has a default center point for rotation which is the top left corner, and doesn't fit for my case.
To achieve my specific rotation, I do 3 successive transformations using matrices, like this:
public function rotateAroundCenter(object:DisplayObject, container:DisplayObject, angleDegrees:Number):void {
var matrix:Matrix = object.transform.matrix;
var rect:Rectangle = object.getBounds(container);
matrix.translate(-(rect.left + (rect.width / 2)), -(rect.top + (rect.height / 2)));
matrix.rotate((angleDegrees / 180) * Math.PI);
matrix.translate(rect.left + (rect.width / 2), rect.top + (rect.height / 2));
object.transform.matrix = matrix;
}
This bit of code does the trick and I can rotate displayObjects around their container center like I want to.
Problem: For some of these objects (couldn't find a discriminating factor between those who work and those who don't), any time I try to apply a 180 degrees rotation to put them upside down using previous bit of code, Flash unloads the SWF, which seems very much like a crash to me. I only get this crash for some of these objects, but if they crash once they crash anytime I apply a 180 degrees rotation using my function.
I suspect a memory leak, but then, if 90 or 270 degrees rotations work, why would this specific case make my whole program crash?
Any clues about this issue will be very appreciated. Thanks!
I am trying to make an actor follow the player's finger (long touch). I'm positive I have the math right, but the actor fails to move exactly to where the player touched.
Here is an illustration of my problem:
When the touch is near the top, the actor goes beyond the visible scene at the top.
When the touch is near the bottom, the actor goes out of the visible scene at the bottom.
Same goes for the left and right.
When the touch is performed in the middle of the scene the actor moves perfectly to the touch. In short, the further the touch is away from the middle the more pronounced the distance between the actor and the touch is. In other words; the closer the touch is to the middle, the closer the actor moves towards the touch.
Please note that when the touch was near the bottom or the top the distance between the touch and the actor was more pronounced then when the touch was on the right or the left; as the top/bottom are further from the mid point.
Here is the code used to follow the actor towards the touch:
Lang: Lua
Lib: Cocosd2-x 3.1
local velocity = 1.4
local x, y = self.sprite:getPosition()
-- self.dest[X/Y] are cached coordinates to where the actor should move next.
local angle = math.atan2(touch.y - y, touch.x - x)
local deltaX = velocity * math.cos(angle)
local deltaY = velocity * math.sin(angle)
local newX = x + deltaX
local newY = y + deltaY
self.sprite:setPositionX(newX)
self.sprite:setPositionY(newY)
Things I've tried:
Changed the scale of background layer and sprites. No change
Changed the algorithm used to compute the angle. No change.
Created a red dot and set its position to the exact touch x/y to determine if there was some weird transformation issue when determining the actor's point. The red dot was always perfectly under the touch.
Discovered the issue. When I created the Actor sprite I set its z-index to 100. When I uncommented out the call that set the z-index, everything worked perfectly. In my situation, this particular sprite must always be above all other sprites. What I did to fix the issue is set the z-index much lower than what I had originally set it to; which ended up being 15.
sprite:setPositionZ(15)
From my observation it appears that the sprite is having some type of scale applied to its position the larger the z-index is of the sprite.
Update 1
Using :setPositionZ(int) will unnecessarily scale your sprite bigger in some cases. I now use :setGlobalZOrder(int) with much better success:
sprite:setGlobalZOrder(15)
I'm writing a paint program that uses shape brushes to draw by using the matrix function.
Everything works well aside from the fact that it's not smooth at all. There will be gaps in the painting if the mouse is moved at a high speed.
I've looked everywhere but haven't been able to find any solution.
The code basically looks like this:
//Press mouse within container. Uses Matrix to draw instances of the brush.
private function handleMouseDown_drawContainer(e:MouseEvent):void
{
_matrix.identity();
_matrix.translate(mouseX - 10, mouseY - 30);
_layout.bitmapData.draw(_layout.brush, _matrix);
_layout.drawContainer.addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove_drawContainer);
_layout.drawContainer.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp_drawContainer)
}
//Move mouse within container. Uses Matrix to draw instances of the brush.
private function handleMouseMove_drawContainer(e:MouseEvent):void
{
_matrix.identity();
_matrix.translate(mouseX - 10, mouseY - 30);
_layout.bitmapData.draw(_layout.brush, _matrix);
}
If anyone could help me figure out how to smooth out the drawing, I'd be forever grateful! =p
Thanks in advance.
You probably need some kind of interpolation between the mouse positions... there are of course many ways, I'll describe one very easy to implement but a bit hard to fine tune. Basically instead of drawing in each mouse position, you use an easing equation that follows the mouse with some delay... this way the described line will be a bit smoother, and will draw a few times between each mouse position.
So instead of doing (pseudocode):
onMouseMove {
draw(mouseX, mouseY);
}
You do something like:
x = 0;
y = 0;
onEnterFrame {
x += (mouseX - x) * 0.2;
y += (mouseY - y) * 0.2;
draw(x, y);
}
Although maybe what you really need is a way to limit the maximum distance between points, so if the mouse moves more in one frame, you interpolate points between the two positions and draw as many times as it's needed.
Or if you're looking for smoother lines (avoid sharp corners) maybe you also need to use beziers to control the resulting line.
Anyway, it all depends on the kind of drawing you're looking for.
I have a task:
I need to place about 100 sprites on one canvas (with prepared grid on it). I need to place them as invisible (circles) stones, on the board, and make visible only on mouseover.
The problem I come across is following, I can't place those objects accurately into the nodes on the grid.
E.g.
if I define stones (it's just a sprite, as I said earlier) this way:
var stone:StoneSprite = new StoneSprite();
stone.x = this.x + 2*cellWidth;
stone.graphics.beginFill( 0x000000 );
stone.graphics.drawCircle(stone.x , this.y + cellWidth, cellWidth/3 );
stone.graphics.endFill();
rawChildren.addChild(stone);
They don't sit on the node...
See image:
http://img.skitch.com/20091014-kuhfyjeg1g5qmrbyxbcerp4aya.png
And if I do it this way:
var stone:StoneSprite = new StoneSprite();
stone.graphics.beginFill( 0x000000 );
stone.graphics.drawCircle(this.x + 2*cellWidth , this.y + cellWidth, cellWidth/3 );
stone.graphics.endFill();
rawChildren.addChild(stone);
The stone is displayed correctly in the grid node... See image 2:
http://img.skitch.com/20091014-f595tksjxramt98s7yfye591bh.png
So I wonder what is the difference between these 2 approaches.
Also, I think I need to pass correct coordinates to the stone class... In case I would like to change some properties of the stone object. E.g. visibility, or radius.
Could you please suggest, what's wrong in defining coordinates as stone.x, stone.y
How to fix the problem with incorrect positioning.
Would really appreciate ideas about the problem, I am trying to solve for so long :(
Assume x & y are 30 and cellWidth is 30.
First Example:
stone.x = 30 + 60; //90
drawCircle(90, 60, 10);
This means if you were to draw a rectangle around your circle, it would be at [170,50]. (x,y).
Second Example:
stone.x = 0;
drawCircle(90, 60, 10)
This means the rectangle around your circle is at [80,50];
In the first example, you are moving the sprite to position x==90. Then drawing a circle whose center is at x==90 inside the sprite. So relative to this, you're at x==180. But because a circle's x,y coords are the center, subtract 10 for the radius to get the boundary x position.
In the second example, the sprite defaults to position x==0 relative to this and you're drawing the circle inside the sprite at position x==90. (therefore it begins at x==80).
I am not sure what's causing the issue - might be some padding induced by the container - can't say without testing. But I believe that adding a Sprite (say board) to canvas.rawChildren and using it as the parent for the grid and stones would fix the issue.