Javascript update functions - javascript

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

Related

Do calls to requestAnimationFrame stack?

I have the following functions
function render() {
init = timeStep(init)
if (steps <= yQuotient) {
requestAnimationFrame(render)
}
}
export function fire() {
setup();
render();
}
I then call fire() whenever I need to start/restart the application. My question is whether this will result in multiple requestAnimationLoop()'s active simulatenously as they build up like eventListeners do when called repeatedly, presumably affecting performance.
Do I need to amend my fire() function to something like this?
export function fire() {
cancelAnimationFrame(render)
setup();
render();
}
Or does requestAnimationLoop() just automatically know to end it's current loop when a new one is started?
Yes, calls to requestAnimationFrame will stack all the callbacks into the map of animation frame callbacks.
Each painting frame, the keys of this map are all gotten and looped over, allowing to schedule a new animation frame callback from such a callback, for firing at the next painting frame.
So yes, scheduling multiple times the same callback in the same event loop iteration will worsen the performances of your page, since it will have to do multiple times the same work.
It's quite unclear how all your system works, but a quite often used strategyfor games and interactive animations is to keep a single main animation loop running all the time and calling sub-tasks. External events only modifying states of objects that get visited from these sub-tasks.

Can't use GSAP inside function to target MovieClip on stage (Animate CC)

