Can't detect collision in 3D JavaScript - javascript

I am using three.js to make a simulation of the Brownian Motion and I'm stuck on a part where I need to get the little molecules to collide against each other. This is what I have so far:
function intersects(sphere, other){ //check if the distance between one sphere and the other is less than radius of both (4)
var distance = Math.sqrt((sphere.position.x - other.position.x) * (sphere.position.x - other.position.x) +
(sphere.position.y - other.position.y) * (sphere.position.y - other.position.y) +
(sphere.position.z - other.position.z) * (sphere.position.z - other.position.z));
if(distance < (4)){
return true;
} else {
return false;
}
}
function checkCollision(current){
for(var i = 0; i < balls.length; i++) {
if(intersects(balls[current], balls[i]) == true){
// balls[current].velocity.negate();
alert('hey');
}
}
}
When I run the code, I know for certain that the balls don't collide/intersect with each other, however I continuously get an alert box. I've tried to check if it's less than (sphere.radius + other.radius) but I don't think that's correct since it didn't seem to work. Also when I do keep it '< 4', it messes up the performance and it starts to run slowly at around 5 fps or less. checkCollision gets used here during the animation, so basically it checks it every time.
function animate(){
for(var i = 0; i < balls.length; i++){
balls[i].position.add(balls[i].velocity);
checkWallBoundaries(i);
checkCollision(i);
}
THREEx.WindowResize(renderer, camera);
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
stats.update();
}
I don't know why I can't get this to work. If someone could help me, that'd be greatly appreciated.
edit: Here's a picture of what happens when I uncomment the balls[current].velocity.negate() line https://puu.sh/uG1eS.png. The balls keep going back and forth but they're not even remotely close to each other, so I don't know why collision is being detected

Every ball collides with itself. You need to exclude i === current
for(var i = 0; i < balls.length; i++) {
if(current === i) continue;
if(intersects(balls[current], balls[i]) == true){
alert('hey');
}
}

Related

JavaScript game starts fast and slows down over time

