Handle multiple enemies firing bullets at the same time - javascript

I'm trying to make all my enemies simultaneously shoot bullets at the player. My code works for one enemy shooting at a time, but what I'm trying to do is to make them all fire simultaneously.
For brevity's sake I'm using this simple condition to trigger the fire_bullets function : if (player.x > thisEnemy.x) { //fire bullets. What I intended to do is, the farther the player moves to the right, the more enemies start shooting bullets. Problem is the condition is only working for the first enemy in the array, while the other ones simply won't fire any bullet. You can see demo here :
https://jsfiddle.net/Lau1989/796xr7vg/
Here is my fire_bullets() function :
function fire_bullets(thisEnemy) {
var HTMLbullets = document.querySelectorAll('.HTMLbullets');
for (var b = 0; b < HTMLbullets.length; b++) {
var time = new Date().getTime()/1000 - startTime;
if (bullets[b].isOut && time > 0.5) {
if (player.x > thisEnemy.x) {
bullets[b] = bullets_pool(thisEnemy.x, thisEnemy.y);
}
startTime = new Date().getTime()/1000;
}
if (!bullets[b].isOut) {
bullets[b].y -= 4;
if (bullets[b].y <= 50) { //check if bullet is out of range and recycle it
bullets[b].isOut = true;
var thisBullet = bullets.splice(b, 1)[b];
thisBullet.x = -100;
bullets.push(thisBullet);
}
}
HTMLbullets[b].style.left = bullets[b].x +"px";
HTMLbullets[b].style.top = bullets[b].y +"px";
}
}
My latest try was to add the fire_bullets function as a property to each enemy object and then call it whenever their x position is lower than the player x position, but it only made the last enemy being triggered to fire its bullets, while the other ones stopped shooting theirs.
How should I proceed to make all my enemies simultaneously fire bullets at the player ? Is there a good performance-wise solution to do it, considering that each level frequently has dozens of enemies firing bullets at the same time ?

Related

Need help modifying skew.js for Y axis rotation

Here's the site in question: https://marks-groovy-project-2fa056.webflow.io/
I want to rotate each letter by 90 degrees on their Y axis while scroll is active, and return them back to their original position as soon as scrolling stops.
Visualization: in top view, a letter should rotate 90deg counter-clockwise when scroll is activated, which will render the letter invisible in front view ( the viewport) while scrolling, and then turn back 90 degrees clockwise when scrolling ends, so that each letter is visible again.
Method: used skew.js and slightly modified it:
skew.js is applied to an entire section. I want to apply it to every instance of a span with id="letter-animation". I've appropriately renamed the constant and referenced the #.
const speed is a remnant from skew.js. I haven't yet figured out how to rewrite it. It expresses the amount of skew as a function of the difference in newPixel/oldPixel. Which I don't want. My rotation needs to be 90deg every time. Once in, once out.
letter.style.transform = "rotateY(45deg)" used to be "rotateY(" + speed + "deg)" in the old script. (technically it was "skewY", not "rotateY" but you get my point). const speed would then be replaced with whatever new constant is appropriate as mentioned in point 2.
I've set up this codepen to isolate the script in question. https://codepen.io/mhedinger/pen/yLJaLmp
const letter = document.querySelector("#letter-animation")
let currentPixel = window.pageYOffset
const looper = function(){
const newPixel = window.pageYOffset
const diff = newPixel - currentPixel
const speed = diff * 11
letter.style.transform = "rotateY(45deg)"
currentPixel = newPixel
requestAnimationFrame(looper)
}
looper()
Here's the tutorial that explains how skew.js works: https://www.superhi.com/video/skew-on-scroll-effect
And here's an example of it working, according to the video tutorial above: https://codepen.io/emgiust/pen/rdOJwQ
const section = document.querySelector("section");
let currentPixel = window.pageYOffset
//looper keeps running and keeps track of where the new pixel is
const looper = function () {
const newPixel = window.pageYOffset;
const diff = newPixel - currentPixel
const speed = diff * 0.35;
section.style.transform = "skewY(" + speed + "deg)"
currentPixel = newPixel;
requestAnimationFrame(looper)
}
looper();
Can anybody help me get this working? So far, the main issue seems to be that they're spans and not sections, but it could also just be my complete absence of understanding of javascript.
I'm hoping to control the transition speed, curve, and delay via css, but if it has to be controlled in JS, i'd also appreciate some advice on how to do this.
Thank you everyone in advance for trying to help.
Cheers,
Mark
NOTE: there is another script running (fullpage.js) which simulates a swiping experience during scroll. deactivate it temporarily to get a better view of what’s happening during scroll while you’re checking things out/setting things up. End-product, a letter animation that synchronously rotates each letter by 90 degrees (rendering the words invisible) for the duration of the swipe/scroll, and returning them to normal once the section snaps into place.
In case anybody is still interested in this, I have figured it out in the meantime.
const letter = document.getElementsByTagName("SPAN");
var timer = null;
window.addEventListener('scroll', function() {
if(timer !== null) {clearTimeout(timer)}
timer = setTimeout(function() {
var i;
for (i = 0; i < letter.length; i++) {
letter[i].style.transform = "rotateY(0deg)";
};
}, 150);
var i;
for (i = 0; i < letter.length; i++) {
letter[i].style.transform = "rotateY(90deg)";
};
}, false);
https://codepen.io/mhedinger/pen/yLJaLmp
EDIT:
I have improved this script for best-practice purposes. This makes it more stable and versatile because it can now be used together with plugins like fullpage.js. Additionally, if desired, the transforms can now also be called manually by referencing the appropriate function.
let letter = document.getElementsByTagName("SPAN");
var timer = null;
var rotateLetter = function() {
Array.from(letter).forEach(function(letter) {
letter.style.transform = "rotateY(90deg)";
});
};
var resetLetter = function() {
Array.from(letter).forEach(function(letter) {
letter.style.transform = "rotateY(0deg)";
});
};
window.addEventListener('scroll', function() {
if(timer !== null) {clearTimeout(timer)}
timer = setTimeout(function() {resetLetter()}, 125);
rotateLetter()
}, false);
https://codepen.io/mhedinger/pen/dypmKZd

How to prevent two canvas objects from appearing in the same location

I am building a Snake arcade game, and though the game is up and working well I am attempting to tweak the game so that the apple will never appear in the same location as one of the snake segments (for those who don't know Snake, it is a classic arcade game in which a snake slithers around the screen eating apples that randomly appear, trying to avoid running into itself or the wall and growing in length each time it eats an apple). Here is the code below that moves the apple around the screen:
Apple.prototype.move = function() {
var randomCol = Math.floor(Math.random()*(widthInBlocks-2)) +1;
var randomRow = Math.floor(Math.random()*(heightInBlocks-2)) +1;
this.position = new Block(randomCol, randomRow);
for (i = 0; i < Snake.segments; i++) {
if (this.position === Snake.segments[i].col && Snake.segments[i].row) {
this.move();
};
};
}
The constructor for the snake is as follows:
var Snake = function() {
this.segments = [
new Block(7, 5),
new Block(6, 5),
new Block(5, 5)
];
this.direction = "right";
this.nextDirection = "right";
};
And the code to draw the snake is as follows:
//function to toggle the colour of the snake's segments
function alternateColour(i) {
var colours = ["limegreen", "yellow"];
if (i % 2 === 0) {
return colours[0];
} else {
return colours[1];
};
};
//draw snake method
Snake.prototype.draw = function() {
this.segments[0].drawSquare("blue"); //snake head will always be blue
for (i = 1; i < this.segments.length; i++) {
this.segments[i].drawSquare(alternateColour(i));
};
};
To me this all looks right, but I am still a big newbie and still new to OOP. I am not sure if I have propertly written the Apple.prototype.move method so that it will never place the apple in the location of a segment of the snake's body. The probability of it happening is low, so in order to know for sure I would have to sit and play the game for hours potentially. Any input would be greatly appreciated.
Note: the game play area is divided into a grid system of rows and columns made up of 10x10 pixel areas using the following code:
var blockSize = 10;
var widthInBlocks = width/blockSize;
var heightInBlocks = height/blockSize;
Thank you.
It looks like you have a mistake in your Apple.prototype.move function when checking whether the apple position clashes with a snake segment.
You're calculating the apple position (randomCol, randomRow), but then not using these values when checking against each snake segment.
Also, you call this.move() when you expect to encounter a clash. But after that function has returned, you will continue to finish any remaining iterations in the previous for loop.
These issues can be resolved with the following changes:
for (i = 0; i < Snake.segments; i++) {
if (randomCol === Snake.segments[i].col && randomRow === Snake.segments[i].row) {
return this.move();
};
};

Move canvas object on touchmove in Javascript

I’m fairly new to web development and I’ve only ever used jQuery to write my scripts. Today however, I’d like to improve my skills and build a little game that could be used on a smartphone as a web app in vanilla JS.
The game’s pretty straightforward:
You hold your phone in portrait mode and control a character that stays at the bottom of the screen and has to dodge objects that are falling on him. The character can only move left or right and thus always stays on the same x-axis. In order to control him, your finger has to stay on the screen. Once you take it off, you lose. Also, the move isn’t triggered by tapping the screen, but by moving your finger left or right.
For now, I’ve only been experimenting to get the hang of touchevents and was able to make the character move when swiping:
document.addEventListener('touchmove',function(e){
e.preventDefault(); //disable scroll
var board = document.getElementById(‘board);
var character = document.getElementById(‘character’);
if (e.targetTouches.length === 1) {
var touch = e.targetTouches[0];
board.classList.add(‘moving’);
character.style.left = touch.pageX + 'px';
}
}, false);
(The ‘moving’ class is used to move the background-position of the board and animate the character’s sprite in plain CSS.)
Separately, I made a little script that puts objects with random classes in a container with a set interval. These objects are then animated in css and fall from the top to the bottom of the screen.
Now, here comes the tricky part: the collision detection.
As I said, I’m new to development and vanilla JS, so I searched a bit to figure out how to detect when two objects collide, and it seems that most tutorials do this using canvases. The thing is, I’ve never used them and they scare me quite a bit. What’s more, I think it would render what I’ve done so far useless.
I’m okay with trying the canvas way, but before I do, I’d like to know if there’s any other way to detect if two moving objects collide?
Also, if there turns out to be no real way to do this without canvas, I plan on using this tutorial to learn how to build the app. However, this game wasn’t built for touchscreen devices, and the spaceship’s position changes on certain keystrokes (left & right) :
function update() {
if (keydown.left) {
player.x -= 5;
}
if (keydown.right) {
player.x += 5;
}
player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}
My question is: how should I do to update the position using touchmove instead of keystrokes?
Thank you all in advance.
1) the idea : 'if you stop touching, you loose', is just a bad idea, drop it.
2) most convenient way to control is to handle any touch event (touch start/move/end/cancel), and to have the character align on the x coordinate of this event.
3) the intersection test is just a basic boundig box intersection check.
I made a very basic demo here, that uses touch, but also mouse to ease testing :
http://jsbin.com/depo/1/edit?js,output
a lot of optimisations are possible here, but you will see that touches adjust the ship's position, and that collisions are detected, so it will hopefully lead you to your own solution
Edit : i added default to 0 for left, top, in case they were not set.
boilerplate code :
var collisionDisplay = document.getElementById('collisionDisplay');
// hero ship
var ship = document.getElementById('ship');
ship.onload = launchWhenReady ;
// bad ship
var shipBad = document.getElementById('shipBad');
shipBad.onload = launchWhenReady ;
// image loader
imagesCount = 2 ;
function launchWhenReady() {
imagesCount --;
if (imagesCount) return;
setInterval(animate, 20);
}
var shipBadY = 0;
touch events :
// listen any touch event
document.addEventListener('touchstart', handleTouchEvent, true);
document.addEventListener('touchmove', handleTouchEvent, true);
document.addEventListener('touchend', handleTouchEvent, true);
document.addEventListener('touchcancel', handleTouchEvent, true);
// will adjust ship's x to latest touch
function handleTouchEvent(e) {
if (e.touches.length === 0 ) return;
e.preventDefault();
e.stopPropagation();
var touch = e.touches[0];
ship.style.left = (touch.pageX - ship.width / 2) + 'px';
}
animation :
// animation loop
function animate()  {
// move ship
shipBadY += 1;
shipBad.style.top = Math.ceil(shipBadY) + 'px';
// test collision
var isColliding = testCollide(shipBad);
collisionDisplay.style.display = isColliding ? 'block' : 'none';
}
collision :
// collision test when the enemy and the ship are images
function testCollide(enemi) {
var shipPosX = parseInt(ship.style.left) || 0 ;
var shipPosY = parseInt(ship.style.top) || 0 ;
var shipWidth = ship.width ;
var shipHeight = ship.height;
var badX = parseInt(enemi.style.left) || 0 ;
var badY = parseInt(enemi.style.top) || 0 ;
var badWidth = enemi.width;
var badHeight = enemi.height;
return bBoxIntersect(shipPosX, shipPosY, shipWidth, shipHeight,
badX, badY, badWidth, badHeight);
}
EDIT : in case you're not using images :
// collision test when the enemy and the ship are ** NOT ** images
function testCollide(o) {
var characterPosX = parseInt(character.style.left);
var characterPosY = parseInt(character.style.top);
var characterWidth = parseInt(character.style.width);
var characterHeight = parseInt(character.style.height);
var obstacleX = parseInt(o.style.left) || 0 ;
var obstacleY = parseInt(o.style.top) || 0 ;
var obstacleWidth = parseInt(o.style.width);
var obstacleHeight = parseInt(o.style.height);
return boundingBoxIntersect(characterPosX, characterPosY, characterWidth, characterHeight, obstacleX, obstacleY, obstacleWidth, obstacleHeight);
}
function bBoxIntersect(x1, y1, w1, h1, x2, y2, w2, h2) {
return !(x1 + w1 < x2 || x1 > x2 + w2 || y1 + h1 < y2 || y1 > y2 + w2);
}
mouse events :
// -----------------------------------------------------
// Handle mouse event for easy testing on Browser
document.addEventListener('mousemove', handleMouseEvent);
function handleMouseEvent(e) {
ship.style.left = (e.pageX - ship.width / 2) + 'px';
}

