Stop Movement on Collision - javascript

I'm creating a little game in Javascript and I have created a collision detection function that detects when my 2 images collide. I have a player image and enemy image and I move the player around with the arrow keys. When I collide with the enemy image I want the player to not be able to cross over the image but still be able to move, like colliding with a wall or something. I don't really know how to go about this so I cant supply and example code but I can give you my collide function and player objects;
//PLAYER OBJECTS
var playerImg = new Image();
playerImg.src = "../Images/player.png";
var playerReady = false;
playerImg.onload = function(){
playerReady = true;
};
var player = {
x: 300,
y: 150,
speed: 200
};
//COLLIDE FUNCTION
function CollisionCheck(Img1, Img2, Obj1, Obj2, width){
var colliding = false;
if(Obj1.x < Obj2.x + width && Obj1.x + width > Obj2.x && Obj1.y < Obj2.y + width && Obj1.y + width > Obj2.y){
colliding = true;
}else{
colliding = false;
}
return colliding;
}
Maybe I could detect which side the collision is on and stop the player from moving towards the image whilst colliding?
I call the function with:
if(CollisionCheck(player, enemy, 32)){
}

function checkTouching(img1, img2)
{
// checks if the two images are touching at any coordinate
// given two objects with x, y, width, and height
var touching =
img1.x + img1.width >= img2.x
&& img1.x <= img1.x + img1.width
&& img1.height + img1.y >= img2.y
&& img2.y <= img2.y + img2.y;
if (touching)
{
// images are touching
}
else
{
// images aren't touching
}
}

Related

How would I make a collider that stops the game when it collides with the "character"?