My simple JavaScript game is a Space Invaders clone.
I am using the p5.js client-side library.
I have tried many things to attempt at speeding up the game.
It start off fast, and then over time it get slower, and slower, it isn't as enjoyable.
I do not mean to show every bit of code I have. I am not showing every class, but I will show the main class where everything is happening.
Could someone eyeball this and tell me if you see anything major?
I am new to JS and new to making games, I know there is something called update()
that people use in scripting but I am not familiar with it.
Thank you.
var ship;
var flowers = []; // flowers === aliens
var drops = [];
var drops2 = [];
function setup() {
createCanvas(600, 600);
ship = new Ship();
for (var i = 0; i < 6; i ++) {
flowers[i] = new Flower(i * 80 + 80, 60);
}
flower = new Flower();
}
function draw() {
background(51);
ship.show();
ship.move();
shipDrops();
alienDrops();
dropsAndAliens();
dropDelete();
drop2Delete();
}
// if 0 drops, show and move none, if 5, etc..
function shipDrops() {
for (var i = 0; i < drops.length; i ++) {
drops[i].show();
drops[i].move();
for (var j = 0; j < flowers.length; j++) {
if(drops[i].hits(flowers[j]) ) {
flowers[j].shrink();
if (flowers[j].r === 0) {
flowers[j].destroy();
}
// get rid of drops after it encounters ship
drops[i].evaporate();
}
if(flowers[j].toDelete) {
// if this drop remove, use splice function to splice out of array
flowers.splice(j, 1); // splice out i, at 1
}
}
}
}
function alienDrops() {
// below is for alien/flower fire drops 2
for (var i = 0; i < drops2.length; i ++) {
drops2[i].show();
drops2[i].move();
if(drops2[i].hits(ship) ) {
ship.shrink();
drops2[i].evaporate(); // must evap after shrink
ship.destroy();
if (ship.toDelete) {
delete ship.x;
delete ship.y;
} // above is in progress, deletes after ten hits?
}
}
}
function dropsAndAliens() {
var randomNumber; // for aliens to shoot
var edge = false;
// loop to show multiple flowers
for (var i = 0; i < flowers.length; i ++) {
flowers[i].show();
flowers[i].move();
// ******************************************
randomNumber = Math.floor(Math.random() * (100) );
if(randomNumber === 5) {
var drop2 = new Drop2(flowers[i].x, flowers[i].y, flowers[i].r);
drops2.push(drop2);
}
//**************** above aliens shooting
// below could be method, this will ensure the flowers dont
//go offscreen and they move
//makes whtever flower hits this space become the farther most
//right flower,
if (flowers[i].x > width || flowers[i]. x < 0 ) {
edge = true;
}
}
// so if right is true, loop thru them all again and reset x
if (edge) {
for (var i = 0; i < flowers.length; i ++) {
// if any flower hits edge, all will shift down
// and start moving to the left
flowers[i].shiftDown();
}
}
}
function dropDelete() {
for (var i = drops.length - 1; i >= 0; i--) {
if(drops[i].toDelete) {
// if this drop remove, use splice function to splice out of array
drops.splice(i, 1); // splice out i, at 1
}
}
}
function drop2Delete() {
for (var i = drops2.length - 1; i >= 0; i--) {
if(drops2[i].toDelete) {
// if this drop remove, use splice function to splice out of array
drops2.splice(i, 1); // splice out i, at 1
}
}
}
function keyReleased() {
if (key != ' ') {
ship.setDir(0); // when i lift the key, stop moving
}
}
function keyPressed() {
// event triggered when user presses key, check keycode
if(key === ' ') {
var drop = new Drop(ship.x, height); // start ship x and bottom of screen
drops.push(drop); // when user hits space, add this event to array
}
if (keyCode === RIGHT_ARROW) {
// +1 move right
ship.setDir(1);
} else if (keyCode === LEFT_ARROW) {
// -1 move left
ship.setDir(-1);
} // setir only when pressing key, want continuous movement
}
Please post a MCVE instead of a disconnected snippet that we can't run. Note that this should not be your entire project. It should be a small example sketch that just shows the problem without any extra code.
But to figure out what's going on, you need to debug your program. You need to find out stuff like this:
What is the length of every array? Are they continuously growing over time?
What is the actual framerate? Is the framerate dropping, or does it just appear to be slower?
At what point does it become slower? Try hard-coding different values to see what's going on.
Please note that I'm not asking you to tell me the answers to these questions. These are the questions you need to be asking yourself. (In fact, you should have all of these answers before you post a question on Stack Overflow!)
If you still can't figure it out, then please post a MCVE in a new question post and we'll go from there. Good luck.

Moving a player in tilemaps

