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
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?
I made a game where you can walk on a 2d grid world (Pokémon style) and currently you just hop from tile to tile instead of a nice walking animation in between.
I'm right now working on that walking animation, and it all works, except that the browser doesn't reflow/repaints fast enough.
If I closely zoom in on the sprite I can see the sprite moving and doing only half of the replaces he needs to do. This creates a lag feeling, which I obviously not want. So I googled today and learned about reflow and repaints and that the browsers stacks the animations until a certain time and then executes them in batches.
I want to avoid the stacking of animations so I searched on Google, and found a lot of hacks, which are not working for me, unfortunately...
I used hacks like requesting the offsetTop, hiding and showing the element, and some others which are easily to be found online. None of them worked.
I then learned here: http://dev.opera.com/articles/view/efficient-javascript/?page=3#reflow that the browser may reflow in the background, without making it visible. (probably why the hacks weren't working)
Do you have any way so I can make the browser visibly reflow?
New to using Adobe Edge, though very familiar with Flash/AS. I need to do animation sequence that is not flash-based, so trying out Adobe Edge. The animation itself is all done, everything works correctly. However, when the JS is loaded on the site and viewed (at least in Chrome/FF) when an object is easing out it creates black bars behind it - looks like it's skidding to a halt.
These disappear when anything is moved - background, any div, anything layered on top, etc. Can handle with setInterval flashing a transparent div on top of it, but seems a bit of a ridiculous way to solve. Has anybody else run into this? Is there a setting I'm missing?
Figured this out after ton of testing, etc. Basically the way Adobe Edge works - at least at this point - is that if you put the animation on top of something else, the background color will "leak" through the animation and show up as skid mark looking lines. After playing with every setting in their UI, nothing would handle. Final work around was to put a background image behind the animation that matched, so when it showed through it wasn't detectable.
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
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.