HTML5 + JavaScript - Mouse Positioning - html

I'm fairly new to HTML5, but I'm learning, and for now - I'm working on a really simple game.
What I'm trying to do is get the mouse X and Y position related to the canvas, and have an image to follow the mouse (like a crosshair, to aim).
But for now, I just want to pull the mouse values.
So, I have a function called init, which initialises everything. It's called when an image sprite is loaded:
function init(){
drawBg();
startDrawing();
document.addEventListener('keydown', checkKeyDown, false);
document.addEventListener('keyup', checkKeyUp, false);
document.addEventListener('ommousemove', mouseTarget, false);
}
I'm not 100% if the 'ommousemove' is correct, not sure what I'm suppose to put their. I then have the mouseTarget function:
function mouseTarget(e){
var mouseX;
var mouseY;
if(e.offsetX){
mouseX = e.offsetX;
mouseY = e.offsetY;
}
else if(e.layerX){
mouseX = e.layerX;
mouseY = e.layerY;
}
console.debug("Mouse X: " + mouseX + " Mouse Y: " + mouseY);
}
I also have a function called 'draw', which is called every 5 frames (every update), so I'm assuming I need to check the mouse position within that?
function draw(){
mouseTarget();
}
But then I get an error: Uncaught: TypeError: Cannot read property 'offsetX' of undefined.
What am I doing wrong here?
Thanks

The problem (as you suspected) is with this line
document.addEventListener('ommousemove', mouseTarget, false);
It should be
document.addEventListener('mousemove', mouseTarget, false);
The e parameter in the mouseTarget function will only contain the event information when called via an event. In your case it is never being called via an event, but only via the draw function.
That is why you are getting the Cannot read property 'offsetX' of undefined. error, as in reality you are trying to access undefined.offsetX
What you should do is keep a the mouse position in separate variables and then just reference them in the 'draw' function.

Related

Object Undefined but it seems to be Defined actionscript

First I am still new to coding so take it easy on me. Bit of back tracking before I show the code. I got a book on how to make games with ActionScript 3, only thing is it mainly works under the assumption your working with Photoshop & Flash Builder together rather than adobe animate/flash. So it has you do things like embed images, and I'm not sure how to change the code to define the images, which is exactly the problem. However at the same time, the stage is coming up as undefined access! I really, I mean how can the stage be undefined... Well any way, Heres an example of one of the Undefined Properties:
///
class BetterScrolling extends Sprite
var ForegroundImage: Class;
var foregroundImage: DisplayObject = ForegroundImage();
var foreground = ForegroundImage;
///
Theres some code in-between.
///
function BetterScrolling(){
foreground.x = -((foreground.width - stage.width) / 2);
foreground.y = -((foreground.height - stage.height) / 2);
}
///
The point of this code is to create a scrolling Background. However I'm kinda complicating it because I have an X and an Y variable, yet I also have a slowed background in addition to my foreground. I will now link to the complete code as is currently, http://pastebin.com/WHg9DGsB Every change in that code I made with a reason in mind, even if it is a stupid one... so please don't be distracted by the other errors that I'm sure are in there... for now just the defining of my images.
There a number of issues that will keep your code from compiling.
Stage is not available when your class loads. Any code that is not inside a function will run when the application is initialized (before anything is even seen on the screen). Your error is because of these lines:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
Those lines are floating in your class declaration when stage does not yet exist.
What you want to do is move that code (and any code that isn't a variable or function definition) into a function. If you want it to run immediately, put it in your constructor (the function named the same as your class). The stage however is also not always available yet in your constructor, so to be safe, you should do the following:
function BetterScrolling() {
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, stageReady);
}else{
stageReady();
}
}
function stageReady(e:Event = null):void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//any other code that needs the stage and should run as soon as possible
}
You have a bunch of brackets and code that don't seem to belong anywhere. Lines 45 - 71 will not compile properly. Most likely, you want that code in your constructor/stage ready method as well, so adding that in, you would have something like this:
function BetterScrolling() {
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, stageReady);
}else{
stageReady();
}
}
function stageReady(e:Event = null):void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
foreground.x = -((foreground.width - stage.width) / 2);
foreground.y = -((foreground.height - stage.height) / 2);
background.x = -((background.width - stage.width) / 2);
background.y = -((background.height - stage.height) / 2);
cloud.x = -((cloud.width - stage.width) / 2);
cloud.y = -((cloud.height - stage.height) / 2);
character.x = 370
character.y = 320
rightInnerBoundary = (stage.stageWidth / 2) + (stage.stageWidth / 4)
leftInnerBoundary = (stage.stageWidth / 2) + (stage.stageWidth / 4)
topInnerBoundary = (stage.stageHeight / 2) + (stage.stageHeight / 4)
bottomInnerBoundary = (stage.stageHeight / 2) + (stage.stageHeight / 4)
}
You have vars that are blank classes, then you try to instantiate them
var BackgroundImage: Class;
var backgroundImage: DisplayObject = BackgroundImage();
This will cause a runtime error because BackgroundImage is null/undefined. Most likely, you want to export a library object in FlashPro as a class? To do that, right/alt click the object in question in the library, and go to it's properties. Check off 'export for actionscript' and give it a class name. In this case, call it BackgroundImage. Then you replace the above code with:
var backgroundImage:BackgroundImage = new BackgroundImage();
As an aside, it safer to only declare you class vars that reference other objects/classes and instantiate them in the constructor. To change it like that, change the above line to this:
var backgroundImage:BackgroundImage;
Then in your constructor, do:
backgroundImage = new BackgroundImage();
First, DisplayObject.stage property is defined only when the DisplayObject in question is attached to display list. As a general policy, never try to access stage in the constructors. You need to subscribe a certain event that will tell you when stage is really available.
public function IWannaStage()
{
// WRONG
x = stage.stageWidth >> 1;
y = stage.stageHeight >> 1;
// RIGHT
if (stage) onStage();
else addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
// Stage is really available from this point on.
x = stage.stageWidth >> 1;
y = stage.stageHeight >> 1;
}
Second, I think you're trying to create instances incorrectly. If ForegroundImage is a class, then:
A = ForegroundImage; // Wrong, you assign the reference to the class.
B = ForegroundImage(); // Wrong, this actually is type casting.
C = new ForegroundImage(); // Correct way to create a new instance of a class.
D = new ForegroundImage; // If constructor does not need any arguments you can omit brackets.

