everytime I resume some scene, the main character keeps walking along, because I think it's remember the movement from before the scene was paused. I set the velocity.x and velocity.y to 0 before pause the scene. But doesn't works. Any idea? Thanks!
Here is my code:
function workPopUp (){
this.scene.pause();
this.scene.launch('popup');
this.work.destroy();
}
This is the normal behaivor of velocity:
if (this.cursorKeys.left.isDown)
{
this.kid.setVelocityX(-200);
this.kid.anims.play('left', true);
}
else if (this.cursorKeys.right.isDown)
{
this.kid.setVelocityX(200);
this.kid.anims.play('run', true);
}
else
{
this.kid.setVelocityX(0);
this.kid.anims.play('idle', true);
};
if (this.cursorKeys.up.isDown && this.kid.body.touching.down)
{
this.kid.setVelocityY(-480);
this.kid.anims.play('jump', true);
}
if(this.cursorKeys.up.isDown && this.cursorKeys.right.isDown){
this.kid.anims.play('jump', true);
}else if(this.cursorKeys.up.isDown && this.cursorKeys.left.isDown){
this.kid.anims.play('jump', true);
}
UPDATE
I still don't know why it was happening, so I'd love if someone else could find a better way, but I did find a way to stop it.
In the tutorial I reference below, they had you add a wake function to reset the cursor keys by putting this line into your create:
this.sys.events.on('wake', this.wake, this);
And then this function:
wake: function() {
this.cursors.left.reset();
this.cursors.right.reset();
this.cursors.up.reset();
this.cursors.down.reset();
},
As I said, that didn't work for me. So instead, I set a boolean in my wake function:
wake: function() {
this.sleeping = true;
},
and then in my Update function, I check for the bool and reset the keys there:
update: function (time, delta)
{
if (this.sleeping)
{
this.sleeping = false;
this.cursors.left.reset();
this.cursors.right.reset();
this.cursors.up.reset();
this.cursors.down.reset();
}
Like I said, this works when putting the reset in my wake function didn't. Somewhere between my wake function running and the first update, the cursor was being updated to down, but I can't figure out where.
Hope this helps.
Original Post
I'm having the same problem and I think it's some change in the a recent version of Phaser 3.
I followed this tutorial:
https://gamedevacademy.org/how-to-create-a-turn-based-rpg-in-phaser-3-part-3/
The tutorial mentions having this problem where the sprite is moving after the scene resumes and adding an on wake function to reset the cursor keys. That wasn't working for me.
I downloaded the source code from the tutorial and found it didn't have this issue, but I noticed that the source code comes with a phaser.min.js whereas I was referencing the latest version online in my html file. When I updated the tutorial source code to use the latest version, the issue occurred.
Hope this context helps, I'll continue to troubleshoot and update if I find the issue.
I had similar problem with in my game when pausing and resuming the scene, so if I was pressing a key and paused the game, after resuming the player would continue the movement event if I was not pressing the key anymore.
So this is what I did
in my playScene add an event on pause
this.sys.events.on("pause, () => { this.player.sleep() })
in my player class created a function to reset all the key values that is called whenever the scene is paused
sleep() {
this.keys.left.reset();
this.keys.right.reset();
this.keys.up.reset();
this.keys.down.reset();
this.keys.jump.reset();
this.keys.fire.reset();
}
Probably there is a better way of handling this, but for what I want at the moment it works
Related
I am trying to build a tic tac toe game but it is not working, what I mean by that is when I click the gameboard, I want the game to start and have my functions accordingly. Now the problem is I want this game to be human vs machine and the machine part(function AI()) is not working properly.
Here's the link codepen
I have all my functions in the "game" function(game ()) which should run when a user clicks on the game-board which is at the end of the js file.
Just try to play the game and you'll understand what I am talking about--weird behaviour and I am scratching my eyes out and still I'm stuck.
I would really appreciate it if anyone could help me. Thanks.
function game(){
symbDisp();
winCheck();
turns += 1;
if (gameEnd == false && turns % 2 == 0) {
AI();
winCheck();
turns += 1;
}
}
AI() function works (more or less). It's actually only the AI that's playing the game. Player moves don't work because you don't tell the symbDisp() function which square was clicked ('this' refers to the document, not the squares)
You could change the eventhandler to form
$('.square').on('click', function() {
game($(this));
});
Inside this anonymous function this refers to the square, as that's the element the event handler was bound to.
Now you also need to pass this square element around a bit by changing your game() and symbDisp() functions to take the element as their arguments and and using that inside symbDisp().
for example:
function game(elem){
symbDisp(elem);
//more stuff
function symbDisp(elem) {
if(elem.text()==='') {
//more stuff
There's also other bugs in your game but I'll leave those for you to tackle.
First symbDisp is receiving window as this instead of the correct td.
change line 10 to
$('.square').on('click', function() { game(this) } );
because of the change you have to pass this to the subfunctions. So make the following changes:
124: function game(ths){
125:
126: symbDisp(ths);
and then change symbDisp to:
function symbDisp (ths) {
if($(ths).text()==='') {
$(ths).text(pTurn);
if(pTurn == player){
pTurn =comp;
}else{
pTurn=player;
}
}
}
There is another error: pTurn is undefined when it first reaches symbDisp function. So change userIcon to:
function userIcon() {
if($(this).attr("id")=="x"){
player = pTurn ="X";
comp ="O";
} else if($(this).attr("id")=="o"){
player = pTurn ="O";
comp ="X";
}
$('#user').fadeOut(1000);
}
see that I setted pTurn when player is setted.
That's it. It should work now. I forked a working version here:
http://codepen.io/anon/pen/oxPyej
Hope it helps
I'm getting into game developing online. I am trying to make an online FPS game, and I've only gotten to the point where I need to update my character. I am trying to keep my code simple, using only a draw and update function. When the html loads, I execute both: (Is this necessary?)
<body onload='DRAW(); UPDATE();'>
The draw function draws the player to the screen, and the update is supposed to check for a keypress to move the character. I am trying to make the script update using this:
function UPDATE()
{
update = setInterval(UPDATE, 60);
}
and to my knowledge, it is working fine because when I try and edit code in my online IDE (c9.io) which I use to test the site, it freezes when the site is running. I am also calling eventListeners in the draw function. (Is this proper if I want to test for a key down every frame?)
function DRAW()
{
window.addEventListener('keydown', function (e) {
keys.keys = (keys.keys || []);
keys.keys[e.keyCode] = true;
});
window.addEventListener('keyup', function (e){
keys.keys[e.keyCode] = false;
});
}
My questions are:
Is there an easier way to make a script update every frame?
Is there a JavaScript addon (like Three.js) I can use to make
developing this easier on myself?
Any knowledge is greatly appreciated.
This makes everything crash:
function UPDATE()
{
update = setInterval(UPDATE, 60);
}
You are recursively creating a new interval every 60ms; the first time you call UPDATE, you create an interval that creates a new interval every 60ms. All newly create intervals do the same. Don't really know what you actually want to do here.
I am also calling eventListeners in the draw function. (Is this proper
if I want to test for a key down every frame?)
It's fine to create eventlisteners in the draw function, provided you only call this function once. Which I guess you don't. Each time you call DRAW() a new set of eventlisteners will be added, and you really don't want that.
What you need is a form of game loop. Explaining how to create an FPS game is a bit more than I can do, but you can start by looking at this article Anatomy of a video game
Currently working on a page containing a video that has to be paused at certain points (like chapters). So I made a function that will stop the video when it hits the next "time marker" which looks like this:
function vidPause(nextMarker){
var timeMarker = nextMarker;
if(videoPlayer.currentTime >= timeMarker) {
videoPlayer.pause();
videoPlayer.removeEventListener('timeupdate', vidPause());
}
};
And I'm trying to fire it this way:
videoPlayer.addEventListener('timeupdate', vidPause(nextMarker));
But it only seems to fire when the video is loaded. Nothing happens when the video is playing (tested by using a console.log(videoPlayer.currentTime); inside the vidPause function).
Note: I need the function to be called that way so that I can remove the event listener when it hits the time marker, that way it won't stop when the user wants to play the video from that point on.
Thanks in advance for any suggestions!
The function is being called once in the addEventListener line, but that's not actually passing it as a callback.
Try this:
function videoUpdate(e) {
vidPause(nextMarker, videoPlayer.currentTime;); // Now call your function
}
function vidPause(nextMarker, timeStamp){
var timeMarker = nextMarker;
if (timeStamp >= timeMarker) {
videoPlayer.pause();
videoPlayer.removeEventListener('timeupdate', videoUpdate);
}
};
videoPlayer.addEventListener('timeupdate', videoUpdate); // Note no brackets, as it's passing a ref to the function rather than calling it
I don't know what the scope of nextMarker is, but you should be able to start console logging and find out.
I've faced the following scenario quite often so I'm wondering if there is a built-in jQuery way of solving the issue.
Imagine the following code:
$(document).click(function() {
paintCanvas();
});
The problem with this code is that if the user clicks on the screen 50 times in rapid succession you are going to overload the browser with 50 calls to paintCanvas.
If paintCanvas is currently executing and a new request is created, we want to queue the new request so that it waits until paintCanvas is finished executing. However, at the same time, we can drop any previously queued calls to paintCanvas as we only care about the final state of the mouse, not all the intermediate states.
Here is some code that solves the problem:
var _isExecuting, _isQueued;
function paintCanvas() {
if (_isExecuting) {
if (!_isQueued) {
_isQueued = true;
setTimeout(function() {
_isQueued = false;
paintCanvas();
}, 150);
}
return;
}
_isExecuting = true;
// ... code goes here
_isExecuting = false;
};
This AJAX queue plugin essentially implements this functionality, but does so only in terms of AJAX. Surely this is a very common problem that can be solved in more generic way?
You shouldn't have to solve this problem with mousemove because the system already does that for you. While paintCanvas is executing, it is not generating hundreds of mousemove events even if the mouse is moving vigorously. Rather, the next event will be the current location of the mouse, not a queue of all the intervening mouse events.
Look at this jsFiddle: http://jsfiddle.net/jfriend00/4ZuMn/.
Wiggle your mouse around in the body (lower, right pane) as fast as you want. Then move the mouse out of the pane and notice that the count stops immediately - there are no more mouse events. It doesn't stack up mouse events ever. Whenever the system is ready for the next mouse event, it gets the latest position of the mouse. Individual mouse moves are NOT queued up - they do not accumulate. You can also see in the listing of mouse events that lots of intervening mouse events are not present (e.g. lots of coordinates are missing) even though the mouse went through more positions. This is because the system wasn't ready to make a mouse event when the mouse was in that position so that position was skipped.
Further, because javascript is single threaded, you will never get a new mouse event while you are currently processing one. The system won't generate a new one until you're done processing the one you're already one. So, you will never, ever see _isExecuting as true in javascript in your code. You simply don't need that check. And, since you don't need that check and it will never be true, none of your queuing code will ever execute. You can see here in this jsFiddle, that you can never catch a mousemove event that was re-entered: http://jsfiddle.net/jfriend00/ngnUT/. The inAction flag is never caught as true, no matter how fast or much you wiggle your mouse around.
Sounds like you want throttle/debounce features.
There are no built in methods that I know of from jQuery, you can use any of these though:
http://benalman.com/projects/jquery-throttle-debounce-plugin/
http://jsperf.com/jquery-throttle-methods
Though #rkw provided a link, I always prefer to show code here on SO. Here's some simple code that kind does what you want. A function that returns a buffered version of another function. This will keep delaying until it stops receiving the event for the given delay. You can tweak this if you don't want to to wait for the delay after the last event. All you'd need to do is keep track of when you first set the timeout and offset the subsequent calls to setTimeout.
Here's a working example http://jsfiddle.net/mendesjuan/qfFjZ/
function createBuffered(handler, delay) {
var timeoutId = null;
return function() {
var me = this;
if (timeoutId) {
window.clearTimeout(timeoutId);
}
timeoutId = setTimeout(function() {
handle.apply(me, arguments);
timeoutId = null;
}, delay);
}
}
I have a jQuery slider on my site and the code going to the next slide is in a function called nextImage. I used setInterval to run my function on a timer, and it does exactly what I want: it runs my slides on a timer. BUT, if I go to the site in Chrome, switch to another tab and return, the slider runs through the slides continuously until it 'catches up'. Does anyone know of a way to fix this. The following is my code.
setInterval(function() {
nextImage();
}, 8000);
How to detect when a tab is focused or not in Chrome with Javascript?
window.addEventListener('focus', function() {
document.title = 'focused';
},false);
window.addEventListener('blur', function() {
document.title = 'not focused';
},false);
To apply to your situation:
var autopager;
function startAutopager() {
autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
window.clearInterval(autopager);
}
window.addEventListener('focus', startAutopager);
window.addEventListener('blur', stopAutopager);
Note that in the latest version of Chromium, there is either a bug or a 'feature' which is making this less reliable, requiring that the user has clicked at least once anywhere in the window. See linked question above for details.
I post an answer here: How can I make setInterval also work when a tab is inactive in Chrome?
Just do this:
setInterval(function() {
$("#your-image-container").stop(true,true);
nextImage();
}, 1000);
inactive browser tabs buffer some of the setInterval or setTimeout functions.
stop(true,true) - will stop all buffered events and execute immadietly only last animation.
The window.setTimeout() method now clamps to send no more than one timeout per second in inactive tabs. In addition, it now clamps nested timeouts to the smallest value allowed by the HTML5 specification: 4 ms (instead of the 10 ms it used to clamp to).
A few ideas comes to mind:
Idea #1
You can make it so that a short burst is idempotent. For example, you could say:
function now() {
return (new Date()).getTime();
}
var autopagerInterval = 8000;
function startAutopager() {
var startImage = getCurrentImageNumber();
var startTime = now();
var autopager = setInterval(
function() {
var timeSinceStart = now() - startTime();
var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
if (getCurrentImageNumber() != targetImage)
setImageNumber(targetImage); // trigger animation, etc.
},
autopagerInterval
);
return autopager;
}
This way even if the function runs 1000 times, it will still run in only a few milliseconds and animate only once.
note: If the user leaves the page and comes back, it will have scrolled. This is probably not what the original poster wants, but I leave this solution up since it is sometimes what you want.
Idea #2
Another way to add idempotence (while still keeping your nextImage() function and not having it scroll to the bottom of the page) would be to have the function set a mutex lock which disappears after a second (cleared by another timeout). Thus even if the setInterval function was called 1000 times, only the first instance would run and the others would do nothing.
var locked = false;
var autopager = window.setInterval(function(){
if (!locked) {
locked = true;
window.setTimeout(function(){
locked=false;
}, 1000);
nextImage();
}
}, 8000);
edit: this may not work, see below
Idea #3
I tried the following test:
function f() {
console.log((new Date()) + window.focus());
window.setTimeout(f, 1000);
}
f();
It seems to indicate that the function is being called every second. This is odd... but I think this means that the callbacks are being called, but that the page renderer refuses to update the page in any graphical way while the tab is unfocused, delaying all operations until the user returns, but operations keep piling up.
Also the window.focus() function doesn't say if the window has focus; it GIVES focus to the window, and is thus irrelevant.
What we want is probably this: How to detect when a tab is focused or not in Chrome with Javascript? -- you can unset your interval when the window loses focus (blur), and reset it when it gains focus.
I don't know exactly what is going on in your function nextImage(), but I had a similar issue. I was using animate() with setInterval() on a jQuery image slider that I created, and I was experiencing the same thing as you when I switched to a different tab and back again. In my case the animate() function was being queued, so once the window regained focus the slider would go crazy. To fix this I just stopped the animate() function from queuing.
There are a couple ways you can do this. the easiest is with .stop(), but this issue and ways to fix it are documented in the jQuery docs. Check this page near the bottom under the heading additional notes: http://api.jquery.com/animate/
I had faced similar issue, somehow this code below works fine for me.
var t1= window.setInterval('autoScroll()', 8000);
window.addEventListener('focus', function() {
focused = true;
window.clearInterval(t1);
t1 = window.setInterval('autoScroll()', 8000);
},false);
window.addEventListener('blur', function() {
focused = false;
window.clearInterval(t1);
},false)
function autoScroll()
{
if ( running == true){
if ( focused = true){
forwardSlide();
}
}
else {
running = true;
}
}
If you are using Soh Tanaka's image slider then just add this...to solve your Google Chrome issue:
$(".image_reel").stop(true, true).fadeOut(300).animate({ left: -image_reelPosition}, 500 ).fadeIn(300);
Take note of the .stop() function. Ignore the fading in and out stuff, that's what I used on my version
Thanks
Seconding the comment by jgerstle to use page visibility events instead, see https://www.w3.org/TR/page-visibility/#example-1-visibility-aware-video-playback for more around subscribing to 'visibilitychange' for hidden/visible states.
This seems to be more useful than focus/blur these days as it covers visible-but-not-selected windows if concerned also about multi-window operating systems.