Aegidius
 Plüss   Aplulogo
     
 www.aplu.ch      Print Text 
© 2021, V10.4
 
  JGameGrid
 
 

The source code of all examples is included in the JGameGrid distribution.

Ex06: Mouse Events Using a GGMouseListener

In almost all modern computer programs the mouse is used as human-machine interface. This is not the case for computer games, because for quick interactions the keyboard is a better input device. Nevertheless we will learn how to implement mouse events because many simulation applications will use the mouse to select initial conditions. As a general rule, it is simpler to integrate the game grid window in a standard GUI using a GUI builder than create the controls (buttons, sliders, etc.) as actors yourself. But a custom designed control may give a more individual aspect of your game application.

In JGameGrid all mouse interactions are notified by a GGMouseListener like in the standard Java event model. But the mouse events are implemented more gentle and user friendly than in the Java API. (The implementation is inspired by mouse handlers in other high level languages.) All what you have to do is to implement the GGMouseListener interface that declares the single method mouseEvent(). The parameter let you find out what was the reason of the mouse event (event type) and the current mouse cursor position where the event was generated. In order to activate the event machine, you register your mouse listener by calling addMouseListener(). By passing a mouse event mask, you inform the event machine about the type of mouse events you are interested in. Your registered callback method mouseEvent() will only be triggered for the selected events. The mouse event mask is an or-combination of constants defined in GGMouse and covers the usual mouse actions of the left and right mouse button. Changes of the mouse cursor position and leaving or entering the playground are also considered as a mouse event. In contrary to the usual mouse event implementations, you may register as many mouse listeners as you want. This helps you to write clean OO programs because most of time actors should get notification of mouse events and there are normally many actors around.

In the following example we simulate a software power-on switch that lightens a electric bulb. In the same way you could create other virtual manipulators, instruments and gears. The bulbs and switches use two sprite images: one when turned off, one when turned on. Comes first the Bulb class, where we pass a type id to the constructor to select the type of lamp (red, green, blue). The corresponding sprite images are named bulb0_0.gif, bulb0_1.gif for the red lamp (off, on) etc.

import ch.aplu.jgamegrid.*;

public class Bulb extends Actor
{
  public Bulb(int type)
  {
    super("sprites/bulb" + type  + ".gif"2);
  }
}

The Switch class implements the GGMouseListener interface. The callback method mouseEvent() will use the mouse position to distinguish between the different switches. It then toggles the switch image (on/off) using showNextSprite() and turns the lamp on or off resp. We link each switch to its bulb by passing the bulb reference to the constructor.

At this point it is time to go a little bit deeper into the basic design of JGameGrid. JGameGrid performs an automatic refresh of the visible window in every simulation cycle. If we do no start the simulation cycling by pressing the Run button or by calling doRun(), there is no automatic refresh of the graphics situation and no change is detected. In this example we only use mouse events (that are generated from the event dispatch thread) and it is a waste of resources to run the simulation machine. As a drawback we must force the update ourselves by calling GameGrid's refresh() method. The mouse notification method mouseEvent() must return a boolean value that indicates that the event is "consumed" by this particular mouse listener and no following mouse listener will get a notification. Because all of the three listeners should get a notification, we return false (not consumed).

import ch.aplu.jgamegrid.*;

public class Switch extends Actor implements GGMouseListener
{
  private Bulb bulb;

  public Switch(Bulb bulb)
  {
    super("sprites/switch.gif", 2);
    this.bulb = bulb;
  }

  public boolean mouseEvent(GGMouse mouse)
  {
    Location location =
      gameGrid.toLocationInGrid(mouse.getX(), mouse.getY());
    if (location.equals(getLocation()))
      showNextSprite();
    bulb.show(getIdVisible());
    gameGrid.refresh();
    return false;
  }
}

The application class just creates the three bulbs and their corresponding switches and positions them in the playground. But the most important thing to mention in this context is the registration of the three GGMouseListeners by calling addMouseListener() three times.