I'm still pretty new to this, so I don't know how to create a collider. My end goal is to have a game like the chrome dinosaur game. Same principles, and all. My question is, though, how do I even make a collider. I will be using a .gif for the "dinosaur". I'd like to make it where if this collider were to touch another collider, the game stops and a "game over" is shown. I have tried to create a collider, but they just keep showing up underneath the screen where the game is shown. Ant tips, tricks, or advice? Thanks
Code is as follows:
let img; //background
var bgImg; //also the background
var x1 = 0;
var x2;
var scrollSpeed = 4; //how fast background is
let music; //for music
let catBus; //catbus
//collider variables
let tinyToto;
let tiniestToto;
let hin;
let totoWithBag;
let noFace;
let happySoot;
var mode; //determines whether the game has started
let gravity = 0.2; //jumping forces
let velocity = 0.1;
let upForce = 7;
let startY = 730; //where cat bus jumps from
let startX = 70;
let totoX = 900;
let totoY = 70;
let tinToX = 900;
let tinToY = 70;
var font1; //custom fonts
var font2;
p5.disableFriendlyErrors = true; //avoids errors
function preload() {
bgImg = loadImage("backgwound.png"); //importing background
music = loadSound("catbus theme song.mp3"); //importing music
font1 = loadFont("Big Font.TTF");
font2 = loadFont("Smaller Font.ttf");
//tinyToto.setCollider("rectangle",0,25,75,75)
}
function setup() {
createCanvas(1000, 1000); //canvas size
img = loadImage("backgwound.png"); //background in
x2 = width;
music.loop(); //loops the music
catBus = {
//coordinates for catbus
x: startX,
y: startY,
};
/*
tinyToto = {
x: totoX,
y: totoY,
}
tinTo = {
x : tinToX,
y: tinToY,
}
*/
catGif = createImg("catgif.gif"); //creates catbus
catGif.position(catBus.x, catBus.y); //creates position
catGif.size(270, 100); //creates how big
/*
tinyToto = createImg("TinyToto.gif")
tinyToto.position(tinyToto.x, tinyToto.y)
tinyToto.size(270,100)
tiniestTo = createImg("tiniest Toto.gif")
tiniestTo.position(tinToX.x, tinToY.y)
tiniestTo.size(270,100)
*/
mode = 0; //game start
textSize(50); //text size
}
function draw() {
let time = frameCount; //start background loop
image(img, 0 - time, 0);
image(bgImg, x1, 2, width, height);
image(bgImg, x2, 2, width, height);
x1 -= scrollSpeed;
x2 -= scrollSpeed;
if (x1 <= -width) {
x1 = width;
}
if (x2 <= -width) {
x2 = width;
} //end background loop
fill(128 + sin(frameCount * 0.05) * 128); //text colour
if (mode == 0) {
textSize(20);
textFont(font1);
text("press SPACE to start the game!", 240, 500); //what text to type
}
fill("white");
if (mode == 0) {
textSize(35);
textFont(font2);
text("CATBUS BIZZARE ADVENTURE", 90, 450); //what text to type
}
catBus.y = catBus.y + velocity; //code for jumping
velocity = velocity + gravity;
if (catBus.y > startY) {
velocity = 0;
catBus.y = startY;
}
catGif.position(catBus.x, catBus.y);
//setCollider("tinyToto")
}
function keyPressed() {
if (keyCode === 32 && velocity == 0) {
//spacebar code
mode = 1;
velocity += -upForce;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
well, this is how I would generally do that kind of thingy:
function draw(){
for(let i in objects) // objects would be cactuses or birds
if(objects[i].x > player.x &&
objects[i].x < player.x + player.width &&
objects[i].y > player.y &&
objects[i].y < player.y + player.height){
noLoop()
// maybe do something else here
} // you could also use: for(let object of objects)
}
or if you want to do class stuff:
let player = new Player()
class Entity {
hasCollided_pointRect(_x, _y, _width, _height){
if(this.x > _x &&
this.x < _x + _width &&
this.y > _y &&
this.y < _y + _height){
return true
}
}
}
class Cactus extends Entity {
update(){
if(hasCollided_pointRect(player.x, player.y, player.width, player.height))
lossEvent()
}
}
class Player {
// ...
}
function lossEvent(){
noLoop()
}
this is a pretty classy way to do it and for a small game you really don't need all of this
also MDN has a nice article on rect with rect & point with rect collisions,
point with point collision is just (x == x && y == y)
https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
this is one of my recent loss "functions":
if(flag.health <= 0){
noLoop()
newSplashText("You lost!\nPress F5 to restart!", "center", "center", 1)
}
The way I handled game states in my Processing games was by making seperate classes for them. Then my main sketch's draw function looked something like
fun draw()
{
currentState.draw();
}
Each gamestate then acted as their own sketches (for example a menu screen, playing, game over, etc), and had a reference to the main sketch which created the states. They would then alter the main's currentState to, i.e., a new GameOverState() etc. where needed.
For now, don't worry about doing that too much if all you want a really simple gameoverscreen with an image and some text.
I would suggest a structure like this instead. Use this pseudocode in your main draw function:
fun draw()
{
if (gameOver)
{
// show game over screen
img(gameOver);
text("game over!");
// skip rest of the function
return;
}
// normal game code goes here
foo();
bar();
// update game over after this frame's game code completes
gameOver = checkGameOver();
}
Now you need a way of checking for a collision to determine the result of checkGameOver()
For the collision handling, check out Jeffrey Thompson's book/website on collision handling. It's an amazing resource, I highly recommend you check it out.
From the website I just linked, here's an excerpt from the website talking about handling collisions between 2d rectangles.
And here's a modified version of the collision handling function listed there (I updated the variable names to be a little more intuitive)
boolean rectRect(float rect1X, float rect1Y, float rect1Width, float rect1Height, float rect2X, float rect2Y, float rect2Width, float r2h)
{
// are the sides of one rectangle touching the other?
if (rect1X + rect1Width >= rect2X && // r1 right edge past r2 left
rect1X <= rect2X + rect2Width && // r1 left edge past r2 right
rect1Y + rect1Height >= rect2Y && // r1 top edge past r2 bottom
rect1Y <= rect2Y + r2h)
{ // r1 bottom edge past r2 top
return true;
}
return false;
You can use that function in your checkGameOver() function which would return a bool depending on whether your collision criteria are met.
For your game, you would loop over every obstacle in your game and check whether the dino and the obstacle overlap.
Pseudocode:
boolean checkGameOver()
{
foreach (Obstacle obstacle in obstacles)
{
if (rectRect(dino, obstacle))
{
return true;
}
}
return false;
}

How to check if a drawn wall is touching player (canvas) for collisions?

I have a 2D map using canvas html element and I have drawn a red square as a player, and a wall out of light blue beneath it. I want to know how I can detect if the player (red square) is touching the wall (light blue). I do not have classes or anything, just drawn squares using the canvas element, with set positions.
CODE:
var ctx = document.getElementById("canvas").getContext('2d')
document.getElementById("canvas").tabIndex = 1;
// quick way to get focus so keypresses register
ctx.font = '8px sans';
var offsetx = 0
var offsety = 0
var things = [
[0,100,300,50]
]
function offset() {
ctx.save();
ctx.translate(offsetx,offsety);
// clear the viewport
ctx.clearRect(-offsetx, -offsety, 300,300);
ctx.fillStyle = "red";
ctx.fillRect(50-offsetx,50-offsety,8,8)
// draw the other stuff on the screen, which have the set positions in the array.
var l = things.length;
var i = 0;
for (i = i; i < l; i++) {
var x = things[i][0];
var y = things[i][1];
var sizex = things[i][2]
var sizey = things[i][3]
ctx.fillStyle = 'lightblue';
ctx.fillRect(x, y, sizex, sizey);
ctx.fillStyle = 'black';
}
ctx.restore();
}
offset(); // the first call to draw all the elements.
document.getElementById("canvas").addEventListener('keydown', function(e) {
if (e.keyCode === 37) { // left
offsetx++;
} else if (e.keyCode === 39) { // right
offsetx--;
} else if (e.keyCode === 38) { // up
offsety++;
} else if (e.keyCode === 40) { // down
offsety--;
}
offset();
}, false);
setInterval(function() {
// in here i would check for the collisions
}, 10);
I figured it out on my own, since noone else would. Basically you give the drawn walls, (with set posisiton) some set positions for where the resistance or collision point should be. then, before the player is move, in the move function you check to see if that player is on, right before, or in that wall. if so, return, otherwise continue. here is my code example:
jsfiddle.net/57xm0fw1/1/

How to detect the side on which collision occured

This is my first post so I'm trying to make my problem as clear as possible. I'm making a game and I want to improve my collision detection. This is because I want to check what side is being hit and stop the player from moving past it without using something general like if(collision(player, enemy)) player.x = enemy.x - player.w(width) because if the player were to collide with the top it wouldn't keep the player on top.
In the code it checks if any one of the statements is true and then returns it but it doesn't tell me which statement was the one that was equal to true so I can stop the player from moving accordingly, if that makes sense. If you have a more efficient collision detection for me to use it would be greatly appreciated.
I've already tried to make a position variable to be equal to whatever side gets collided into and then stop the player from moving past it but it only works for the left side and won't let my player jump over the enemy or block.
function collision(object1, object2) {
return !(
object1.x > object2.x + object2.w ||
object1.x + object1.w < object2.x ||
object1.y > object2.y + object2.h ||
object1.y + object1.h < object2.y
)
}
//Only works for the left side
if(collision(player, enemy)) player.x = enemy.x - player.w
I expect it to be able to tell me what side is being collided into and then either stop the player from moving past/into it and for the player to be able to be on top of the block/enemy without just being pushed to the left.
You'll want to calculate the distance between the x's and y's and also use the minimum distance that they could be colliding along each axis to find the depth along both axes. Then you can pick the smaller depth and move along that one. Here's an example:
if(collision(player, enemy)){
// Most of this stuff would probably be good to keep stored inside the player
// along side their x and y position. That way it doesn't have to be recalculated
// every collision check
var playerHalfW = player.w/2
var playerHalfH = player.h/2
var enemyHalfW = enemy.w/2
var enemyHalfH = enemy.h/2
var playerCenterX = player.x + player.w/2
var playerCenterY = player.y + player.h/2
var enemyCenterX = enemy.x + enemy.w/2
var enemyCenterY = enemy.y + enemy.h/2
// Calculate the distance between centers
var diffX = playerCenterX - enemyCenterX
var diffY = playerCenterY - enemyCenterY
// Calculate the minimum distance to separate along X and Y
var minXDist = playerHalfW + enemyHalfW
var minYDist = playerHalfH + enemyHalfH
// Calculate the depth of collision for both the X and Y axis
var depthX = diffX > 0 ? minXDist - diffX : -minXDist - diffX
var depthY = diffY > 0 ? minYDist - diffY : -minYDist - diffY
// Now that you have the depth, you can pick the smaller depth and move
// along that axis.
if(depthX != 0 && depthY != 0){
if(Math.abs(depthX) < Math.abs(depthY)){
// Collision along the X axis. React accordingly
if(depthX > 0){
// Left side collision
}
else{
// Right side collision
}
}
else{
// Collision along the Y axis.
if(depthY > 0){
// Top side collision
}
else{
// Bottom side collision
}
}
}
}
Working example
Here's a working example that you can play around with. Use the arrow keys to move the player around.
player = {
x: 9,
y: 50,
w: 100,
h: 100
}
enemy = {
x: 100,
y: 100,
w: 100,
h: 100
}
output = document.getElementById("collisionType");
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d")
function collision(object1, object2) {
return !(
object1.x > object2.x + object2.w ||
object1.x + object1.w < object2.x ||
object1.y > object2.y + object2.h ||
object1.y + object1.h < object2.y
)
}
function draw() {
ctx.clearRect(0, 0, 400, 400)
ctx.lineWidth = "5"
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.rect(player.x, player.y, player.w, player.h);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.rect(enemy.x, enemy.y, enemy.w, enemy.h);
ctx.stroke();
}
function handleCollision() {
if (collision(player, enemy)) {
var playerHalfW = player.w / 2
var playerHalfH = player.h / 2
var enemyHalfW = enemy.w / 2
var enemyHalfH = enemy.h / 2
var playerCenterX = player.x + player.w / 2
var playerCenterY = player.y + player.h / 2
var enemyCenterX = enemy.x + enemy.w / 2
var enemyCenterY = enemy.y + enemy.h / 2
// Calculate the distance between centers
var diffX = playerCenterX - enemyCenterX
var diffY = playerCenterY - enemyCenterY
// Calculate the minimum distance to separate along X and Y
var minXDist = playerHalfW + enemyHalfW
var minYDist = playerHalfH + enemyHalfH
// Calculate the depth of collision for both the X and Y axis
var depthX = diffX > 0 ? minXDist - diffX : -minXDist - diffX
var depthY = diffY > 0 ? minYDist - diffY : -minYDist - diffY
// Now that you have the depth, you can pick the smaller depth and move
// along that axis.
if (depthX != 0 && depthY != 0) {
if (Math.abs(depthX) < Math.abs(depthY)) {
// Collision along the X axis. React accordingly
if (depthX > 0) {
output.innerHTML = "left side collision"
} else {
output.innerHTML = "right side collision"
}
} else {
// Collision along the Y axis.
if (depthY > 0) {
output.innerHTML = "top side collision"
} else {
output.innerHTML = "bottom side collision"
}
}
}
} else {
output.innerHTML = "No collision"
}
}
keyStates = []
function handleKeys() {
if (keyStates[39]) {
player.x += 2 //Move right
} else if (keyStates[37]) {
player.x -= 2 //Move left
}
if (keyStates[38]) {
player.y -= 2 //Move up
}
if (keyStates[40]) {
player.y += 2 //Move down
}
}
function main() {
handleKeys();
draw();
handleCollision();
window.requestAnimationFrame(main);
}
window.onkeydown = function(e) {
keyStates[e.keyCode] = true
}
window.onkeyup = function(e) {
keyStates[e.keyCode] = false
}
main();
<h2 id="collisionType"></h2>
<canvas id="canvas" width='300' height='300'></canvas>
Reacting to the collision
Now that you know the side the collision happened on, it should be fairly trivial to decide how to react. It would be very similar to what you are currently doing for the left side just flip some signs around and change the axis.
Other Considerations
You may want to take into account your player's velocity (if it has one) otherwise the detection may fail.
If the player's velocity is too high, it might 'tunnel' through the enemy and no collision will be detected.
The player's movement can also look jittery if the velocity is not stopped upon collision
Can your objects rotate or have more than 4 sides? If so, you'll probably want to use another method as described below.
Here's a good answer to another post that talks in depth about collision engines
Other Methods
As for other collision detection methods, there's quite a few but one that comes to mind is Separating Axis Theorem which is a little more complex than what you have but will work with more complex convex shapes and rotation. It also tells you the direction and distance needed to move to resolve the collision. Here's a site that has interactive examples and goes in-depth on the subject. It doesn't appear to give a full implementation but those can be found other places.

How to add a logic statement to an object entering a moving area

I am trying to make a game. The object of the game is to move the square across the screen without hitting a raindrop falling from the roof. How do i make it so that if one of the raindrops enters the square, the square returns to the beginning of the canvas or x =0. Here is the code:
var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');
var WIDTH = 1000;
var HEIGHT = 700;
var x = 0;
var y = HEIGHT-20;
var xPos = [0];
var yPos = [0];
var speed = [1];
var rainDrops = 50;
var rectWidth = 20;
var rectHeight = 20;
for (var i = 0; i < rainDrops; i++) {
xPos.push(Math.random()* WIDTH);
yPos.push(0);
speed.push(Math.random() * 5);
}
function rainFall () {
window.requestAnimationFrame(rainFall);
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i <rainDrops; i++) {
//Rain
ctx.beginPath();
ctx.arc(xPos[i], yPos[i], 3, 0, 2 * Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
//Rain movement
yPos[i]+=speed[i];
//Box
ctx.fillStyle = 'red';
ctx.fillRect(x, y, rectWidth, rectWidth);
if (yPos[i] > HEIGHT) {
yPos[i]= 0;
yPos[i]+=speed[0];
}
//This is the part where I need the Help!!!!!!!!!
if (){
x = 0;
}
}
};
//Move Object
function move (e) {
if (e.keyCode === 37) {
ctx.clearRect (0, 0, WIDTH, HEIGHT);
x -=10;
}
if (e.keyCode === 39) {
ctx.clearRect (0, 0, WIDTH, HEIGHT);
x+=10;
}
canvas.width=canvas.width
}
//Lockl Screen
window.addEventListener("keydown", function(e) {
// Lock arrow keys
if( [37,39,].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
}, false);
rainFall();
document.onkeydown = move;
window.addEventListener("load", doFirst, false);
Conditional statements
I am never too sure how to answer these types of questions. As you are a beginner I don't want to overwhelm you with code and techniques, but at the same time I don't want to give an answer that perpetuates some bad techniques.
The short answer
So first the simple answer from your code where you wrote
//This is the part where I need the Help!!!!!!!!!
// the test checks the center of the drop
// if drop is greater than > top of player (y) and (&&)
// drop x greater than > left side of player x and (&&) drop is less than <
// right side of player (x + rectWidth) then drop has hit player
if (yPos[i] > y && xPos[i] > x && xPos[i] < x + rectWidth ){
x = 0; // move player back
}
BTW you are drawing the player rectangle for each rain drop. You should move that draw function outside the loop.
The long answer
Hopefully I have not made it too confusing and have added plenty of comments about why I did this and that.
To help keep everything organised I separate out the various elements into their own objects. There is the player, rain, and keyboard handler. This is all coordinated via the mainLoop the is called once a frame (by requestAnimationFrame) and calls the various functions to do all that is needed.
The player object holds all the data to do with the player, and functions to draw and update the player (update moves the player)
The rain object holds all the rain in an array called rain.drops it has functions to draw and update the rain. It also has some functions to randomize a drop, and add new drops.
To test if the rain has hit the player I do it in the rain.update function (where I move the rain) I don`t know what you wanted to happen when the rain hits the player so I just reset the rain drop and added 1 to the hit counter.
I first check if the bottom of the rain drop drop.y + drop.radius is greater than the top of the player if(drop.y + drop.radius >= player.y){
This makes it so we dont waste time checking rain that is above the player.
The I test for the rain in the x direction. The easiest is the test the negative (if the rain is not hitting the player) as the logic is a little simplier.
If the right side of the drop is to the left of the left side of the player, or (use || for or) the left side of the drop is to the right of the right side of the player than the drop can not be hitting the player. As we want the reverse condition we wrap it in a brackets a put a not in front if(! ( ... ) )
The test is a little long so I break it into 2 lines for readability.
// drop is a single rain drop player is the player
if (drop.y + drop.radius >= player.y) {
if ( ! (drop.x + drop.radius < player.x ||
drop.x - drop.radius > player.x + player.width) ) {
// code for player hit by rain in here
}
}
The rain.update function also checks if the rain has hit the bottom of the canvas and resets it if so.
Demo
I copied your code from in the question and modified it.
addEventListener("load",function(){ // you had onload at the bottom after all the code that gets the canvas
// etc. Which kind of makes the on load event pointless. Though not needed
// in this example I have put it in how you can use it for a web page.
// Using onload event lets you put the javascript anywhere in the HTML document
// if you dont use onload you must then only put the javascript after
// the page elements you need eg Canvas.
var canvas = document.getElementById('gameCanvas');
var ctx = canvas.getContext('2d');
ctx.font = "20px arial";
var frameCount = 0; // counts the frames
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var currentMaxDrops = 5; // rain will increase over time
const numberFramesPerRainIncrease = 60 * 5; // long name says it all. 60 frames is one second.
const maxRainDrops = 150; // max number of rain drops
// set up keyboard handler
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
requestAnimationFrame(mainLoop); // request the first frame of the animation (get it all going)
//==========================================================================================
// Setup the keyboard input stuff
const keys = { // list of keyboard keys to listen to by name.
ArrowLeft : false,
ArrowRight : false,
}
function keyEvent(event){ // the key event argument event.code hold the named key.
if(keys[event.code] !== undefined){ // is this a key we want
event.preventDefault(); // prevent default browser action
keys[event.code] = event.type === "keydown"; // true if keydown false if not
}
}
//==========================================================================================
const player = { // object for everything to do with the player
x : 0, // position
y : HEIGHT - 20,
width : 20, // size
height : 20,
speed : 4, // speed per frame
color : "red",
showHit : 0, // when this is > 0 then draw the player blue to indicate a hit.
// This counter is counted down each frame so setting its value
// determins how long to flash the blue
hitCount : 0, // a count of the number of drops that hit the player.
status(){ // uses hit count to get a status string
if(player.hitCount === 0){
return "Dry as a bone.";
}
if(player.hitCount < 5){
return "A little damp.";
}
if(player.hitCount < 15){
return "Starting to get wet.";
}
return "Soaked to the core";
},
draw(){ // draw the player
if(player.showHit > 0){
player.showHit -= 1; // count down show hit
ctx.fillStyle = "blue";
}else{
ctx.fillStyle = player.color;
}
ctx.fillRect(player.x,player.y,player.width,player.height);
},
update(){ // this updates anything to do with the player
// Not sure how you wanted movement. You had it so that you move only when key down events
// so I have done the same
if(keys.ArrowLeft){
player.x -= player.speed; // move to the left
keys.ArrowLeft = false; // turn off the key. If you remove this line then will move left while
// the key is down and stop when the key is up.
if(player.x < 0){ // is the player on or past left side of canvas
player.x = 0; // move player back to zero.
}
}
if(keys.ArrowRight){
player.x += player.speed; // move to the right
keys.ArrowRight = false; // turn off the key. If you remove this line then will move right while
// the key is down and stop when the key is up.
if(player.x + player.width >= WIDTH){ // is the player on or past right side of canvas
player.x = WIDTH - player.width; // move player back to inside the canvas.
}
}
}
}
//==========================================================================================
const rain = { // object to hold everything about rain
numberRainDrops : 50,
drops : [], // an array of rain drops.
randomizeDrop(drop){ // sets a drop to random position etc.
drop.x = Math.random() * WIDTH; // random pos on canvas
drop.y = -10; // move of screen a little so we dont see it just appear
drop.radius = Math.random() *3 + 1; // give the drops a little random size
drop.speed = Math.random() * 4 + 1; // and some speed Dont want 0 speed so add 1
return drop;
},
createDrop(){ // function to create a rain drop and add it to the array of drops
if(rain.drops.length < currentMaxDrops){ // only add if count is below max
rain.drops.push(rain.randomizeDrop({})); // create and push a drop. {} creates an empty object that the function
// randomizeDrop will fill with the starting pos of the drop.
rain.numberRainDrops = rain.drops.length;
}
},
draw(){ // draw all the rain
ctx.beginPath(); // start a new path
ctx.fillStyle = 'blue'; // set the colour
for(var i = 0; i < rain.drops.length; i ++){
var drop = rain.drops[i]; // get the indexed drop
ctx.arc(drop.x, drop.y, drop.radius, 0, 2 * Math.PI);
ctx.closePath(); // stops the drops rendered as one shape
}
ctx.fill(); // now draw all the drops.
},
update(){
for(var i = 0; i < rain.drops.length; i ++){
var drop = rain.drops[i]; // get the indexed drop
drop.y += drop.speed; // move down a bit.
if(drop.y + drop.radius >= player.y){ // is this drop at or below player height
// checks if the drop is to the left or right of the player
// as we want to know if the player is hit we use ! (not)
// Thus the next if statement is if rain is not to the left or to the right then
// it must be on the player.
if(!(drop.x + drop.radius < player.x || // is the rigth side of the drop left of the players left side
drop.x - drop.radius > player.x + player.width)){
// rain has hit the player.
player.hitCount += 1;
player.showHit += 5;
rain.randomizeDrop(drop); // reset this drop.
}
}
if(drop.y > HEIGHT + drop.radius){ // is it off the screen ?
rain.randomizeDrop(drop); // restart the drop
}
}
}
}
function mainLoop () { // main animation loop
requestAnimationFrame(mainLoop); // request next frame (don`t need to specify window as it is the default object)
ctx.clearRect(0, 0, WIDTH, HEIGHT);
frameCount += 1; // count the frames
// when the remainder of frame count and long name var is 0 increase rain drop count
if(frameCount % numberFramesPerRainIncrease === 0){
if(currentMaxDrops < maxRainDrops){
currentMaxDrops += 1;
}
}
rain.createDrop(); // a new drop (if possible) per frame
rain.update(); // move the rain and checks if the player is hit
player.update(); // moves the player if keys are down and check if play hits the side of the canvas
player.draw(); // draw player
rain.draw(); // draw rain after player so its on top.
ctx.fillStyle = "black";
ctx.fillText("Hit " + player.hitCount + " times.",5,20);
ctx.setTransform(0.75,0,0,0.75,5,34); // makes status font 3/4 size and set position to 5 34 so I dont have to work out where to draw the smaller font
ctx.fillText(player.status(),0,0); // the transform set the position so text is just drawn at 0,0
ctx.setTransform(1,0,0,1,0,0); // reset the transform to the default so all other rendering is not effected
};
});
canvas {
border : 2px black solid;
}
<canvas id="gameCanvas" width=512 height=200></canvas>
Hope this was helpfull.

