Basic canvas collision not working in for loops - javascript

I'm encountering a collision issue that I can't quite figure out. The point of my program is to generate a random number of circles (between 2 and 15) with random velocities in a bounding box that is 1920x900. If they touch each other, they're supposed to fly off in opposite directions (not great physics, I know, but that'll come later.)
To do this, I've got four arrays: two for the coordinates of the circles (xcords[] and ycords[], and two for the momentum of each circle (xdirs[] and ydirs[]).
Here's my collision function
function collides(x, y)
{
if(Math.hypot(xcords[y]-xcords[x], ycords[y]-ycords[x]) < 50)
{
return true;
}
else return false;
}
When I hardcode certain values, such as
if(collides(xcords[1],xcords[0])
{
xdirs[0] *= -1;
xdirs[1] *= -1;
ydirs[0] *= -1;
ydirs[1] *= -1;
}
then it works fine. The two circles I hardcode will collide correctly. But when I try to apply this to every circle:
for(i=0; i<circles; i++)
{
for(j=0; j<circles; j++)
{
if(collides(xcords[i], xcords[j]))
{
xdirs[i] *= -1;
xdirs[j] *= -1;
ydirs[i] *= -1;
ydirs[j] *= -1;
}
}
}
Then the circles just ignore each other, and I have no idea why. This is the only time I use a double for loop in this code, but I do the first for loop multiple times, and it handles it correctly for every other function.
Here's a jsfiddle for it. https://jsfiddle.net/sekbr0pg/
The bounding box is a little off, but it's enough to see that the collision is wonky.

Let's take circle 1 and circle 2. You want to check whether they collide or not only once. Is the following loop good for that?
for(i=0; i<circles; i++) {
for(j=0; j<circles; j++){
// if collides ...
}
}
Answer is no, and the reason is that they will run twice, for i=1 and j=2 and i=2 and j=1. So basically it won't change anything since -1*-1 = 1. In your loop change j=0 to j=i+1.
Also your collides function accept circles, so I think collides(i,j) will do the job.

Related

Collision detection is not returning inside limits

Full code here
I am trying to setup the functions to detect collisions and for now just log to the console. This is the section for checkCollision function;
Player.prototype.update = function(dt) {
checkCollision(this.leftLimit, this.rightLimit);
this.leftLimit = this.x - 40.5;
this.rightLimit = this.x + 40.5;
}
function checkCollision(playerl,playerr) {
for (var i = 0; i < 5; i++) {
var thisEnemy = allEnemies[i];
if (thisEnemy.leftlimit > playerl && thisEnemy.rightLimit < playerr) {console.log("1")}
else {console.log('else')}
}
}
Question
The character is never registering as colliding with the enemy, why is this not working?
Testing/Debugging
I know this function is working as consoles logging else, I've also put logging in other locations and when in the Enemy.prototype.update function, console was showing values like 202.000000093, since the for..else function is using < or >, not absolute values, that should be fine, but still nothing is matching inside the player left and right limits. I also tried changing the Enemy limits to be smaller, +/- 40.5, incase the enemy was too wide to fit inside the player limits.
player.leftLimit and player.rightLimit are undefined when checkCollision method is first running
I added a better if statement to check if there's a collision;
if (
thisEnemy.leftLimit < player.rightLimit &&
thisEnemy.rightLimit > player.leftLimit &&
thisEnemy.upperLimit > player.lowerLimit &&
thisEnemy.lowerLimit < player.upperLimit) {
console.log("collision");
}

Issue with moving a mesh in Babylon.js

I'm attempting to make a Red Alert style game, just to sharpen my JS skills , and get a basic understanding of game development. I'm attempting to move a block mesh from one part of the ground to another. However, it moves the block instantly, instead of animating it.
Here's my babylonjs-playground...
http://www.babylonjs-playground.com/#OYE6Q
I think the issue's with this block of code...
var moveUnit = function (position, item) {
if (position.x > 0) {
while (item.position.x < position.x) {
item.position.x += 0.001;
}
} else {
while (item.position.x > position.x) {
item.position.x -= 0.001;
}
}
if (position.z > 0) {
while (item.position.z < position.z) {
item.position.z += 0.001;
}
} else {
while (item.position.z > position.z) {
item.position.z -= 0.001;
}
}
}
while (item.position.x < position.x) {
item.position.x += 0.001;
}
By using the while loop, your are updating position to the final position in increments within the same frame of the game. It is equivalent to saying:
item.position.x = position.x;
Because of this, you see it jump from its initial position to its final position from one frame to the next; regardless of how you update the position.
If you want to simulate movement over time, you need to move the object in increments toward it's goal over multiple frames. If the increments are chosen correctly, and the frames are fast enough, it will look like smooth movement.
To accomplish this, objects need to have some idea of where they are moving across frames, and you need to introduce the concept of time into your game.
Take a look at this tutorial for an example of the concept.
BABYLON.js has a built in animate function, which handles time constraints for meshes automatically. Here's a link to a working example!
http://www.babylonjs-playground.com/#OYE6Q#4

Tooltips for data in javascript using p5.js

I am trying to make tooltips for a data visualization I made using p5.js but I am completely lost. Nothing I tried works. This is my code as is.
var table;
var i;
var j;
var cellValue;
var label;
var test;
function preload() {
matrix = loadTable("dataLayer2matrix.csv","csv")
labels = loadTable("dataLayer2labels.csv","csv")
test = matrix
}
function setup() {
createCanvas(1500,1500)
noStroke()
fill(0,0,255,10)
angleMode(DEGREES)
background(255,255,255)
matrixStartX = 200
matrixStartY = 250
var matrixRows = matrix.getRows()
var matrixSize = matrixRows.length
// Experiment with grid
fill(75, 75, 75, 50)
for (r = 0; r <= matrixSize; r++) {
rect(matrixStartX , matrixStartY + r * 20 - 1 , 20 * matrixSize, 1)
rect(matrixStartX + r * 20 - 1 , matrixStartY, 1, 20 * matrixSize)
}
// Draw matrix
for (var mr = 0; mr < matrixSize; mr++) {
for (var mc = 0; mc < matrixSize; mc++) {
cellValue = matrixRows[mr].getNum(mc)
fill(49,130,189,cellValue*10)
rect(mc * 20 + matrixStartX, mr * 20 + matrixStartY, 19 ,19)
}
}
// Labels - horizontal
fill(75, 75, 75, 255)
labelsRow = labels.getRows()
for (mc = 0; mc < matrixSize; mc++) {
label = labelsRow[0].getString(mc)
text(label, 10, mc*20+matrixStartY + 15)
}
// Labels - vertical
push()
translate(matrixStartX + 15, matrixStartY - 15)
rotate(-90)
for (mc = 0; mc < matrixSize; mc++) {
label = labelsRow[0].getString(mc)
text(label, 0, mc*20)
}
pop()
//Tooltip when clicked
}
/* if(mouseIsPressed){
fill(50);
text(cellValue, 10,10,70,80);
}*/
}
}
It makes this image:
I want it so that when I go over a square I get the data in it. I really can't seem to do it. Thanks.
I think the advice telling you to use bootstrap is missing the fact that you're using p5.js. Bootstrap is more for dealing with html components, not internal Processing sketches.
Instead, you probably want to do this with p5.js code. The best thing you can do is break your problem down into smaller steps:
Step 1: Can you draw a single rectangle?
Instead of trying to add this new functionality to your existing sketch, it might be easier if you start with a simpler example sketch with just a single rectangle.
Step 2: Can you detect when the mouse is inside that rectangle?
If you know where you're drawing the rectangle, you know its coordinates. You also know the coordinates of the mouse from the mouseX and mouseY variables. So to detect whether the mouse is inside the rectangle, you simply have to use if statements that compare the coordinates of the mouse to the coordinates of the rectangle. There are a ton of resources on google for this, and it might help if you draw some examples out on a piece of paper.
Also, don't worry about the tooltip just yet. Just do something simple like change the color of the rectangle when the mouse is inside it.
Step 3: Can you display the information box?
Again, do this in its own sketch first. Maybe create a function that takes a position and the information you want to display as parameters and displays it in a rectangle. Don't worry about making it a tooltip yet. Just get it displaying. Use hard-coded values for the information.
Step 4: Can you combine your small example sketches?
You have code that triggers when the mouse is inside a rectangle. You have code that draws the tooltip. Can you make it so the tooltip is drawn when the mouse is inside the rectangle?
Step 5: Only when all of the above works, then you should start thinking about adding it to your full sketch.
Instead of using an example rectangle, you'll have to use the rectangles you're drawing on the screen. Instead of calling the tooltip function with hard-coded values, use the values you get from the squares.
Take on those pieces one at a time, and make small steps toward your goal. Then if you get stuck, you can post an MCVE of the specific step you're on. Good luck!

