I wasn't sure how to word this, because I don't actually know what exactly causes this bug. I'm trying to put together a simple Asteroids knockoff.
When the player shoots, a new object (Bullet) is created using array.push(...). Once this bullet goes beyond the canvas (out of bounds), it is deleted using array.splice(...);
The problem is that the bullets are moving in unpredictable ways. I don't know how to word it so here's the full code (working, including html/css): https://pastebin.com/tKiSnDzX
Hold spacebar for a few seconds (to shoot) and you'll see the issue clearly. You can also use A/D to turn and W to go forward.
Here's what I think is happening. The code runs fine as long as there is only one bullet on the screen (in the array). This means that either the incorrect element is being deleted or the values that go into the constructor of the object are messed up somewhere along the way.
Exhibit A (bullet constructor and its methods):
function Bullet(x,y,rot,vel) {
this.x = x;
this.y = y;
this.rot = rot;
this.vel = (vel+5);
this.move = function() {
this.x += this.vel*Math.cos(this.rot-Math.PI/2);
this.y += this.vel*Math.sin(this.rot-Math.PI/2);
}
this.draw = function() {
engine.circle(this.x, this.y, 4, "black");
var c = engine.canvas.getContext('2d');
c.translate(this.x, this.y);
c.rotate(this.rot);
c.beginPath();
c.strokeStyle="#00FF00";
c.strokeRect(-5, -5, 10, 10);
c.closePath();
c.stroke();
}
}
Exhibit B (function that creates/deletes the bullets):
shoot: function() {
if(engine.keyDown.sp == true) {
if(this.fire > 20) {
engine.bullets.unshift(new Bullet(this.x, this.y, this.rot, this.velocity));
this.fire = 0;
} else {
this.fire++
}
}
for(i = 0; i < engine.bullets.length; i++) {
engine.bullets[i].move();
engine.bullets[i].draw();
if(engine.bullets[i].x > engine.canvas.width+5 || engine.bullets[i].x < -5
|| engine.bullets[i].y > engine.canvas.height+5 || engine.bullets[i].y < -5) {
console.log('bullet gone, '+i);
engine.bullets.splice(i, 1);
}
}
}
the array is declared like so: bullets: []
Thank you for any answers.
How about just tag any bullets that need to die as you come across them in your loop with something like engine.bullets[i].dead = true; Then, at the end outside the loop, filter out the dead bullets with engine.bullets = engine.bullets.filter(b => !b.dead);
You're using splice inside a for loop. When you remove element index 1, then element index 2 becomes index 1, and element index 3 becomes index 2. But your i variable is already 1, so the next iteration of the loop goes to the new index 2. But the new index 2 is the original index 3, and the original index 2 is skipped. You might be better served by a linked list:
var bulletList = null;
function bullet(){
this.next = bulletList;//if there was a list, record that
if (this.next)//and set that one to point back to this
this.next.prev = this;
bulletList = this;//place new bullet at start of list
this.previous = null;
this.draw = function(){
//do stuff here
this.next && this.next.draw();//call next item in the list, if any
if (shouldIBeRemoved){//placeholder, obviously
if (this.next && this.prev){//remove from middle of list
this.prev.next = this.next;
this.next.prev = this.prev;
}
else if (this.next && !this.prev){//remove from beginning of list
bulletList = this.next;
this.next.prev = null;
}
else if (this.prev && !this.next){//remove from end of list
this.prev.next = null;
}
else if (!this.prev && !this.next){//remove only item in list
bulletList = null;
}
}
}
}
then to draw every bullet, simply call:
if (bulletList)
bulletList.draw();
The problem was that I was translating the context in which all the bullets are, each time a new bullet was created. This meant that each bullet would be moved by x and y away from the previous one. It made it seem like the bullets were being created where they weren't supposed to be. The "unpredictability" was caused by the fact that the bullet takes on the player's rotation, so whenever a new bullet was created, it's rotation was increased by however much the player rotated before the new bullet was fired, on top of the previous bullet's rotation.
Putting context.save(); before the translation/rotation of the bullet's hitbox and context.restore(); after it perfectly solved the issue:
Bullet.draw = function() {
engine.circle(this.x, this.y, 4, "black");
if(hitbox == true) {
var c = engine.canvas.getContext('2d');
c.save();
c.translate(this.x, this.y);
//c.rotate(this.rot);
c.beginPath();
c.strokeStyle="#00FF00";
c.strokeRect(-5, -5, 10, 10);
c.closePath();
c.stroke();
c.restore();
}
}
Someone else mentioned that I was using array.splice(); in a for loop. This made it so that when a bullet (i) is deleted, the bullet right after (i+1) is moved one index back (i). So that bullet was essentially skipped over.
I could notice this sometimes when looking at the bullets while one was deleted- They "jumped" ahead.
The solution was to put i -= 1 after bullets.splice(i, 1);. This makes the next iteration of the loop go one index back, solving the occassional stuttering of the bullets:
shoot: function() {
if(engine.keyDown.sp == true) {
if(this.fire > 5) {
engine.bullets.unshift(new Bullet(this.x, this.y, this.rot, this.velocity));
this.fire = 0;
}
}
if(this.fire<=5) {
this.fire++
}
for(i = 0; i < engine.bullets.length; i++) {
engine.bullets[i].move();
engine.bullets[i].draw();
if(engine.bullets[i].x > engine.canvas.width+5 || engine.bullets[i].x < -5
|| engine.bullets[i].y > engine.canvas.height+5 || engine.bullets[i].y < -5) {
engine.bullets.splice(i, 1);
i-=1;
}
}
}
Thanks for all the answers.
Related
Been following along with Dan Shiffmans videos, trying to brush up on my Object orientated programing using classes.
Ive wrote some code that generates bubbles with random diameters at random positions, using p5's noise function to give the bubbles some movement.
My intention is for the bubbles to pop (be removed from the array with splice()) every time a bubble reaches the edges of the canvas or when two or more bubbles intersect.
The code run as desired, but after a while it crashes throwing up the error "Uncaught TypeError: Cannot read property 'x' of undefined (sketch: line 15)"
Ive tried hacking around but no joy, if anyone could shed some light on why this error occurs, or general pointers on my approach i would be most grateful. Here's the code in question.
var balls = [];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
for (var i = 0; i < balls.length; i++) {
balls[i].showBall();
balls[i].moveBall();
for (var j = 0; j < balls.length; j++) {
if (balls[i].x < 0 + balls[i].r ||
balls[i].x > width - balls[i].r ||
balls[i].y < 0 + balls[i].r ||
balls[i].y > height - balls[i].r ||
balls[i].life >= 220 ||
i != j && balls[i].intersect(balls[j])) {
balls.splice(i, 1);
}
}
}
}
class Ball {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.t = 0.0;
this.t2 = 107.0;
this.life = 0;
}
showBall() {
noFill();
stroke(this.life);
strokeWeight(2);
ellipse(this.x, this.y, this.r * 2);
}
moveBall() {
this.x += map(noise(this.t), 0, 1, -1, 1) * 0.5;
this.y += map(noise(this.t2), 0, 1, -1, 1) * 0.5;
this.t += 0.02;
this.life += 0.15;
}
intersect(other) {
if (dist(this.x, this.y, other.x, other.y) < this.r + other.r) {
return true;
} else {
return false;
}
}
}
function randBubbleGen() {
let foo = floor(random(11));
console.log(foo);
if (foo >= 5) {
let b = new Ball(random(41, 359),
random(41, 359),
random(5, 40));
balls.push(b);
}
}
setInterval(randBubbleGen, 1000);
<script src="https://cdn.jsdelivr.net/npm/p5#1.3.1/lib/p5.js"></script>
Thanks!
P
The first part of the problem is a classic splice issue:
const arr = [..."abcde"];
for (let i = 0; i < arr.length; i++) {
if (i === 2) { // some arbitrary condition
arr.splice(i, 1);
}
else {
console.log(i, arr[i]);
}
}
What happened here? After splicing the element at index 2, "c", the length of arr becomes 4, yet i++ still happens, skipping an element "d" which is never printed or visited in the loop. The solution is to i-- after each splicing operation or iterate in reverse so that splice doesn't cause unvisited elements to be skipped.
As for your error, the problem is that your inner loop over all j splices out an element, then continues on, acting as if balls[i] wasn't just removed. Based on the above demonstration, we know that after balls.splice(i, 1), balls[i] becomes the next element after the original i for the rest of that iteration of the outer loop body. This is a bug because some collisions will be skipped for i+1 after the spliced element, but won't cause errors unless i happens to be the last element in the balls array. In that case, balls[i+1] is undefined and you can't access properties on undefined.
The solution is to break out of the inner j loop after splicing out an element. That's in addition to iterating in reverse or using i-- after each splice call to avoid skipping balls.
From a time complexity standpoint, splice is a poor choice because it's O(n). If you have n collisions in the balls array, you'll need to loop over it a factor of n times, causing a triply-nested loop running in your update code.
A better general approach is to create a new array of elements that survived a round, then resassign that new array to the old balls array after the frame. This involves some allocation overhead.
Other tips:
Use const instead of let wherever possible.
Use let instead of var for loop counters and mutable variables. Ideally, never use var or let, although p5 promotes mutability due to its window-attached functions.
Prefer forEach and for ... of loops to classical C-style for loops.
You can return dist(this.x, this.y, other.x, other.y) < this.r + other.r since it's already a boolean, no need for if bool return true else return false verbosity.
Keep rendering and position updating separate as much as possible. It probably doesn't matter much for this animation, but as things get more complex, it can be odd when something dies but still gets rendered for a frame as is the case here.
Move the collision detection and edge detection to external functions -- the if (balls[i].x < 0 + balls[i].r ... condition is difficult to read.
I have an object called Scene and it stores screen dimensions as well as an array of Shape objects, each of which have an x and y coordinate. I would like to scramble a Scene object and get a scrambledScene object so that I can compare the scrambledScene to the original. Here is the function I've come up with:
function scrambleScene(scene) {
var scrambledScene = {...scene};
for(var i = 0; i < scene.shapes.length; i++) {
scrambledScene.shapes[i].x = getRandInt(0, scene.width);
scrambledScene.shapes[i].y = getRandInt(0, scene.height);
}
return(scrambledScene);
}
The problem is when this function is run, it returns an object that is identical to the Scene object that was passed to it. Nothing was changed. Here are definitions of the functions I used. I am quite new to OOP so feel free to give pointers (unlike JS, why does var clone = object just return a pointer and not another object?!!?!?!!).
function getRandInt(min, max) {
return(Math.floor(Math.random() * (max - min + 1)) + 1);
}
function Shape(shapeX, shapeY, shapeSize, shapeType) {
this.x = shapeX;
this.y = shapeY;
this.size = shapeSize;
this.type = shapeType;
//circle uses arc() function, which takes the center of the circle as a reference
//circle sets the radius to this.size
//square uses rect() function, which take the upper left corner as a reference
//square sets the height and width of the square to this.size
if(this.type !== 'circle' && this.type !== 'square') {
console.error('Invalid shapeType: ', this.shapeType);
}
this.centerX = function() {
if(this.type === 'square') {
return(this.size/2 - this.x);
}
if(this.type === 'circle') {
return(this.x);
}
}
this.centerY = function() {
if(this.type === 'square') {
return(this.size/2 - this.y);
}
if(this.type === 'circle') {
return(this.y);
}
}
this.isInside = function(point_x, point_y) {
if(this.type === 'square') {
//canvas y increases as you go down
//if point_x is greater than x + size, then its far too right
//if point_x is less than x, then its far too left
//if point_y is greater than y + size, then its below
//if point_y is less than y, then its above
//if none of these are true then its inside
if(point_x <= x + size && point_x >= x && point_y <= y + size && point_y >= y) return(true);
}
if(this.type === 'circle') {
//checks distance from point to center of the circle
//if its greater than the radius of the circle then its outside
//if its less than or equal to the radius then its inside
const distance = Math.sqrt(Math.pow(point_x - x, 2) - Math.pow(point_y - y, 2));
if(this.distance >= size) return(true);
}
}
}
function Scene(numberOfShapes, sceneWidth, sceneHeight) {
this.shapes = [];
for(var i = 0; i < numberOfShapes; i++) {
var shapeType = Math.random() < 0.5 ? 'square' : 'circle';
this.shapes[i] = new Shape(getRandInt(0, sceneWidth), getRandInt(0, sceneHeight), 100, shapeType)
}
this.width = sceneWidth;
this.height = sceneHeight;
}
So the Object was being changed, it was just that the clone of that Object was also being changed to be the exact same.
In the scrambleScene function I tried to create is what's called a shallow clone of the Scene object passed. What I really needed was a deep clone. A shallow clone is like if you copied a folder with files inside on Windows, but instead of actually copying the files inside, the files were replaced with shortcuts to those files. If you edit the original file and open the shortcut, you will see the edit because its just a shortcut, not a new file. A deep clone is similar to when you copy a folder with all the files inside. If you edit an original file, its copy won't be changed because they are two different files.
If you continue the analogy, when I ran the scrambleScene function it edited the original file, and when I look at the Shapes, it was the same because it was just a shortcut, not a new file. I needed to copy the file, not create a shortcut.
You can create a completely independent object by using JSON. There are some limitations, but for my case it worked.
I'm working with a very simple example of a p5.js that was part of the supplemental material for Learning Processing. They provide .js versions of all of the examples from the book, and my data viz project will go on the web. What I want to do is use this simple example to act as a template for when I create my actual data viz. I want to get the basic animation working first before I add a bunch of other code.
Here is the code I'm working with:
var message = "random characters flying home!";
// An array of Letter objects
var letters;
function setup() {
createCanvas(400, 200);
// Load the font
textFont("Georgia", 20);
// Create the array the same size as the String
letters = [];
// Initialize Letters at the correct x location
var x = 50;
var y = height/2;
for (var i = 0; i < message.length; i++) {
letters[i] = new Letter(x, y, message.charAt(i));
x += textWidth(message.charAt(i));
}
}
function draw() {
background(255);
for (var i = 0; i < letters.length; i++) {
// Display all letters randomly
letters[i].random();
}
// If the mouse is pressed the letters return to their original location
if (mouseIsPressed) {
letters[i].display();
}
}
function Letter(x, y, letter) {
// The object knows its original " home " location
// As well as its current location
this.homex = this.x = x;
this.homey = this.y = y;
this.letter = letter;
this.theta = 0;
// Bring the letters back to their original position
this.display = function() {
fill(0);
textAlign(LEFT);
this.x = this.homex;
this.y = this.homey;
text(this.letter, this.x, this.y);
}
// Position the letters randomly
this.random = function() {
this.x += random(width);
this.y += random(height);
this.theta += random(-0.1, 0.1);
}
// no longer using this function, but it was part of the original 'if' statement
// At any point, the current location can be set back to the home location by calling the home() function.
//this.home = function() {
//this.x += lerp(this.x, this.homex, 0.05);
//this.y += lerp(this.y, this.homey, 0.05);
//this.theta += lerp(this.theta, 0, 0.05);
//text(this.letter);
}
};
ISSUE 1: What it's supposed to do is initially display individual letters on the canvas. And it does that. But I also get the following error in my console:
sketch.js:31 Uncaught TypeError: Cannot read property 'home' of undefined
sketch.js:31 is the line at the end of the 'if' statement under draw(). My question is what is 'home' referring to and how can I fix it.
ISSUE 2: What's supposed to happen when mouseIsPressed is the letters move into their correct configuration, i.e., "random characters flying home!" But nothing happens when I press down on the mouse.
Your code does not produce the errors you mentioned.
Instead, running your code produces an unexpected token: } error because you have an extra } at the end of your code. Get rid of it.
At that point you have a different error: sketch.js:29 Uncaught TypeError: Cannot read property 'display' of undefined. Looking at your draw() function, which includes line 29, we see this:
function draw() {
background(255);
for (var i = 0; i < letters.length; i++) {
// Display all letters randomly
letters[i].random();
}
// If the mouse is pressed the letters return to their original location
if (mouseIsPressed) {
letters[i].display();
}
}
Notice that your if(mousePressed) statement is after the for loop. What do you expect the value of i to be when you get to the if statement? Since it's outside the loop, i is out of scope, so its value is undefined! That's why you're getting this error.
To fix it, you need to rearrange your if statements so that they happen inside the loop:
function draw() {
background(255);
for (var i = 0; i < letters.length; i++) {
if (mouseIsPressed) {
// If the mouse is pressed the letters return to their original location
letters[i].display();
} else {
// Display all letters randomly
letters[i].random();
}
}
}
This gets rid of your errors, but your random logic is still off. You're just adding random values to your letters, so they fly off the screen and you can't see them.
Instead, add smaller values to their positions, and make sure you reset their positions when the user clicks.
I hope this code explains what I'm trying to do. I have a pool table, and I want the balls to accelerate into the pockets if they are close enough. At this point I'm not yet checking the distance, just working to figure out how to do it.
I'm sure there is a better way!
balls.forEachAlive(
pockets.forEachAlive( moveBallTowardPocket, this), this);
Update: The following code is working except one thing, the scale change for balls on the first five pockets. Acceleration is working for all balls to all pockets. Scale change is only working on the last pocket, not the first five.
function update() {
pockets.forEachAlive(function(pocket) {
accelerateBallToPocket(flipper, pocket, 60);
balls.forEachAlive(function(ball) {
accelerateBallToPocket(ball, pocket, 60);
});
});
//...
}
function accelerateBallToPocket(ball, pocket, speed) {
if (typeof speed === 'undefined') {
var speed = 120;
}
var pocket_body_x = pocket.body.x;
var pocket_body_y = pocket.body.y;
var ball_body_x = ball.body.x;
var ball_body_y = ball.body.y;
// move ball toward pocket if close enough
var dx = ball_body_x - pocket_body_x; //distance ship X to enemy X
var dy = ball_body_y - pocket_body_y; //distance ship Y to enemy Y
var dist = Math.sqrt(dx*dx + dy*dy); //pythagoras
if (dist < pocket_radius * pocket_leniency_factor) {
// accelerate ball to pocket on right angle
var angle = Math.atan2(pocket.y - ball.y,
pocket.x - ball.x);
ball.body.rotation = angle + game.math.degToRad(90);
ball.body.force.x = Math.cos(angle) * speed;
ball.body.force.y = Math.sin(angle) * speed;
// change scale
// FIXME only works on the last pocket lower right
if (ball === flipper) {
ball.scale.setTo(Math.tan(pocket.x - ball.x),
Math.tan(pocket.y - ball.y));
} else {
ball.scale.setTo(Math.sin(pocket.x - ball.x),
Math.cos(pocket.y - ball.y));
}
} else {
// reset the scale when the ball is out of range of the pocket
ball.scale.setTo(1.0, 1.0);
}
}
2nd Update:
The following, based on the solution, has me going in the right direction again, I think...
for (var i = 0; i < pockets.children.length; i++) {
accelerateBallToPocket(cue, pockets.children[i], 60);
if (cue.pocketing) break;
}
for (var i = 0; i < balls.children.length; i++) {
if (balls.children[i].pocketing) continue;
for (var j = 0; j < pockets.children.length; j++) {
accelerateBallToPocket(balls.children[i], pockets.children[j], 60);
if (balls.children[i].pocketing) return;
}
}
Ok, the problem is that you set the scale to 1 if the ball isn't close to a pocket. And, as you check each ball against each pocket, there will always be one pocket (that is checked later in the loop) that the ball is not close too, except the last pocket in the pocket list. So, even if the ball scale is set to the correct value, it will be reset when the next pocket is being checked.
What you can do is check whether a ball is close to at least one pocket, if it is then it can't be close the the other pockets so you don't check again agaist the other pockets.
// Consider that every ball is not inside a pocket
balls.forEachAlive(function(ball) {
ball.inPocket = false;
});
flipper.inPocket = false; // You should really add the flipper to the balls group to remove duplicate code
pockets.forEachAlive(function(pocket) {
if(!flipper.inPocket) accelerateBallToPocket(flipper, pocket, 60);
balls.forEachAlive(function(ball) {
if(!ball.inPocket) accelerateBallToPocket(ball, pocket, 60);
});
});
Then, in your move function you have to set the inPocket member to true if a ball is close to the pocket.
function accelerateBallToPocket(ball, pocket, speed) {
...
if (ball === flipper) {
ball.scale.setTo(Math.tan(pocket.x - ball.x),
Math.tan(pocket.y - ball.y));
ball.inPocket = true;
} else {
ball.scale.setTo(Math.sin(pocket.x - ball.x),
Math.cos(pocket.y - ball.y));
ball.inPocket = true;
}
} else {
// reset the scale when the ball is out of range of the pocket
ball.scale.setTo(1.0, 1.0);
}
}
And alternative would be to revers the loop order, first iterate through all balls and for each ball check each pocket, once you find that is in a pocket continue the outer loop (skipping the check for the other pockets). In order to do this your accelerateBall function should return true or false, being true when the ball is close enough to the pocket and false otherwise.
I would re-write your iterations like this:
for (var i = 0; i < pockets.children.length; i++) {
accelerateBallToPocket(cue, pockets.children[i], 60);
if (cue.pocketing) break;
}
// Stumped...
for (var i = 0; i < balls.children.length; i++) {
// No need for the check here, each ball should have pocketing=false, set at the top of the update loop
// This means, that balls.children[i].pocketing will always be false here
for (var j = 0; j < pockets.children.length; j++) {
accelerateBallToPocket(balls.children[i], pockets.children[j], 60);
if (balls.children[i].pocketing) break; // stop checking the rest of the pockets for this ball
}
}
So i have been working hard at a game using HTML5 and JavaScript. I am trying to make a space invaders styled game and as a result i have an array of enemies. I have separate functions dedicated to creating the array of enemies, drawing them to screen, moving the enemies and finally removing them.
the removal of enemies however is causing an issue. This is my logic
if an enemies health is less than or equal to 0, delete the enemy from the array and shrink the arrays length by 1. Now logic would dictate that this can be a calamity, if you start shooting and killing enemies from the start of the array, as the arrays length will be reduced and this is exactly my problem, so low and behold my code.
function hostile(x, y) {
this.speed = 1;
this.health = 100;
this.x = x;
this.y = y;
this.height = 32;
this.width = 32;
this.isDead = false;
this.direction = 0;
this.deadCount = 0;
this.firing = false;
//this.moving = true;
this.move = function () {
if (this.isDead === false && gameStart === true) {
context.clearRect(0, 0, canvas1.width, canvas1.height);
if (this.x > canvas.width - 64) {
this.y += 10;
this.direction = 0;
}
if (this.x < 0) {
this.y += 10;
}
if (this.direction === 1) {
this.x += this.speed;
} else {
this.x -= this.speed;
}
if (this.x < 0) {
this.direction = 1;
}
if (this.y > 420) {
this.x = 600;
}
}
};
this.draw = function () {
context.drawImage(sprite, 0, 480, 65, 68, this.x, this.y, 65, 65);
};
this.reset = function () {
context.clearRect(this.x, this.y, 65, 65);
this.x = 20;
this.y = 20;
this.health = 100;
};
};
var enemylist = [];
function createEnemies() {
for (var i = 0; i < 6; i++) {
enemylist.push(new hostile(75 * i, 20));
}
};
function deleteEnemy(a) {
enemylist.splice(a);
enemyBulletList.splice(a);
//enemylist.length = enemylist.length-1;
//enemyBulletList.length = enemyBulletList.length - 1;
};
createEnemies();
function moveEnemies() {
for (var i = 0; i < enemylist.length; i++) {
if (enemylist[i].isDead === false && gameStart === true) {
if (enemylist[i].x > canvas.width - 64) {
enemylist[i].y += 10;
enemylist[i].direction = 0;
}
if (enemylist[i].x < 0) {
enemylist[i].y += 10;
}
if (enemylist[i].direction === 1) {
enemylist[i].x += enemylist[i].speed;
} else {
enemylist[i].x -= enemylist[i].speed;
}
if (enemylist[i].x < 0) {
enemylist[i].direction = 1;
}
if (enemylist[i].y > 420) {
enemylist[i].x = 600;
}
}
}
};
So to explain my problem, i can shoot and kill enemies from the array, this will also remove them from the screen. However if i shoot an enemy from the start of the array i cause all the enemies to cleared off the screen and the game to crash. If you need more information, feel free to ask.
By request, i have submitted more code relating to my question. The code above includes the hostile function and other functions associated directly with it.
EDIT: Vitim.us had offered a very useful tip regarding my question, he suggested to create a flag of some sort (var dead = false/true etc.) and once the value is changed the specific instance can simply be removed from the screen away from the player.
Don't manually update the array like that. delete is for removing named properties. If you want to remove elements from an Array, use splice:
function deleteEnemy(a) { // capitalized functions are usually reserved for constructors
enemylist.splice(a);
enemyBulletList.splice(a);
}
Also, var enemylist = [6] doesn't do what you think it does. It creates an array with a single element, [6]. You should create an empty array and then enemylist.push(new hostile(...)) to add them to the array.
This will avoid you having to manually set the length (which you should not ever have to do.)
You can implement this in various ways
You can implement a method to hostile to remove itself from screen,
To this each instance should keep a reference to itself on screen, it can be a direct reference to DOM or it can be a property like hostile.entitieId that correlate to the onscreen object.
When hostile.health<=0 you flag hostile.isDead = true; and automatically call a method to remove it from screen, than notify other method to finally delete the instance from your enemyList[]
You can either check this on the game tick or you can build it in a event dispatch fashion, using getter and setter for the health property.
this.setHeath = function(value){
//set entity heath
if(health<=0){
//remove itself from screen
//notify other method to clear this instance from the enemyArray[]
}
}