Clickable enemies

Hi im totally new to javascript and need help.im making an HtML javascript game. I just wanted to ask how do i get my enemies to be clickable?? i have managed to successfully create my enemies for my game but currently they come down from the top of the game screen and exit at the bottom. If the player touches any of the enemies then it goes to game over but i want the player to be able to click on the enemies then proceed to game over instead. Ive been trying for a couple of weeks now and im lost.
Also my player currently is being controlled by the mouse, as in the mouse is the player.
Do i need to change my collison test?? im just not sure how to make the player be able to click on the enemies. do i need to register a 'click' function like onmouseclick etc?
im using:
window.addEventListener("mousedown",onDown,false);
window.addEventListener("mousemove",onMove,false);
window.addEventListener("mouseup",onUp,false);
thanks any help would be great!! just need a sbit of help to go in the right direction.
Thanks in advance :)
this is the function for when the player is moving the mouse (player). it works as my player is controlled by the mouse movememt:
function onMove(e) {
if (!e) var e = window.event;
//get mouse position
var posx = 0;
var posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
var totalOffsetX = 0;
var totalOffsetY = 0;
var currentElement = canvas;
do{
totalOffsetX += currentElement.offsetLeft;
totalOffsetY += currentElement.offsetTop;
}
while(currentElement = currentElement.offsetParent)
mouseX = posx - totalOffsetX;
mouseY = posy - totalOffsetY;
}
}
and for mouse up:
function onUp(e) {
mouseDown = false;
}
for enemies, i have done:
enemies = new Array();
createEnemies();
and the function with the animations for the enemy objects (food and fruit items in the game) :
function createEnemies() {
var enemy
if(level>2 && Math.random()<0.2) {
var breakfastItems = Math.floor(Math.random() * breakfastsheets.length);
var tmpAnimation = new Animation(breakfastsheets[breakfastItems],4,2)
enemy = new Skull(tmpAnimation,Math.random()*(canvas.width-tmpAnimation.width),-tmpAnimation.height);
} else if(level>3 && Math.random()<0.2) {
var randomVegetable = Math.floor(Math.random() * vegetablesheets.length);
var tmpAnimation = new Animation(vegetablesheets[randomVegetable],4,2)
enemy = new Skull(tmpAnimation,Math.random()*(canvas.width-tmpAnimation.width),-tmpAnimation.height);
}else {
var randomFruit = Math.floor(Math.random() * enemysheets.length);
var tmpAnimation = new Animation(enemysheets[randomFruit],4,2)
enemy = new Skull(tmpAnimation,Math.random()*(canvas.width-tmpAnimation.width),-tmpAnimation.height);
}
enemy.setExplosionSound(explosionSoundPool);
enemies.push(enemy);
}
forgot to say that the 'Skull' thats in the enemies is this one: forget the missiles though im not using them.
function Skull (image, x,y, width, height) {
//call constructor of parent object
DisplayObject.call(this,'skull', image, x,y, width, height);
//initialise objects
this.img.play();
this.img.setLoop(true);
this.img.setRange(0,4);
//private variables
var dying = false;
var alive = true;
var speed = 5;
var explosionSound;
//public methods
this.update = function(game_area, missiles) { //game area is a Rect2d, missiles is an array of display objects.
this.y+=speed;
this.img.next();
if(!dying && missiles) {
for(var i = 0; i<missiles.length; i++) {
if(Collision.test(missiles[i],this)) {
missiles[i].kill();
dying = true;
this.img.setRange(4,8);
this.img.setLoop(false);
this.img.setFrame(0);
//play explosion sound.
if(explosionSound) explosionSound.play(0.5);
}
}
}
if(Collision.isOutside(this,game_area) || (dying && !this.img.isPlaying())) {
alive = false;
}
}
//set a sound to be played when the enemy is hit.
this.setExplosionSound = function (soundPool) {
explosionSound = soundPool;
}
this.isDying = function () {
return dying;
}
this.isDead = function () {
return !alive;
}
}
Skull.prototype = new DisplayObject();
Assuming the enemies are square objects that move around the screen,
What you can do is create a class for enemies that contain their current position with:
function newEnemy(){
this.topLeftx = 'some random value'
this.topLefty = 'some random value'
this.bottomRightx = 'some random value'
this.bottomRighty = 'some random value'
this.isSelected = false;
...
}
Then have a method that is called when the user clicks, and goes through the list of enemies one by one. For each enemy, call a 'hit test' function that will check if the user's (x,y) coordinates -on the mouse- are inside the square of the enemy.
If any of the shapes are selected, then set them to true, and on the next draw cycle, have selected enemies drawn differently or not drawn at all i.e. destroyed?
If the enemies are circular then you will need an x,y coordinate with a radius for each one. Then, simply check to see if a line drawn between the center of the circle and the mouse coordinates are less than the radius of the circle itself. Use the Pythagorean theorem to find the lengths.

Categories