import ch.aplu.jgamegrid.*;
import
 java.awt.Color;

public
 class Ex06 extends GameGrid
{
  
public Ex06()
  
{
    
super(7, 4, 40, false);
    
setBgColor(new Color(210, 210, 210));
    
for (int i = 0; i < 3; i++)
    
{
      Bulb bulb 
= new Bulb(i);
      
addActor(bulb, new Location(2*+ 1, 1));
      Switch aSwitch 
= new Switch(bulb);
      
addActor(aSwitch, new Location(2*+ 1, 3));
      
addMouseListener(aSwitch, GGMouse.lPress);
    
}
    
show();
  
}

  
public static void main(String[] args)
  
{
    
new Ex06();
  
}
}

Execute the program locally using WebStart.

GG6

 

 

 

Needless to mention that you could integrate a control panel containing controls and indicators into your sophisticated GUI application by using JGameGrid's bean component.

 

Ex06a: Drag and Drop, the Mouse Event Mask

In the following example we introduce a very common technique of creating images by clicking and moving them by drag and drop. The implementation is a bit subtle because of the interaction between the mouse press, drag and release events. The basic idea is the following: the press event is used to store the current location and to set a flag indicating that this particular honey pot is the drag state. The drag event checks if the new location is empty and updates the current location. So you can see the moving pot during the drag operation. The release event sets the pot to the final location and clears the state flag. Here is the code:

import ch.aplu.jgamegrid.*;

public
 class Honey extends Actor implements GGMouseListener
{
  
private Location lastLocation;
  
private boolean isDragging = false;

  
public Honey()
  
{
    
super("sprites/honey.gif");
  
}

  
public boolean mouseEvent(GGMouse mouse)
  
{
    Location location = gameGrid.toLocationInGrid(mouse.getX(), mouse.getY());
    
switch (mouse.getEvent())
    
{
      
case GGMouse.lPress:
        lastLocation 
= location.clone();
        
if (gameGrid.getOneActorAt(location) == this)
          isDragging 
= true;
        
break;
      
case GGMouse.lDrag:
        
if (isDragging && gameGrid.isEmpty(location))
        
{
          
setLocation(location);
          lastLocation 
= location.clone();
        
}
        
break;
      
case GGMouse.lRelease:
        
if (isDragging)
        
{
          
setLocation(lastLocation);
          isDragging 
= false;
        
}
        
break;
    
}
    
return false;
  
}
}

The application program also uses a mouse listener to create the honey pots. If there is already a pot at the specific location, no additional pot is created. Every honey instance has his own mouse listener. Because we are interested in the press, drag and release events of the left button, we register the mouse listeners with the GGMouse.lPress | GGMouse.lDrag | GGMouse.lRelease mask. The Bear is the same as already used in Ex04.

import ch.aplu.jgamegrid.*;
import java.awt.*;

public class Ex06a extends GameGrid implements GGMouseListener
{
  public Ex06a()
  {
    super(10, 10, 60, Color.green, false);
    setTitle("Click to create a honey pot, press and drag to move it");
    addActor(new Bear(Honey.class), new Location(0, 0));
    addMouseListener(this, GGMouse.lPress);
    show();
    doRun();
  }

  public boolean mouseEvent(GGMouse mouse)
  {
    Location location = toLocationInGrid(mouse.getX(), mouse.getY());
    if (isEmpty(location))  // Do not create an actor if cell is occupied
    {
      Honey honey = new Honey();
      addActor(honey, location);
      addMouseListener(honey, GGMouse.lPress | GGMouse.lDrag | GGMouse.lRelease);
    }
    return false;  // Don't consume the event, other listeners must be notified
  }

  public static void main(String[] args)
  {
    new Ex06a();
  }
}

Execute the program locally using WebStart.

You must hurry up to create the honey pots because the bear is very hungry, but once created, you may bring the pots to a save place by dragging them out of the bear's track.

GG5