I am using vanilla tilemaps, I am not sure if there is software out there related to tilemaps, but if there is be assured I am just using plain javascript, I have an issue though, I want to move the x of a player when a button is pressed, but it doesn't move, the player is green, and is identified by the number 4 on the tilemap.
it registers that I press the button(in console), but doesn't move the player at all, can anyone point out the issue? look at lines 62-89, thats where the error mostly occurs except for some global variables.
here's a link to the jsfiddle, I used this because I needed to show that the blocks don't move.
http://jsfiddle.net/8jr2ha3h/
var playerY = 0;
var playerX = 0;
var moveLeft = 65;
var moveRight = -65;
//THE PLAYER
player.onload = function(){
for(var i = 0; i < mapArray.length; i++){
for(var j = 0; j < mapArray[i].length; j++){
if(mapArray[i][j]==4){
context.drawImage(player, playerX, playerY, 45,37);
}
playerX+=45;
}
playerX = 0;
playerY +=37;
}
};
//KEY FUNCTIONS
document.onkeydown = function(e) {
//identifying that it's a window event.
e = e || window.event;
switch(e.which || e.keyCode) {
//37 is key for left arrow.
case 37:
{
playerX = playerX - moveLeft;
console.log(playerX);
console.log('left');
}
break;
}
}
Seems as though you're only drawing the player in player.onload(). You'll likely want to have all the rendering code in a single render() function, and possibly call that in player.onload() and then also call that function whenever the screen changes (the player moves, enemies move/die, the map changes for whatever reason... there are any number of reasons you'd need to redraw).
You may want to consider a main game loop here, which would (very simply) be something to the effect of:
while (true) {
checkForInputFromThePlayer(); // this can update player coordinates, etc
doSomeAI(); // Move some enemies around, have them attack the player
render();
}
EDIT: A great example of a Game Loop can be seen in yckart's answer to requestAnimationFrame at a limited framerate

jump algorithm isn't working when reaching a block

This is my jsfiddle: http://jsfiddle.net/seekpunk/whZ44/17/
As you can see in my jsfiddle when the ball reach a block the jump function is not working.I know i am missing something in my algorithm that i am using to make the ball jump but i can't figure it out i would appreciate some help from you
if (InAir) {
if (InAir == 1) {
if (ball.y > jumpMaxHeight) {
ball.y -= gravity;
} else {
InAir = 2;
}
}
if (InAir == 2) {
if (ball.y < 390) {
ball.y += gravity;
} else {
ball.y = 390;
InAir = false;
ball.color = "black";
}
}
} else if (keydown.up && !InAir) {
InAir = 1;
ball.color = "#4285F4";
}
for (var j = 0; j < Blocks.collection.length; j++) {
if (Collision(ball, Blocks.collection[j])) {
//console.log("collision");
ball.y = (Blocks.collection[j].blockY - ball.radius) ;
}
}
Maybe here is something to start with: http://jsfiddle.net/d247V/3/
I updated the jump to have a default jump of 80 (high enough to get to next platform), and then on keydown.up i update that with the current ball.y position + the default
I think though the issue is how you are tracking the ball being in the air or not, when a collision is detected, the ball is technically no longer in the air, but you didn't have anything saying as such, see code snipped below basically how #mainguy said but with a slight modification to not keep reassigning ball.y, in the fiddle it works pretty well:
if( InAir )
{
for (var j = 0; j < Blocks.collection.length; j++) {
if (Collision(ball, Blocks.collection[j])) {
//console.log("collision");
var calc = (Blocks.collection[j].blockY - ball.radius);
if( ball.y != calc ) {
ball.y = calc;
ball.color = "black";
InAir = 0;
}
}
}
}
My fiddle though broke the gravity portion of the code, because you now need to also know if the x of the circle is passed the x barrier of the rectangle, and fall if not. So this is by no means a complete solution, but if you jump and go right or left from a barrier, the gravity process works as expected as long as no collisions exist, you will fall down to the bottom. There are slight other tweaks but I think you will be able to find them by the comment //Tweaked next to the parts I added.
It seems like your collision detection is working pretty well.
Its the gameloop that has some issues.
You should not do a collision detection on keypress up because this will only fire once. You need to check for collides all the time while the ball is in the air.
Like so:
... } else if (keydown.up && !InAir) {
InAir = 1;
ball.color = "#4285F4";
}
if (InAir){
for (var j = 0; j < Blocks.collection.length; j++) {
if (Collision(ball, Blocks.collection[j])) {
//console.log("collision");
ball.y = (Blocks.collection[j].blockY - ball.radius) ;
InAir=false;
}
}
}
With his code you can jump on the first plattform. (Note also that i changed ball.y positioning).
But some issues remain:
The Ball can not leave the plattform because as soon as he is airborne the collision with the plattform he is lying on kicks in.
If you move the Ball left or right over the plattform border it would be way more fun if he starts falling down again, instead of hovering in the air. (Trust me, i played some games).
Maybe you should delay collision detection until the ball has gained some height to escape the collision detection.
I update your fiddle and converted it to a plunker (with firebug you have way better debugging functionality here) Play with me!
Not a perfect answer but i hope this will help you.

Shoot 3 bullets on set times from each enemy

