Handling Mouse Events
Setup
You may find a completed “features/events/HandlingMouseEvent” sample project for TypeScript, Haxe, ES6 or ES5 online, the following describes how to handle mouse events from an empty project.
Run the following commands:
mkdir HandlingMouseEvents
cd HandlingMouseEvents
yo openfl
Next, download openfl.png and save it to the “dist” directory.
Open the “src/app.ts”, “src/app.js” or “src/App.hx” file and add some code to load and display the image.
import Bitmap from "openfl/display/Bitmap";
import BitmapData from "openfl/display/BitmapData";
import openfl.display.Bitmap;
import openfl.display.BitmapData;
import Bitmap from "openfl/display/Bitmap";
import BitmapData from "openfl/display/BitmapData";
var Bitmap = require ("openfl/display/Bitmap").default;
var BitmapData = require ("openfl/display/BitmapData").default;
BitmapData.loadFromFile ("openfl.png").onComplete ((bitmapData) => {
var bitmap = new Bitmap (bitmapData);
bitmap.x = 100;
bitmap.y = 100;
this.addChild (bitmap);
});
BitmapData.loadFromFile ("openfl.png").onComplete (function (bitmapData) {
var bitmap = new Bitmap (bitmapData);
bitmap.x = 100;
bitmap.y = 100;
addChild (bitmap);
});
BitmapData.loadFromFile ("openfl.png").onComplete ((bitmapData) => {
var bitmap = new Bitmap (bitmapData);
bitmap.x = 100;
bitmap.y = 100;
this.addChild (bitmap);
});
BitmapData.loadFromFile ("openfl.png").onComplete (function (bitmapData) {
var bitmap = new Bitmap (bitmapData);
bitmap.x = 100;
bitmap.y = 100;
this.addChild (bitmap);
}.bind (this));
Interactive Objects
If you have already completed the Displaying a Bitmap and Adding Animation tutorials, then you should be familiar with creating a Bitmap
objects. Each of these objects is called a DisplayObject
, which is compatible with the “display list”, or scene graphs of objects that will be rendered automatically. Bitmap
objects are not interactive objects, however.
The abstract InteractiveObject
base class defines objects that provide interactive events, such as openfl.events.MouseEvent
and openfl.events.TouchEvent
.
The most common InteractiveObject
in OpenFL is called a Sprite
. A Sprite
is an object container, and is interactive. It is somewhat similar to a div
element. Sprite
objects are lightweight and are often used for convenience in positioning objects, or to allow interaction or draw primitive vector shapes.
Our Bitmap
is visible, but not interactive, so we can make it a child of a Sprite
in order to start making it interactive. We will also enable the Sprite
buttonMode
property, which makes the mouse cursor turn into a click cursor when you hover over the object.
Let us change the code so that instead of bitmap
as a child directly, we add it as a child of a new Sprite
object instead. While we are at it, we will enable buttonMode
to give us an interactive mouse cursor.
var bitmap = new Bitmap (bitmapData);
bitmap.x = 100;
bitmap.y = 100;
var sprite = new Sprite ();
sprite.addChild (bitmap);
sprite.buttonMode = true;
this.addChild (sprite);
Handling a MOUSE_DOWN
Event
First, we can begin handling mouse events by adding an import for openfl.events.MouseEvent
:
import MouseEvent from "openfl/events/MouseEvent";
import openfl.events.MouseEvent;
import MouseEvent from "openfl/events/MouseEvent";
var MouseEvent = require ("openfl/events/MouseEvent").default;
There are multiple events available normally in the browser (such as "click"
, "mousedown"
or "mouseup"
), but these are only available to elements that have been added to the DOM. This is a similar concept to the way events work in OpenFL, but OpenFL events work even when using 2D canvas or WebGL rendering. The names of OpenFL events are similar to the DOM, but use “camel-case”, like "mouseDown"
and "mouseUp"
. For this example, we will use the MouseEvent
type, but you can also use literal strings.
Below addChild (sprite)
in the code, we can also listen for MouseEvent.MOUSE_DOWN
event:
sprite.addEventListener (MouseEvent.MOUSE_DOWN, (e:MouseEvent) => {
alert ("MOUSE DOWN");
});
sprite.addEventListener (MouseEvent.MOUSE_DOWN, function (e) {
js.Browser.alert ("MOUSE DOWN");
});
sprite.addEventListener (MouseEvent.MOUSE_DOWN, (e) => {
alert ("MOUSE DOWN");
});
sprite.addEventListener (MouseEvent.MOUSE_DOWN, function (e) {
alert ("MOUSE DOWN");
}.bind (this));
Now, if you click on the icon, you should get a browser alert
message that you clicked the object.
Simple Dragging
OpenFL provides convenience methods for simple drag-and-drop behaviors, called startDrag
and stopDrag
. We can use this to add a simple drag-and-drop behavior, in combination with another event listener for MouseEvent.MOUSE_UP
.
Every MouseEvent
includes references for both the target
and currentTarget
of the MouseEvent
. In our listener, we could reference sprite
directly, but we will use currentTarget
to illustrate this behavior of mouse events.
The difference between target
and currentTarget
is that the currentTarget
property will match the object on which you added an event listener. In our project, the sprite
only contains one non-interactive object. In a larger project, you may have many children that are interactive. The target
in that case would be the exact child object that triggered the event. If we expanded our project to include 20 objects that listen to mouse events, using currentTarget
would allow us to share one listener among multiple objects.
sprite.addEventListener (MouseEvent.MOUSE_DOWN, (e:MouseEvent) => {
e.currentTarget.startDrag ();
});
sprite.addEventListener (MouseEvent.MOUSE_UP, (e:MouseEvent) => {
e.currentTarget.stopDrag ();
});
sprite.addEventListener (MouseEvent.MOUSE_DOWN, function (e) {
e.currentTarget.startDrag ();
});
sprite.addEventListener (MouseEvent.MOUSE_UP, function (e) {
e.currentTarget.stopDrag ();
});
sprite.addEventListener (MouseEvent.MOUSE_DOWN, (e) => {
e.currentTarget.startDrag ();
});
sprite.addEventListener (MouseEvent.MOUSE_UP, (e) => {
e.currentTarget.stopDrag ();
});
sprite.addEventListener (MouseEvent.MOUSE_DOWN, function (e) {
e.currentTarget.startDrag ();
}.bind (this));
sprite.addEventListener (MouseEvent.MOUSE_UP, function (e) {
e.currentTarget.stopDrag ();
}.bind (this));
Adding Animation
If you want to make a drag behavior more exciting, you can add a delay between the position of the mouse cursor, and the position of the object you are dragging. This requires listening to both MouseEvent.MOUSE_DOWN
, MouseEvent.MOUSE_UP
and to Event.ENTER_FRAME
.
The following is an example of how you could make an object trail behind the mouse cursor. It is important for code like this that you listen to the stage
, or root of your project, for MouseEvent.MOUSE_UP
events, because trailing the cursor means that is possible that while the user may start by clicking down on the sprite
object, when they release they may be over a different object, or no object. In this case, it is important to catch that the user released the mouse button.
import Event from "openfl/events/Event";
import openfl.events.Event;
import Event from "openfl/events/Event";
var Event = require ("openfl/events/Event").default;
let offsetX = 0;
let offsetY = 0;
let targetX = 0;
let targetY = 0;
let dragging = false;
sprite.addEventListener (MouseEvent.MOUSE_DOWN, (e:MouseEvent) => {
offsetX = sprite.x - e.stageX;
offsetY = sprite.y - e.stageY;
dragging = true;
});
this.stage.addEventListener (MouseEvent.MOUSE_UP, (e:MouseEvent) => {
dragging = false;
});
this.stage.addEventListener (Event.ENTER_FRAME, (e:Event) => {
if (dragging) {
targetX = this.stage.mouseX + offsetX;
targetY = this.stage.mouseY + offsetY;
}
let diffX = targetX - sprite.x;
let diffY = targetY - sprite.y;
if (Math.abs (diffX) < 1) {
sprite.x = targetX;
} else {
sprite.x += (diffX * 0.2);
}
if (Math.abs (diffY) < 1) {
sprite.y = targetY;
} else {
sprite.y += (diffY * 0.2);
}
});
var offsetX = 0;
var offsetY = 0;
var targetX = 0;
var targetY = 0;
var dragging = false;
sprite.addEventListener (MouseEvent.MOUSE_DOWN, function (e) {
offsetX = sprite.x - e.stageX;
offsetY = sprite.y - e.stageY;
dragging = true;
});
stage.addEventListener (MouseEvent.MOUSE_UP, function (e) {
dragging = false;
});
stage.addEventListener (Event.ENTER_FRAME, function (e) {
if (dragging) {
targetX = stage.mouseX + offsetX;
targetY = stage.mouseY + offsetY;
}
var diffX = targetX - sprite.x;
var diffY = targetY - sprite.y;
if (Math.abs (diffX) < 1) {
sprite.x = targetX;
} else {
sprite.x += (diffX * 0.2);
}
if (Math.abs (diffY) < 1) {
sprite.y = targetY;
} else {
sprite.y += (diffY * 0.2);
}
});
let offsetX = 0;
let offsetY = 0;
let targetX = 0;
let targetY = 0;
let dragging = false;
sprite.addEventListener (MouseEvent.MOUSE_DOWN, (e) => {
offsetX = sprite.x - e.stageX;
offsetY = sprite.y - e.stageY;
dragging = true;
});
this.stage.addEventListener (MouseEvent.MOUSE_UP, (e) => {
dragging = false;
});
this.stage.addEventListener (Event.ENTER_FRAME, (e) => {
if (dragging) {
targetX = this.stage.mouseX + offsetX;
targetY = this.stage.mouseY + offsetY;
}
let diffX = targetX - sprite.x;
let diffY = targetY - sprite.y;
if (Math.abs (diffX) < 1) {
sprite.x = targetX;
} else {
sprite.x += (diffX * 0.2);
}
if (Math.abs (diffY) < 1) {
sprite.y = targetY;
} else {
sprite.y += (diffY * 0.2);
}
});
var offsetX = 0;
var offsetY = 0;
var targetX = 0;
var targetY = 0;
var dragging = false;
sprite.addEventListener (MouseEvent.MOUSE_DOWN, function (e) {
offsetX = sprite.x - e.stageX;
offsetY = sprite.y - e.stageY;
dragging = true;
}.bind (this));
this.stage.addEventListener (MouseEvent.MOUSE_UP, function (e) {
dragging = false;
}.bind (this));
this.stage.addEventListener (Event.ENTER_FRAME, function (e) {
if (dragging) {
targetX = this.stage.mouseX + offsetX;
targetY = this.stage.mouseY + offsetY;
}
var diffX = targetX - sprite.x;
var diffY = targetY - sprite.y;
if (Math.abs (diffX) < 1) {
sprite.x = targetX;
} else {
sprite.x += (diffX * 0.2);
}
if (Math.abs (diffY) < 1) {
sprite.y = targetY;
} else {
sprite.y += (diffY * 0.2);
}
}.bind (this));
Next Steps
You can look at our other samples, like the “features/events/HandlingKeyboardEvents” or “features/media/AddingSound” samples.