package org.flixel.system.input;
import org.flixel.FlxCamera;
import org.flixel.FlxG;
import org.flixel.FlxGroup;
import org.flixel.FlxPoint;
import org.flixel.FlxSprite;
import org.flixel.system.replay.MouseRecord;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Array;
import flash.events.MouseEvent;
import flash.events.TouchEvent;
/**
* This class helps contain and track the pointers in your game.
* Automatically accounts for parallax scrolling, etc.
*
* @author Ka Wing Chin
*/
public class Mouse extends FlxPoint
{
protected String ImgDefaultCursor = "org/flixel/data/pack:cursor";
/**
* Current "delta" value of mouse wheel. If the wheel was just scrolled up, it will have a positive value. If it was just scrolled down, it will have a negative value. If it wasn't just scroll this frame, it will be 0.
*/
public int wheel;
/**
* Current X position of the mouse pointer on the screen.
*/
public int screenX;
/**
* Current Y position of the mouse pointer on the screen.
*/
public int screenY;
/**
* A display container for the mouse cursor.
* This container is a child of FlxGame and sits at the right "height".
*/
protected FlxGroup _cursorContainer;
/**
* This is just a reference to the current cursor image, if there is one.
*/
protected FlxSprite _cursor;
/**
* Helper variables for recording purposes.
*/
protected int _lastWheel;
protected FlxPoint _point;
protected Array<Pointer> _pointers;
/**
* The current active pointers.
*/
public int activePointers;
/**
* Constructor
*/
public Mouse(FlxGroup CursorContainer)
{
super();
_cursorContainer = CursorContainer;
screenX = 0;
screenY = 0;
_lastWheel = wheel = 0;
_cursor = null;
_point = new FlxPoint();
_pointers = new Array<Pointer>();
_pointers.add(new Pointer());
activePointers = 0;
}
/**
* Clean up memory.
*/
public void destroy()
{
_cursorContainer = null;
_cursor = null;
_point = null;
_pointers.clear();
_pointers = null;
}
/**
* Either show an existing cursor or load a new one.
*
* @param Graphic The image you want to use for the cursor.
* @param Scale Change the size of the cursor. Default = 1, or native size. 2 = 2x as big, 0.5 = half size, etc.
* @param XOffset The number of pixels between the mouse's screen position and the graphic's top left corner.
* @param YOffset The number of pixels between the mouse's screen position and the graphic's top left corner.
*/
public void show(String Graphic,float Scale,int XOffset,int YOffset)
{
_cursorContainer.visible = true;
if(Graphic != null)
load(Graphic,Scale,XOffset,YOffset);
else if(_cursor == null)
load();
}
/**
* Either show an existing cursor or load a new one.
*
* @param Graphic The image you want to use for the cursor.
* @param Scale Change the size of the cursor. Default = 1, or native size. 2 = 2x as big, 0.5 = half size, etc.
* @param XOffset The number of pixels between the mouse's screen position and the graphic's top left corner.
*/
public void show(String Graphic,float Scale,int XOffset)
{
show(Graphic,Scale,XOffset,0);
}
/**
* Either show an existing cursor or load a new one.
*
* @param Graphic The image you want to use for the cursor.
* @param Scale Change the size of the cursor. Default = 1, or native size. 2 = 2x as big, 0.5 = half size, etc.
*/
public void show(String imgCursor,float Scale)
{
show(imgCursor,Scale,0,0);
}
/**
* Either show an existing cursor or load a new one.
*
* @param Graphic The image you want to use for the cursor.
*/
public void show(String Graphic)
{
show(Graphic,1,0,0);
}
/**
* Either show an existing cursor or load a new one.
*/
public void show()
{
show(null,1,0,0);
}
/**
* Hides the mouse cursor
*/
public void hide()
{
_cursorContainer.visible = false;
}
/**
* Read only, check visibility of mouse cursor.
*/
public boolean getVisible()
{
return _cursorContainer.visible;
}
/**
* Load a new mouse cursor graphic
*
* @param Graphic The image you want to use for the cursor.
* @param Scale Change the size of the cursor.
* @param XOffset The number of pixels between the mouse's screen position and the graphic's top left corner.
* @param YOffset The number of pixels between the mouse's screen position and the graphic's top left corner.
*/
public void load(String Graphic,float Scale,int XOffset,int YOffset)
{
if(_cursor != null)
_cursorContainer.remove(_cursor);
if(Graphic == null)
Graphic = ImgDefaultCursor;
_cursor = new FlxSprite(screenX,screenY,Graphic);
_cursor.offset.x = XOffset;
_cursor.offset.y = YOffset;
_cursor.scale.x = Scale;
_cursor.scale.y = Scale;
_cursor.ignoreDrawDebug = true;
_cursor.cameras = new Array<FlxCamera>();
_cursor.cameras.addAll(new FlxCamera[]{new FlxCamera(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight())});
_cursorContainer.add(_cursor);
}
/**
* Load a new mouse cursor graphic
*
* @param Graphic The image you want to use for the cursor.
* @param Scale Change the size of the cursor.
* @param XOffset The number of pixels between the mouse's screen position and the graphic's top left corner.
*/
public void load(String Graphic,float Scale,int XOffset)
{
load(Graphic,Scale,XOffset,0);
}
/**
* Load a new mouse cursor graphic
*
* @param Graphic The image you want to use for the cursor.
* @param Scale Change the size of the cursor.
*/
public void load(String Graphic,float Scale)
{
load(Graphic,Scale,0,0);
}
/**
* Load a new mouse cursor graphic
*
* @param Graphic The image you want to use for the cursor.
*/
public void load(String Graphic)
{
load(Graphic,1,0,0);
}
/**
* Load a new mouse cursor graphic
*/
public void load()
{
load(null,1,0,0);
}
/**
* Unload the current cursor graphic. If the current cursor is visible, then
* the default system cursor is loaded up to replace the old one.
*/
public void unload()
{
if(_cursor != null)
{
if(_cursorContainer.visible)
load();
else
{
_cursorContainer.remove(_cursor);
_cursor = null;
}
}
}
/**
* Called by the internal game loop to update the pointers positions in the game world.
* Also updates the just pressed/just released flags.
*/
public void update()
{
Pointer o;
int i = 0;
int l = _pointers.size;
while(i < l)
{
o = _pointers.get(i);
o.screenPosition.x = (float) Gdx.input.getX(i);
o.screenPosition.y = (float) Gdx.input.getY(i);
if((o.last == -1) && (o.current == -1))
o.current = 0;
else if((o.last == 2) && (o.current == 2))
o.current = 1;
o.last = o.current;
++i;
}
updateCursor();
}
/**
* Internal function for helping to update the cursor graphic and world coordinates.
*/
protected void updateCursor()
{
Pointer o = _pointers.get(0);
//actually position the flixel mouse cursor graphic
if(_cursor != null)
{
_cursor.x = o.screenPosition.x;
_cursor.y = o.screenPosition.y;
}
//update the x, y, screenX, and screenY variables based on the default camera.
//This is basically a combination of getWorldPosition() and getScreenPosition()
FlxCamera camera = FlxG.camera;
screenX = (int) ((o.screenPosition.x - camera.x)/(camera.getZoom() * camera._screenScaleFactorX));
screenY = (int) ((o.screenPosition.y - camera.y)/(camera.getZoom() * camera._screenScaleFactorY));
x = screenX + camera.scroll.x;
y = screenY + camera.scroll.y;
}
/**
* Fetch the world position of the specified pointer on any given camera.
*
* @param Pointer The pointer id.
* @param Camera If unspecified, first/main global camera is used instead.
* @param Point An existing point object to store the results (if you don't want a new one created).
*
* @return The pointer's location in world space.
*/
public FlxPoint getWorldPosition(int Pointer,FlxCamera Camera,FlxPoint Point)
{
if(Camera == null)
Camera = FlxG.camera;
if(Point == null)
Point = new FlxPoint();
getScreenPosition(Pointer,Camera,_point);
Point.x = _point.x + Camera.scroll.x;
Point.y = _point.y + Camera.scroll.y;
return Point;
}
/**
* Fetch the world position of the specified pointer on any given camera.
*
* @param Pointer The pointer id.
* @param Camera If unspecified, first/main global camera is used instead.
*
* @return The pointer's location in world space.
*/
public FlxPoint getWorldPosition(int Pointer,FlxCamera Camera)
{
return getWorldPosition(Pointer,Camera,null);
}
/**
* Fetch the world position of the specified pointer on any given camera.
*
* @param Pointer The pointer id.
*
* @return The pointer's location in world space.
*/
public FlxPoint getWorldPosition(int Pointer)
{
return getWorldPosition(Pointer,null,null);
}
/**
* Fetch the world position of the first pointer on any given camera.
* NOTE: Mouse.x and Mouse.y also store the world position of this pointer on the main camera.
*
* @param Camera If unspecified, first/main global camera is used instead.
* @param Point An existing point object to store the results (if you don't want a new one created).
*
* @return The pointer's location in world space.
*/
public FlxPoint getWorldPosition(FlxCamera Camera,FlxPoint Point)
{
return getWorldPosition(0,Camera,Point);
}
/**
* Fetch the world position of the first pointer on any given camera.
* NOTE: Mouse.x and Mouse.y also store the world position of this pointer on the main camera.
*
* @param Camera If unspecified, first/main global camera is used instead.
*
* @return The pointer's location in world space.
*/
public FlxPoint getWorldPosition(FlxCamera Camera)
{
return getWorldPosition(0,Camera,null);
}
/**
* Fetch the world position of the first pointer on any given camera.
* NOTE: Mouse.x and Mouse.y also store the world position of this pointer on the main camera.
*
* @return The pointer's location in world space.
*/
public FlxPoint getWorldPosition()
{
return getWorldPosition(0,null,null);
}
/**
* Fetch the screen position of the specified pointer on any given camera.
*
* @param Pointer The pointer id.
* @param Camera If unspecified, first/main global camera is used instead.
* @param Point An existing point object to store the results (if you don't want a new one created).
*
* @return The pointer's location in screen space.
*/
public FlxPoint getScreenPosition(int Pointer,FlxCamera Camera,FlxPoint Point)
{
if(Camera == null)
Camera = FlxG.camera;
if(Point == null)
Point = new FlxPoint();
if(Pointer >= _pointers.size)
return Point;
Pointer o = _pointers.get(Pointer);
Point.x = (o.screenPosition.x - Camera.x)/(Camera.getZoom() * Camera._screenScaleFactorX);
Point.y = (o.screenPosition.y - Camera.y)/(Camera.getZoom() * Camera._screenScaleFactorY);
return Point;
}
/**
* Fetch the screen position of the specified pointer on any given camera.
*
* @param Pointer The pointer id.
* @param Camera If unspecified, first/main global camera is used instead.
*
* @return The pointer's location in screen space.
*/
public FlxPoint getScreenPosition(int Pointer,FlxCamera Camera)
{
return getScreenPosition(Pointer,Camera,null);
}
/**
* Fetch the screen position of the specified pointer on any given camera.
*
* @param Pointer The pointer id.
*
* @return The pointer's location in screen space.
*/
public FlxPoint getScreenPosition(int Pointer)
{
return getScreenPosition(Pointer,null,null);
}
/**
* Fetch the screen position of the first pointer on any given camera.
* NOTE: Mouse.screenX and Mouse.screenY also store the screen position of this pointer on the main camera.
*
* @param Camera If unspecified, first/main global camera is used instead.
* @param Point An existing point object to store the results (if you don't want a new one created).
*
* @return The pointer's location in screen space.
*/
public FlxPoint getScreenPosition(FlxCamera Camera,FlxPoint Point)
{
return getScreenPosition(0,Camera,Point);
}
/**
* Fetch the screen position of the first pointer on any given camera.
* NOTE: Mouse.screenX and Mouse.screenY also store the screen position of this pointer on the main camera.
*
* @param Camera If unspecified, first/main global camera is used instead.
*
* @return The pointer's location in screen space.
*/
public FlxPoint getScreenPosition(FlxCamera Camera)
{
return getScreenPosition(0,Camera,null);
}
/**
* Fetch the screen position of the first pointer on any given camera.
* NOTE: Mouse.screenX and Mouse.screenY also store the screen position of this pointer on the main camera.
*
* @return The pointer's location in screen space.
*/
public FlxPoint getScreenPosition()
{
return getScreenPosition(0,null,null);
}
/**
* Resets the just pressed/just released flags and sets mouse to not pressed.
*/
public void reset()
{
_pointers.clear();
_pointers.add(new Pointer());
}
/**
* Check to see if the mouse is pressed.
*
* @param Pointer The pointer id.
*
* @return Whether the screen is pressed.
*/
public boolean pressed(int Pointer)
{
if(Pointer >= _pointers.size)
return false;
return _pointers.get(Pointer).current > 0;
}
/**
* Check to see if the mouse is pressed.
*
* @return Whether the screen is pressed.
*/
public boolean pressed()
{
return pressed(0);
}
/**
* Check to see if the screen was just pressed.
*
* @param Pointer The pointer id.
*
* @return Whether the screen was just pressed.
*/
public boolean justPressed(int Pointer)
{
if(Pointer >= _pointers.size)
return false;
return _pointers.get(Pointer).current == 2;
}
/**
* Check to see if the screen was just pressed.
*
* @return Whether the screen was just pressed.
*/
public boolean justPressed()
{
return justPressed(0);
}
/**
* Check to see if the screen was just released.
*
* @param Pointer The pointer id.
*
* @return Whether the screen was just released.
*/
public boolean justReleased(int Pointer)
{
if(Pointer >= _pointers.size)
return false;
return _pointers.get(Pointer).current == -1;
}
/**
* Check to see if the screen was just released.
*
* @return Whether the screen was just released.
*/
public boolean justReleased()
{
return justReleased(0);
}
/**
* Event handler so FlxGame can update the pointer.
*
* @param FlashEvent A <code>TouchEvent</code> object.
*/
public void handleMouseDown(TouchEvent FlashEvent)
{
if(FlashEvent.touchPointID >= _pointers.size)
_pointers.add(new Pointer());
Pointer o = _pointers.get(FlashEvent.touchPointID);
if(o.current > 0)
o.current = 1;
else
o.current = 2;
activePointers++;
}
/**
* Event handler so FlxGame can update the pointer.
*
* @param FlashEvent A <code>TouchEvent</code> object.
*/
public void handleMouseUp(TouchEvent FlashEvent)
{
if(FlashEvent.touchPointID >= _pointers.size)
_pointers.add(new Pointer());
Pointer o = _pointers.get(FlashEvent.touchPointID);
if(o.current > 0)
o.current = -1;
else
o.current = 0;
activePointers--;
}
/**
* Event handler so FlxGame can update the mouse.
*
* @param FlashEvent A <code>MouseEvent</code> object.
*/
public void handleMouseWheel(MouseEvent FlashEvent)
{
wheel = FlashEvent.delta;
}
/**
* If the mouse changed state or is pressed, return that info now
*
* @return An array of key state data. Null if there is no data.
*/
// TODO: This should record all pointers, not just the first one.
public MouseRecord record()
{
Pointer o = _pointers.get(0);
if((o.lastX == o.screenPosition.x) && (o.lastY == o.screenPosition.y) && (o.current == 0) && (_lastWheel == wheel))
return null;
o.lastX = (int) o.screenPosition.x;
o.lastY = (int) o.screenPosition.y;
_lastWheel = wheel;
return new MouseRecord(o.lastX,o.lastY,o.current,_lastWheel);
}
/**
* Part of the keystroke recording system.
* Takes data about key presses and sets it into array.
*
* @param Record Array of data about key states.
*/
// TODO: This should play all pointers, not just the first one.
public void playback(MouseRecord Record)
{
Pointer o = _pointers.get(0);
o.current = Record.button;
wheel = Record.wheel;
o.screenPosition.x = Record.x;
o.screenPosition.y = Record.y;
updateCursor();
}
/**
* A helper class to store the state of the pointers in game.
*/
public static class Pointer
{
/**
* The current pressed state of the pointer.
*/
public int current;
/**
* The last pressed state of the pointer.
*/
public int last;
/**
* The current position of the pointer in screen space.
*/
public FlxPoint screenPosition;
/**
* The last X position of the pointer in screen space.
*/
public int lastX;
/**
* The last Y position of the pointer in screen space.
*/
public int lastY;
public Pointer()
{
current = 0;
last = 0;
screenPosition = new FlxPoint();
lastX = 0;
lastY = 0;
}
}
}