The logic of multiple travelling animations in javascript - javascript

I have an image of a bug. I want to make 5 copies of that image fly in from the side of the screen and bounce around the screen and bounce off the sides. I want them to all have different starting positions and different directions.
so I made some a global variables
var flyVar;
var flySpeed = 5;
var widthMax = 0;
var heightMax = 0;
var xPosition = 0;
var yPosition = 0;
var xDirection = "";
var yDirection = "";
var bugFly;
var count = 1;
var bug = "bug";
I have a function called setBugs() that I use to set the value of widthMax and heightMax depending on the size of the users screen.
I have a bugStartingPlace function to set the initial starting place for each bug. I won't post the whole function but it does the same for "bug1" through "bug5", giving them different values.
function bugStartingPlace(bugName) {
//Accepts string as argument and sets the starting position and starting direction of each bug.
if (bugName == "bug1") {
xPosition = 0;
yPosition = 100;
xDirection = "right";
yDirection = "up";
}
}
I have a function called flyBug() that does the animation and sets the position of the image. It consists of a bunch of statements like this. I know it works because I can make it work with 1 bug. The problem is doing it with 5 bugs.
function flyBug() {
if (xDirection == "right" && xPosition > (widthMax - document.getElementById("bugImage").width - flySpeed))
xDirection = "left";
<!--More flow control statements are here-->
document.getElementById("bug1").style.left = xPosition + "px";
document.getElementById("bug1").style.top = yPosition + "px";
<!-- More statements are here that set the position of the image -->
}
So, I need some way to get the animation going with the body onload() event. One problem is that setInterval does not allow functions that contain parameters. So I can't put multiple statements in the body onload event that pass "bug1" as a parameter to this function, "bug2" as a parameter to this function and so on. That's why I made the global count variable. That way, any time I need to change the name of the bug, I change the name of count and then do
bug = bug + count;
But that adds a lot of complexity. I need the name of the bug for the bugStartingPlace() function, so I need to change the value of count and also change the value of bug before I use that function. Once I use the bugStartingPlace() function, that changes the value of the global variables. Then I need to use flyBug() before I change the value of bug again.
I guess one of the problems is that I'm using global variables for direction and position even though I have multiple bugs. It works fine for one bug but not for multiple bugs.
Can anyone give me tips on how the logic of this program should work?

setInterval allows, like setTimeout, the use of parameters in the function BUT:
setInterval(funcName(param1,param2...), 100);
wont work. Youll get it to work like that:
var func = function () { funcName(param1,param2..); }
setInterval(func, 100);
To understand that part of javascript, read through dougles crockfords explanation of functions, he tells about this very clear and deep. Link to a video of him
EDIT: Sry i understood your question wrong...
The problem why it wont work is, like you figured out the global vars. You could just make bug an object. His actions will then be methods, which can contain a function and so on. If you then initialize a new bug (you can do this a thousand times then), all the vars stay in the object, without conflicting each other. This is a secure way to provide solidness of your code.
You could do it very simple, with nested functions.
Another way would be, to send the name of the bug vie parameter to the, for example, fly function. And the only work in that function with the parameter given to it.

Related

how to use the 'map' function using Brackets and p5.js?

