""Goo" With Director 8
April 12, 2000
by Gary Rosenzweig
This week in the Lingo Lounge we have a request. A reader asks: "There's this program called Goo, that lets you drag and stretch images from anywhere you click on the mouse. In Director 8, they have the image lingo and one example that lets you pull on the corners of the image to distort it, but not from anywhere inside the image. Is there a way to do this, a trick of some kind to emulate Goo?"
At first, I thought: well, no, there still isn't a way to do something like this. Then, a few seconds later it occurred to me that there is a way. Not only that, but it was pretty simple.
The new Director 8 imaging Lingo includes copyPixels, a command that lets you take a rectangular area of one image and copy it into a rectangular area of another. But you can also take that rectangular area and copy it into a quad area in another. This quad would be represented by four points, just like sprite quads. The rectangle's four corners would be stretched to match these four points, even if they do not represent a perfect rectangle. When the user clicks on a point in the image to drag it, we can look at the image as four separate rectangles. Figure 1 shows these rectangles and how the click point divides them.
Once the user clicks the image and holds down the mouse button, the fun begins. We take these four rectangles and create a list of four images. Then, every frame, we redraw the four images into the member. However, instead of using the original rectangle locations of these four images, we will use four quads. These four quads will be generated by the original edge positions of the four rectangles, plus the new location of the cursor.
Figure 2 shows what the quads would look like if the user drags down and to the right. Three points of each quad are the same as the original rectangles of the four images. However, the middle point of each rectangle is not locked to the cursor.
To create a program to do this, we only need one behavior. This should be attached to the image's sprite. This behavior starts off by recording constants, such as the width and height of the image, the location of the upper left corner of the sprite,and the original image so that it can be restored when the sprite ends. We will also use the property "pImageList" to store the four sub-images, as well as "pDrag" to determine if the user is currently stretching the image.
property pDrag
property pImageList
property pWidth, pHeight
property pClickPoint
property pOriginalImage
property pUpperLeft
on beginSprite me
pDrag = FALSE
pWidth = sprite(me.spriteNum).member.width
pHeight = sprite(me.spriteNum).member.height
pOriginalImage = duplicate(sprite(me.spriteNum).member.image)
pUpperLeft = point(sprite(me.spriteNum).left,sprite(me.spriteNum).top)
end
When the user clicks down in the image, we record the click location relative to the upper left corner of the sprite. Then, we create a list of four new images, populating each with the quarter of the original image that it represents.
on mouseDown me
pDrag = TRUE
pClickPoint = the clickLoc - pUpperLeft
x = pClickPoint.locH
y = pClickPoint.locV
origImage = sprite(me.spriteNum).member.image
pImageList = []
add pImageList, image(x,y,32)
pImageList[1].copyPixels(origImage,rect(0,0,x,y),rect(0,0,x,y))
add pImageList, image(pWidth-x,y,32)
pImageList[2].copyPixels(origImage,rect(0,0,pWidth-x,y),rect(x+1,0,pWidth,y))
add pImageList, image(x,pHeight-y,32)
pImageList[3].copyPixels(origImage,rect(0,0,x,pHeight-y),rect(0,y+1,x,pHeight))
add pImageList, image(pWidth-x,pHeight-y,32)
pImageList[4].copyPixels(origImage,rect(0,0,pWidth-x,pHeight-y),rect(x+1,y+1,pWidth,pHeight))
end
For frames after the click, the "pDrag" property is TRUE. Every frame we then figure out the four quads that represent the new four sections of the image. We use copyPixels to copy the rectangles into these quads.
on exitFrame me
if pDrag then
x1 = pClickPoint.locH
y1 = pClickPoint.locV
pCurrentPoint = the mouseLoc - pUpperLeft
x2 = pCurrentPoint.locH
y2 = pCurrentPoint.locV
origImage = sprite(me.spriteNum).member.image
origImage.copyPixels(pImageList[1],\
[point(0,0),point(x1,0),point(x2,y2),point(0,y1)],\
rect(0,0,x1,y1))
origImage.copyPixels(pImageList[2],\
[point(x1,0),point(pWidth,0),point(pWidth,y1),point(x2,y2)],\
rect(0,0,pWidth-x1,y1))
origImage.copyPixels(pImageList[3],\
[point(0,y1),point(x2,y2),point(x1,pHeight),point(0,pHeight)],\
rect(0,0,x1,pHeight-y1))
origImage.copyPixels(pImageList[4],\
[point(x2,y2),point(pWidth,y1),point(pWidth,pHeight),point(x1,pHeight)],\
rect(0,0,pWidth-x1,pHeight-y1))
end if
end
The dragging stops when the user lifts up the mouse. We will also place an on endSprite handler in this behavior to restore the original member image when the sprite leaves the Stage or the movie stops.
on mouseUp me
pDrag = FALSE
end
on mouseUpOutside me
pDrag = FALSE
end
on endSprite me
sprite(me.spriteNum).member.image = pOriginalImage
end
This last handler could also be used as an undo button. It will restore the image to its original picture. Since this program will allow the user to continually drag and distort the image, you could also store another version of the image just as every drag starts, and have a single-action undo that puts this image back into the member. The sample movie here lets you play with a face, a typical example of such an application. Have fun.
Director 8 Download for Mac or PC.
Gary Rosenzweig's latest book is "Advanced Lingo for Games." In it, you can find the source code for more than 20 complete games. More information about the book can be found at http://clevermedia.com/resources/bookstore/book4.html. It can be purchased there, or in your local bookstore.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.