I'm trying to create a simple game with kineticJS on my canvas(Just some practice) and managed to get my player to shoot bullets. The same goes for the enemies that are spawned. They shoot a bullet each time the last bullet leaves the stage.
However: I'd like all the enemies(Variable number) to shoot 3 bullets at a 2 seconds interval. But i'm stuck completely and can't figure a way how to get it done.
Could anyone please look at my fiddle and see what's up?
http://jsfiddle.net/eRQ3P/6/
Note: line 573 is the function that loops(And draws the bullets and such every 30FPS)
Here's the code where i create a new bullet object:(Line 406 in fiddle)
function Enemybullet(destinationX, destinationY, enemySprite) {
this.id = 'bullet';
this.x = enemySprite.getX()+(enemySprite.getWidth()/2);
this.y = enemySprite.getY()+(enemySprite.getHeight()/2);
var targetX = destinationX - this.x,
targetY = destinationY - this.y,
distance = Math.sqrt(targetX * targetX + targetY * targetY);
this.velX = (targetX / distance) * 5;
this.velY = (targetY / distance) * 5;
this.finished = false;
this.sprite = new Kinetic.Circle({
x: this.x,
y: this.y,
radius: 3,
fill: 'black',
name: 'enemyProjectile'
});
this.draw = function(index) {
var mayDelete = false;
this.x += this.velX;
this.y += this.velY;
this.sprite.setAbsolutePosition(this.x, this.y);
//console.log(this.sprite.getX());
/*
if(enemyCollision(this) == true) {
mayDelete = true;
}*/
if (bulletLeftField(this.sprite) == true) {
mayDelete = true;
}
if (mayDelete == true) {
this.sprite.remove();
enemies[index].bullets.splice(0, 1);
createEnemyBullet(enemies[index]);
}
ammoLayer.draw();
}
}
And the function providing a new bullet: (line 247 in fiddle)
function createEnemyBullet(enemy) {
var blt = new Enemybullet(player.sprite.getX(), player.sprite.getY(), enemy.sprite);
ammoLayer.add(blt.sprite);
enemy.bullets.push(blt);
}
Probably the hardest part of this problem is figuring out when to draw each bullet to make three be fired in every 2-second interval. To make the bullets fire evenly, you want to divide the number of frames in the interval by the number of bullets to fire in that interval.
Because you're running the game at 30 frames per second, 2 seconds equals 60 frames.
60 frames / 3 bullets = 20 frames/bullet
So, we're going to create a new bullet for each enemy every 20 frames, or every 20th time refreshLoop() is called, and inside refreshLoop(), you now have to loop through all of the bullets each enemy has in its bullets array, because there can now be more than just one.
The fact that there can be more than one bullet in the bullets array introduces a new problem to the way bullets are removed from the array. Previously, you relied on the fact that one bullet at a time means it will always be the first one in the array, thus your code called bullets.splice(0, 1);. However, when the player is moving around and the enemies fire at the different locations, it is completely possible to have a bullet leave the screen and be removed sooner than one that was fired before it. This would cause the correct bullet sprite to be removed, but the first bullet in the array would be removed from bullets, so it wouldn't be updated anymore in refreshLoop(), and it would just sit on the screen doing nothing.
In order to avoid this, it is necessary to pass to the enemy bullets' draw() function the index in bullets at which the bullet being drawn is located. Since you need to loop through the array anyway, the index is already at hand in refreshLoop(), so just pass this to draw(). Now, every time a bullet needs to be removed, you can just call bullets.splice(bulletIndex, 1);
I hope you don't mind; I forked your fiddle to update it with the changes listed below.
EDIT: A new fiddle for burst-fire instead of sustained fire.
// Inside your Enemybullet definition
// One simple change to draw(), pass in the index of the bullet in the array
this.draw = function(indexEnemy, indexBullet) {
var mayDelete = false;
...
if (bulletLeftField(this.sprite) == true) {
mayDelete = true;
}
if (mayDelete == true) {
this.sprite.remove();
// Since you now have multiple bullets, you'll have to make
// sure you're removing the correct one from the array
enemies[indexEnemy].bullets.splice(indexBullet, 1);
}
ammoLayer.draw();
}
...
// Inside your refreshLoop function
// If there are enemies they should be checked
if (enemies.length > 0) {
for (var i = 0; i < enemies.length; i++) {
enemies[i].draw();
// At 30 frames per second, 3 bullets in 2 seconds would be
// one bullet for every 20 frames. So, every 20 frames,
// create a new bullet for each enemy
if ((enemyShootTimer % 20) == 0) {
createEnemyBullet(enemies[i]);
}
// The same way you draw all of the player's bullets,
// loop through the array of bullets for this enemy,
// and draw each one, passing in the new parameters
if (enemies[i].bullets.length > 0) {
for (var j = 0; j < enemies[i].bullets.length; j++) {
enemies[i].bullets[j].draw(i, j);
}
}
}
}
// Update loop for burst-fire instead of sustained fire
var burstTime = 10; // 10 frames between bullets, 3 per second
var needToShoot = ((enemyShootTimer % burstTime) == 0);
if (enemies.length > 0) {
for (var i = 0; i < enemies.length; i++) {
enemies[i].draw();
// if the enemies still have bullets to shoot this burst
// and if 10 frames have passed since the last shot
// ( enemyBurstCounter is declared outside refreshLoop() )
if (enemyBurstCounter < 3 && needToShoot) {
createEnemyBullet(enemies[i]);
}
if (enemies[i].bullets.length > 0) {
for (var j = 0; j < enemies[i].bullets.length; j++) {
enemies[i].bullets[j].draw(i, j);
}
}
}
if ((enemyShootTimer % 60) == 0) {
enemyBurstCounter = 0; // if 2 seconds have passed, reset burst counter
} else if (needToShoot) {
enemyBurstCounter++; // if the enemies shot, update burst counter
}
}

