Using requestAnimationFrame instead of setInterval - javascript

I ran across an issue where my code worked just fine in Chrome but in Safari it began to stutter. I read somewhere that "Safari caps intervals at 1000ms and then adds its own exponential delay, doubling every iteration." That being said I am trying to change my code to work both on Safari and Chrome using requestAnimationFrame but am having issues wrapping my head around the subject.
Essentially what I am trying to do is ease a div across a page with each click using requestAnimationFrame instead of setInterval.
Any guidance would be appreciated.
Here is the Javascript:
let progressAvatar = document.querySelector('.box');
progressAvatar.addEventListener('click', checkClick);
var clicks = 0;
function checkClick() {
clicks += 1;
if (clicks == 1) {
startingLocationOfAvatar();
} else if (clicks == 2) {
locationOfAvatar();
}
}
function startingLocationOfAvatar() {
let speed = 10;
// Initial location of Avatar
let pos = 0;
// Ending location of Avatar
let progressBarWidthDivided = 53;
let id = setInterval(frame, speed);
function frame() {
if (pos == progressBarWidthDivided) {
clearInterval(id);
} else {
pos++;
progressAvatar.style.marginLeft = pos + "px";
}
}
}
// Move the avatar based on its previous location
function locationOfAvatar() {
let speed = 10;
// Pos becomes last location of movePixels
let pos = 53;
let id = setInterval(frame, speed);
// movePixels adds last location by its new location
let movePixels = pos * 2;
function frame() {
if (pos == movePixels) {
clearInterval(id);
} else {
pos++;
progressAvatar.style.marginLeft = pos + "px";
}
}
}
Here is the Html:
<div class="box">
</div>
Here is the Css:
.box {
height: 100px;
width: 100px;
background-color:red;
}
Lastly here is a jsfiddle:
Move Div Across Screen

I will let experts answer, but as a 2 weeks coding noob this is what i know, you can compile all individual animation functions into a grand Animation function. And call that function with request animation frame. Trying to make a sensible game myself, i have totally given up on manipulating css values and coding in pure Javascript.
Note, dependent where you will put your mini-functions - the photos/graphical items will display either on top or under eachother visually.
It should look something like this:
function drawEverything(){
context.clearRect(0,0,width,height);
context.save();
draw();
draw1();
draw2();
context.restore();
requestAnimationFrame(drawEverything);
}
requestAnimationFrame(drawEverything);

Related

Scrolling speeds up on calling a requestanimationframe multiple times

I'm trying to create a slider with an image gallery and to make it scroll smooth using the requestAnimationFrame.
It works almost perfect except one thing. If you slide more then 2 times in any direction the scroll speeds up and it looks bad. I would like to have the same speed every time I slide to right or left.
Can anyone give me a hint of how to do that?
var currentPos = -200;
var incrementer = .05;
var id;
function scrollNext() {
incrementer += 1;
currentPos = Math.pow(1.05, incrementer);
item.scrollLeft += currentPos;
id = requestAnimationFrame(scrollNext);
if (!curr_slide.nextElementSibling) {
if (item.scrollLeft >= curr_slide.offsetLeft) {
item.scrollTo(curr_slide.offsetLeft, 0);
cancelAnimationFrame(id);
}
if (item.scrollLeft < curr_slide.offsetLeft) {
item.scrollTo(curr_slide.offsetLeft, 0);
cancelAnimationFrame(id);
}
} else {
if (item.scrollLeft >= curr_slide.nextElementSibling.offsetLeft) {
item.scrollTo(curr_slide.nextElementSibling.offsetLeft, 0);
cancelAnimationFrame(id);
}
}
}
scrollNext();
curr_slide.nextElementSibling.classList.add('activeSlide');
curr_dot.nextElementSibling.classList.add('currentDot');

Why is my player moving faster and faster when I use the controls. HTML web game

