I'm currently working on a game in node using socket.io and drawing onto canvas. I'm noticing that when I click during the game, character movement slows to a crawl. I would ideally like to maintain the draw rate that the game begins at and determine what's causing these memory issues. I'm looking to find out how I can debug this in a deterministic way
For context: I'm updating x,y coordinates in the game loop according to which keys are active (dictated by keyup and keydown events). I'm sending player information to the server via sockets about ~60 times a second.
To get more specific, here's a recording of the page's memory timeline:
The steep increase happens right around the time of the click event. The original jump (before the 6 extra listeners are added) is happening once the game starts. As you can see it's going a little wild on that click.
I have no handlers bound to the click event but the JS Heap grows rapidly and listeners seem to be added which confuses me. Here's a link to my repo, below is a chunk from game.js that has to do with keypresses and may be somehow involved:
var sendKey = function (activeK) {
player.xSpeed = 0;
player.ySpeed = 0;
if (activeK[KEY_W]) {
player.ySpeed = -SPEED;
}
if (activeK[KEY_A]) {
player.xSpeed = -SPEED;
}
if (activeK[KEY_S]) {
player.ySpeed = SPEED;
}
if (activeK[KEY_D]) {
player.xSpeed = SPEED;
}
if (activeK[SPACE]) {
activate(player)
}
}
document.onkeydown = function(e) {
if (activeKeys.hasOwnProperty(e.keyCode)) {
activeKeys[e.keyCode] = true;
sendKey(activeKeys)
}
}
document.onkeyup = function(e) {
if (activeKeys.hasOwnProperty(e.keyCode)) {
activeKeys[e.keyCode] = false;
sendKey(activeKeys)
}
}
Thanks!
Note: I originally started from scratch to try to learn a bunch but will likely switch to a game making framework.
Related
I'm trying to write a code so that when a rect() reaches a certain point, a song will start playing. I was having trouble with my actual code so I started a new test file to mess around with it and try to get it to work (my actual js file is very long & I wanted something short and simple) but I just ran into the problem again.
The code is supposed to work so if the mouse is pressed, the left square will slide over to the right square, and when it hits the right square, the song will play. If the mouse is clicked again, the song will stop.
I've gotten most of that to work, but the trouble comes in when I add in
if ( backtoblack.isPlaying() ) {
backtoblack.stop();
} else {
backtoblack.play();
}
Here's the complete code for the sketch:
var backtoblack;
var rect1X = 20;
var speed = 1;
var mouseWasPressed;
function preload(){
backtoblack = loadSound('assets/backtoblack.mp3');
}
function setup() {
createCanvas(590,630);
background("#704e34");
}
function draw(){
fill("#fff");
rect(rect1X, 20, 120, 120);
rect(450, 20, 120, 120);
if (mouseWasPressed == true ) {
if(rect1X <= 390){
rect1X += speed;
}
}
if ( backtoblack.isPlaying() ) {
backtoblack.stop();
} else {
backtoblack.play();
}
}
function mousePressed(){
mouseWasPressed = true;
}
The problem is that your if else block that toggles whether the song is playing is inside the draw() function. That means that 60 times per second, you toggle the song! It's like you're constantly hitting the play and stop buttons. Then when you switch tabs, the draw() function is paused, which is why it stops toggling.
To fix your problem, you need to not toggle the song every frame. Perhaps put it inside the mousePressed() function to test things out.
Taking a step back, I'd also encourage you to debug your code (that guide is for Processing, but here is a guide on JavaScript). It's really great that you put together a smaller example program to test things out, but you should also try to step through the code line by line, or add print statements, to figure out what's going on. Stepping through or adding print statements would have helped you realize what was going on.
Anyway, good luck!
I'm using Tracking JS to help detect if a users eyes are open and then only playing audio if it detects less than 3 objects, face, mouth, and one eye. I have it mostly convinced and working but the event is tracking and updating the data way too frequently, resulting in a very choppy and jarring experience.
Currently, I have the tracker checking constantly with the tracker on as follows:
tracker.on('track', function(event) {
if (event.data.length > 2 ) {
document.body.classList.add("hide");
pauseAudio();
} else {
document.body.classList.remove("hide");
playAudio();
}
Is there a way to run this function less frequently or specify how many times it should run per second?
You can use some sort of throttling mechanisem, lodash has it build it.
_.throttle, gets a function & time of throttling, and returns a throttled function, so you can use it as:
const handler = function(event) {
if (event.data.length > 2 ) {
document.body.classList.add("hide");
pauseAudio();
} else {
document.body.classList.remove("hide");
playAudio();
}
};
const throttledHandler = _.throttle(handler, 100); // 100ms
tracker.on('track', throttledHandler);
I'm having an issue where I have a phantom game object floating around in my JavaScript program that's still attached to my keyboard input handler (keymaster.js).
In the code below, I run startGame in demo mode when the page first loads, in order to display a simulated game while the user is reading the splash screen.
Then when the user presses the "Start" button, I rerun startGame. However, at this point, whenever the user presses a keystroke, two bullets are fired instead of one. I've discovered that there are two separate 'game' objects responding to the keystrokes, and each is firing a bullet.
How can I completely reset my game state between games and kill all associated objects in memory?
var startGame = function(demoMode) {
this.game = new TypingFrenzy.Game({
"ctx": ctx,
"ctx_kbd": ctx_kbd,
"demoMode": demoMode
});
this.currentGameView = new TypingFrenzy.GameView(this.game, ctx);
this.currentGameView.start();
}
startGame(true)
Below is the code where I bind my event handlers, in response to meager's comment:
GameView.prototype.bindKeyHandlers = function () {
var ship = this.ship;
for (i = 33; i <= 64; i++) {
var chr = String.fromCharCode(i);
key(chr, function (event, handler) { ship.processKeystroke(event, handler) });
}
};
Unbinding my key listeners from my game object allowed my game object to be deleted. I used the following command:
key.unbind('a');
Thanks meager!
This solved the problem. See my edits to the original question.
key.unbind('a');
i'm using video-js media player with flash fallback to dynamically play and change mp4-videos (h.264 - only source available) on a site i'm working on.
My problem is, every time i'm changing the video/source, the browser eats more and more memory until it is out of memory and crashes.
the problem occurs on every browser, flash player hardware acceleration enabled and disabled.
Player is initialized like this:
_V_.options.flash.swf = "../Scripts/ThirdParty/video-js.swf";
_V_.options.flash.iFrameMode = true; //false didn't help
_V_.players = {};
_V_("main_video", { "techOrder": ["flash", "html5"] }).ready(function () {
$.b4dvideo.videoPlayer = this;
if (!$.b4dvideo.contentInitialised) {
$.b4dvideo.contentInitialised = true;
$.b4dvideo._loadContent();
}
this.on("pause", function () {
this.posterImage.show()
});
this.on("ended", function () {
$.b4dvideo.videoPlayer.pause();
$.b4dvideo.videoPlayer.currentTime(0);
$.b4dvideo.videoPlayer.pause();
this.posterImage.show()
});
});
And changing the source of the player
if (!$.b4dvideo.videoPlayer.paused()) {
$.b4dvideo.videoPlayer.pause();
}
$.b4dvideo.videoPlayer.currentTime(0);
$.b4dvideo.videoPlayer.pause();
$.b4dvideo.videoPlayer.src(videoPath);
$.b4dvideo.videoPlayer.play();
It looks like the flash player is keeping the whole video in memory and never releasing it.
Any ideas on that?
I have even tried using jwplayer - same problem :-(
Update 1:
I also created a js-fiddle demonstrating this issue... just press play several times and watch your memory
http://jsfiddle.net/fwcJh/2/
The problem is this:
In the following example, http://jsfiddle.net/GmgGY/2/
when you click on the orange button it creates a new div. When you click on this div it plays an oscillator. If you push a key on the keyboard (keydown) it plays it as well. It then stops playing it when the keyboard character is lifted (keyup). This is good and what I want.
However, when you click the orange button multiple times and create multiple synths. When you push a key on the keyboard all of them play (which is what I want) but only the last created one seems to respond to the keyup event.I want all of them to respond to the keyup event.Not just the last one.
I am not sure how to fix this.
Each dynamically created div has a unique ID but also a class that is universal to all of them. I thought there might be a way to select the class ( synth.class) and launch a universal oscillator.disconnect() on keyup ???
Another thing I'm thinking is my problem might need some kind of iterating thread that compensates for whatever DOM issue is causing this (assuming it isn't just exclusively the programming thus far). But I am not sure.
The Javascript code is below. I tried to keep it as minimal as possible but I couldn't figure out how to make it any smaller than this and still have it be clear. I omitted the html and css elements but kept them in the JSfiddle example.
$(function(){
var SynthCreationModule = (function(){
context = new webkitAudioContext();
var orangeButton;
var applicationArea = document.getElementById("applicationArea"),
orangeButton = document.getElementById("orangeButton"),
counterSynth = 1;
counterPitchInput = 1;
orangeButton.addEventListener("click",createSynth, false);
function createSynth () {
var synth = document.createElement("div");
synth.className = "synth";
synth.id = "synthid" + (counterSynth++);
applicationArea.appendChild(synth);
var pitchInput = document.createElement('input');
pitchInput.type = "range";
pitchInput.className = "pitchInputClass";
pitchInput.id = "pitchInput" + (counterPitchInput++);
pitchInput.min = "0";
pitchInput.max="2000";
synth.appendChild(pitchInput);
synth.onmousedown= function () {
oscillator = context.createOscillator(),
oscillator.type = 2;
oscillator.frequency.value = pitchInput.value;
oscillator.connect(context.destination);
oscillator.noteOn(0);
};
synth.onmouseup = function () {
oscillator.disconnect();
};
// Keydown & keyup events to launch oscillator. ( These don't work properly if you create two or more synths. Playing a key down works, but keyup only works on the last created synth. The previous created synths will continue to create additional oscillators but the keydown will not work to stop them.
var keydown = false;
$('body').keydown(function() {
if(!keydown){
synth.onmousedown();
keydown = true;
}
});
$('body').keyup(function() {
synth.onmouseup();
keydown = false;
});
$(synth).draggable();
};
}());
});
Your problem is actually that you never explicitly declare and scope "oscillator" - so it's going into globals. Try putting "this." in front of each occurrence of "oscillator", and it will work.
This isn't ideal code, though, because you're attaching a whole extra body event handler for each synth - your code
$('body').keydown(function() {
if(!keydown){
synth.onmousedown();
keydown = true;
}
});
is creating a whole separate function call and calling attachEventHandler on the body under the hood, with "synth" bound to the new version; it might be better to track the list of synths (even getting them back from a body.getElementsBySelector()) and calling noteOn/Off on each one. Up to you, though.