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.
Related
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 ?
I'm eleven and new to programming, and I'm making a simple platformer for a game comp at my school using javascript.
Right now I'm working on the code that makes the character jump. It's more complex than the character just going up and then down, because I want the movements to be fluent and look realistic. When the character jumps, it leaves the ground fast, then slows down as it goes higher, and when it reaches a certain point, it will start to fall slowly. It will speed up as it falls (probably by using some type of acceleration variable), and then hit the ground and stop completely.
I want the character to be able to move left and right in the air, and if the key is held, jump once, and then when the character hits the ground, if the key is still held, to jump again. (the in-game character should be able to jump quite high)
I've tried to do this already, but I had some hilarious errors happening.
Here's my (very broken) code:
//movement (x)
var maxSpeed = 12.5;
var xForce = 0;
var kingXPos = 0;
//movement (y)
var yForce = 0;
var kingYPos = 202;
//LV design
var floorHeight = 150;
var draw = function() {
//background and basics
background(255, 0, 0);
image(getImage("creatures/Winston"), kingXPos, kingYPos, 50, 50);
//level features (only the floor right now)
fill(0, 0, 0);
rect(0, 250, 400, floorHeight);
//right movement
if (keyIsPressed && keyCode === RIGHT) {
kingXPos = kingXPos + xForce;
xForce = xForce + 0.25;
if (xForce >= maxSpeed && keyIsPressed) {
xForce = maxSpeed;
}
}
//left movement
if (keyIsPressed && keyCode === LEFT) {
kingXPos = kingXPos + xForce;
xForce = xForce - 0.25;
if (xForce <= -maxSpeed && keyIsPressed) {
xForce = -maxSpeed;
}
}
//jump (not yet functional)
if (keyTyped && keyCode === UP && kingYPos === floorHeight + 50) {
kingYPos = kingYPos + yForce;
yForce = yForce - 0.5;
}
//other physics
if (!keyIsPressed) {
kingXPos = kingXPos + xForce;
if (xForce > 0) {
xForce = xForce - 0.25;
}
else if (xForce < 0) {
xForce = xForce + 0.25;
}
}
};
That's fairly impressive for someone just starting. You seem to have an intuitive understanding of geometry. However, there are some domain knowledge you may not be aware of due to how much education you've had.
In physics, the correct set of equations that describes motion is:
1. velocity = change_in_location / time
2. acceleration = change_in_velocity / time
Another thing you need to be aware of is that gravity is a form of acceleration. Specifically it is a downward acceleration of 9.8m/s/s
So rewriting all of the above:
new_location = (velocity * time) + old_location
new_velocity = (acceleration * time) + old_velocity
If you assume a constant time animation loop you can assume that time = 1. So that simplifies it to:
new_location = velocity + old_location
new_velocity = acceleration + old_velocity
This is enough to simulate gravity. Since gravity is just an acceleration:
gravity = SOME_NUMBER; // tune this to get the gravity you want
kingYPos = kingYPos + kingYVelocity;
kingYVelocity = kingYVelocity + gravity;
To jump just give the object an instant boost in velocity:
// jump:
kingYVelocity = -SOME_OTHER_NUMBER; // negative because "up"
Note: Domain knowledge is knowledge outside of programming that a programmer must understand in order to solve a particular problem. For example, a programmer who writes an accounting software should have some knowledge of accounting. In practice, not all programmers in the industry make the effort to acquire domain knowledge because sometimes there's a systems analyst/consultant writing the requirements for the software. But when you write your own software you have no choice but to acquire some domain knowledge.
All I need is to have this object travel left and right across the top of the canvas. Currently it spawns and travels right absolutely fine, then stops once it reaches the right edge of the canvas.
//mainEnemy Variables
var mainEnemy_x = 10;
var mainEnemy_y = 10;
var mainEnemyHeight = 50;
var mainEnemyWidth = 25;
var mainEnemyRight = true;
var mainEnemyLeft = false;
var mainEnemy_dx = 2;
//Drawing the Main Enemy
function drawMainEnemy()
{
ctx.beginPath();
ctx.rect(mainEnemy_x, mainEnemy_y, mainEnemyHeight, mainEnemyWidth);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
}
//Movement speed of mainEnemy
if(mainEnemyRight && mainEnemy_x < canvas.width-mainEnemyWidth)
{
mainEnemy_x += 5;
}
else if(mainEnemyLeft && mainEnemy_x > 0)
{
mainEnemy_x -= 5;
}
//mainEnemy moves across the top of the canvas
if(mainEnemy_x + mainEnemy_dx - mainEnemyWidth > canvas.width)
{
mainEnemy_dx = -mainEnemy_dx;
}
ball_x += dx;
ball_y += dy;
mainEnemy_x += mainEnemy_dx;
}
This is all the code relevant to the object I need help with. I've tried just reversing it's x movement, with the mainEnemy_dx = -mainEnemy_dx; line, but this isn't working. I can see this code is an absolute mess at the moment, I just need to get it working then time for some serious cleanup.
Any and all help would be greatly appreciated!
First of all, you have two movement systems. One with the left and right flags and constants added or subtracted from x and the other with dx. You should just use one or the other, the latter being simpler.
For the jitter, you have to either also check that the current dx is positive when going over the right by border (and negative on left) and then switch the sign, or move the object left when a collision with right border is found.
At the moment you are moving the object 7 units right every time, then when border is found only dx is used (2 or -2) but since your object can be over the border it might vibrate between 2 and -2 always. But at least the right branch will always try to move 5 units right even when dx is negative.
Using a debugger to step through the code and inspecting the variables and branches taken while vibrating on the right edge will show exactly how it behaves.
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';
}
I'm working on the Collision system for my game; which is a top down shooter, the character is always static - and everything else (Map/Level), moves around him.
The character also rotates so it's always facing the mouse position.
With that in mind, I can't seem to get my head around my collision system, which needs to take into account of the character rotation, right?
I basically just want to check if the given object is at all 'touching' my character/sprite. I'm not so sure if the maths I'm using is correct.
This is my collision detection (called every update):
function detectCollisions(){
//Detect for game props
if(collides(Map, TestProp)){
console.debug("Touching...");
}
}
function collides(a, b){
//ctxMap.setTransform(1, 0, 0, 1, -Map.x + gameWidth/2, -Map.y + gameHeight/2);
//var transX = -Map.x + gameWidth/2;
//var transY = -Map.y + gameHeight/2;
//need to take player rotation into account too!
//console.debug(a.x + " " + b.x + " " + b.width + " " + Player.width); //A Width
/*return a.x < b.x + b.width && a.x + Player.width > b.x &&
a.y < b.y + b.height && a.y + Player.height > b.y;*/
var xOffset = Math.cos(Player.characterRotation); //+ Player.width;
var yOffset = Math.sin(Player.characterRotation); //+ Player.height;
return Map.x + xOffset > b.x && Map.x + xOffset < b.x + b.width &&
Map.y + yOffset > b.y && Map.y + yOffset < b.y + b.height;
}
Also, not sure if this is relevant, but this is the transform used to move my Map Canvas:
ctxMap.setTransform(1, 0, 0, 1, -Map.x + gameWidth/2, -Map.y + gameHeight/2);
Would much appreciate it if someone helped me out here :) Thanks!
Personally, I wouldn't worry so much about the character colliding. The reason I say that is simple.
Let's saw you're walking real close to a wall. Then you turn to follow the mouse, and the sprite then overlaps the wall. What do you do now? Either you stop the turning, which would screw up movements, or you let the sprite overlap and the player gets completely stuck until they turn free again.
My preference would be to use a collision circle. If the player is closer than R pixels from the wall, count it as a collision and stop the player from moving. This way, even if the player turns, the sprite will never cause the player to get stuck and he will always be able to move away from the wall.
I entered ludum dare this time around and did a tutorial to explain my base code. The tutorials can be found here: http://www.philjeffes.co.uk/wordpress/?p=63
This demonstrates an example of circle based collision detection - please feel free to use any of the code. The following code is an adaptation of that code for general usage:
function CollisionCheck(obj1,obj2){
// If the two objects are less the sum of their collision radii apart then they have collided
// Note that one obj is obj (with a loc and a size) and the other is this.
// Returns true if the objects are touching
var dist = obj2.size + obj1.size; // The distance they must be apart to be not touching
if(obj1.x-obj2.x>dist || obj1.x-obj2.x<-dist)
return false; // Too far apart in x plane
if(obj1.y-obj2.y>dist || obj1.y-obj2.y<-dist)
return false; // Too far apart in y plane
var xDist = obj1.x-obj2.x;
var yDist = obj1.y-obj2.y;
var hyp = Math.sqrt((xDist*xDist)+(yDist*yDist));
if(hyp<dist)
return true;
return false;
}
EDIT
Removed the Math.abs calls as pointed out by vals in the comments.