Control enemys speed RequestAnimationFrame - javascript

i need help to discover how to do this
Basicly im trying to build a game like pacman, i have a matrix that defined where is the blocks, the pacman, the enemys and the balls, here is my matrix.
var MeshDataPac =
[
"------------------------------",
"-ooooooooooooo--ooooooooooooo-",
"-o----o------o--o------o----o-",
"-o----o------o--o------o----o-",
"-oooooooooooooooooooooooooooo-",
"-o----o--o----------o--o----o-",
"-oooooo--ooooo--ooooo--oooooo-",
"------o------ -- ------o------",
"------o- -o------",
"------o- ---- ---- -o------",
"- o- - e - -o -",
"------o- ---------- -o------",
"------o- -o------",
"------o- ---------- -o------",
"-ooooooooooooo--ooooooooooooo-",
"-o----o------o--o------o----o-",
"-ooo--oooooooo--ooooooooooooo-",
"---o--oooo oooo------",
"---o--o--o-----------o-o--o---",
"-oooooo--ooooo--oooooo-o--ooo-",
"-o-----------o--o-----------o-",
"-oooooooooooooooXoooooooooooo-",
"------------------------------"
];
to discover colisions between my pacman and the blocks and balls i discover where is the position of the "-" and "o" and the movement on each keypress is always the SCALE that i gave at the begin on creating the map for example 10, this kinda works well.
But now i need to animate the enemys "e" and i want that they move like when i press a key but randomly, if i try to increment the position on my animate function with the same as the pacman the speed is to fast, i want to control that speed but i also want that he moves always 1 block on my matrix, the only way that i know to reduce speed in this case is to put the position increment lower, but i cant do that as i said, because i want him to move 10 or SCALE each time
Tryed to use SetTimeout inside my enemyMove function and tryed to give a timeout to request animationframe but first seems like bad approach, then it becomes kinda buggy
here is my keypress function
function handleKeyPressed(e) {
var PacMan = scene.getObjectByName('PacMan');
gameSong.play();
switch(String.fromCharCode(e.which))
{
case "w": if(!detectaColisao(PacMan.position.x, PacMan.position.y + SCALE))
PacMan.position.y += SCALE;
break;
case "a": if(!detectaColisao(PacMan.position.x - SCALE, PacMan.position.y))
PacMan.position.x -= SCALE;
break;
case "s": if(!detectaColisao(PacMan.position.x, PacMan.position.y - SCALE))
PacMan.position.y -= SCALE;
break;
case "d": if(!detectaColisao(PacMan.position.x + SCALE, PacMan.position.y))
PacMan.position.x += SCALE;
break;
}
}
function anima()
{
moveEnemys();
var delta=clock.getDelta();
orbitCamera.update(delta);
requestAnimationFrame( anima);
renderer.render(scene, camera);
}
how can i do that the moveEnemys become slower but without changing the number of position increment that i want, that i have a animation like when i press a key?

Right now, the moveEnemys function gets called every time anima is run. As you've mentioned, this means moveEnemys is happening too many times and causing your enemies to move too quickly. Try replacing your anima function with this:
var enemyTimer = null;
function anima() {
if (enemyTimer == null) {
// The enemy timer has not been created yet
// Making the second argument 1000 means moveEnemys will get called
// once per second
enemyTimer = setInterval(moveEnemys, 1000);
}
var delta=clock.getDelta();
orbitCamera.update(delta);
requestAnimationFrame( anima);
renderer.render(scene, camera);
}
This way, the first time anima is called, you set up an interval causing moveEnemys to happen once per second. Modify 1000 as necessary to change how often moveEnemys occcurs.

requestAnimationFrame callbacks have current time stamp as the first argument and you should utilize that to run your app at a desired frame rate. This is how IMO the mainloop for most games should look like:
var _prevTime = 0.0;
var _at = 0.0;
var _stepSize = SOME_NUMBER;
var _frame = 0;
function loop(newTime){
newTime /= 1000;
var tick = newTime - _prevTime;
_prevTime = newTime;
tick = Math.max(tick, SOME_MAX_TICK); // important: prevent slow updates from spiraling out of control.
_at += tick;
while (_at > _stepsize){
_at -= _stepsize;
_frame += 1;
CALL_UPDATE_HERE();
}
CALL_DRAW_HERE();
requestAnimationFrame(loop);
}

Related

Variable inside setInterval(function, var) is not changing / updating with increment