Video scrubber not stopping after scrubbing

I've created a custom scrub bar which means the scrub handle is being drug along a specific axis. I can drag the handle just fine, but when I start dragging and move the mouse off the handle and release, the handle does not stop. I have to be over the actual handle when I stop dragging in order for it to stop.
That wouldn't be an issue, but the handle is pretty small so it would be nice if I could figure out a way to stop dragging the handle when the mouse is on or off.
A good example is Youtube. You can start dragging the handle and while moving the handle move your mouse off and release. The handle stops even though you're not releasing directly over it.
bottom_bar.scrubber.handle.addEventListener(MouseEvent.MOUSE_DOWN, scrubberDown);
bottom_bar.scrubber.handle.addEventListener(MouseEvent.MOUSE_UP, scrubberUp);
function scrubberDown(e:Event):void
{
flvPlayback.pause();
var object = e.target;
var bounds:Rectangle = new Rectangle();
bounds.x = e.currentTarget.width - bottom_bar.scrubber.handle.width;
bounds.y = e.currentTarget.y;
bounds.width = bottom_bar.scrubber.width - (bottom_bar.scrubber.handle.width);
bounds.height = bottom_bar.scrubber.height - bottom_bar.scrubber.handle.height;
object.startDrag(false, bounds);
}
function scrubberUp(e:Event):void
{
var _math:Number =((bottom_bar.scrubber.handle.x) / (960) * flvPlayback.totalTime);
var object = e.target;
object.stopDrag();
flvPlayback.seek(_math);
flvPlayback.play();
}
Register MouseEvent.MOUSE_UP in scrubberDown handler, and for the stage, so user can stop dragging in any position.
bottom_bar.scrubber.handle.addEventListener(MouseEvent.MOUSE_DOWN, scrubberDown);
//bottom_bar.scrubber.handle.addEventListener(MouseEvent.MOUSE_UP, scrubberUp);
function scrubberDown(e:Event):void {
stage.addEventListener(MouseEvent.MOUSE_UP, scrubberUp);
//Your current code
}
function scrubberUp(e:Event):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, scrubberUp);
var _math:Number =((bottom_bar.scrubber.handle.x) / (960) * flvPlayback.totalTime);
bottom_bar.scrubber.handle.stopDrag();
flvPlayback.seek(_math);
flvPlayback.play();
}