Collision detection simple snake game

Together with a friend of mine we are creating a multiplayer snake game. We are both beginners with JavaScript, so it is a real challenge for us.
So far I've managed to create this:
http://jsfiddle.net/tbmluijten/RG76t/3/
This is the collision detection code I have so far:
Snake.prototype.collision = function (x, y, array) {
for(var i = 0; i < Snake.length; i++){
if(Snake.pieces[0].x == x && Snake.pieces[0].y == y)
return true;
}
return false;
};
The problem I have is the collision with the snake itself. I can't figure out what I am doing wrong. Note that I am looking for collision with the snake itself not with the borders since we are going to put a loop into that. :-)
The short answer is - you are not checking for collision at all!
The working collision: http://jsfiddle.net/RG76t/10/
Explanation:
At first you need to put the collision method in the game loop function.
// line 32
if (game.snakes.length !== 0) {
for (i = 0; i < game.snakes.length; i++) {
var s = game.snakes[i];
s.paint(ctx, game);
// Check for collision.
if (s.collision()) {
// Do something, if the collision happens.
alert('collision');
}
}
}
Then in the collision method check if the first piece collides with any other. The loop starts from the 4th piece, since the snake's head can't really touch it's "neck" (2nd and 3rd pieces).
Snake.prototype.collision = function () {
// Loop the snake pieces from the 4th one.
for(var i = 3; i < this.length; i++){
// Check if this piece collides with the first piece.
if(
this.pieces[0].x === this.pieces[i].x &&
this.pieces[0].y === this.pieces[i].y
) {
return true; // collision
}
}
return false;
};
Also notice that Snake.length and Snake.pieces[i] are changed to this.length and this.pieces[i]. The keyword this refers to the instance of a Snake on which you invoke the collision method. When you were using Snake in this piece of code, you were checking the properties of a constructor.