Jump Animation in JavaScript

My newest Hobby Project is a very simple Jump'n'Run Game using JavaScript. I already wrote some code (with the help of a tutorial at lostdecadegames) and read everything about the GameLoop.
var start = true;
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1200;
canvas.height = 480;
document.body.appendChild(canvas);
var jumping = false;
var gravity = 1.5;
var pressed = true;
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "background.png";
// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "hero.png";
// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function () {
monsterReady = true;
};
monsterImage.src = "monster.png";
// Game objects
var hero = {
speed_x: 50,
speed_y_up: 50,
speed_y_down: 50, // movement in pixels per second
velocity_x: 50,
velocity_y: 50
};
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
// Update game objects
var update = function (modifier) {
if(38 in keysDown) { // Player holding up
jumping = true;
//hero.y -= hero.speed_y_up * modifier;
}
if (40 in keysDown) { // Player holding down
hero.y += hero.speed_y_down * modifier;
}
if (37 in keysDown) { // Player holding left
hero.x -= hero.speed_x * modifier;
}
if (39 in keysDown) { // Player holding right
hero.x += hero.speed_x * modifier;
}
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (heroReady) {
if(hero.y > 0 && hero.y < 480 && hero.x <= -32)
{
hero.x = hero.x + 1232;
ctx.drawImage(heroImage, hero.x, hero.y);
}
else if(hero.y > 0 && hero.y < 480 && hero.x >= 1200)
{
hero.x = hero.x - 1232;
ctx.drawImage(heroImage, hero.x, hero.y);
}
else if(jumping)
{
ctx.drawImage(heroImage, hero.x, hero.y-100);
jumping = false;
}
else ctx.drawImage(heroImage, hero.x, hero.y);
}
if (monsterReady) {
ctx.drawImage(monsterImage, monster.x, monster.y);
}
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 500);
render();
then = now;
};
// Starting the game!
reset();
var then = Date.now();
setInterval(main, 1); // Execute as fast as possible
As you can see, I already added a fix gravity var and some speed vars. The Hero moves very smooth, so this is no problem.
I have 2 problems with the jump-Animation:
The Hero stays in the air, when the Up-Key is keep being pressed. I tried to fix this with some boolean vars, but I couldn't figure it out how to get the Hero down again.
Right now, I implemented a "dirty hack" which causes the Hero to be repainted 50px higher, but I want a smooth Jump, so that the Hero gets slower while going up and speeds up while falling. I looked up so many Tutorials and so much Example Code, but I'm too stupid to figure it out, how I get my desired Animation.
Hope you guys can give me some advice for my problem (I'm not asking for the final code, I just need some tips).
It's hard to understand exactly what the if statements inside of if (heroReady) are doing because the numbers don't mean anything to me, but it seems to me like your problem is in there.
First of all, it seems to me like jumping should the first condition checked. If one of the first conditions is true, then it doesn't matter whether or not he's jumping. I can't easily tell when each condition is true, though, so I'm going to assume that when the player is holding up,
else if(jumping)
{
ctx.drawImage(heroImage, hero.x, hero.y-100);
jumping = false;
}
gets executed like normal.
Now, assuming that, I think your issue is that jumping is determined solely by whether or not the player is holding up, because as soon as jumping is true, it becomes false. This is incorrect.
Jumping should be set to true when the player presses the up key, but it should be set to false when they remove it. It should be set to false when the animation hits the ground.
Another issue that you have is the fact that you aren't actually using the hero's attributes to render its jumping location, you're simply offsetting it. Perhaps that is just your workaround until the problem is solved, but it makes it hard to tell when the character hits the ground, because you can't start lower the character (increasing the y value) after they jump, since you never raised them by decreasing the y value.
So how do we fix this?
Here are my recommendations. You might find more elegant ways to do it by the time you're done due to refactoring, but the way you have it set up right now I think it will work fine:
Set jumping as soon as they press up, like you're doing, but only if jumping == false, because presumably your hero can't do mid-air jumps.
Immediately after you set jumping (and inside the same if statement), update their velocity.
In your update section, add another if for whether or not the player is jumping, regardless of whether or not they are pressing any keys. If they are, decrease their momentum based on gravity. Then, add a check for if their momentum is the opposite of how much you increase it when they start jumping. In other words, check if they are moving down at exactly the same rate they were moving up when they started jump. This happens at exactly the y-coordinate that they began the jump from. (This is more reliable that just checking their position, because it will work from multiple y-locations.) The alternative would be to store a variable with the y-coordinate they were at when they jumped. Either way, if their jump has ended, set jumping to false.
Since you're updating their coordinates based on jumping, in your render function, you can eliminate any jumping logic and just draw the image based on the coordinates.
Does that help at all?

How to determine which enemy is hit and destroy it alone

http://jsfiddle.net/5DB6K/
I have this game being made where you shoot enemies from the sides of the screen. I've got the bullets moving and being removed when they reach the end of the screen (if they didn't hit any enemy) and removing the enemy when they collide with it.
//------------collision----------------//
if(shot === true){
bulletY = $('.bullet').position().top + 2;
bulletX = $('.bullet').position().left + 2;
$('.enemy').each(function(){
if($('.enemy').hasClass('smallEnemy')){
enemyY = $(this).position().top + 7;
enemyX = $(this).position().left + 7;
if(Math.abs(bulletY - enemyY) <= 9 && Math.abs(bulletX - enemyX) <=9){
$(this).remove();
score = score + 40;
bulletDestroy();
}
}
});
}
However, the bullet destroys every enemy if the collision check is right which isn't what I want. I want to check if the enemy has the class of either smallEnemy, medEnemy, or lrgEnemy and then do the collision check which is what I thought I had but it doesn't seem to work.
Also, the game starts to lag the more and more time goes on. Would anyone know the reason for that?
This will remove all enemies any time a small enemy is present, due to your .each conditions. Try this:
if($(this).hasClass('smallEnemy')){
enemyY = $(this).position().top + 7;
enemyX = $(this).position().left + 7;
if(Math.abs(bulletY - enemyY) <= 9 && Math.abs(bulletX - enemyX) <=9){
$(this).remove();
score = score + 40;
bulletDestroy();
}
As for lag, it's due to memory availability and overhead. Instead of looping through your "enemeies", I would attach an observer to your bullets, and whenever they intersect with .enemy you should fire a custom event to remove this enemey. Much less code too.

Categories