Simulate Mouse Click in AS3

I am working on an AS3 project and I am struggling with one particularly fragile part which will need a lot of refactoring in the near future. Just unit testing separate classes in isolation does not catch all issues we are running into. For example, we might forget to disable mouse events on a transparent overlay and thereby block all clicks on a button. Therefore, I am trying to write a test that simulates real user input.
I have tried to manually send a MouseEvent to the stage at the correct position:
stage.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, true, 380, 490, stage));
Since the stage has no click event handler, I expected the event to propagate through the hierarchy to the button that will actually handle it (as it does when I physically click the mouse). However, it doesn't.
I know that I could just dispatch the event on the button, but that will not detect if the object is somehow obstructed. Is there some way to simulate mouse events, such that they will properly propagate through the hierarchy?
Edit:
I managed to do it by re-implementing the propagation behavior of Flash:
Edit 2:
My previous solution didn't work if there was a partly transparent overlay with a click handler, like a Sprite with a few Shapes in it. The problem is that the hitTestPoint method returns true even if the object in question is completely transparent at that point. Therefore, I modified it to check the actual pixel value:
private function clickObject(obj:DisplayObject) : void
{
var relPos:Point = new Point(obj.width / 2, obj.height / 2);
var globalPos:Point = obj.localToGlobal(relPos);
simulateClick(obj.stage, globalPos);
}
private function simulateClick(obj:InteractiveObject, globalPos:Point) : Boolean
{
// first, check if we have any children that would rather handle the event
var container:DisplayObjectContainer = obj as DisplayObjectContainer;
if (container != null)
{
if (container.mouseChildren)
{
for (var i:int = 0; i < container.numChildren; ++i)
{
var child:DisplayObject = container.getChildAt(i);
var interactive:InteractiveObject = child as InteractiveObject;
if (interactive != null)
{
if (simulateClick(interactive, globalPos))
{
// if we have found a handler in the children, we are done
return true;
}
}
}
}
}
if (!obj.mouseEnabled) {
return false;
}
if (obj.hitTestPoint(globalPos.x, globalPos.y))
{
var localPos:Point = obj.globalToLocal(globalPos);
// check if object is visible at the clicked location
var pixel:BitmapData = new BitmapData(1, 1);
pixel.draw(obj, new Matrix(1, 0, 0, 1, -localPos.x, -localPos.y));
var color:uint = pixel.getPixel32(0, 0);
if ((pixel.getPixel32(0, 0) & 0xff000000) != 0)
{
// if yes, dispatch the click event
var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, true, localPos.x, localPos.y, obj);
obj.dispatchEvent(e);
return true;
}
}
return false;
}
Unfortunately, there is still at least one case not covered: If the object is a mask for another object. I have no idea how to check for this, since it could be mask anywhere in the display hierarchy. I would have to traverse the whole tree and check every single display object to find this out.
So, my question remains: Isn't there an easier way to do this?
I've had issues with events in AS3 as well. I've found that the best way is to have the eventListeners added to the same object that's dispatching the events. In your case, adding the .addEventListener to the stage and sending the function as a function on a child clip. eg:
stage.addEventListener(MouseEvent.CLICK, object.object.clicked);
I hope this may help. I've used this method with success in the past.
You can use stage.getObjectsUnderPoint(new Point(pointerX , pointerY )); function , that will return You array with objects . Than remove overlay object and last instance in array should be deepest DisplayObject.
note: last instance can be graphic or such thing , so You should loop through parent objects to find nearest InteractiveObject .
Also , dont forget that parent objects can have mouseChildren = false or mouseEnabled = false

Make an object snap to another ojbect, then follow its path with pure ActionScript?

