Using the setInterval function, I'm trying to create a sprite once every second on code.org using javascript, so my first version of the code looks like
setInterval( function() {
createSprite(200,200,20,20)
}, 1000)
My problem is that putting setInterval inside of the Draw function causes it to not work properly and a sprite is created every tick after one second has passed, and when the setInterval is not put into function Draw it does not draw the sprite like I want it too.
One solution I have tried is putting the Draw function inside of setInterval but it is not recognized and gives the error message "Draw is defined, but it is not called in your program".
Is there a different version of setInterval that works inside of Draw function, a way to put Draw inside of setInterval successfully, a way to make the sprite show up even though it is outside Draw, or a different way to solve this problem?
Specifically what I'm looking for is to create a sprite once every second, have it show up on screen, be able to choose different velocities for each sprite each time a new one is spawned, and being able to put this function inside of an if function and still have it work as intended.
a piece of code showing something that partially works is shown here:
https://studio.code.org/projects/gamelab/ApXezLpMzV3TfEfHx1CrhFyuteYDSKWe_6Hx0NdJgnc
It works in the regards that it spawns a sprite every second, but if I try to assign one of the sprites that got spawned a velocity, It only works for the first one, as shown here:
https://studio.code.org/projects/gamelab/ApXezLpMzV3TfEfHx1CrhFyuteYDSKWe_6Hx0NdJgnc
the only way I think a solution could be made would be by declaring a class, and then creating a sprite of this class inside the setInterval function, but I do not know exactly how to do this.
So i think that your problem is that the sprite generates only after a second, right?
If so, please try this:
createSprite(200,200,20,20);
setInterval( function(){ createSprite(200,200,20,20)},1000);
See comments:
// just a helper function to generate random velocities
function random_in_range(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min }
var monster = createSprite(200,200,20,20);
monster.velocityX = 5;
setInterval(function() {
// as you needed to set velocity for a newly created sprite
// you need to have this sprite as a variable
var fireball = createSprite(monster.x,monster.y,4,4);
// now you can set it's velocity
fireball.velocityX = random_in_range(1,6);
// basically that's it.
// as you don't do anything else with a "fireball"
// you can just forget about it, and you don't need to save it anywhere
}, 1000);
function draw() {
background("white");
createEdgeSprites();
monster.bounceOff(edges);
drawSprites();
}
The link with the working code
Looking at your original code and your question I think that you may have some basic misconseptions about JS (sorry if I misjudged). Explained them in the comments to your code. I also added some lines to illustrate my points:
var spawner = createSprite(200,200,20,20);
var remember_spawner = spawner // ADDED
// After a new sprite created it does't change 'spawner' variable
createSprite(150,200,15,15).velocityY = 3; // ADDED
console.log(remember_spawner === spawner) // ADDED // you see it's the same
// you need to assign the newly created sprite to a variable
// you can think of this as:
// I need give them different names so that they can understand to whom am I taking to
// and if you don't name them they won't listen to you at all
var spawner2 = createSprite(100,200,10,10); // ADDED
spawner2.velocityY = 1 // ADDED // now you cat change velocity of another sprite
console.log(spawner !== spawner2) // ADDED // and it is another sprite
// var thing_to_be_spawned = createSprite(spawner.x,spawner.y,4,4);
// You probably don't need this. And you don't use the variable anyway.
// This sprite created at the same time as the spawner.
// But if you need it, and you want it to move - change it's velocity (thing_to_be_spawned.velocityX = something) not the velocity of spawner
// And it would be better if you'll name the function passed to setInterval
// and call it instead of repeating it. Like so:
// function fire() { ... } // define the function
// fire() // call the function
// setInterval(fire, 1000) // call the function every second
setInterval(function(){
console.log("This function executed every second") // ADDED
console.log("Fire!") // ADDED
createSprite(spawner.x,spawner.y,4,4);
console.log("Done") // ADDED
},1000);
console.log("Next line executed only once") // ADDED
spawner.velocityX=5;
// The fact that it's placed after setInterval() does mean that
// it will be executed after call to setInterval()
// but it doesn't mean that it will be executed after the function passed to setInterval(). Let's call it fire(), shall we?
// Actually, the fire() function will be called only after all the code in this file
// And setInterval() is also called only once, only the fire() passed to it called every second
function draw() { // Here you don't call draw() you only define it, so that code.org can call it whenever it wants
// looking at the code draw function we can't tell when or how often it's called
// it depends on the implementation details of code.org.
// We can add console.log to find out
console.log("Draw called") // ADDED
background("white");
createEdgeSprites();
spawner.bounceOff(edges);
drawSprites();
}
console.log("'fire()' not called yet") // ADDED
Console logs can be seeing in Debug Console of studio.code.org. It opens with a click on Debug Commands. Use it! I mean console.log(). I could also say "use Debug Commands!" but debug is poorly implemented in studio.code.org and can be misleading... You should definitely give it a try, but your trust you should put in console.log().
Related
I am extending mxgraph delete control example to add delete like controls to nodes which are generated dynamically in my graph. The source code for the example is available here
The problem is in this part of the code -
// Overridden to add an additional control to the state at creation time
mxCellRendererCreateControl = mxCellRenderer.prototype.createControl;
mxCellRenderer.prototype.createControl = function(state)
{
mxCellRendererCreateControl.apply(this, arguments);
var graph = state.view.graph;
if (graph.getModel().isVertex(state.cell))
{
if (state.deleteControl == null)
mxCellRendererCreateControl.apply inside the overridden call back of createControl seems to work as intended (calls the original function before creating additional controls) with the initial state of the graph on load. But, once I add nodes dynamically to the graph and the callback is invoked by mxgraph's validate/redraw, the control goes into an infinite loop, where 'apply' function basically keeps calling itself (i.e, the callback).
I am a bit clueless because when I debug, the context(this) looks fine, but I can't figure out why instead of invoking the prototype method, it just keeps invoking the overridden function in a loop. What am I doing wrong?
It looks like you are not cloning your original function the right way, please try the following :
Function.prototype.clone = function() {
var that = this;
return function theClone() {
return that.apply(this, arguments);
};
};
Add that new method somewhere in your main code so it will available in the whole application, now you can change your code to :
// Overridden to add an additional control to the state at creation time
let mxCellRendererCreateControl = mxCellRenderer.prototype.createControl.clone();
mxCellRenderer.prototype.createControl = function(state) {
mxCellRendererCreateControl(state);
var graph = state.view.graph;
if (graph.getModel().isVertex(state.cell)) {
if (state.deleteControl == null) {
// ...
}
}
// ...
};
This should work if I understood your problem correctly, if it does not, please change the old function call back to the apply. Otherwise let me know if something different happened after the Function prototype change.
It seems that your overriding code is being called multiple times (adding a simple console.log before your overriding code should be enough to test this)
Try to ensure that the code that overrides the function only gets called once, or validate whether the prototype function is the original or yours.
Here is an example of how you can check if the function is yours or not
if (!mxCellRenderer.prototype.createControl.isOverridenByMe) {
let mxCellRendererCreateControl = mxCellRenderer.prototype.createControl;
mxCellRenderer.prototype.createControl = function(state) { /* ... */ };
mxCellRenderer.prototype.createControl.isOverridenByMe = true;
}
There are other ways, like using a global variable to check if you have overriden the method or not.
If this doesn't fix your issue, please post more about the rest of your code (how is this code being loaded/called would help a lot)
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
I searched a lot for a solution to this certainly-not-unique problem, but I have not found anything that will work in my context of an HTML page.
I have an input text that contains some kind of source-code that generates something, and I can show a preview of that something on the same HTML page (by updating the background image, for example). Note that the source could be a LaTeX file, an email, a Java program, a ray-trace code, etc. The "action" to generate the preview has a certain cost to it, so I don't want to generate this preview at each modification to the source. But I'd like the preview to auto-update (the action to fire) without the user having to explicitly request it.
Another way to phrase the problem is to keep a source and sink synchronized with a certain reasonable frequency.
Here's my solution that's too greedy (updates at every change):
$('#source-text').keyup(function(){
updatePreview(); // update on a change
});
I tried throttling this by using a timestamp:
$('#source-text').keyup(function(){
if (nextTime "before" Now) { // pseudocode
updatePreview(); // update on a change
} else {
nextTime = Now + some delay // pseudocode
}
});
It's better, but it can miss the last updates once a user stops typing in the source-text field.
I thought of a "polling loop" for updates that runs at some reasonable interval and looks for changes or a flag meaning an update is needed. But I wasn't sure if that's a good model for an HTML page (or even how to do it in javascript).
Use setTimeout, but store the reference so you can prevent it from executing if further editing has occurred. Basically, only update the preview once 5 seconds past the last keystroke has passed (at least in the below example).
// maintain out of the scope of the event
var to;
$('#source-text').on('keyup',function(){
// if it exists, clear it and prevent it from occuring
if (to) clearTimeout(to);
// reassign it a new timeout that will expire (assuming user doesn't
// type before it's timed out)
to = setTimeout(function(){
updatePreview();
}, 5e3 /* 5 seconds or whatever */);
});
References:
clearTimeout
setTimeout
And not to self-bump, but here's another [related] answer: How to trigger an event in input text after I stop typing/writing?
I tweaked #bradchristie's answer, which wasn't quite the behavior I wanted (only one update occurs after the user stops typing - I want them to occur during typing, but at a throttled rate).
Here's the solution (demo at http://jsfiddle.net/p4u2mhb9/3/):
// maintain out of the scope of the event
var to;
var updateCount = 0;
var timerInProgress = false;
$('#source-text').on('keyup', function () {
// reassign a new timeout that will expire
if (!timerInProgress) {
timerInProgress = true;
to = setTimeout(function () {
timerInProgress = false;
updatePreview();
}, 1e3 /* 1 second */ );
}
});
I'm working on a JavaScript driven site where I will have a lot of stuff that need's to be executed in a certain order. A lot of the stuff involves animations and AJAX-loading. Some pseudo code could look like this:
Load JSON formated data
Generate HTML-elements using the loaded JSON data and render them inside a div
Make the elements inside the div scrollable using a jQuery UI slider
Randomize a number between 1 and the total number of loaded elements
Make the jQuery UI slider scroll (animate) to the element that represents the randomized number for a duration of 500 milliseconds
Load more JSON formated data
Replace other elements on the page
And so on...
Each step in this is wrapped in a function - one function loads the JSON data, another generates the HTML-elements, a third initializes the jQuery UI slider and so on. Encapsulating the code in functions makes the code easier to read for me, but above all I want to be able to call the functions in different orders depending on what happens on the page and I want to be sure that one function has finished running before the next one is executed.
If there was just regular functions that didn't involve AJAX or jQuery animations I'd just execute the functions I want to execute, one after the other. The problem is that I need to wait for the animations and data retrieving functions to finish before moving on. To aid me both the animation and AJAX methods in jQuery allow me to send along a callback. But here's where I get lost.
What I want it to do is the following:
Load JSON data. If the loading is successful, go on and...
Generate HTML-elements
Make the elements scrollble
Randomize a number between 1 and the total number of loaded elements and pass it to...
A function that makes the jQuery slider slide (animated) to the element. When the animation is finished...
Load more JSON formated data. If the loading is successful, go on and...
Replace other elements on the page
The ideal thing would be if I could set up this sequence/chain of events in one single place, for example inside an event handler. If I want to call the functions in a different order or not call all of them I would just set up a different sequence/chain. An example could be:
Randomize a number between 1 and the total number of loaded elements and pass it to...
A function that makes the jQuery slider slide (animated) to the element. When the animation is finished...
This means that I'd have to be in control over the callbacks in each step.
I hope you understand what I'm looking for. I want to control the entire execution sequence from a single function. This function would be "the conductor of the orchestra" and all the other functions would be the different instrument sections of the orchestra. This conductor functions need's ears so it can hear when the violinist is finished with her solo and can tell the horns to start playing. Excuse me for the corny allegory, but I hopes it makes it easier to understand what I want to do.
Thanks in advance!
/Thomas
Would the jQuery .queue() function help you?
Could you store a sequencer variable that is an array (which you would be able to change) and then call a sequencer at the end of each function?
You could then pass a step code through each function and cross-reference that with the sequencer variable as to what the next step should be.
Pseudo Code:
var func['1'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
var func['2'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
var func['3'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
var func['4'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
function sequencer(seq) {
seq = seq + 1;
window.func[seq]
}
I tried executing this code:
var seq = 0;
var func = [];
func[1] = function(seq) {
setTimeout(function() {
console.log("Executing function 1");
sequencer(seq);
}, 2000);
}
func[2] = function(seq) {
console.log("Executing function 2");
sequencer(seq);
}
func[3] = function(seq) {
console.log("Executing function 3");
}
function sequencer(seq) {
seq = seq + 1;
func[seq].call();
}
sequencer(seq);
But the result (in Firebug) is:
Executing function 1
func[seq] is undefined
[Break on this error] func[seq].call();
I think that the problem is caused by context, but I'm not sure. JavaScript is sensitive to the context in which a function is called.
/Thomas
I found that what I was trying to achieve was slightly overkill for my purposes. So I decided to go with a different approach. I can send one or more boolean variables as a parameters to a function and use them to decide whether to execute a second function or not. Here's an example:
$("#justOneStep").click(function() {
loadImage(false);
});
$("#twoStepsPlease").click(function() {
loadImage(true);
});
function loadImage(boolDoMore) {
// Do the stuff that loads an image
...
if(boolDoMore) {
nextFunction();
}
}
function nextFunction() {
// Do some more stuff
...
}
Not very fancy but easy to understand and control and sufficient for my needs at the moment.
/Thomas
I am trying to call showUpload(); from within two setTimeouts. Neither works. It seems to be out of scope and I'm not sure why. I tried this.showUpload() which didn't work either.
$(document).ready(function(){
var progress_key = $('#progress_key').val();
// this sets up the progress bar
$('#uploadform').submit(function() {
setTimeout("showUpload()",1500);
$("#progressbar").progressbar({ value:0}).fadeIn();
});
// uses ajax to poll the uploadprogress.php page with the id
// deserializes the json string, and computes the percentage (integer)
// update the jQuery progress bar
// sets a timer for the next poll in 750ms
function showUpload() {
$.get("/myid/videos/uploadprogress/" + progress_key, function(data) {
if (!data)
return;
var response;
eval ("response = " + data);
if (!response)
return;
var percentage = Math.floor(100 * parseInt(response['bytes_uploaded']) / parseInt(response['bytes_total']));
$("#progressbar").progressbar({ value:percentage})
});
setTimeout("showUpload()", 750);
}
});
Thank you for your time.
As #Daniel said, this should work:
setTimeout(showUpload, 750);
Please note that the quotes should be removed (this is why it isn't being executed until the timeout runs out). Right now, you are passing a string, which is evaled when the timeout runs out. This eval will happen in a different scope, which is why you are seeing the problem you are seeing.
Instead, passing a reference to the showUpload function to setTimeout will allow your function to be executed later. Keep in mind that when it runs, it will be in a different scope, so you may have other scope issues, like with progress_key. You will need to create a closure around showUpload to capture that parameter.
It looks like you need to remove the parenthesis from showUpload in both your setTimeout calls. Otherwise you will be invoking the showUpload method instead of passing it as a parameter:
setTimeout(showUpload, 750);