how to keep a object in array between other objects in array (canvas slider)

I am making a slider with kineticjs where you can can dynamically add more handles to gain more handles. Important is that the handles may not cross over eachother. Because it is important that the order of rank is still te same.
I have made what checks if the object what is higher in order has a lower x value than the object that is one lower in order. If I have made 5 handles, the last one works perfect. If I drop it on the left from the 4th it will put nicely right from the 4th. But if I put the 4th on the left of the 3th it will just go there and the 5th will be put close right to the 3th instead that the 4th does that.
How can it happen? Is there a solution for this problem?
container.addEventListener('mouseup', function(e) {
handles = layer.getChildren();
for(var m=handles.length; m--;)
{
if(m>0)
{
if (layer.get('#myRect'+m)[0].getAbsolutePosition().x < layer.get('#myRect'+(m-1))[0].getAbsolutePosition().x)
{
handles[m].setX(layer.get('#myRect'+(m-1))[0].getAbsolutePosition().x + 15);
}
}
}
layer.draw();
Update();
});
I have discovered that the layer.getChildren is quite messy. Each time he gives the objects an other rankorder. The layer.get('#myRect'+(m-1))[0] however is more reliable. I have kept the layer.getChildren for the counting.
EDIT: I came to discover that when you push the layer.getChildren in a selfmade array, it is more reliable while you have still the array options (layer.getChildren is unreliable for rank order).
The problem with my design is that you can have a moment where you have true on both if. Then he does always the if and thats not what you always want. So I have made a function where it calculates if your handle goes to the right or left and then looks if its across another one. Sorry for messy explanation and code.
var latestcoordinate = 0;
var newcoordinate = 0;
container.addEventListener('mousedown', function(e) {
latestcoordinate = 0;
for (var x = 0; x < array.length; x++) {
latestcoordinate += parseInt(array[x].getAbsolutePosition().x);
}
});
container.addEventListener('mouseup', function(e) {
newcoordinate = 0;
for (var x2 = 0; x2 < array.length; x2++) {
newcoordinate += parseInt(array[x2].getAbsolutePosition().x);
}
for(var m=array.length; m--;)
{
if(m<array.length-1 && newcoordinate < latestcoordinate)
{
if (array[m].getAbsolutePosition().x < array[m+1].getAbsolutePosition().x)
{
array[m].setX(array[m+1].getAbsolutePosition().x + 15);
}
}
if(m>0 && newcoordinate > latestcoordinate)
{
if (array[m].getAbsolutePosition().x > array[m-1].getAbsolutePosition().x)
{
array[m].setX(array[m-1].getAbsolutePosition().x - 15);
}
}
}
layer.draw();
Update();
});
Not that this is the solution, but I think you want to add an escape from your for loop or make it a 'for in' loop
for(var m=handles.length; m--;)
{
if(m>0) // <--- why isn't this clause in the for loop logic?
{
if (layer.get('#myRect'+m)[0].getAbsolutePosition().x < layer.get('#myRect'+(m-1))[0].getAbsolutePosition().x)
{
handles[m].setX(layer.get('#myRect'+(m-1))[0].getAbsolutePosition().x + 15);
}
}
else
break;
}

Categories

Resources