I am still trying to come to grips with how make an object snap to another ojbect, then follow its path with pure ActionScript (snap an arrow oject to a circle, then the circle follows the direct of the arrow when play button in hit).
Can somebody please help me with an small example so I can get my head round it, any help will be much appreciated. I am trying to create an application aimed towards something like this
http://itunes.apple.com/us/app/basketball-coachs-clipboard/id317785081?mt=8
I have got my drawing line working but do now know how to make the object follow the line, here is how I have drawn my line on the stage. Please could you give me a clue of how to do this.
function startPencilTool(e:MouseEvent):void
{
pencilDraw = new Shape();
board.addChild(pencilDraw);
pencilDraw.graphics.moveTo(mouseX, mouseY);
pencilDraw.graphics.lineStyle(shapeSize.width);
board.addEventListener(MouseEvent.MOUSE_MOVE, drawPencilTool);
}
function drawPencilTool(e:MouseEvent):void
{
pencilDraw.graphics.lineTo(mouseX, mouseY); /
}
function stopPencilTool(e:MouseEvent):void
{
board.removeEventListener(MouseEvent.MOUSE_MOVE, drawPencilTool);
}
1st
If you mean by "following its path", that the object follows another object, then simply do
obj2.x = obj1.x;
obj2.y = obj1.y;
to follow the exact coordinates. If you want to make some distance between them, then
obj2.x = obj1.x + dx;
obj2.y = obj1.y + dy;
choose dx and dy according to your wish.
2nd
If you want to make an app, where you can "draw an arrow" or "draw a path" and then an object should follow it, then you can try to store the coordinates of the mouse, while "drawing the arrow", then snap the object you want to these coordinates.
var coordinates:Array = [];
stage.addEventListener("mouseDown", md);
function md(evt:*):void
{
//empty the coordinates
coordinates = [];
//add listener when mouse is released
stage.addEventListener("mouseUp", mu);
//add a listener for enterframe to record the mouse's motion
addEventListener("enterFrame", recordMouse);
}
function mu(evt:*):void
{
stage.removeEventListener("mouseUp", mu);
removeEventListener("enterFrame", recordMouse);
//snap the object to the drawn line and play it
addEventListener("enterFrame", playRecording);
}
function recordMouse(evt:*):void
{
coordinates.push(new Point(stage.mouseX, stage.mouseY));
}
function playRecording(evt:*):void
{
//snap object to the recorded coordinates
myObject.x = coordinates[0].x;
myObject.y = coordinates[0].y;
//delete first element of array
coordinates.splice(0, 1);
//stop playing if there are no more points
if(coordinates.length == 0) removeEventListener("enterFrame", playRecording);
}
Place a movieclip on the stage and name it myObject. Then add the code and compile the swf.
Also, while "recoring" the coordinates, you can also draw some lines.
Change md function to this:
function md(evt:*):void
{
//empty the coordinates
coordinates = [];
//add listener when mouse is released
stage.addEventListener("mouseUp", mu);
//add a listener for enterframe to record the mouse's motion
addEventListener("enterFrame", recordMouse);
//clear graphics, and initialize line
with(graphics) clear(), lineStyle(1, 0xff0000), moveTo(stage.mouseX, stage.mouseY);
}
and recordmouse to this.
function recordMouse(evt:*):void
{
coordinates.push(new Point(stage.mouseX, stage.mouseY));
//draw the line
with(graphics) lineTo(stage.mouseX, stage.mouseY);
}
3rd
If you want to follow a pre-drawn line, then you have several options depending on your task. But everything depends on, how you exactly want to "snap" your object.

how to capture mouseclick in actionscript 3.0

How do I capture the position of a mouseclick from the user in my Flash window using Actionscript 3.0?
Ron DeVera is close, but I wouldn't use an inline function, and the object passed to the function is not Event, but MouseEvent.
stage.addEventListener(MouseEvent.CLICK, _onStageMouseDown);
function _onStageMouseDown(e:MouseEvent):void
{
trace(e);
}
//traces
//[MouseEvent type="click" bubbles=true cancelable=false eventPhase=2 localX=96 localY=96 stageX=96 stageY=96 relatedObject=null ctrlKey=false altKey=false shiftKey=false buttonDown=false delta=0]
All of the properties in the output above are available through the object that gets passed to the Event Listener Method, _onStageMouseDown(e:MouseEvent); Hence the following
function _onStageMouseDown(e:MouseEvent):void
{
trace(e.localX);
trace(e.stageX);
//Note that the above two traces are identical as we are listening to the stage for our MouseEvent.
}
They explained it well, but here's the full code to illustrate it a little more for you:
addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event: MouseEvent) : void
{
// these are the x and y relative to the object
var localMouseX: Number = event.localX;
var localMouseY: Number = event.localY;
// these are the x and y relative to the whole stage
var stageMouseX: Number = event.stageX;
var stageMouseY: Number = event.stageY;
}
Location defined by what context? The whole page? One or more specific clickable controls?
You may query any DisplayObject's mouseX and mouseY whenever you like.