I'm an HTML5 newbie and I was wondering if someone could tell me what I'm doing wrong here. I would like to be able to use GSAP to animate a vector file I'd add to the stage and would need to be able to make it animate when I call a function, however when I try to do this I keep getting cannot tween a null object, but if it's not wrapped in a function the animation plays fine.
I created a new HTML5 canvas to see if the issue persisted and it did, so this is what I did:
Added a symbol to a blank HTML5 canvas, made it a Movie Clip and drew a circle. I called the instance mcThing
In the Timeline, I selected the first frame and went into Actions
I wrote:
function playAnimation() {
TweenMax.to(this.mcThing, 3, {y:500});
}
playAnimation();
When testing in Chrome, I get cannot tween a null object. If I reference it as mcThing (omitting the this. I instead get mcThing is not defined.
If I then remove the function and just have this:
TweenMax.to(this.mcThing, 3, {y:500});
It plays fine, but now I can't call it when I need to.
Some context:
Essentially what I currently have is a WebSocket listening for messages. When it receives a message, it's added to the queue. I am trying to get it to play an animation and insert the text from that message. The text itself should be okay: I used CreateJS to instantiate a text in the code and TweenMax works there, the problem is animating shapes/drawings. I suppose I could instantiate all the shapes in the code itself and TweenMax would work then but I don't think this is realistic as the animation/shapes are fairly complex, so I'm trying to target the stage. The animation would play out, stop, then the message would be removed from the queue and the next one would play (same animation, different text).
I think this is a scope issue, but I'm not sure what I need to change. Any help would be much appreciated!
This issue is because of the scope. Your playAnimation is not scoped to this, so it is called in the global scope.
Try this:
this.playAnimation = function() {
TweenMax.to(this.mcThing, 3, {y:500});
}
this.playAnimation();
Putting your mcThing into the function scope would also work:
var thing = this.mcThing;
function playAnimation() {
TweenMax.to(thing, 3, {y:500});
}
playAnimation();
Or you could scope the function call itself!
function playAnimation() {
TweenMax.to(this.mcThing, 3, {y:500});
}
playAnimation.call(this);
There are lots of ways to get around it once you understand how the scoping works. I recommend the first approach.
Hope that helps!

Am I using Underscore's throttle method correctly?

I am trying to create a draggable line in a graph via Flot. I have a function that accomplishes that and executes on Flot's Plothover event (which is similar to a mouseMove event) when a certain boolean is true. The function gets called continuously and this has caused the resulting animation to lag significantly. To solve this I tried two approaches:
First I tried using setTimeout. This helped the function run better, but I was unsatisfied. The animation began to lag again if the webpage was left open for more than a minute, I have no idea why. If anyone knows whats up with that any insight would be appreciated.
Second, I tried Underscore's throttle function. I am a little unsure of the syntax, and after some research and debugging this is what I settled on. The following code is inside the event handler:
var throttled1 = _.throttle(singleLine, 50);
throttled1(position);
Where singleLine is the following function, defined outside the event handler:
function singleLine(position) {
adjustLine1[0] = [position, Number.NEGATIVE_INFINITY];
adjustLine1[1] = [position, Number.POSITIVE_INFINITY];
graphData.push({ data: adjustLine1, lines: { show: true }, color: "gray" });
plot.setData(graphData);
plot.draw();
graphData.pop();
}
Keep in mind plot.draw() is a pretty long function (it redraws the entire graph). Anyway, it appears to work because singleLine is successfully called by throttled1(position). However, it is not improving performance at all. Am I using it correctly? Any other insights into how to make this run better are also welcomed. Thanks.
var throttled1 = _.throttle(singleLine, 50);
throttled1 must be initialized oustide of the event listener, so it can track calls and timers internally, event after event.

Running multiple jquery functions together

I know this question has been asked a lot of times, and I have seen the solutions to them on SO as well as other forums. Most of the times the solution suggested is to use Web Workers.
A game I'm developing requires me to run multiple functions at the same time. One of them is an on click function and other is a setInterval.
My approach at doing this can be seen here in this JSFiddle. (keep clicking in gray area to make player jump).
The whole idea is to continuously spawn those blue obstacles after an interval of 1000ms.
In my earlier approach the obstacles would spawn only when I click to make player jump, otherwise they wouldn't as expected.
How can I run such two functions side by side in order to achieve
the aim of spawning obstacles while also making player jump.
Secondly, what would be the best approach to carry out this process
in view of game development i.e attaining a certain level of
efficiency so that the animations are not affected.
Here is the HTML and Javascript code I've been working on:
<div class="container">
<div class="player"></div>
<div class="obstacle-container">
<div class="obstacle"></div>
</div>
</div>
$.fn.animator = function () {
var hit_list, done = false;
$(".container").click(function () {
if (!done) {
$(".obstacle").stop().animate({
left: "-=105%"
}, 10000, "linear");
$(".player").stop().animate({
bottom: "+=100px"
}, {
duration: 300,
complete: function () {
$(".player").animate({
bottom: "0"
}, 800);
},
step: function () {
//Test for collision
hit_list = $(".player").collision(".obstacle");
if (hit_list.length !== 0) {
$(function () {
if (!done) {
$(".container").append("Game Over!");
return false;
}
});
done = true;
}
}
});
}
});
};
$(function () {
$('.container').animator();
});
var interval = null;
$(".obstacle-container").obstacle_generator();
$.fn.obstacle_generator = function () {
interval = setInterval(function () {
$(".obstacle-container").append('<div class="obstacle"></div>');
}, 1000);
};
The generic concept you want to investigate is known as a game loop.
Almost every game will be built using some variant of this system:
Initialise game
Loop:
Check for user input
Update any actors
Draw the scene
Wait until it's time to repeat
A game running at 60 frames per second would perform this loop 60 times per second, or about once every 16ms.
Compared to your original question, you wouldn't need to be running multiple execution threads (running multiple functions together) to achieve this.
You are, in a way, already using a similar loop. jQuery maintains its own loop for updating animations. Where you are checking for collisions as part of your animation step, this is the sort of thing you would do in a hypothetical Player.update() method. You want to move this code out of jQuery, and in to a loop that you control.
Since you're running in a browser, the generic game loop becomes a bit more simple:
Check for user input - this can still be handled by event handlers, jQuery or not. Rather than directly changing properties like CSS position, though, they should act upon the state of the game object. For example, by changing the velocity of a Player object.
Update any actors - the important part of your loop. You should check how many milliseconds have passed since you last looped, since the browser doesn't guarantee that your code will be run exactly, or at least, 60 times per second. You should then loop through all of your game objects and update them all. In your Player.update() method, you would want to move it according to its velocity and the time passed, for example.
Draw the scene - if you're using DOM elements, then the browser handles drawing for you, of course. If you were using a <canvas> element, then you would do drawing yourself as part of the loop here.
Wait until it's time to repeat - this will be up to the browser to do for you, as part of normal setInterval/setTimeout behavior.
A simple game loop in JavaScript can look like this:
var gameObjects = [];
// Initialise game, create player objects etc, add them to the array
var gameLoop = function() {
// Loop through gameObjects, and call their respective update methods
};
setInterval(gameLoop, 16); // Try to run the loop 60 times per second.
In a complex game, you wouldn't have just a basic array to hold all game objects, this is just an basic example.

JavaScript's version of ActionScript's Event.ENTER_FRAME event?

I am trying to learn JavaScript and I am wondering whether JavaScript has a event listener just like ActionScript's ENTER_FRAME. Basically, I want this event listener to listen "all the time" not just wait for any particular instance (mouse click, keyboard event) of event.
This would probably be worth a look too :
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
You're looking for setInterval(func, time). In the case of making it work like ENTER_FRAME, then you would make time very small. So, if you wanted to imitate a frame rate of say, 30 times a second:
// you will need to make sure you have good scoping around the function param.
setInterval(function(){console.log('enterframe')}, 33)
// 33 is about 1000 milliseconds / 30.
Actually, setInterval is in Flash too -- flash.utils.setInterval.
As a side note -- unfortunately, setInterval (in both Flash and JS) can work against the native refresh rate. In Flash ENTER_FRAME avoids this -- you render when the swf re-renders. In the browser, well, setInterval simply can't do that.
HTML5 provides access to the requestAnimationFrame()
<canvas id="canvas" width="400" height="400"></canvas>
<script>
window.onload = function () {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
var counter = 0;
(function drawFrame () {
window.requestAnimationFrame(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
console.log(counter++);
// animation code goes here
}());
};
</script>
Credit goes to Keith Peters for helping sort this out. Highly recommend his book 'HTML5 animation with Javascript' by FriendsOfEd:
http://www.apress.com/9781430236658
I am still learning how to convert AS3 to JavaScript, but would it not be this function:
createjs.Ticker.addEventListener("tick", gameLoop);
gameLoop is the custom function that will be called on every 'tick'.
Check out this helpful example of writing a game in Adobe Animate CC using JavaScript instead of AS3: https://software.intel.com/en-us/html5/hub/blogs/flash-cc-to-html5
Nope. Not really. A good substitute would be setInterval or setTimeout:
function doAllTheTime() { }
function wrapper() {
doAllTheTime();
setTimeout(wrapper, 40);
}
wrapper();
But even then, you're pretty limited, because you don't have access to any of the event object properties.

Categories

Resources