In javascript, I'm making an HTML canvas game, and in that game I have an object type/constructor called gamePiece. gamePiece has a function called checkCollision:
this.checkCollision = function(piece){
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y <= this.y && piece.y <= (this.y - this.height);
if(collisionX || collisionY){
return true;
} else {
return false;
}
}
which is called by update()
function update(){
context.clearRect(0, 0, game.width, game.height);
for(var i = 0; i < gamePieces.length; i++){
gamePieces[i].update();
for(var mi = 0; mi < gamePieces.length; mi++){
gamePieces[i].checkCollision(gamePieces[mi]);
if(gamePieces[i].checkCollision(gamePieces[mi]) == true){
gamePieces[i].collisionFunction();
}
}
}
}
setInterval(function(){update();}, 1);
I have another object that is supposed to give a speed boost upon colliding with another game piece, and it logs every time it gives a speed boost.
var speedBooster = new gamePiece(25,25,"red",300,300,0);
speedBooster.collisionFunction = function(){
for(var whichpiece = 0; whichpiece < gamePieces.length; whichpiece++){
if(speedBooster.checkCollision(gamePieces[whichpiece]) == true && gamePieces[whichpiece] != this){
gamePieces[whichpiece].speed += 10;
console.log("gamePieces[" + whichpiece + "] has been given a speed boost.");
}
}
}
But it gives a speed boost whenever a piece is behind it, and I put the "piece.x >= this.x &&" there for a reason. Why is JavaScript ignoring the condition I gave it?
Try
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y >= this.y && piece.y <= (this.y + this.height);
if(collisionX && collisionY){
return true;
} else {
return false;
}
To test if two objects overlap. Where the object has x,y as the top left and w,h as width and height
//Returns true if any part of box1 touches box2
function areaTouching(box1,box2){
return ! (box1.x > box2.x + box2.w ||
box1.x + box1.w < box2.x ||
box1.y > box2.y + box2.h ||
box1.y + box1.h < box2.y)
}
Related
So, i have started building a game 2d just a few day so its make me so confuse with some reason of the movement character in the tilemap.In my tilemap, every per tiles2 is have the width and height 16px and the whole map is 800 x 1250, every movement of my character will add/sub 1 in per step, when I calculating detection collisions, the position became wrong position specifically when character move a step then the position return to far though i try to divide 16 px in every movement of character.
This is my movement:
this.setting_walking_speed = 3 ;
if (this.player.control_direction[0] == 1) {
this.player.x -= this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 0;
} else if (this.player.control_direction[1] == 1) {
this.player.y -= this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 2;
} else if (this.player.control_direction[2] == 1) {
this.player.x += this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 1;
} else if (this.player.control_direction[3] == 1) {
this.player.y += this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 3;
}
var posf = {
x:Math.floor( this.player.y /16 ) ,
y:Math.floor( this.player.x /16 )
};
this.collide(posf);
console.log(posf.x , posf.y);
}
And the collision function is:
The this.setting_minblocksize\[k\] = 16;
this.bound = this.draw_collision();
function rectangularCollision({rect1, rect2 }) {
return (
rect1.x >= rect2.x &&
rect1.x <= rect2.x &&
rect1.y <= rect2.y &&
rect1.y >= rect2.y
)
}
this.collide = function(player){
// console.log(this.bound);
this.bound.forEach((boundaries) => {
if(
rectangularCollision({,
rect1: player,
rect2: boundaries
})
){
console.log('collide');
}
})
}
this.draw_collision = function () {
var obj = [];
this.ctxt.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < canvas.height; i++) {
for (var j = 0; j < canvas.width; j++) {
var data = 0;
if (i >= 0 && j >= 0 && i < this.map.layers[1].height && j < this.map.layers[1].width) {
var data = this.map.layers[1].data[i * this.map.layers[1].width + j];
for (var k = 0; k < 1; k++) {
this.ctxt.fillStyle = 'red';
if (data != 0) {
obj.push({
x: j ,
y: i
});
this.ctxt.fillRect(
(j * this.setting_minblocksize[k]) ,
(i * this.setting_minblocksize[k]) ,
this.setting_minblocksize[k],
this.setting_minblocksize[k]
);
}
}
}
}
}
return obj;
}
My codepen link is right here
Thank you all for helping me!
I am new to stack and not quite sure how to use it. But here I am. I am working on a ecosystem project, and I have an animal class with 2 different genders(0 for female, 1 for male). When 2 different genders intersect each other than I want to remove those 2 objects and add a couple(different object, static) object on that position. I kinda did it but it only works for a couple of seconds. Then the code just breaks. In the console it says,
“Uncaught TypeError: Cannot read property ‘intersects’ of undefined”
Here's the question on the processing forum in case I get a solution which might help others: https://discourse.processing.org/t/multiple-object-intersection-and-removal/22900/2
Here's the sketch.js file:
var animats = [];
var couples = [];
function setup() {
frameRate(30);
createCanvas(displayWidth, 470);
for(var i = 0; i < 50; i++)
{
animats[i] = new Animat(random(0, width), random(0, height));
}
}
function draw() {
background(255,100,100);
for(var i = animats.length-1; i >= 0; i--) {
animats[i].birth();
animats[i].grow();
for(var j = i; j >= 0; j--) {
if(j != i && animats[i].intersects(animats[j])) {
animats.splice(i, 1);
animats.splice(j, 1);
}
}
}
}
Here's the animat class file:
function Animat(x, y) {
this.x = x;
this.y = y;
this.gender;
var g = random(0,1);
var c;
if(g > 0.5) {
c = 0;
this.gender = 0;
} else {
c = 255;
this.gender = 1;
}
this.speed = 1;
this.age = 0;
this.length = 0.5;
this.birth = function() {
//gender
//create
noStroke();
fill(c);
text("n", this.x, this.y, this.length, this.length);
ellipse(this.x, this.y, this.length * 2, this.length * 2);
//move
switch(floor(random(0,4))) {
case 0:
this.x += this.speed;
break;
case 1:
this.y += this.speed;
break;
case 2:
this.x -= this.speed;
break;
case 3:
this.y -= this.speed;
break;
default:
this.x++;
this.y--;
}
//bounce
if(this.x > width || this.x < 4){
this.speed *= -1;
}
if(this.y > height || this.y < 4){
this.speed *= -1;
}
}
this.grow = function() {
this.age += 0.01;
this.length += 0.05;
//age checks
if(this.age > 10) {
this.speed + 5;
} else if(this.age > 21) {
this.length = 25;
this.speed = this.speed
//console.log("max age:" + this.age)
} else if(this.age > 70) {
//die
} else {
}
//length checks
if(this.length > 25) {
this.length = 25;
//console.log("max length");
}
}
//relationship
this.intersects = function(other) {
var d = dist(this.x, this.y, other.x, other.y);
var r = this.length + other.length;
if(d < r) {
if(((this.gender == 0) && (other.gender == 1)) || ((this.gender == 1) && (other.gender == 0))) {
return true;
} else {
this.speed *= -1;
}
} else {
return false;
}
}
//mate
this.couple = function() {
if(((this.gender == 0) && (other.gender == 1)) || ((this.gender == 1) && (other.gender == 0))) {
return true;
} else {
this.speed *= -1;
}
}
//die
/*this.die = function() {
if(this.age > 50) {
return true;
} else {
return false;
}
}*/
}
Here's the codepen link for results I am getting:
https://codepen.io/AbrarShahriar/pen/XWXwLPM
Try changing your nested for loop to:
for (var i = animats.length - 1; i >= 0; i--) {
animats[i].birth();
animats[i].grow();
for (var j = i; j >= 0; j--) {
if (j != i && animats[i].intersects(animats[j])) {
animats.splice(i, 1);
animats.splice(j, 1);
break; //exit the inner loop after a match
}
}
}
In other words, add a break; after two animats have coupled and have been removed from the array. The error was probably caused by you trying to call the intersects method of an animat that had already been removed.
you need to keep animats[i] as long as the for-loop for j has not finished.
Here the code you need to fix:
for(var i = animats.length-1; i >= 0; i--) {
animats[i].birth();
animats[i].grow();
let remove = false; // mark 'i' as NOT REMOVE by default
for(var j = i; j >= 0; j--) {
if(j != i && animats[i].intersects(animats[j])) {
remove = true; // mark 'i' as to remove when collision detected
animats.splice(j, 1);
}
}
if (remove) { // remove 'i' after compared to all 'j'
animats.splice(i, 1);
}
}
I am trying to implement John Conway's Game of Life in HTML using canvas and JavaScript.
In a 2D array I store the cell's x-y position and state (alive or dead).
I avoid the outer most cells to avoid having to worry about boundary conditions.
Using requestAnimationFrame, I clear the canvas, update the cells for the next generation based on the number of neighbors, then draw them.
I console log the states of the cells, which do change but for some reason they don't get updated in the canvas.
I have already used this link for reference, but to no avail:
Canvas: X value changing in console but not in canvas
Here is the JavaScript code:
var cv = document.querySelector('#cv');
var c = cv.getContext('2d');
var h = cv.height;
var w = cv.width;
//Cell class
function Cell(alive, x, y) {
this.alive = alive;
this.x = x;
this.y = y;
this.draw = function () {
//c.beginPath();
this.x = x;
this.y = y;
if(alive == true) {
c.fillStyle = 'black';
c.fillRect(this.x, this.y, 10, 10);
}
else if(alive == false){
c.fillStyle = 'white';
c.fillRect(this.x, this.y, 10, 10);
}
//c.stroke();
}
}
//2d array to contain Cell objects
var cellArray = new Array(100);
for (var i = 0; i < cellArray.length; i++) {
cellArray[i] = new Array(70);
}
//initial drawing
for(var i = 0; i < cellArray.length; i++) {
for(var j = 0; j < 100; j++) {
var b = Math.round(Math.random() - 0.4);
if(b == 1) {
cellArray[i][j] = new Cell(true, i * 10, j * 10);
cellArray[i][j].draw();
}
else {
cellArray[i][j] = new Cell(false, i * 10, j * 10);
cellArray[i][j].draw();
}
}
}
//find number of neghbor cells
function neighborSum(cell, i, j) {
this.cell = cell;
this.i = i;
this.j = j;
var sum = 0;
if(cellArray[i - 1][j - 1].alive == true) {
sum += 1;
}
if(cellArray[i][j - 1].alive == true) {
sum += 1;
}
if(cellArray[i - 1][j].alive == true) {
sum += 1;
}
if(cellArray[i + 1][j - 1].alive == true) {
sum += 1;
}
if(cellArray[i - 1][j + 1].alive == true) {
sum += 1;
}
if(cellArray[i + 1][j].alive == true) {
sum += 1;
}
if(cellArray[i][j + 1].alive == true) {
sum += 1;
}
if(cellArray[i + 1][j + 1].alive == true) {
sum += 1;
}
return sum;
}
//animate function
function play() {
requestAnimationFrame(play);
c.clearRect(0, 0, w, h);
//check surrounding neighbor cells
for(var i = 1; i < cellArray.length - 1; i++) {
for(var j = 1; j < 70 - 1; j++) {
if( cellArray[i][j].alive == true && ( neighborSum(cellArray[i][j], i, j) > 3 || neighborSum(cellArray[i][j], i, j) < 2 ) ) {
cellArray[i][j].alive = false;
}
else if( cellArray[i][j].alive == true && ( neighborSum(cellArray[i][j], i, j) == 3 || neighborSum(cellArray[i][j], i, j) == 2 ) ) {
cellArray[i][j].alive = true;
}
else if(cellArray[i][j].alive == false && neighborSum(cellArray[i][j], i, j) == 3 ) {
cellArray[i][j].alive = true;
}
}
}
//console.log(cellArray)
//redraw cells alive or dead
for(var i = 1; i < cellArray.length - 1; i++) {
for(var j = 1; j < 70 - 1; j++) {
cellArray[i][j].draw();
}
}
}
requestAnimationFrame(play);
Here is a JSFiddle: https://jsfiddle.net/ew3046st/1/
Okay, so I was able to fix the problem by removing the draw() function and instead I just directly call the fillRect() function in the requestAnimationFrame function. Also, fixed the behavior of the cells by adding another 2d array of the same size to store the state of the cells for the next generation:
...
for(var i = 1; i < cellArray.length - 1; i++) {
for(var j = 1; j < 70 - 1; j++) {
//cellArray[i][j].draw();
c.beginPath();
//cellArray[i][j].draw();
if(cellArray[i][j].alive == true) {
c.fillStyle = 'black';
c.fillRect(cellArray[i][j].x, cellArray[i][j].y, 10, 10);
}
else if(cellArray[i][j].alive == false){
c.fillStyle = 'white';
c.fillRect(cellArray[i][j].x, cellArray[i][j].y, 10, 10);
}
c.stroke();
}
}
...
Here is a working jsfiddle: https://jsfiddle.net/e7u19xpq/1/
I'm doing an app in React/html5/canvas. In the canvas, you as the user can move around in different rooms with mouseclicks. That works, and I have made the collision detection for all the walls for the rooms (the view is 2d like a RTS game).
Now to the problem: When I hit a wall I set user.collision = true; And the next mouseclick will set user.collision = false;and this will make my character move again. Problem is that I now can clip through walls if I click some more times (it clitches through).
Have thought about the logical around this and I can't figure it out, and my research did not help me.
Here is my collision detection function: (All the walls are in the this.props.data)
collision: function(){
for (var i = 0; i < this.props.data.length; i++){
if (user.posX > this.props.data[i].x2 && user.posX < this.props.data[i].x1 &&
user.posY < this.props.data[i].y2 && user.posY > this.props.data[i].y1){
user.collision = true;
}
}
},
Here is my handleMouseClick function:
handleMouseClick: function(event){
var rect = game.getBoundingClientRect();
mouseClick.y = event.nativeEvent.clientY - rect.top;
mouseClick.x = event.nativeEvent.clientX - rect.left;
distance = Math.sqrt(Math.pow(mouseClick.x - user.posX, 2) + Math.pow(mouseClick.y - user.posY,2));
user.directionX = (mouseClick.x - user.posX) / distance;
user.directionY = (mouseClick.y - user.posY) / distance;
if (user.collision = true){
user.collision = false;
}
},
Here is my update function:
update: function(){
context.canvas.height);
if (!user.collision){
if(user.moving === true){
user.posX += user.directionX * user.speed * elapsed;
user.posY += user.directionY * user.speed * elapsed;
this.collision();
if(user.posX >= mouseClick.x -5 && user.posX <= mouseClick.x + 5 && user.posY >= mouseClick.y -5 && user.posY <= mouseClick.y + 5){
user.moving = false;
}
}
}
this.drawUser();
this.drawWalls();
},
How about just reverting to the previous pos if the collision test fails ?
update: function(){
context.canvas.height);
var prevPosX = user.posX;
var prevPosY = user.posY;
if (!user.collision){
if(user.moving === true){
user.posX += user.directionX * user.speed * elapsed;
user.posY += user.directionY * user.speed * elapsed;
this.collision();
if( user.collision ) { // ooops !
user.posX = prevPosX;
user.posY = prevPosY;
}
if(user.posX >= mouseClick.x -5 && user.posX <= mouseClick.x + 5 && user.posY >= mouseClick.y -5 && user.posY <= mouseClick.y + 5){
user.moving = false;
}
}
}
this.drawUser();
this.drawWalls();
},
NB: typo here
if (user.collision = true){
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
So, recently, I've been working on a JS/HTML5 Game Engine. Right now I'm calling it DimSumJs, because like DimSum isn't a full meal, my framework still runs too slowly to make a full game (it can only run about 250 "objects" despite before slowing down, it becomes very noticeable around 300 "objects"). It uses divs inside an iframe.
A sample game is available at http://pandamochi.x10.bz
just view resources with google chrome and you should be able to find the dimsum.js file
//DimSumJS - Open Source Game Engine
//DimSumJS (C) Ruochen Tang
//Can be used commerically, but please give credit
//Constants
var RIGHTKEY = 37;
var UPKEY = 38;
var LEFTKEY = 39;
var DOWNKEY = 40;
var SPACEKEY = 32;
var MASTER_WIDTH = 480;
var MASTER_HEIGHT = 600;
var Game = window.frames[0].document.body;
Game.setAttribute("width",MASTER_WIDTH + "px");
Game.setAttribute("height",MASTER_HEIGHT + "px");
var gl = setInterval("gameLoop();",15);
//Global Vars
var keyDown = new Array();
for (var i = 0; i < 256; i++){
keyDown[i] = false;
}
var gameState = 1;
//Settings
Game.style.backgroundColor = "#000";
//Key
processKeyEvent = function(event){
// MSIE hack
if (window.event)
{
event = window.event;
}
keyDown[event.keyCode] = true;
};
releaseKey = function(event){
// MSIE hack
if (window.event)
{
event = window.event;
}
keyDown[event.keyCode] = false;
}
Game.onkeydown = processKeyEvent;
Game.onkeyup = releaseKey;
var GameObjects = new Array();
function GameObject(xx, yy, w, h, i, inc, gs, name, img){
GameObjects.push(this);
this.width = w;
this.height = h;
this.index = i;
this.currIndex = 0;
this.increment = inc;
this.currInc = 0;
this.x = xx;
this.y = yy;
this.depth = 0;
this.objType = name;
this.image = img;
this.xScale = 1;
this.yScale = 1;
this.scaleString = "scale(" + this.xScale + "," + this.yScale + ")";
this.speed = 0;
this.direction = 0;
this.gravity = 0;
this.gravityDirection = 0;
this.active = true;
this.visible = true;
this.bindToRoom = false;
this.text = "";
this.color = "#FFF";
this.gameState = gs;
this.div = document.createElement("div");
this.div.className=this.objType;
this.div.style.position="absolute";
this.div.style.left= this.x + "px";
this.div.style.top= this.y + "px";
this.div.style.width= this.width + "px";
this.div.style.height= this.height + "px";
this.div.style.backgroundImage = "url(images/" + this.image + ")";
this.div.style[getTransformProperty(this.div)] = this.scaleString;
Game.appendChild(this.div);
this.isDiv = true;
this.classChanged = false;
this.move = move;
this.anim = anim;
this.setScale = setScale;
this.checkCollisionAt = checkCollisionAt;
this.objectAt = objectAt;
this.objectTypeAt = objectTypeAt;
this.toggleActive = toggleActive;
this.extend = extend;
this.unextend = unextend;
this.isType = isType;
this.update = update;
function move(xx,yy){
this.x += xx;
this.y += yy;
}
function anim(){
this.currInc += 1;
if (this.currInc >= this.increment){
this.currInc -= this.increment;
this.currIndex += 1;
if (this.currIndex >= this.index){
this.currIndex -= this.index;
}
}
}
function extend(type) {
this.objType += " " + type;
this.classChanged = true;
}
function unextend(type) {
this.objType = this.objType.replace( /(?:^|\s)type(?!\S)/ , '' );
this.classChanged = true;
}
function isType(type) {
return ((' ' + this.objType + ' ').indexOf(' ' + type + ' ') > -1);
}
function setScale(xx,yy){
this.xScale = xx;
this.yScale = yy;
this.scaleString = "scale(" + this.xScale + "," + this.yScale + ")";
}
function checkCollisionAt(xx,yy,other){
//Check For Collision
xx += this.x;
yy += this.y;
if ((xx + this.width > other.x) && (xx < other.x + other.width) && (yy + this.height > other.y) && (yy < other.y + other.height)){
return true;
}
else{
return false;
}
}
function objectAt(xx,yy,solid){
//Loop All Objects
for (var i = 0; i < GameObjects.length; i++){
if (GameObjects[i] != this && this.isDiv){
if (this.checkCollisionAt(xx,yy,GameObjects[i])){
console.log(i);
return true;
}
}
}
return false;
}
function objectTypeAt(xx,yy,type){
//Loop All Objects
for (var i = 0; i < GameObjects.length; i++){
if (GameObjects[i] != this && GameObjects[i].isType(type) && this.isDiv){
if (this.checkCollisionAt(xx,yy,GameObjects[i])){
return true;
}
}
}
return false;
}
function toggleActive(a){
this.visible = a;
this.update();
this.active = a;
}
function update(){
if ((this.active == false || this.gameState != gameState) && this.isDiv){
this.isDiv = false;
Game.removeChild(this.div);
return;
}
else if(!this.isDiv){
this.isDiv = true;
Game.appendChild(this.div);
}
this.div.style.display = "inline";
if (this.speed != 0){
this.x += this.speed*Math.cos(this.direction*Math.PI/180);
this.y += this.speed*Math.sin(this.direction*Math.PI/180);
}
if (this.bindToRoom == true){
if (this.x < 0){
this.x = 0;
}
if (this.y < 0){
this.y = 0;
}
if (this.x > MASTER_WIDTH-this.width){
this.x = MASTER_WIDTH-this.width;
}
if (this.y > MASTER_HEIGHT-this.height){
this.y = MASTER_HEIGHT-this.height;
}
}
if (!this.visible && this.isDiv){
this.isDiv = false;
Game.removeChild(this.div);
return;
}
if (this.classChanged){
this.div.className = this.objType;
}
this.div.style.zIndex = this.depth;
this.div.style.color = this.color;
this.div.innerHTML = this.text;
this.div.style.left= this.x + "px";
this.div.style.top= this.y + "px";
this.div.style[getTransformProperty(this.div)] = this.scaleString;
this.div.style.backgroundPosition = this.currIndex * this.width +"px 0";
}
}
function getTransformProperty(element) {
// Note that in some versions of IE9 it is critical that
// msTransform appear in this list before MozTransform
// By ZachAstronaut
var properties = [
'transform',
'WebkitTransform',
'msTransform',
'MozTransform',
'OTransform'
];
var p;
while (p = properties.shift()) {
if (typeof element.style[p] != 'undefined') {
return p;
}
}
return false;
}
Right now, whenever an object is not in the current gameState, becomes inactive, or is not visible, I will remove the div from the game's iframe. I have checks to make sure not to run any unnecessary scripts in the update() function. Is there anyway I can improve my speed?
Are you familiar with profilers? Google Chrome includes a fairly good one. When I run your program and start profiling it, Chrome reports that your definition of isType is expensive.
function isType(type) {
return this.objType && new RegExp("(^|\\s)" + type + "(\\s|$)").test(this.objType);
}
Sure enough, this is expensive. Dynamically constructing RegExps can be costly.
To avoid that cost, lift out the definition of the regular expression out of isType if you can. Assuming the set of types is fixed, you can pre-compute the regexps for all the types at toplevel, store them in an object, and then do a simple lookup to get the precomputed regexp. If you don't know them all up front, you can still cache regexps from prior calls to isType.
var priorTypeRegexps = {};
function isType(type) {
var aRegexp;
if (! priorTypeRegexps[type]) {
priorTypeRegexps[type] = new RegExp("(^|\\s)" + type + "(\\s|$)");
}
aRegexp = priorTypeRegexps[type];
return this.objType && aRegexp.test(this.objType);
}