I am building a browser pet raising game. My plan is to use if/else to determine what the HP drop rate should be for the pet. If below a certain hunger / happiness, the HP will drop faster and faster.
I am using a variable setInterval, and the value inside is not update, but the value is updating when printing to the console.
let hp = 100;
let dropHPWeight = 6000;
let dropHPCall = setInterval(dropHP, dropHPWeight);
function dropHP() {
hp = (hp % 360) - 1;
console.log(dropHPWeight);
dropHPWeight = dropHPWeight + 6000;
}
Here I am dropping the HP every 6 seconds, and then as a test, I am seeing if it will increase, but it does not.
Where am I going wrong here?
As some are mentioning in the comments, you cannot change the interval of a setInterval once it has been initiated. You are better off using setTimeout. Like this:
let hp = 100;
let dropHPWait = 6000;
function dropHP() {
hp = (hp % 360) - 1;
dropHPWeight = dropHPWait + 6000;
if (somecondition){
setTimeout(dropHP, dropHPWait)
}
}
dropHP()
Now you call dropHP, which changes the interval, and then uses setTimeout to call itself again after the given increment. I stuck the setTimeout inside some conditional, because you don't want it to run forever (so you have to decide at what point you want it to stop running).

The waypoints i did is working smooth but changing the speed value not effecting anything why?

The only problem i face now is that in the Inspector when changing the Patrol Speed value it's not effecting at all the speed of the character walk.
I did the character to walk in the window > Animator and there i created a new Empty State called it Walk and set the Motion to HumanoidWalk then i set the Walk state to Set as Layer Default State
So now my character is walking all the time and with the script i tell him to walk between the waypoints.
Thep roblem is how to change the walking speed ?
#pragma strict
// The list of Waypoint you want the enemy to traverse
public var waypoint : Transform[];
// The walking speed between Waypoints
public var patrolSpeed : float = 6;
// Do you want to keep repeating the Waypoints
public var loop : boolean = true;
// How slowly to turn
public var dampingLook = 4;
// How long to pause at a Waypoint= 0;
public var pauseDuration : float;
private var curTime : float;
private var currentWaypoint : int = 0;
public var character : CharacterController;
function Start(){
//character = GetComponent(CharacterController);
}
function LateUpdate(){
if(currentWaypoint < waypoint.length){
patrol();
}else{
if(loop){
currentWaypoint=0;
}
}
}
function patrol(){
var nextWayPoint : Vector3 = waypoint[currentWaypoint].position;
// Keep waypoint at character's height
nextWayPoint.y = transform.position.y;
// Get the direction we need to move to
// reach the next waypoint
var moveDirection : Vector3 = nextWayPoint - transform.position;
if(moveDirection.magnitude < 1.5){
Debug.Log("enemy is close to nextwaypoint");
// This section of code is called only whenever the enemy
// is very close to the new waypoint
// so it is called once after 4-5 seconds.
if (curTime == 0)
// Pause over the Waypoint
curTime = Time.time;
if ((Time.time - curTime) >= pauseDuration){
Debug.Log("increasing waypoint");
currentWaypoint++;
curTime = 0;
}
}
else
{
Debug.Log("reaching in rotation " + moveDirection.magnitude);
// This code gets called every time update is called
// while the enemy if moving from point 1 to point 2.
// so it gets called 100's of times in a few seconds
// Now we need to do two things
// 1) Start rotating in the desired direction
// 2) Start moving in the desired direction
// 1) Let' calculate rotation need to look at waypoint
// by simply comparing the desired waypoint & current transform
var rotation = Quaternion.LookRotation(nextWayPoint - transform.position);
// A slerp function allow us to slowly start rotating
// towards our next waypoint
transform.rotation = Quaternion.Slerp(transform.rotation, rotation,
Time.deltaTime * dampingLook);
// 2) Now also let's start moving towards our waypoint
character.Move(moveDirection.normalized * patrolSpeed * Time.deltaTime);
}
}
If it is a public variable it may not be represented in the editor as the change that you have made inside the script, try setting the patrol speed inside the editor.

HTML Canvas animate sequence images is slow on IPAD

I have built a script which takes a sequence of images and displays them on a canvas element in a animation loop.
This works really well on my desktop, but on IPAD (3 retina) it is very slow. Could you suggest any way to improve the performance?
var videoItts = 0;
function playVideo() {
if(videoItts < 92) {
setTimeout(function() {
ctx.clearRect(0,0,canvas.width,canvas.height)
ctx.drawImage(imagesL[videoItts],0,0,1024,636);
requestAnimationFrame(playVideo);
videoItts ++;
}, 1000/22)
}
}
requestAnimationFrame(playVideo);
The imagesL is an array of pre-loaded images.
I would suggest not mixing setTimeout and requestAnimationFrame. You can solve it using only requestAnimationFrame:
var startTime = Date.now();
var fps = 22;
var lastDrawnIndex = null;
var totalFrames = 92;
function drawVideo() {
var currTime = Date.now();
var currFrameIndex = Math.round((currTime - startTime) / (1000/fps)) % totalFrames;
// Since requestAnimationFrame usually fires at 60 fps,
// we only need to draw the image if the frame to draw
// actually has changed from last call to requestAnimationFrame
if (currFrameIndex !== lastDrawnIndex) {
ctx.drawImage(imagesL[videoItts],0,0,1024,636);
lastDrawnIndex = currFrameIndex;
}
requestAnimationFrame(drawVideo);
}
requestAnimationFrame(drawVideo);
The idea is that for every call to requestAnimationFrame we calculate, based on the elapsed time and the desired animation frame rate, which frame index to draw. If it's different from last calculated frame index we draw it. Then we schedule drawVideo to be called next animation frame by calling requestAnimationFrame(drawVideo) at the end.
The code above will loop frames 0-91 continously at 22 fps. I removed the ctx.clearRect call, it is only needed if the frames contains transparency. So you might want to add that back.