I'm currently taking a course on intro to computer programming. It's an online course and doesn't have much help when you're stuck.
I'm using Brackets and p5.js.
I unfortunately don't know how to use the map function, I've tried different possibilities, but so far I haven't been able to solve the question below:
When the mouse button is pressed:
- Use the 'random' function to produce random values ranging from 2 to 14.
- Assign the output to Secure_vault_key0
When the mouse button is released:
- Use the 'random' function to produce random values ranging from 2 to 8.
- Assign the output to Secure_vault_key1
When any key is pressed:
- Make Secure_vault_key2 equal to the value of 'key'
When the mouse button is pressed:
- Use the 'map' function to scale mouseX to values ranging from 14 to 77.
- Assign the output to Secure_vault_key3
When the mouse button is pressed:
- Use the 'map' function to scale mouseY to values ranging from 22 to 76.
- Assign the output to Secure_vault_key4
Whilst the mouse is being dragged:
- Use the 'map' function to scale mouseX to values ranging from 14 to 80.
- Assign the output to Secure_vault_key5
This time you'll need to create the relevant event handlers yourself.
There are many possible ways of investigating this case, but you
should use ONLY the following commands:
- The assignment operator aka. the equals sign !
- mouseX, mouseY
- key, keyCode
- random
- map
*/
//declare the variables
var Secure_vault_key0;
var Secure_vault_key1;
var Secure_vault_key2;
var Secure_vault_key3;
var Secure_vault_key4;
var Secure_vault_key5;
function preload()
{
//IMAGES WILL BE LOADED HERE
}
function setup()
{
createCanvas(512,512);
//initialise the variables
Secure_vault_key0 = 0;
Secure_vault_key1 = "";
Secure_vault_key2 = "";
Secure_vault_key3 = 0;
Secure_vault_key4 = 0;
Secure_vault_key5 = 0;
}
///////////////////EVENT HANDLERS///////////////////
//Create event handlers here to open the safe ...
function mouseDragged()
{
console.log("mouseDragged", mouseX, mouseY);
Secure_vault_key5 = map(mouseX, 14, 80);
}
function mousePressed()
{
console.log("mousePressed");
Secure_vault_key0 = random(2,14);
Secure_vault_key3 = map(mouseX, 14, 76);
}
function keyPressed()
{
console.log("keyPressed");
Secure_vault_key2 = key;
}
function mouseRealesed()
{
console.log("mouseReleased");
Secure_vault_key1 = random(2,8);
}
///////////////DO NOT CHANGE CODE BELOW THIS POINT///////////////////
Check out the p5.js reference page for map() : https://p5js.org/reference/#/p5/map
It looks like you're only using three parameters in your map functions, and it requires five (with an optional sixth parameter). The five necessary parameters are as follows (in this order):
variable you want to map the value of (in your case mouseX)
the current minimum of that value (if you're working with mouseX, you most likely want to use zero)
the current maximum of that value (again, if you're working with mouseX, you probably want to use the width of your canvas here, which you can do using the built in width variable or hardcoding in the value)
the new minimum value you want to be stored in one of your Secure_vault variables
the new maximum value you want
It might seem silly or redundant that you need to specify the current maximum and minimum of a built-in variable like mouseX, but it's just one of those programming things where the computer demands as much explicit instruction as possible in order to properly execute your instructions.
Look at the second example on the reference page linked above for a good example of using the map() function with mouseX. And if you're going to be working in p5.js beyond this project these reference pages are a really great place to look for answers to all kinds of questions!
update!! I just corrected in below code. use height and width
/*oh I also met such issues, I know I have to define five arguments, I just can't understand what the second and third arguments should be, I wrote 0,mouseY/X, but it's not correct.
only SecretStoreCombination0 is correct, I've used up the chances today, I will try tomorrow!*/
function keyReleased(){
SecretStoreCombination0 = random()*10+1;
SecretStoreCombination2 = key;
}
function mouseReleased(){
SecretStoreCombination1 = map(mouseY,0,height,3,13);
SecretStoreCombination4 = map(mouseY,0,height,20,79);
}
function mousePressed(){
SecretStoreCombination3= map(mouseX,0,width,6,69);
SecretStoreCombination5= map(mouseY,0,height,16,73);
}

Optimize animation with javascript assigning value

I am building an animation with lots of effects and animation in a website. I am trying to optimize the efficiency of those animations since some of them are a little complex to low CPU/RAM devices. The animations are not smooth as I want as you can see here https://www.empresasite.com.br
So I realize in many parts of my code I do this:
var x = 38; //this value changes every 50ms
document.getElementById("a").style.left = document.getElementById("b").style.left = document.getElementById("c").style.left = document.getElementById("d").style.left = document.getElementById("e").style.left = x + "px";
Actually it's a simplification above, I run the code above with at least 13 elements a = b = c = d .... m = x; and at least with 4 properties (left, height, box-shadow and background-color).
So I was wondering if there is any better alternative to assign the same value to multiple elements/objects at once?
Maybe the code below would be faster? I used it but I didnt see a significant improvement in animation, maybe I should have seen it?
var x = 38;
x = x + "px";
document.getElementById("a").style.left = x;
document.getElementById("b").style.left = x;
document.getElementById("c").style.left = x;
document.getElementById("d").style.left = x;
document.getElementById("e").style.left = x;
I think the code above should be faster right? I say this cause every element updates its own property (left) retrieving the value from "x". In the first example I gave MAYBE javascript is assigning the value of the previous element in the chain of "=" sign so it has to assign "x" to the first element then assign the value of the first element to the second... go on.
Do you know exactly what jquery does when I use this:
$(".elements").css({left:x});
Does it use some optimization?
You could increase performance no-end by using translate instead of modifying position.
Using the jQuery variation you asked will not make any difference, as you are still modifying position left.
After playing around with most of the javascript benchmarking tools online I came up to this conclusion:
1) Jquery is the faster method of all native js solutions I used. Maybe Jquery uses some sort of optimization when you apply the same property to lots of elements at once! So you should rely on $(".class").css("left",x) to apply the x value to left property for hundreds of elements and it will be the faster solution;
2) The second solution is apply x individually TO EACH element. Example:
var x = 38;
document.getElementById("a").style.left = x;
document.getElementById("b").style.left = x;
3) The worst solution was actually the one I was using in the website that I was facing not smooth animations. So avoid this:
document.getElementById("a").style.left = document.getElementById("b").style.left = ... = ... = x;
The difference from the 1st solution to the 3rd is really noticeable. You can check it in the links below (pay special attention to the animation at the top):
1) https://www.empresasite.com.br/?q=principal&before -> this is using the 3rd solution
2) https://www.empresasite.com.br/?q=principal -> this is using the 1st solution
In a computer with lots of resources you may not see a difference but if you run this in a computer with 4GB of RAM or less you will see a big impact!
Hope this helps anyone that does not have smooth animations!