How to speed up this moving algorithm? In Javascript

I have an Array of 16 billiard balls in JS and want to move each ball smoothly with its direction and speed.
For that I set up a timer, calling UpdateThis() every 42ms (for 24 fps).
The problem is that UpdateThis() takes 53ms as firebug states.
Now UpdateThis iterates over every ball and calls UpdateBall(ball).
I assume that the problem lies there.UpdateBall looks like this:
function UpdateBall(ball)
{
if(ball.direction.x != 0 && ball.direction.y != 0) {
//ball moving!
for(var i = 0; i < balls.length; i++) {
//CheckCollision(ball, balls[i]); //even without this it takes 53 ms!
}
var ps = VAdd(ball.position, VMul(ball.direction, ball.speed)); //Multiply Direction with speed and add to position!
if(ps.x < Bx || ps.y < By || ps.x > Bw || ps.y > Bh) { //Bounce off the wall!
ball.direction = VMul(ball.direction, -1); //Invert direction
ball.speed *= 1;
ps = VAdd(ball.position, VMul(ball.direction, ball.speed)); //Calc new position!
}
ball.position = ps;
ball.MoveTo(); //See explanation at the bottom.
ball.speed *= GRK; //Gravity
if(ball.speed < 0.05) {
ball.speed = 0;
}
}
}
it seems that the most time is spent in ball.MoveTo() which looks like this:
function()
{
this.image.style.left = this.position.x + "px";
this.image.style.top = this.position.y + "px";
}
-- UPDATE --
function UpdateThis() {
for(var i = 0; i < balls.length; i++) {
var cur = balls[i];
UpdateBall(cur);
balls[i] = cur;
}
}
and onload looks like
nx = setInterval(function() { UpdateThis(); }, 42);
Does somebody have any ideas on how to speed this up?
-- UPDATE 2 --
You can download the folder with the HTML file here (the password is password)
What about separating the position updates from the drawing? So have something like this (untested code):
function DrawBall(ball)
{
ball.MoveTo(); //Take this line out of UpdateBall
}
-
function UpdateThis() {
for(var i = 0; i < balls.length; i++) {
var cur = balls[i];
UpdateBall(cur);
balls[i] = cur;
}
}
-
function DrawThis() {
for(var i = 0; i < balls.length; i++) {
DrawBall(balls[i]);
}
setTimeout(function() { DrawThis(); }, 42);
}
-
nx = setInterval(function() { UpdateThis(); }, 42);
setTimeout(function() { DrawThis(); }, 42);
If indeed it's the moving of the position that's slow, this way the logic update still happens at 42ms, and the framerate is no faster than 42ms but it can skip frames. (I haven't actually tried this, so this is all theoretical and you may need to tweak some stuff)
Why moving may be (and most probably is) slow?
Move functionality could be slow, because it has more things to do than simple variable assignment. It has to actually render some element to some other place. You could test this if you run this on IE9. I anticipate it should run faster since it uses hardware video acceleration.
As for the other routine I hope others will dissect it. :)
Questions for you
Can you please describe how do balls move? Sporadically? How do you call UpdateBall() for each ball? Do you queue those calls?
Provide VMul and VAdd functionality
Have you played with styling? Maybe relative positioning of balls' immediate parent may speed up rendering. And setting overflow:hidden on it as well. I don't know. Depends on how you've done it. Hence a JSFiddle would be very helpful.
A suggestion
Instead of using setInterval to call your function you should maybe just queue them and let them execute as fast as it gets. And just for the sake of it, provide a central setInterval with some watcher that they don't run too fast.
But I guess that it still utilizes your processor to 100% which isn't good anyway.
Very important note: Don't run you app while Firebug's enabled because it's a well known fact that Javascript executes much slower when Firebug is running.
That's tough, if MoveTo() is in fact your bottleneck, since there is not a whole lot going on there. About the only things I can think of, right off hand, are
1) Cache the style property of the image and position for faster lookups. Everytime you see a dot in the object chain it's requires stepping through the scope chain. Ideally you can cache this property at the time the parent of MoveTo() is constructed.
2) Are the 'px' strings required? It may result in an invalid CSS specification, but it may still work. I have a hard time believing 2 string concats would really change all that much though.
The main problem here is likely the fact that anytime you change the DOM, the browsers re-flows the entire page. Your only other option may be to refactor such that instead of changing the styles, you actually remove the previous contents, and replace it with the a document fragment describing the new state. This would result in only 2 re-flows for the entire step (1 for removal, 1 for addition), instead of 2 for each ball.
EDIT: Regarding #1 above, when I say cache, I don't mean just locally in the function call. But perhaps as a closure in the parent object. For example:
var Ball = function(img){
var style = img.style;
var posX;
var posY;
function MoveTo(){
style.left = posX + "px";
style.right = posY + "px";
}
};

Categories