How can one force the browser to redraw an image?

I'm working on a JavaScript game that involves throwing a snowball. I need the snowball to render as often as possible during its flight path. Chrome does all the calculations, including setting the style.left and style.top properties, but doesn't actually redraw the snowball until it reaches its destination. Opera doesn't have this problem.
A relevant point is that putting in an alert() after renderSnowball() fixes the problem, except using the alert() is an obvious issue.
Here's my code so far:
function throwSnowball()
{
var theta = parseFloat(angleField.value) * Math.PI/180 ;
var Vir = parseFloat(velocityField.value) ;
if (!isNaN(Vir) && !isNaN(theta) )
{
Vix = Math.cos(theta) * Vir * 50;
Viy = Math.sin(theta) * Vir * 50;
time = new Date() ;
var timeThrown = time.getTime() ;
while (snowballPosY > 0)
{
current = new Date() ;
var currentTime = current.getTime() ;
var timeElapsed = (currentTime - timeThrown)/5000 ;
snowballPosX += Vix * timeElapsed;
snowballPosY += Viy * timeElapsed;
Viy -= GRAVITY * timeElapsed ;
renderSnowball() ; //renderSnowball() sets the style.left
// and style.top properties to snowballPosX pixels
// and snowballPosY pixels respectively
timeThrown = currentTime ;
}
snowballPosX = 0 ;
snowballPosY = 50 ;
renderSnowball() ;
}
}
You're totally blocking the main thread. Have you tried using a setTimeout (even with a zero timeout) to allow other things to happen during your animation?
If you're willing to use experimental technology, requestAnimationFrame would be even better.
Edit: the setTimeout approach would look something like this (replacing the while loop):
var drawAndWait = function() {
if (snowballPosY > 0) {
// movement/drawing code here
setTimeout(drawAndWait, 20 /* milliseconds */);
} else {
// reset code that would normally go after your while loop
}
};
drawAndWait();
So each time the drawing finishes, it arranges for itself to be invoked again, if appropriate. Note that your throwSnowball function will return quickly; the throwing isn't actually done until later on. This takes awhile to get used to doing correctly; don't be too concerned if it's not intuitive at first.
Try getting out of the tight loop. Chrome may not want to redraw until your function exits. Try using setInterval or setTimeout to give Chrome a chance to repaint.

How to make a real Javascript timer

I'm looking for a way to manipulate animation without using libraries
and as usual I make a setTimeout in another setTimout in order to smooth the UI
but I want to make a more accurate function to do it, so if I want to make a 50ms-per-piece
animation, and I type:
............
sum=0,
copy=(new Date()).getMilliseconds()
function change(){
var curTime=(new Date()).getMilliseconds(),
diff=(1000+(curTime-copy))%1000 //caculate the time between each setTimeout
console.log("diff time spam: ",diff)
sum+=diff
copy=curTime
var cur=parseInt(p.style.width)
if (sum<47){//ignore small error
//if time sum is less than 47,since we want a 50ms-per animation
// we wait to count the sum to more than the number
console.log("still wating: ",sum)
}
else{
//here the sum is bigger what we want,so make the UI change
console.log("------------runing: ",sum)
sum=0 //reset the sum to caculate the next diff
if(cur < 100)
{
p.style.width=++cur+"px"
}
else{
clearInterval(temp)
}
}
}
var temp=setInterval(change,10)
I don't know the core thought of my code is right,anyone get some ideas about how to make a more accurate timer in most browser?
Set the JsFiddle url:
http://jsfiddle.net/lanston/Vzdau/1/
Looks too complicated to me, use setInterval and one start date, like:
var start = +new Date();
var frame = -1;
var timer = setInterval(checkIfNewFrame, 20);
function checkIfNewFrame () {
var diff = +new Date() - start;
var f = Math.floor(diff / 50);
if (f > frame) {
// use one of these, depending on whether skip or animate lost frames
++frame; // in case you do not skip
frame = f; // in case you do skip
moveAnimation();
}
}
function moveAnimation () {
... do whatever you want, there is new frame, clear timer past last one
}

Categories