How do I use the AddForce function? It won't work

I don't know why the sprite wont jump... I want to use AddForce() instead of directly changing the velocity.
var trump;
function Start() {
// Assigns the Rigidbody to a variable
trump = GetComponent(Rigidbody2D);
// Variable Switches:
}
function FixedUpdate() {
GetComponent.<Rigidbody2D>().velocity.x = Input.GetAxis("Horizontal") * 10;
if (Input.GetKeyDown(KeyCode.UpArrow)) {
GetComponent.<Rigidbody2D>().AddForce(Vector2(0, 10));
}
}
instead of
GetComponent.<Rigidbody2D>().AddForce(Vector2(0, 10));
try this
GetComponent.<Rigidbody2D>().AddForce(Vector2.up * 10);
Hope this works
Try this:
GetComponent.<Rigidbody2D>().AddForce(Vector2(0, 10), ForceMode2D.Impulse);
This will launch him into the air in an instant. I believe the problem is that you're using ForceMode2D.Force (by default), which expects to be called multiple times over several ticks. For example, ForceMode2D.Force could be used to stay on when pushing an object like a car forward.
You may consider changing this function in the future to provide smoother jumping. One good method would be applying force according to a sin function period.

Multiple simultanous animations, simulation of 'animate' easing and one 'step' call for a jQuery collection