I am making an HTML5 web game and am in the process of making the player movement. I am not using any game engine, just pure HTML, CSS, and JavaScript. My problem is that whenever I load my game, it starts out fine where I can move around at normal speeds but if I move back and forth a few times, the player starts speeding up and if I keep doing this, it speeds up to unbearable speeds. I have no idea what is happening.
How my code works is when the key d is pressed then in the keysPressed object D is set to true instead of false,
let keysPressed = {
'd': false,
'a': false,
'w': false,
's': false, }
Then, it executes a function that moves the player.
function move() {
if (keysPressed['d'] == true) { // check if its right
let player = document.querySelector('.player');
var id = setInterval(frame, 20);
function frame() {
if (keysPressed['d'] == false) {
clearInterval(id);
} else {
player.style.left = player.offsetLeft + 2 + 'px';
}
}
}
if (keysPressed['a'] == true) { // check if its left
let player = document.querySelector('.player');
var id = setInterval(frame, 20);
function frame() {
if (keysPressed['a'] == false) {
clearInterval(id);
} else {
console.log(player.offsetLeft)
player.style.left = player.offsetLeft - 2 + 'px';
}
}
}
}
I know that it isn't the cleanest code but I just wanna fix this bug first before tackling this.
Thanks
You are calling setInterval many times over which is compounding and causing the symptom you're describing. I think you only need to call setInterval once, and then just change the left/right variables depending on the keypress.. something like
let intervalID, player = document.querySelector('.player'),
dir, offset, isMoving = false;
function changeDirection(keysPressed) {
if (!isMoving) move();
if (keysPressed['d']) {
dir = 'left';
offset = 'offsetLeft';
} else if (keysPressed['a']) {
dir = 'right';
offset = 'offsetRight';
}
}
function move() { // called just once
if (isMoving) return;
isMoving = true;
intervalID = setInterval(function() {
player.style[dir] = (+player[offset] + 2) + 'px';
}, 20);
}

window.move in the negative direction issue

I have a section of code that I have been fooling around with. The goal of the code is to have four buttons, when you press the open button a window is opened in the top left corner of the screen, when you press the move button the window is supposed to move in an infinite loop around the screen starting in the positive X direction and moving clockwise. I am having an issue with the window moving in the negative X direction. Whenever the widow reaches the bottom righthand corner of my computer screen it will just stop. I do not know how to fix it, I just figured I would put a negative symbol before the direction that I want it to move. The moving function is under var moveWindow.
<html>
<head>
<script>
var aWindow;
var current = 0;
function openWindow() {
aWindow = window.open("", "", "width=400, height = 200");
aWindow.document.write("This is my new Window");
}
function closeWindow(){
if(aWindow) {
aWindow.close();
}
}
var moveWindow = function windowMove() {
var rightLimit = screen.width -400;
var topLimit = screen.height - screen.availHeight;
var bottomLimit = screen.height - 200;
if (aWindow) {
if (aWindow.screenY <= topLimit && aWindow.screenX != rightLimit) {
aWindow.moveBy(100, 0)
}
else if (aWindow.screenX <= rightLimit && aWindow.screenY != topLimit) {
aWindow.moveBy(0, 100)
}
else if (aWindow.screenY <= topLimit && aWindow.screenX != rightLimit) {
aWindow.move(-100, 0)
}
else if (aWindow.screenX <= rightLimit && aWindow.screenX != topLimit) {
aWindow.move(0, -100)
}
}
}
function startWindow(){
timer = setInterval(moveWindow, 350);
}
function stopWindow() {
clearInterval(startWindow)
}
</script>
</head>
</script>
</head>
<body>
<button onclick="openWindow();">Open</button>
<button onclick="closeWindow();">Close</button>
<button onclick="startWindow();">Move</button>
<button onclick="stopWindow();">Stop</button>
</body>
</html>
There are several issues with your conditions:
The inequality (!=) will often be true also when you reached the border. This is because the window does not stop exactly at the offset you had planned for it.
The outer window size is greater than 400x200 pixels, as there are borders. This makes the values you currently have for rightLimit (and other such variables) too tight.
You are testing for topLimit but never for bottomLimit. Also there is no provision for something like leftLimit.
You pass the wrong variable to clearInterval
Because of several metrics which influence the position of the popup window (like border, minimum distance from the screen's end, ...etc), it will be hard to determine where exactly it bumps into a side. As Windows will not let the popup window go outside of the screen, it will be easier to just let the popup window move and see if it actually did move. In case it didn't, then you know the side was reached and the direction should change.
It will also be easier the maintain the current direction in a variable instead of trying to detect what the current direction is based on the coordinates.
For detecting whether the window actually moved, you need a small time delay to allow the move to happen, so I would introduce a setTimeout for that. But otherwise the code can be much simplified:
var aWindow;
var current = 0; // We will use this to denote the current direction
function openWindow() {
aWindow = window.open("", "", "width=400, height = 200");
aWindow.document.write("This is my new Window");
}
function closeWindow(){
if (aWindow) {
aWindow.close();
}
}
var moveWindow = function windowMove() {
if (aWindow) {
var x = aWindow.screenX;
var y = aWindow.screenY;
aWindow.moveBy([100,0,-100,0][current], [0,100,0,-100][current]);
setTimeout(function () {
if (x === aWindow.screenX && y === aWindow.screenY) { // nothing moved
current = (current + 1) % 4; // next direction
windowMove(); // call an extra time to make the move in the next direction
}
}, 50);
}
}
var timer; // better declare it
function startWindow(){
timer = setInterval(moveWindow, 350);
}
function stopWindow() {
clearInterval(timer); // <--- timer
}

Moving div elements stored in array

var move = function() {
Xpos = Math.round(Math.random() * 95);
food[num].css('left', Xpos + '%');
interval = setInterval(function() {
console.log(i);
var posTop = food[num].offset().top / $(window).height() * 100;
while(posTop < 80) {
if(posTop === 80) {
num++;
break;
}
posTop += 1;
food[num].css('top', posTop + '%');
break;
}
}, speed);
}
//Color the circle
circleColor();
move();
}
OK so this is my code. It creates a circle(a <div> element) on top of the screen and gives it a random x coordinate. Than it puts it in food[] array. The entire code starts by clicking the button, but every time I press the button again the circle that was last moving stops, function creates a new one and the new one moves. Is there a way I can make all elements in the array move without depending on each other?
http://jsfiddle.net/yqwjqx31/
I understand why this happens but I have no idea how to fix it.
First you're using a global variable num in setInterval function handler, so its value get modified while using it in new cercle create, secondly you're clearing interval of the last cercle you created before creating a new cercle. It means you're sharing the same interval between all cercles. Use instead an array of intervals just like var food =[] and use a temporary variable to prevent the index value modification inside your setInterval handler. Here's a working fiddle
//Interval
var interval =[];
var tempNum = num;
interval[num] = setInterval(function() {
var posTop = food[tempNum].offset().top / $(window).height() * 100;
while(posTop < 80) {
if(posTop === 80) {
break;
}
posTop += 1;
food[tempNum].css('top', posTop + '%');
break;
}
}, speed);
Increment your num variable
//Color the circle
circleColor();
move();
num++;
Your move function is only responsible for moving the last generated div via createCircle. If you want to move them all till collision, you need to loop through them all and move them accordingly. Or, you can animate them via CSS.
Here is the working version :
http://jsfiddle.net/yqwjqx31/3/
Notice how the setInterval callback loops through all the div and pushes them down until their height is 80.
var move = function () {
interval = setInterval(function () {
for (var i = 0; i < food.length; ++i) {
var posTop = food[i].offset().top / $(window).height() * 100;
if (posTop < 80) posTop += 1;
food[i].css('top', posTop + '%');
}
}, speed);
}

