I have two questions about Crafty (I've also asked in their google group community, but it seems very few people look at that).
I've followed this tutorial http://buildnewgames.com/introduction-to-crafty/ and also took a look at the "isometric" demo in crafty's website of a bunch of blocks (http://craftyjs.com/demos/isometric/). And I've been trying some stuff by combining what I've learned in both.
(Q1) When I use the fourway component (used in the tutorial a lot), if I hold the left arrow key for example and CTRL-TAB out the current tab while holding left, and then go back (not necessarily holding left anymore), then the my character seems to get stuck in moving to the "left" direction. It also happens for the other 3 directions. Is that a known issue? Is there anyway to fix it without changing crafty?
It happens here with firefox 29 and chrome 34. My code is pretty much the one in the final version presented at the tutorial's end (it's not the same, but even when it was the same I already had this issue).
By the way, when this happens, if I CTRL-TAB out and back again holding that left key, things go back to normal (the movement stops).
(Q2) The isometric-ish features interprets Z as being height, and the gravity component uses Y for height. Isn't this a problem? Can I, maybe, for example, tell gravity to use something else, other than y, for height?
Regarding (Q1), the movement is managed by keydown and keyup events. If you change the tab when the start of a movement was triggered, the fourway component never gets any keyup event to stop again. You could use a workaround like the following:
Crafty.settings.modify("autoPause", true);
Enabling autoPause (somewhere in your init function) will pause your game when the browser tab crafty is running in is inactive. You can then react to this event by triggering keyup events or preventing the player component to move like this:
player.bind('Pause', function() {
this.disableControl();
});
player.bind('Unpause', function() {
this.enableControl();
});
You might want to stop animation there too if you handle that in your player component..
Related
I'm handling touch events on a <canvas> area (using jQuery). I'd like to only handle single touch events, leaving multiple touch events uncancelled (e.g. so you can pinch-and-zoom).
The problem is that no matter how simultaneous the touches are, I get a touchstart with one point, followed by a touchmove with one point, and finally a touchstart with 2 points.
If I cancel the first touchdown event with preventDefault(), there's no zooming, even if I don't cancel after the touchmove nor the second touchdown.
If I don't preventDefault() on that first event, then touchmove events will scroll the page up and down in addition to my handling of the touch movement.
(testing on Android 8.1.0 - Samsung Galaxy Tab A)
I've looked around at various postings and web searches, e.g.:
jquery preventdefault on first touch only
or How to prevent default handling of touch events? or Javascript support for touch without blocking browsers pinch support
... and while not specific to this situation, I get the feeling that I'm out of luck. Seems a shortcoming of touch event handling, however, insofar as it makes multiple touches impossible to detect on the first event.
------------ EDIT -----------
Thanks for the suggestions folks! I do hope someone finds the answer useful, but unfortunately it doesn't fit my purposes, and I thought I should explain why (superfluous, perhaps, but may provide someone more insight).
To give some background, this is for a reusable module that provides an API for elements, including drawing 'sprites' and handling mouse/touch events like 'down', 'up', 'drag', etc. As such, I need to consider pros and cons carefully in the context of reusability and clarity.
The solutions mentioned here, and all others that I've found or indeed can conceive of, require a delay. There are two problems with this:
The minor problem is that any delay-based implementation of "multiple touch" is subjective. Multiple-touching is not timed out — you can theoretically touch with one finger, take a leisurely sip of your coffee (presumably with your other hand), then touch with another finger, and still be able to (e.g.) zoom. If this were the only problem, I could probably live with a pre-determined time-out, but it would be based on my perception of users' habits. (I could forsee, for instance, someone touching a 'sprite' over a dense background like a geographical map, realizing there's some detail they want to focus on, and then trying to zoom in.)
If I did delay on down, say by choosing a 300ms delay, it becomes a bit of a rabbit hole. A lot can happen in about a third of a second; likely, they could start a 'sprite' drag. There are then two choices:
If I wait to make sure it's a single touch, I miss (or cache) at least one 'move' event, and all dragging would then show a slight hesitation at the start. A third of a second is well within the bounds of perceptibility, so this is unacceptable.
Or, I could detect slight movement and assume that it's the start of a motion gesture like dragging. I'd then have to raise the API's 'down' and 'move' events simultaneously, a distasteful twiddle but again tolerable. More ambiguous is the threshold for determining it's actual motion. A very steady touch can easily get 4-6 pixels of movement on a touch screen, and I've seen well over 12 pixels for shaky touches. The gap could well be large enough to show an unseemly jitter.
As you can imagine, this is already a very processor-intensive module, especially problematic on mobile devices. Considering the increased code complexity and size (and further divergence of mouse vs touch event code paths), the possible need to introduce several tweakable settings that may be rather opaque to the user, and the fact that any solution is a compromise (point 1), I've decided that the least bad choice is to live with this limitation. The highest priorities here are smooth graphics handling and lean code (both size and processor intensiveness).
So at this point I'm willing to forego multiple touch gestures on the element. Zooming outside the element works fine, and is not unexpected behaviour — witness Google Maps.
For simpler applications, it should often be acceptable to delay detection of 'touchdown' to check for further touches.
Add a timer for your second tap in the middle of your first tap function.
For example:
$(myzone).touchstart(function(e){
e.preventDefault();
$(myzone).bind('touchstart',myeventTouch)
action = setTimeout(function(e){
$(myzone).unbind('touchstart',myeventTouch)
clearTimeout(action);
}, 500);
})
function myeventTouch(){
//When double tap do..
}
If you don't want to do this, you can also add a jQuery plugin in your page, for example I searched for one and found jquery.doubletap.js https://gist.github.com/attenzione/7098476
Use this:
$(SELECTOR).on('doubletap',function(event){
alert('doubletap');
});
I'm working on a ReactJS app in which I'm using EaselJS to handle multiple canvases, on same page I have to add and remove different canvases on the base of different conditions to render different views. Even after removing a canvas using following code to dispose a canvas component
createjs.Touch.disable(this.stage);
this.stage.removeAllChildren();
this.stage.removeAllEventListeners();
this.stage.enableDOMEvents(false);
some events are being triggered. After using application for some time it start to use a lot of processing and memory. After having a look at performance tab in developer tools in chrome, I came to know a timer event is being called for every canvas which ever was added. After inspecting code I come to know that
this.stage.enableMouseOver();
is setting an setInterval timer which is not being removed even after calling all above code and I can't find any way to remove it.
Can anyone please help me to get rid of it.
Thanks in advance
The enableMouseOver method is documented to both add and remove the functionality from a Stage. By passing 0 as the frequency, the interval should be cleared.
stage.enableMouseOver(0);
From the documentation:
Enables or disables (by passing a frequency of 0)
and
frequency: Optional param specifying the maximum number of times per second to broadcast mouse over/out events. Set to 0 to disable mouse over events completely.
I did a quick pass on the code, and it definitely removes the interval.
Question:
I've been working on a first-person maze game with Threejs. I have recently included DeviceOrientationControls to start moving it towards VR, but my previous system for moving the camera is separated from the camera. The camera no longer moves with the arrow keys.
How can I move my camera using arrow keys again while the camera is updated with DeviceOrientationControls?
If possible, how can I automate forward movement relative to the camera's perspective?
Update:
Alex Fallenstedt found a perfect example of what I wanted.
However, I have some questions;
How does the script make the camera move?
How can I simplify this and/or implement this into my work?
Resources:
How to control camera both with keyboard and mouse - three.js
Detecting arrow key presses in JavaScript
How to move camera along a simple path
How to control camera movement with up,down,left,right keys on the keyboard
Comparison:
Here's how it behaved prior (with working controls)
http://orenda.ga/stackoverflow/Nonvr.mp4
Here's how it behaves now (with Orientation)
http://orenda.ga/stackoverflow/VR.mp4
Note:
I've not included my script since I think that it isn't needed for this question. If you need it, please ask and I will insert it here.
To answer you two questions:
1) How does the script make the camera move?
Lets break the script up to its fundamentals. The script begins by adding a bit of state to determine if the user is moving forward.. This state changes when the user interacts with W,A,S,D. We add event listeners that will change this state when a user presses a key or lifts up from a key.. Now, every single frame that is rendered, we can add velocity in specific directions depending on the state of what keys are pressed. This happens here. We now have a concept of velocity. You should console log the velocity values in animate() and checkout how it changes as you move around.
So how does this velocity variable actually move the camera? Well, this script is also using an additional script called PointerLockControls. You can see the full script for PointerLockControls here. Notice how PointerLockControls' only argument is a camera. In order to move the camera, we need to use some nifty functions in PointerLockControls like getObject.. This returns the THREE.js object that you passed into PointerLockControls (aka the camera).
Once we can obtain the camera, we can then move the camera by translating its x, y, and z values by the velocity we created earlier in our animate function.. You can read more about translating objects with these methods in in the Object3D documentation.
2) How can I simplify this and/or implement this into my work?
This is probably the easiest way to implement first person controls to a camera. Everything else in the script example I shared with your earlier is for checks. Like if the user is in a threeJS object, allow them to jump. Or adding a concept of mass and gravity to always pull the user down after they jump. One thing that you might find very useful is to check if the pointer is in the browser's window!. Take the example, break it down to its simplest components, and build from there.
Here is a codepen example that shows you how to move the camera forward smoothly, without pointerlockcontrols, Start at line 53 https://codepen.io/Fallenstedt/pen/QvKBQo
looking at the (quite outdated) documentation on the apple website and across the internet for the touch and gesture javascript events, I can't help but notice that the gesture event which is returned during the function being called, only contains the values 'scale' and 'rotation'. Have I missed something or are they the only two values returned?
It's hard to see the values of a returned object on the iPhone as they are annoyingly only shown as their type and name. e.g when logging the returned object in the console, it just shows up as '[object TouchEvent]'.
What I am trying to achieve is to run a function once a two finger swipe occurs, then whether the swipe was left or right, change the page accordingly.
I have tried a more complex touchevent and the (what I thought would be easier) gestureevent, but the gestureevent only returns the scale and rotation (apparently), and the touchevent seems quite complex in the way I am doing it.
Does anyone know if the object returned is just the scale and rotation, and if so, do you know how I can get the same effect with the touchevent instead?
You should use touchevent that provides you trajectory [of movements] to detect is this trajectory falls into "swipe" category using your own definition of swipe.
Usually "swipe" gesture is context specific: e.g. it should start in particular DOM element and probably end there. It means that for particular DOM element some gesture is not a "swipe" but for its container for example it is a swipe. So you cannot generate bubbling event for that in general.
Zoom and rotation gestures can be detected without knowing context - so system generates them for you.
There are ready to use frameworks and libraries that have swipe gesture detectors. At least for some popular containers like items in vertical list and so on.
I'm in the process of designing a small RPG-like interface where the user will be given the freedom to create the items and weapons they use. Rest assured, that particular system is thought deeply through and is not the cause of my concern. : )
No, it is something related to the mechanism I have set up for the actual drawing of the user's items. I could try to put the design in words, but it would probably be most beneficial if I just took you there, so click here before continuing.
Not bad, eh? It works practically without flaw in everything but IE (haven't coded for it in years), except for one minor issue; it is, in fact, so minor, that I'm quite certain almost all players would use the interface without ever paying it any attention. I, however, am something of a nitpicker with my own designs, and toiling over this one for hours has, alas, led me here.
So, Stack Overflow JavaScript gurus, a bit of help regarding this issue:
At the moment, there are two ways by which you can inject color into the canvas; you can just click squares individually, or you can drag the mouse and fill in tiles as you go along. Well, give that second option a go. Now, did you notice that, while the dragging most definitely occured, your drag didn't actually initiate until you'd moved out of the square you began in.
Sure, no big deal, just go back and single-click the spot that got missed. And that is definitely something that I wouldn't mind settling with; at this point, though, it's just a matter of understanding why it is the code isn't working exactly as it should. Any help would be greatly appreciated.
Also, a run-down of the algorithm if you aren't able to decipher my code:
global variable md (mouse down) set to 0 at start
document.onmousedown sets md to 1; conversely, onmouseup puts it back at 0
user's currently selected color is stored as an index in cur_color
palette of user's colors stored in palette array
palette[cur_color] references the user's currently selected color
upon moving over a tile, if the mouse is being held down, toggle() function initiates
toggle() compares the backgroundColor of the tile in question with the user's cur_color
if they are different, cur_color overwrites, effectively "painting" that portion of the canvas
this continues until the user has let go of their mouse button
Overall a pretty basic method, but that whole mouse-being-pressed-not-registering-until-one-square-late thing is killing me. Again, assistance with getting to the bottom of this matter would most definitely be appreciated.
It's because you don't call tile_over when mousing down initially. Reading through the steps above you can see that.
Here's a fix, add this to the onmousedown function:
var target = e.target || e.srcElement;
if (target.tagName == 'DIV' && target.className == 'tile') {
tile_over(target);
}
Obviously having a framework to handle getting the targets of mouse events and so forth would make this easier.
You'll need to remove the toggle that occurs when you mouseup without having triggered a mouseover, I didn't bother tracking that down as it should be obvious.