The idea: I'm creating a simple WebGL script (using mrdoob's wonderful three.js) that allows the user to control a camera in a world of objects. The camera is supposed to simulate traditional first person shooter cameras (reference Team Fortress 2, for example). That is, the camera moves only when the mouse moves.
The issue: in Javascript, the only way to detect mouse movement is if the cursor itself moves. By comparison, FPS games don't show the cursor -- they only base the movement of the camera off of how the mouse itself moves. So, you can move your mouse all over the mousepad in any direction and it always works.
On a browser though, since camera movement is based on the cursor, you can't move but so far. When the cursor hits the edge of the screen, the user is unable to look any further in that direction (e.g. you move your mouse to the left edge of the screen, you can't look left any more).
The solution: I've thought of two solutions, but neither of which I know how to implement. Either
After the mouse is moved, the javascript resets it to the center of the screen. That way, after every mouse movement the player is free to again move in any direction. The issue with this is that, based on the research I've done, Javascript is unable to control the position of the user's mouse (understandably, as it would be an incomparable nuisance on malignant sites).
Or, the mouse "wraps" around the screen. Meaning, when the user reaches one edge of the screen, the mouse would simply continue on to the other side of the screen. (see: http://www.digicowsoftware.com/detail?_app=Wraparound) However, it appears that this too is not an inherent capability of javascript, but instead is only something a third party program could solve.
So, does the problem make sense? If so, is there any way I can implement the above solutions, or is there another one I'm missing?
For anybody that still interested in achieving this, it is now somewhat available.
Using:
document.addEventListener('pointerlockchange', changeCallback, false);
see example http://www.html5rocks.com/en/tutorials/pointerlock/intro/
The worldwide community is currently working on a draft spec to solve this issue. What you're stating is called "mouse-locking". I've worked a little on the first phase of this standard to help lay out what's needed. Please, vote for these issues and subscribe to the indicated mail lists in order for all of us to get this issue corrected ASAP.
Chromium Bug: http://code.google.com/p/chromium/issues/detail?id=72754
Firefox Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=633602
W3C Mail list: http://www.w3.org/Bugs/Public/show_bug.cgi?id=9557
Draft proposal: https://docs.google.com/document/d/1uV4uDVIe9-8XdVndW8nNGWBfqn9ieeop-5TRfScOG_o/edit?hl=es&authkey=CM-dw7QG
However, there's still a way you can achieve your objective (which is the other way i found): A native plugin that takes control of the mouse.
(I'm making a game too which is a FPS but currently won't be released due to this limitation)
You're right about all of this. Standards-based web tech isn't going to give you mouse capturing like you want.
That said: you might be able to craft (or find) a special SWF that can collect mouse movement data and pass that to javascript. It won't constrain cursor movement, although you can use CSS to conceal the cursor while mouse capturing is active. But it might be able to e.g. continue firing "move mouse left" events even when the cursor has reached the left edge of the screen.
Any such SWF will probably fail to capture movement when the cursor is outside the viewport i.e. over the browser chrome.
Given that it's apparently not possible to do this as such in HTML5/Javascript, what about this variant: treat the mouse position (not mouse movement) as representing the rate of turning.
So if the mouse is more than a certain threshold left of the center, the camera turns left; the farther left the mouse is, the faster the camera turns. To stop turning, the player moves the mouse back toward the center.
To me this is an annoying UI, at least initially, but maybe the player would get used to it. Since we don't have any perfect solutions, it may be worth trying. You can mitigate the problem by allowing the arrow keys to work the way they do in many FPSes, rotating the camera when they are pressed down.
Related
I have a desktop web app (skyviewcafe.com) that I’m trying to make more mobile-friendly. As one step in that process, I’ve taken a star chart and made it touch-draggable, and also made a view of the orbits of the planets both draggable and zoomable with touch gestures.
But here’s an interesting problem that I imagine must have happened to others before: It’s possible to use the default panning and zooming behavior of a mobile web browser to move my web page around until the only thing in view is a component that itself takes over touch gestures using preventDefault.
Once this happens, it’s impossible to zoom back out and bring the whole web page back into view. All pinch/spread zooming is sucked in by my component. For lack of a better term, I’m calling this a “zoom trap”. I’ve tried to search online for any discussion of this problem, but can’t find the right words to match anything.
I came up with an ad hoc solution that’s currently deployed at http://test.skyviewcafe.com. If I’m in a “zoom trap” I can touch the screen with three fingers and a translucent gray panel comes up to block touch gestures from reaching my touch-responsive canvas. Normal default web browser pan and zoom then becomes possible again, and the user can zoom back out. After that, touching with three fingers again clears the gray panel out of the way.
While this solves the problem in a way, it’s not a standard well-known gesture, and it would be hard to provide enough on-screen prompting to make necessary gesture clear.
Ideally I’d like to be able to respond to a standard gesture like a double-tap by zooming out the web page, but as far as I can tell, other than the initial zoom factor when a web page loads, web browser zooming isn’t something a web app can control dynamically.
Has anyone else run into this problem? Are there standard touch gestures for dealing with this? Are there ways in JavaScript that I haven’t discovered yet to dynamically control mobile web browser zooming?
The task is to draw a curve ob canvas. The problem is that if mouse is moved too fast, the coordinates are skipped and not captured.
(Html5/Js canvas capturing mouse coords when it moves fast - my previous post..)
Is there a cross-browser way to limit mouse speed inside an element (div, canvas, etc.)?
I assume by "limiting mouse speed" you actually mean enable capturing high volume of mouse events so that you get more detailed information, or resolution, of the mouse path.
The browser will normally work at a high-level when it comes to mouse events. The system will capture the mouse events, but the browser will do many other tasks such as pushing events, bubbling them etc. and only capture the current mouse position when it actually can.
To compensate for this you need to use all sort of tricks such as splines.
Possible workaround
I don't intend to make a broad answer for this as it will quickly become out of scope to go through the steps and scenarios you would need for a spline approach (interpolation, knee-breaks which require relative angle tracking, smoothing etc.).
However, there is a new API called Pointer Lock API (see demo and source in that link as well) which allow the browser to work at a lower level closer to the system, so it can spawn mouse events faster and at a higher volume than it could otherwise.
It do have some drawbacks as with all low-level approaches:
You need to render your own cursor
Mouse movements are not limited to the edges so you need to provide wrapping or limits yourselves
It will request user for permission
Not supported in all browsers
And it target games and 3D more than drawing application
But this is the closest you will get to high volume of mouse events without interpolation etc.
I'm trying to explore how feasible it is to create an HTML5 interaction where a touch can be conditionally captured by the initial direction of the motion.
The goal is to capture and track the motion of the touch only if it initially moves in a horizontal direction. Combined with a responsive page layout which only scrolls vertically, we should be able to use horizontal swipe motion to do something cool by tracking it.
The problem is in the seeming impossibility (especially on iOS) of performing touch sequence capture conditionally.
In order to track a touch (and by this I mean specifically obtaining the stream of x,y coordinates which represent the position of the finger over time), touchstart has to be preventDefaulted in order to prevent the page from engaging native momentum-scroll. Native momentum-scroll, while in operation, suspends all JS execution (setTimeout, rAF, jQuery animate et al...) and even CSS keyframe/animation/transition execution.
I would really like to know if there's a way to somehow condition the preventDefault() of the original touchstart event. It's completely possible for JS to store that event object, and then not call it until some later time (when it is determined that we are indeed interested in preventing the native scroll from starting).
But this is certain to fail because the default behavior of not running preventDefault() on that event is to engage native-scroll, which then will block JS execution for the entire remaining duration of the scroll. Failing to return the event listener function attached to touchstart does not appear to be an option. It would freeze everything.
The tentative answer, then, without any additional insight, is that all swipes must be captured if we want to be able to capture it at all, and scrolling has to be "faked" via external means à la (iScroll)[http://cubiq.org/iscroll-5-ready-for-beta-test] (personally I would want to explore some sort kind of combination of rAF and window.scrollTo and would be surprised if iScroll 5 does not employ these APIs)
Incidentally the description for the 4th demo there got me really excited, but it turns out that all it does is create a page section that iScrolls horizontally while the rest of the page behaves regularly, which is entirely mundane.
One major barrier to creating immersive experiences in the browser (using WebGL and similar) is the set of limitations placed on mouse control.
For instance a first person shooter control scheme essentially requires the program to grab the mouse and re-center it so as to allow infinite movement in any direction for the cursor. This is a no-no because it would give the web programmer too much control. Hopefully one day we will see a plugin that allows a site to request permission to move the mouse to allow this behavior.
However I think there are some ways to improve things without going that far. I am wondering if it's possible to allow access to the mouse position once the mouse moves off of the window (focus is still on window)?
I was playing this game using Google Chrome: http://www.chromeexperiments.com/detail/x-wing/?f=
and my biggest issue was that to get to a corner, I have to carefully keep my mouse on the corner of the browser window. If I push it off the window my ship would stay where the mouse's last window position was, which is not exactly in the corner. And I would crash into the wall.
To make this better, the browser should be able to receive mouse updates when the mouse is outside of the window. In the context of this type of game if the mouse leaves the window it should continue to send updated positions to the browser.
Is there any provision for this?
To answer your question, no, you can't get mouse events from outside the window (including its position).
There is the Mouse Lock API, which is designed specifically for the case you describe. It locks the cursor to the current window. Support is virtually non-existent right now, but one day..!
A hint :
function thumb_mouse_down(e) {
e.target.setCapture();
return false;
}
function doc_mouse_up(e) {
e.target.releaseCapture();
}
setCapture() does the trick. A working example is here.
That really seems like a far bigger security issue than allowing the developer to reposition the cursor. The answer is no, there's no such thing. And there probably won't ever be one. Sorry!
Update: I was, of course, talking about the capturing outside the window that would be a problem. It's very likely that there will ever be an API that locks the mouse, maybe after asking the user's permission. As nickf pointed out, they're already working on it -https://www.w3.org/TR/pointerlock/
Original defunct link - http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html
Im using JavaScript, the HTML5 canvas-element and WebGL to make a simple 3D-game in first person view for fun.
Ideally, I would like to control my movement by using the keyboard to move and the mouse to look around, like you usually do in FPS-games. As you probably understand, there are some limits to this in the browser, since the mouse cant be captured:
When using the onmousemove event, no further movement will be detected when the mouse pointer reaches the border of my screen (which means that I wont be able to run in a circle for example)
Seeing the mouse move across the screen is not the end of the world, but it is a little annoying
From what I know, it's impossible to hide the mouse as well as setting it's position in JavaScript. Hence, my question is this:
If we cant to those things, what can we do in order to get close to the desktop gaming experience when it comes to the mouse in the browser?
And I mean right now, using current APIs. Not "what could be changed in some standard to make life easier". Also, I realize that I could use the keyboard to look around, but then we're back in 1995 when Quake were actually played like that. And of course I know that it would be easier to write a desktop application or use Flash at least, but Im trying to push JavaScript's limits here.
Apart from those things, what are your suggestions? Any kind of reference, existing game, crazy idea, hack or even browser specific solution would be appreciated.
I have done some experiments with mousehiding for a game, as far as I recall it was only Opera that I didn't make behave, so I gave it the cross instead. One crucial point is that some browsers will display a completely invisible cursor image as a black box, but with just one almost invisible pixel it'll work. Feel free to take the mousehiding part and the cursor file. http://ebusiness.hopto.org/iimdtdt/
I have thought a bit about the look around part myself, for the up/down movement it is easy, since you will cap this anyway, and all you have to do is to make sure that the cap is in sync with the mouse movement cap. For the sideways part, I suggest that you try messing with the sensitivity, when the mouse nears the edge of the screen sensitivity should go up it the direction towards the screen edge, and down in the direction away from the screen edge. I haven't tried out this method, so I can't tell how well it will actually work, but it should help keep the mouse in the middle area even if the user spins around more one way than the other.
Good luck with the project, sounds exciting.
Your hopes and dreams are now possible with the new Pointer Lock API