Javascript sprite rotation animation on click

I'm trying to figure out how to create a rotating image effect using a sprite sheet in javascript. What I'm trying to do:
Two buttons:
Left button: Rotate 15 frames to the left.
Right button: Rotate 15 frames to the right.
I realize that there are jquery plugins that would allow me to easily do this, but I want to try it from scratch. Beyond the general idea, I don't know where to proceed. Any tips would be greatly appreciated.
Check out this jsFiddle to see a working example
Based on your question, it sounds like you're trying to learn how to animate a sprite and not actually rotate a single image. If so, here is how you would animate a sprite. Note: this uses an image of a man running. In your question, you asked about a rotating image effect. In either case, you are simply looking at different slice of a sprite and then animation is solely dependent on the sprite. As long as your sprite displays a rotating image then the image will appear to rotate.
If you need a plugin to actually rotate an image, see here.
JavaScript
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.js" type="text/javascript"></script>
<script type="text/javascript">
var imgWidth = 240;
var imgHeight = 296;
var ximages = 6;
var yimages = 5;
var currentRow = 0;
var currentColumn = 0;
function MoveSprite(dir) {
if (dir == "left") {
currentColumn--;
if (currentColumn < 0)
{
currentColumn = ximages -1;
if (currentRow == 0) {
currentRow = yimages - 1;
}
else {
currentRow--;
}
}
}
else {
currentColumn++;
if (currentColumn == ximages) {
currentColumn = 0;
if (currentRow == yimages - 1) {
currentRow = 0;
}
else {
currentRow++;
}
}
}
$("#txtRow").val(currentRow);
$("#txtColumn").val(currentColumn);
$("#spritesheet").css("backgroundPosition", -imgWidth * currentColumn + "px " + -imgHeight * currentRow + "px");
}
</script>
HTML
<button onclick="MoveSprite('left');return false;">Move Left</button><button onclick="MoveSprite('right');return false;">Move Right</button>
<div id="spritesheet"></div>
CSS
<style type="text/css">
#spritesheet {
height: 296px;
width:240px;
background-image:url('walking_spritesheet.png');
}
</style>
Sample Sprite (1440x1480):
If you are familiar with MovieClip in flash, I made a library that gives you a similar interface in javascript. https://github.com/wolthers/SpriteClip.js
you could try
css3 (rotation) ex : http://antimatter15.com/misc/rotatedgooglecss3.html
canvas (javascript) ex : https://developer.mozilla.org/en/Drawing_Graphics_with_Canvas
svg (dom or other libs) ex : http://www.svgbasics.com/rotate.html , http://raphaeljs.com/reference.html

Categories