Here is the problem, I've got a tree structure of html blocks, global container is of a fixed width(X) and height(Y). When i click one of the blocks on a level, all other blocks shrink to some size, while the clicked one gets enlarged to the leftover space, and the sublevels show up on it's place.
For all the shrinking i'm using default animate function with easing effect, when shrinking 1 level, to avoid enlargement bugs i have to do something like this:
$tabs.not($obj).animate({height:32<<$obj.getVerUp().length+"px"},{duration:300,
step:function() {
$obj.height(function(){
var sum = 0;
$tabs.not($obj).each(function(){
sum += $(this).height();
});
return $obj.getCont().height()-sum+"px";
});
}
});
$tabs are all the tabs of current level, $obj - is the one tab that i want to enlarge
The main problem is:
When i open up a tab that is on a deep level, i have to animate all the tabs of higher levels to shrink a little bit more, thus the $obj X and Y would change, so the current animation has to use new values, but if i call 3 different animations on different levels i'm bound to get a bug, when one of the animations on a deeper level finishes 1 step earlier, while the one on the level above, would enlarge the object by 5-10 more pixels and that space wouldn't be used up.
The second problem is that there has to be about 50 object animating with easing at the same time, which is a little bit overkill.
And the last problem is when i call step callback on animation as shown above, i have a strange feeling that it calls the step separately for each animation of the $tabs collection, while i need 1 step for all the tabs in the list (to avoid unnecessary scripts)
There might be some other way to fix all that, but i have yet to discover all jQuery functions, so from what i see the only way is to simulate easing, and do everything in one single animation.
I don't really want to use setInterval and determining when do i need to clear it plus calculating each of the easing values, if there is a simple way doing it.
Does jQuery has some sort of empty animation easing, e.g.
$().css("height":starth+"px").animate({height:endh},{duration:300,
step:function(fn) {
// all the animation actions here via fn end value
}
});
Thanks in advance.
What I need - is not a completely working solution in code, just some enlightenment in those subjects:
Is there a legal way to call one step function for a collection of animated elements, or, maybe, it does call step once when I use one .animate on collection.
I'd be really appreciated if someone would shed some light over how does jquery handle multiple .animate, would they be used in one global function that works on .setInterval? or would they be having massive number of those .setIntervals that are equivalent to setTimeout (which most browsers can't handle in large amounts);
Is there a way to simulate 'animate' easing, some function name maybe, or a special trick to achieve that (the only thing I see is a hidden element or 'window' property to change maybe)
Or some directed pushes with functions I should study, that could help me achieve my goals
Guess i pretty much found the answer to my questions:
http://james.padolsey.com/javascript/fun-with-jquerys-animate/
Here's the empty animation from the link above with 1 step function with desired values, going to post the result later on if it all works out.
var from = {property: 0};
var to = {property: 100};
jQuery(from).animate(to, {
duration: 100,
step: function() {
console.log( 'Currently # ' + this.property );
}
});
Yes it all worked great, no desynch, and a good speed, since only 1 animate, found making one universal function for the animation - waste of resourses, so it is pretty specific, but still, here it is:
animate: function($obj) {
var T = this;
...
T.arr = new Array();
// gathering the array
$obj.each(function(i){
var size;
T.arr[i] = {obj:$(this), rest:$(this).getSibl(), cont:$(this).getCont()}
if($(this).hasClass("vert"))
{
size = "height";
T.arr[i].to = yto;
}
else
{
size = "width";
T.arr[i].to = xto;
T.arr[i].children = $(this).getChld();
}
T.arr[i].rest.each(function(){
$(this).attr("from",$(this)[size]());
});
});
// animating prop
jQuery({prop:0}).animate({prop:1}, {
duration: 300,
step: function() {
var i;
var P = this;
var newval;
var sum;
var size;
for(i = 0; i < T.arr.length; i++)
{
size = T.arr[i].obj.hasClass("vert") ? "height":"width";
sum = 0;
T.arr[i].rest.each(function(){
// new value of width/height, determined by the animation percentage
newval = parseInt($(this).attr("from")) + (T.arr[i].to-$(this).attr("from"))*P.prop;
$(this)[size](newval);
sum += newval;
});
T.arr[i].obj[size](T.arr[i].cont[size]()-sum);
}
}
});
},

Why does my my gravity work in this?

http://davzy.com/gameA/
I can't figure out a smart way to get gravity. Now with this it detects which block the character is over but it does't drop to that block!
Is there a better way to do gravity? I'd like to do this without a game library.
I don't know what you mean by "get gravity"; your question is unclear. I assume that if you can detect when the block is over, you can use the following formula:
s(t) = ut + 1/2at2
Where s is the distance at time t, u is the initial velocity (which in your case would be zero), and a is the acceleration (on Earth this is 9.8m/s2). Essentially you would be adjusting the top position of your object based on the value you get at time t (so original top position of object + s(t)). I would imagine you would use some sort of animation loop. Perhaps a setInterval. Maybe others with more experience in Javascript animation can chime in about the best way to implement this. However, this would be the formula that you would be using to figure out where the object is at time t, if it falls.
Basically gravity in a platformer goes like this:
var currentGrav = 0.0;
var gravAdd = 0.5; // add this every iteration of the game loop to currentGrav
var maxGrav = 4.0; // this caps currentGrav
var charPosY = getCharPosY(); // vertical position of the character, in this case the lower end
var colPosY = getColDow(); // some way to get the vertical position of the next "collision"
for(var i = 0; i < Math.abs(Math.ceil(currentGrav)); i++) { // make sure we have "full pixel" values
if (charPosY == colPosY) {
onGround = true;
break; // we hit the ground
}
onGround = false;
charPosY++;
}
Now to jump one could simply do this:
if (jumpKeyPressed && onGround) {
currentGrav = -5.0; //
}
You can, if you want(and understand C), check out my game for a basic platformer(with moving platforms) here:
http://github.com/BonsaiDen/Norum/blob/master/sources/character.c

Categories

Resources