The source code of all examples is included in the JGameGrid distribution.
Ex23: Dynamic Sprite Transformation
Normally the displayed sprite image of an actor is taken from a disk file in gif, jpg or png format. When rotated actors are used, the image is rotated by library code when the actor is created and the images are stored in a sprite buffer. (For an actor with multiple sprite ids, this procedure is applied to every sprite image.)
For applications where multiple sprite images are used that differ only in size and rotation angle, it is cumbersome to create all the images statically using an image editor. To simplify your work you can transform the one given sprite image dynamically by size and rotation with the Actor class getScaleImage() methods. Using the returned BufferedImage you create new actors with one or several sprite images. With this approach it is very simple to produce special visual effects.
For the demonstration we use one sprite image explosion.gif and show it like coming out of the black background. The application class creates the actor and passes it to the ScaledActor class.
The class ScaledActor extracts the sprite image and creates a single dynamic actor with ten scaled and rotated sprite images, each with an increasing sprite id. The act() method shows consecutive images by cycling through the sprite ids.
Execute the program locally using WebStart.
Ex24: Overlaid Actor Dragging
For many games, mouse interactions play an important role. It is not uncommon to move actors by mouse dragging and we should learn how to implement actor movements even when several actors are superposed. Here the principles: When the mouse button is pressed, it is necessary to detect which actor images intersect with the current mouse cursor. For the dragging only the actor displayed on top is concerned. If only standard mouse callbacks are used, a lot of coding is necessary to do this simple operation. To make your life easier, JGameGrid introduced the concept of a "mouse touch": For every actor you can define a "mouse touch area" (non-transparent image pixels, rectangle/circle of any size and position) and register a MouseTouchListener that reports via its callback method when the mouse cursor intersects the area.
Normally all actors under the current mouse cursor will send a notification. If only the top actor's event is needed, you can register the MouseTouchListener with the onTopOnly flag set to true.
In the following example ten chip-like actors with four different colors (generated dynamically using Graphics2D) are first stacked in the upper left cell. It's your challenge to move them into the corresponding color box with as few mouse-drags as possible.
First comes the ChipActor class, where the sprite image is created using RadialGradientPaint to prettify the chip image. The advantage of code-generated images compared to predefined disk images is the ease to produce many different chip colors in no time.
In the application class we first label the color boxes using TextActors. Then we create ten ChipActors colored randomly using four predefined colors.
We turn now our special attention to the callback method mouseTouched() that is registered with addMouseTouchListener() for lPress, lDrag and lRelease events. Because we are only interested in events from the top actor, we set the onTopOnly flag to true. When a lPress event is fired, we store the current cell location and the pixel coordinates of the mouse cursor relative to the image. The first is necessary to bring the dragged actor back to its origin if we move the mouse so fast that the image cannot follow. The coordinate relative to the sprite image is used to calculate the image center location while dragging. JGameGrid reports a release event, even if the mouse button is released outside the image, but in this case the parameter spot reports the coordinates (-1,-1). Therefore in the lRelease case we check for spot.x and set the actor back to its original cell (to avoid that the actor remains at a partially dragged position). actor.setOntop() is called in the lPress event to ensure that the selected actor moves on top of all other actors independent of the previous paint order.
(One special case should be mentioned: If the mouse is pressed outside an image and then dragged inside, no drag events are fired.)
Because the simulation loop is not running, we must repaint the game grid ourselves by calling refresh(). Whenever a chip is released, we check with isOver() if all the chips are in the right color box. To do this we reclaim all actors in every cell and check if they have the corresponding color.
Execute the program locally using WebStart.