I'm making a game where your mouse is a cross hair and you click on zombies moving across the screen. I'm having troubles figuring out how to find if the mouse has clicked on a zombie. The zombies are made in JavaScript so I can't use the onclick attribute in HTML. This is my code.
var mouseX;
var mouseY;
$(document).ready(function(){
var canvasWidth = 640;
var canvasHeight = 480;
var canvas = $("#gameCanvas")[0];
var context = canvas.getContext("2d");
var score = 0;
var timer = 0;
var spawnZombie = false;
//crosshair
var crossHair = new Image();
var crosshairX = 50;
var crosshairY = 50;
crossHair.src = "media/crosshair.png";
//zombies
var zombies = [];
var zombieLeft = new Image();
zombieLeft.src = "media/zombieLEFT.gif";
var zombieRight = new Image();
zombieRight.src = "media/zombieRIGHT.gif";
var fps = 30;
setInterval(function(){
update();
draw();
}, 1000/fps);
function update(){
timer += 1;
crosshairX = mouseX - 445;
crosshairY = mouseY - 125;
if(timer >= 70){
timer = 0;
spawnZombie = true;
}
zombies.forEach(function(zombie) {
zombie.update();
document.body.onmousedown = function() {
console.log(zombie.x.toString() + ", " + zombie.y.toString());
//if(mouseX)
};
});
zombies = zombies.filter(function(zombie){
return zombie.active;
});
if(spawnZombie){
zombies.push(Zombie(null, "left"));
zombies.push(Zombie(null, "right"));
spawnZombie = false;
}
}
function draw(){
context.clearRect(0,0, canvasWidth, canvasHeight);
context.fillStyle = "#000";
context.font = "20px Comic Sans MS";
context.fillText("Score: " + score, 50, 50);
zombies.forEach(function(zombie) {
zombie.draw();
});
context.drawImage(crossHair, crosshairX, crosshairY, 100, 100);
}
function Zombie(I, dir){
I = I || {};
I.active = true;
I.speed = 5;
I.y = getRandomInt(50, 350);
if(dir == "left"){
I.x = 800;
}
else if(dir == "right"){
I.x = -100;
}
I.width = 100;
I.height = 100;
I.inBounds = function() {
return I.x >= 0 && I.x <= canvasWidth &&
I.y >= 0 && I.y <= canvasHeight;
};
I.draw = function(){
if(dir == "left"){
context.drawImage(zombieLeft, this.x, this.y, this.width, this.height);
}
else if(dir == "right"){
context.drawImage(zombieRight, this.x, this.y, this.width, this.height);
}
};
I.update = function(){
if(dir == "left"){
this.x -= this.speed;
}
else if(dir == "right"){
this.x += this.speed;
}
};
I.onclick = function(){
I.remove();
};
return I;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
});
$( document ).on( "mousemove", function( event ) {
mouseX = event.pageX;
mouseY = event.pageY;
});
This is the specific spot where I'm trying to detect if the zombie has been clicked on within my update functio
zombies.forEach(function(zombie) {
zombie.update();
document.body.onmousedown = function() {
console.log(zombie.x.toString() + ", " + zombie.y.toString());
//if(mouseX)
};
});
I can't use the onclick attribute in HTML.
But you can use the addEventListener method in your javascript:
eg.
zombieLeft.addEventListener('click', myFunction, false);
document.body.onmousedown = function(event) {
console.log(zombie.x.toString() + ", " + zombie.y.toString());
if(event.pageX == zombie.x && event.pageY == zombie.y){
//Zombie clicked
}
};
This is pseudo code. You can attach event and you can check for x and y.
Related
I have a canvas game in my webpage and it operates with arrow key controls, but whenever somebody tries to play it the page scrolls. Is there any way I can prevent it? The code for my game is here. All I need is for the page to not be bouncing up and down whenever somebody is trying to play. I know it would be easier to just use the wasd keys but to me that feels like putting duct tape on a leak on the hull of a boat instead of actually fixing it. Any suggestions? I'm using google apps script HTML service so I'm not sure if using jquery is possible or if it is whether its going going to be hours and hours of work that are eventually ditched in favor of a quicker solution. Anyways, hope somebody can help.
<h1> example html</h1>
<p>exampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTML</p>
<h2>example html </h2>
<canvas id='my' width = '640' height = '480' style = 'display: none;'></canvas>
<script>
var paused = false
function PausePlay(){
if (paused === false)
{paused = true;}
else{paused = false;}
}
var canvas = document.getElementById("my");
var ctx = canvas.getContext("2d");
function paddle(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speedModifier = 0;
this.hasCollidedWith = function(ball) {
var paddleLeftWall = this.x;
var paddleRightWall = this.x + this.width;
var paddleTopWall = this.y;
var paddleBottomWall = this.y + this.height;
if (ball.x > paddleLeftWall &&
ball.x < paddleRightWall &&
ball.y > paddleTopWall &&
ball.y < paddleBottomWall) {
return true;
}
return false;
};
this.move = function(keyCode) {
var nextY = this.y;
if (keyCode == 40) {
nextY += 5;
this.speedModifer = 1.5;
} else if (keyCode == 38) {
nextY += -5;
this.speedModifier = 1.5;
} else {
this.speedModifier = 0;
}
nextY = nextY < 0 ? 0 : nextY;
nextY = nextY + this.height > 480 ? 480 - this.height : nextY;
this.y = nextY;
};
}
var player = new paddle(5, 200, 25, 100);
var ai = new paddle(610, 200, 25, 100);
var ball = {
x: 320,
y: 240,
radius: 7,
xSpeed: 2,
ySpeed: 0,
playerscore: 0,
aiscore: 0,
reverseX: function() {
this.xSpeed *= -1;
},
reverseY: function() {
this.ySpeed *= -1;
},
reset: function() {
alert('The score is now ' + this.playerscore + ' to ' + this.aiscore);
this.x = 20;
this.y = 24;
this.xSpeed = 2;
this.ySpeed = 0;
},
isBouncing: function() {
return ball.ySpeed != 0;
},
modifyXSpeedBy: function(modification) {
modification = this.xSpeed < 0 ? modification * -1 : modification;
var nextValue = this.xSpeed + modification;
nextValue = Math.abs(nextValue) > 9 ? 9 : nextValue;
this.xSpeed = nextValue;
},
modifyYSpeedBy: function(modification) {
modification = this.ySpeed < 0 ? modification * -1 : modification;
this.ySpeed += modification;
}
};
function tick() {
updateGame();
draw()
window.setTimeout("tick()", 1000 / 60);
}
function updateGame() {
if (paused === false){
ball.x += ball.xSpeed;
ball.y += ball.ySpeed;
if (ball.x < 0) {
ball.reset();
ball.aiscore = ball.aiscore + 1;
}
if (ball.x > 640) {
ball.reset();
ball.playerscore = ball.playerscore + 1
}
if (ball.y <= 0 || ball.y >= 480) {
ball.reverseY();
}
var collidedWithPlayer = player.hasCollidedWith(ball);
var collidedWithAi = ai.hasCollidedWith(ball);
if (collidedWithPlayer || collidedWithAi) {
ball.reverseX();
ball.modifyXSpeedBy(0.25);
var speedUpValue = collidedWithPlayer ? player.speedModifier : ai.speedModifier;
ball.modifyYSpeedBy(speedUpValue);
}
for (var keyCode in heldDown) {
player.move(keyCode);
}
var aiMiddle = ai.y + (ai.height / 2);
if (aiMiddle < ball.y) {
ai.move(40);
}
if (aiMiddle > ball.y) {
ai.move(38);
}
}
}
function draw() {
if(paused === false){
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 640, 480);
renderPaddle(player);
renderPaddle(ai);
renderBall(ball);
}
}
function renderPaddle(paddle) {
ctx.fillStyle = "blue";
ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
}
function renderBall(ball) {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI, false);
ctx.fillStyle = "pink";
ctx.fill();
}
var heldDown = {};
window.addEventListener("keydown", function(keyInfo) {
heldDown[event.keyCode] = true;
}, false);
window.addEventListener("keyup", function(keyInfo) {
delete heldDown[event.keyCode];
}, false);
function playPong(){
canvas.style.display = 'block';
tick()
}
function show(){
var canvas = document.getElementById('my')
canvas.style.display = 'block';
}
</script>
<div>
<button onclick = 'hide()'> Hide or show the games</button>
<br>
<button onclick = 'PausePlay()'> Pause/play games</button>
<br>
</div>
<br><br><br><br>
<button onclick = 'playPong()'> Play pong </button>
You may use overflow: hidden; CSS property in order to control the ability of scrolling. If you need to prevent vertical/horizontal scrolling only, so you may use overflow-x and overflow-y More about overflow property here.
I'm trying to make a platforming game, and I've been working on the collision for the past 2 weeks. The collision detection is working, but the collision itself (as in, keeping the player out of the tile) is not, no matter what I try. I've tried looking up how to do this, but all I'm finding is how to do the detection part, which I already have done. What do I do after I detect collision?
It was written from scratch, and the player is rectangular, and so are the tiles.
Here's the basic code:
var Player = function(hue, x, y, xSize, ySize, health) {
this.hue = hue;
this.position = new PVector(x, y);
this.originalPosition = new PVector(x, y);
//this.previousPosition = new PVector(x, y);
//this.ppp = new PVector(x, y);
//this.virtualPosition = new PVector(x, y);
//this.predictedPosition = new PVector(x, y);
this.velocity = new PVector(0, 0);
//this.predictedVelocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
}
/*Player.prototype.testCollision = function(tile) {
if (this.predictedPosition.y < tile.position.y + tile.size.y && this.predictedPosition.y + this.size.y > tile.size.y && this.predictedPosition.x < tile.position.x + tile.size.x && this.predictedPosition.x + tile.size.x > tile.position.x) {
return false;
} else {
return true;
}
};*/
Player.prototype.ifColliding = function(tile) {
if (this.position.x < tile.position.x + tile.size.x && this.position.x + tile.size.x > tile.position.x) {
/*if (this.position.x + this.size.x > tile.position.x) {
this.position.set(tile.position.x - this.size.x, this.position.y);
} else if (this.position.x < tile.position.x + tile.size.x) {
this.position.set(tile.position.x + tile.size.x, this.position.y);
}*/
this.velocity.set(0, this.velocity.y);
//this.acceleration.set(0, this.acceleration.y);
/*if (this.ppp.x < tile.position.x + tile.size.x && this.ppp.x + tile.size.x > tile.position.x) {
if (this.ppp.x + this.size.x > tile.position.x) {
this.position.set(tile.position.x - this.size.x, this.position.y);
} else if (this.ppp.x < tile.position.x + tile.size.x) {
this.position.set(tile.position.x + tile.size.x, this.position.y);
}
} else if (this.previousPosition.x < tile.position.x + tile.size.x && this.previousPosition.x + tile.size.x > tile.position.x) {
this.position.set(this.ppp.x, this.position.y);
} else {
this.position.set(this.previousPosition.x, this.position.y);
}*/
}
if (this.position.y < tile.position.y + tile.size.y && this.position.y + this.size.y > tile.size.y) {
this.velocity.set(this.velocity.x, 0);
this.acceleration.set(this.acceleration.x, 0);
this.yColliding = true;
/*if (this.position.y + this.size.y > tile.position.y) {
this.position.set(this.position.x, tile.position.y - this.size.y);
rect(0, 20, 0, 0);
} else if (this.position.y < tile.position.y + tile.size.y) {
this.position.set(this.position.x, tile.position.y + tile.size.y);
rect(20, 20, 0, 0);
}*/
}
}
Player.prototype.update = function(tiles) {
//this.ppp.set(this.previousPosition.x, this.previousPosition.y);
//this.previousPosition.set(this.position.x, this.position.y);
this.velocity.add(this.acceleration);
/*this.predictedVelocity.set(this.velocity.x, this.velocity.y);
this.predictedVelocity.add(this.acceleration);
this.virtualPosition.set(this.position.x, this.position.y);
this.virtualPosition.add(this.velocity);
this.predictedPosition.set(this.virtualPosition.x, this.virtualPosition.y);
this.predictedPosition.add(this.predictedVelocity);
var collDcted = false;
for (var i = 0; i < tiles.length; i++) {
if (this.testCollision(tiles[i], true) === false) {
collDcted = false;
}
}*/
//if (collDcted) {
this.position.add(this.velocity);
//}
}
The commented out code is failed attempts. The non-commented code is the closest I could get it to working.
This is a sample collision I made:
<!DOCTYPE html>
<html>
<body>
<p id="Health">Health</p>
<canvas id="gameCanvas" width="600" height="480" style = "border:1px solid gray"></canvas>
<script>
// Adding keyboard evt listener
document.addEventListener("keydown", keyPressed);
document.addEventListener("keyup", keyReleased);
//defining canvas
var canvas;
var canvasContext;
//defining Player variables
var PLAYER_X = 100;
var PLAYER_Y = 100;
var PLAYER_WIDTH = 20;
var PLAYER_HEIGHT = 20;
var PLAYER_HEALTH = 100;
//defining keypress codes
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
var KEY_UP = 38;
var KEY_DOWN = 40;
//variables used to test movement
var keyHeld_Up = false;
var keyHeld_Down = false;
var keyHeld_Left = false;
var keyHeld_Right = false;
//Keypress?
function keyPressed(evt) {
if(evt.keyCode == KEY_UP) {
keyHeld_Up = true;
}
if(evt.keyCode == KEY_DOWN) {
keyHeld_Down = true;
}
if(evt.keyCode == KEY_LEFT) {
keyHeld_Left = true;
}
if(evt.keyCode == KEY_RIGHT) {
keyHeld_Right = true;
}
//prevents page from scrolling when arrow keys are pressed
evt.preventDefault();
}
//Key Released?
function keyReleased(evt) {
if(evt.keyCode == KEY_UP) {
keyHeld_Up = false;
}
if(evt.keyCode == KEY_DOWN) {
keyHeld_Down = false;
}
if(evt.keyCode == KEY_LEFT) {
keyHeld_Left = false;
}
if(evt.keyCode == KEY_RIGHT) {
keyHeld_Right = false;
}
}
//Initialize Canvas and Game Loop
window.onload = function() {
console.log("Is this thing on?");
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
var framesPerSecond = 30;
setInterval(function() {
drawObjects();
movePlayer();
damageTest();
}, 1000/framesPerSecond);
}
// Drawing function
function colorRect(x,y, width,height, color, health) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.color = color;
this.health = health;
this.update = function() {
this.draw();
}
this.draw = function() {
canvasContext.beginPath();
canvasContext.rect(this.x, this.y, this.width, this.height);
canvasContext.fillStyle = this.color;
canvasContext.fill();
canvasContext.closePath();
}
};
// Creating Objects
var Screen = new colorRect( 0, 0, 600, 480, 'black', 0);
var Player = new colorRect( PLAYER_X, PLAYER_Y, PLAYER_WIDTH, PLAYER_HEIGHT, 'red', PLAYER_HEALTH);
var Box = new colorRect( 200, 200, 30, 30, 'green', 0);
var Spike = new colorRect( 300, 300, 25, 25, 'white', 0);
// Drawing Objects
function drawObjects() {
Screen.update();
Spike.update();
Player.update();
Box.update();
}
//Collision Test
function collides( a, b ) {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
//Movement based on keypress events
function movePlayer() {
if(collides( Player, Box ) === false) {
if(keyHeld_Up) {
Player.y -= 2;
}
if(keyHeld_Down) {
Player.y += 2;
}
if(keyHeld_Left) {
Player.x -= 2;
}
if(keyHeld_Right) {
Player.x += 2;
}
}
}
//Testing Collision for damage
function damageTest() {
if(collides( Player, Spike ) === true) {
Player.health -= 1;
}
//Displaying Health in <body>
document.getElementById("Health").innerHTML = "Health: " + Player.health;
}
</script>
</body>
</html>
The code I made stops the player in its tracks completely when hitting the box, but you could create individual collision circumstances for when objects collide on each side of another object, and use those to detect collision.
I hope this helped! If you have any questions regarding this code, just ask! (To run code snippet you might want to go full screen and click inside canvas)
Im making a simple pong game and when you move the red box up with 'w' the ball still bounces on nothing back to the left. I feel like maybe the bounding box is set up incorrectly to the left side. I cant figure out what I did wrong?
var canvas;
var context;
var timer;
var interval = 1000 / 60;
var player1;
var player2;
var ball;
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
//player = new Player();
player1 = new GameObject();
player2 = new GameObject();
ball = new GameObject();
timer = setInterval(animate, interval);
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height);
ball.move();
//Move the Player to the right
if (w) {
console.log("");
player1.y += -8;
}
if (s) {
console.log("");
player1.y += 8;
}
if (d) {
console.log("");
player2.y += -8;
}
if (u) {
console.log("");
player2.y += 8;
}
if (player1.y > canvas.height - player1.height / 2) {
player1.y = canvas.height - player1.height / 2;
}
if (player1.y < player1.height / 2) {
player1.y = player1.height / 2;
}
if (player2.y > canvas.height - player2.height / 2) {
player2.y = canvas.height - player2.height / 2;
}
if (player2.y < player2.height / 2) {
player2.y = player2.height / 2;
}
//bounce
if (ball.x > canvas.width - ball.width / 2) {
ball.vx = -ball.vx;
//ball.x = 300;
color = "#ff0000";
}
if (ball.x < 0 + ball.width / 2) {
//this flips it if its a negative sign.
ball.vx = -ball.vx;
//ball.x = 300;
color = "#FF4500";
}
//-------------------------------------------------------
//Define Booleans for each key
var w = false;
var s = false;
var u = false;
var d = false;
//Add Event Listeners
document.addEventListener("keydown", press);
document.addEventListener("keyup", release);
document.addEventListener("keydown", presss);
document.addEventListener("keyup", releases);
//Event Functions
function press(e) {
//---This logs key codes into the browser's console.
console.log("Pressed" + e.keyCode);
if (e.keyCode == 87) {
w = true;
}
if (e.keyCode == 83) {
s = true;
}
}
function release(e) {
//---This logs key codes into the browser's console.
//console.log("Released" + e.keyCode);
if (e.keyCode == 87) {
w = false;
}
if (e.keyCode == 83) {
s = false;
}
}
function presss(e) {
//---This logs key codes into the browser's console.
//console.log("Pressed" + e.keyCode);
if (e.keyCode == 40) {
u = true;
}
if (e.keyCode == 38) {
d = true;
}
}
function releases(e) {
//---This logs key codes into the browser's console.
//console.log("Released" + e.keyCode);
if (e.keyCode == 40) {
u = false;
}
if (e.keyCode == 38) {
d = false;
}
}
// JavaScript Document
function GameObject() {
//player's location
this.x = canvas.width / 4;
this.y = canvas.height / 2;
//player's dimensions
this.width = 50;
this.height = 250;
//barriers
//ballss velocity or speed on each axis
this.vx = 8;
this.vy = 0;
//player's color
var red = "#ff0000";
this.blue = "#0000FF";
this.color = "#ff0000";
this.other = "#0000FF";
//This draws the player to the screen
this.drawRect = function() {
context.save();
context.fillStyle = this.color;
context.translate(this.x, this.y);
context.fillRect((-this.width / 2), (-this.height / 2), this.width, this.height);
context.restore();
}
this.second_drawRect = function() {
context.save();
context.fillStyle = this.blue;
context.translate(canvas.width / 1.5, this.y);
context.fillRect((-this.width / 2), (-this.height / 2), this.width, this.height);
context.restore();
}
this.drawCircle = function() {
context.save();
context.fillStyle = this.color;
context.translate(this.x, this.y);
context.beginPath();
context.arc(0, 0, 50, 0, 360 * Math.PI / 180, true)
context.fill();
context.stroke();
//context.fillRect((-this.width/2), (-this.height/2), this.width, this.height);
context.restore();
}
//This changes the player's position
this.move = function() {
this.x += this.vx;
this.y += this.vy;
}
this.left = function() {
return this.x - this.width / 1;
}
this.right = function() {
return this.x + this.width / 2;
}
this.top = function() {
return this.y - this.height / 4;
}
this.bottom = function() {
return this.y + this.height / 4;
}
//////////////////////////////////////////////////////////////
this.leftt = function() {
return this.x - this.width / 2;
}
this.rightt = function() {
return this.x + this.width / 2;
}
this.topp = function() {
return this.y - this.height / 2;
}
this.bottomm = function() {
return this.y + this.height / 2;
}
this.hitTestObject = function(obj) {
if (this.left() < obj.right() &&
this.right() > obj.left() &&
this.top() < obj.bottom() &&
this.bottom() > obj.top()) {
return true
}
return false;
}
}
<canvas id="canvas" width = "1024" height ="800" >
Your browser is outdated and does not support HTML5. Please update to the latest version.
</canvas>
function Shape(x, y, w, h, fill) {
this.x = x || 0;
this.y = y || 0;
this.w = w || 1;
this.h = h || 1;
this.fill = fill || '#AAAAAA';
}
Shape.prototype.draw = function(ctx) {
ctx.fillStyle = this.fill;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
Shape.prototype.contains = function(mx, my) {
return (this.x <= mx) && (this.x + this.w >= mx) &&
(this.y <= my) && (this.y + this.h >= my);
}
function CanvasState(canvas) {
this.canvas = canvas;
this.width = canvas.width;
this.height = canvas.height;
this.ctx = canvas.getContext('2d');
var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
if (document.defaultView && document.defaultView.getComputedStyle) {
this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
}
var html = document.body.parentNode;
this.htmlTop = html.offsetTop;
this.htmlLeft = html.offsetLeft;
this.valid = false;
this.shapes = [];
this.dragging = false;
this.selection = null;
this.dragoffx = 0;
this.dragoffy = 0;
var myState = this;
canvas.addEventListener('selectstart', function(e) { e.preventDefault(); return false; }, false);
canvas.addEventListener('mousedown', function(e) {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var shapes = myState.shapes;
var l = shapes.length;
for (var i = l-1; i >= 0; i--) {
if (shapes[i].contains(mx, my)) {
var mySel = shapes[i];
myState.dragoffx = mx - mySel.x;
myState.dragoffy = my - mySel.y;
myState.dragging = true;
myState.selection = mySel;
myState.valid = false;
return;
}
}
if (myState.selection) {
myState.selection = null;
myState.valid = false;
}
}, true);
canvas.addEventListener('mousemove', function(e) {
if (myState.dragging){
var mouse = myState.getMouse(e);
myState.selection.x = mouse.x - myState.dragoffx;
myState.selection.y = mouse.y - myState.dragoffy;
myState.valid = false;
}
}, true);
canvas.addEventListener('mouseup', function(e) {
myState.dragging = false;
}, true);
canvas.addEventListener('dblclick', function(e) {
var mouse = myState.getMouse(e);
myState.addShape(new Shape(mouse.x - 10, mouse.y - 10, 20, 20, 'rgba(0,255,0,.6)'));
}, true);
this.selectionColor = '#CC0000';
this.selectionWidth = 2;
this.interval = 30;
setInterval(function() { myState.draw(); }, myState.interval);
}
CanvasState.prototype.addShape = function(shape) {
this.shapes.push(shape);
this.valid = false;
}
CanvasState.prototype.clear = function() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
CanvasState.prototype.draw = function() {
if (!this.valid) {
var ctx = this.ctx;
var shapes = this.shapes;
this.clear();
var l = shapes.length;
for (var i = 0; i < l; i++) {
var shape = shapes[i];
if (shape.x > this.width || shape.y > this.height ||
shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
shapes[i].draw(ctx);
}
if (this.selection != null) {
ctx.strokeStyle = this.selectionColor;
ctx.lineWidth = this.selectionWidth;
var mySel = this.selection;
ctx.strokeRect(mySel.x,mySel.y,mySel.w,mySel.h);
}
this.valid = true;
}
}
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {x: mx, y: my};
}
function init() {
var s = new CanvasState(document.getElementById('canvas1'));
s.addShape(new Shape(40,40,50,50)); // The default is gray
}
<canvas id="canvas1" width="200" height="200" style="border:1px solid #000000;">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<button onclick= "init()">click </button>
On click of a button, I am creating a rectangular element which can be drag and drop inside the canvas element restricted area.
however, Is it possible to create a new rectangular element dynamically on every click of a button which can further be drag and drop inside the canvas boundary.
And the previous rectangular element won't lost.
Doing this from scratch will be a lot of work. I suggest you use a library like fabric.js which has everything you asked plus a lot more to offer. Here is a demo page.
On every button click you was calling init(),.. Causing you CanvasState to reset.
I've just made another function called addShape, and just called init once.
I've also kept a reference to the CanvasState, called s.. So I could do s.addShape.. So changes were very minimal.
Hope this helps..
function Shape(x, y, w, h, fill) {
this.x = x || 0;
this.y = y || 0;
this.w = w || 1;
this.h = h || 1;
this.fill = fill || '#AAAAAA';
}
Shape.prototype.draw = function(ctx) {
ctx.fillStyle = this.fill;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
Shape.prototype.contains = function(mx, my) {
return (this.x <= mx) && (this.x + this.w >= mx) &&
(this.y <= my) && (this.y + this.h >= my);
}
function CanvasState(canvas) {
this.canvas = canvas;
this.width = canvas.width;
this.height = canvas.height;
this.ctx = canvas.getContext('2d');
var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
if (document.defaultView && document.defaultView.getComputedStyle) {
this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
}
var html = document.body.parentNode;
this.htmlTop = html.offsetTop;
this.htmlLeft = html.offsetLeft;
this.valid = false;
this.shapes = [];
this.dragging = false;
this.selection = null;
this.dragoffx = 0;
this.dragoffy = 0;
var myState = this;
canvas.addEventListener('selectstart', function(e) { e.preventDefault(); return false; }, false);
canvas.addEventListener('mousedown', function(e) {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var shapes = myState.shapes;
var l = shapes.length;
for (var i = l-1; i >= 0; i--) {
if (shapes[i].contains(mx, my)) {
var mySel = shapes[i];
myState.dragoffx = mx - mySel.x;
myState.dragoffy = my - mySel.y;
myState.dragging = true;
myState.selection = mySel;
myState.valid = false;
return;
}
}
if (myState.selection) {
myState.selection = null;
myState.valid = false;
}
}, true);
canvas.addEventListener('mousemove', function(e) {
if (myState.dragging){
var mouse = myState.getMouse(e);
myState.selection.x = mouse.x - myState.dragoffx;
myState.selection.y = mouse.y - myState.dragoffy;
myState.valid = false;
}
}, true);
canvas.addEventListener('mouseup', function(e) {
myState.dragging = false;
}, true);
canvas.addEventListener('dblclick', function(e) {
var mouse = myState.getMouse(e);
myState.addShape(new Shape(mouse.x - 10, mouse.y - 10, 20, 20, 'rgba(0,255,0,.6)'));
}, true);
this.selectionColor = '#CC0000';
this.selectionWidth = 2;
this.interval = 30;
setInterval(function() { myState.draw(); }, myState.interval);
}
CanvasState.prototype.addShape = function(shape) {
this.shapes.push(shape);
this.valid = false;
}
CanvasState.prototype.clear = function() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
CanvasState.prototype.draw = function() {
if (!this.valid) {
var ctx = this.ctx;
var shapes = this.shapes;
this.clear();
var l = shapes.length;
for (var i = 0; i < l; i++) {
var shape = shapes[i];
if (shape.x > this.width || shape.y > this.height ||
shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
shapes[i].draw(ctx);
}
if (this.selection != null) {
ctx.strokeStyle = this.selectionColor;
ctx.lineWidth = this.selectionWidth;
var mySel = this.selection;
ctx.strokeRect(mySel.x,mySel.y,mySel.w,mySel.h);
}
this.valid = true;
}
}
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {x: mx, y: my};
}
var s;
function init() {
s = new CanvasState(document.getElementById('canvas1'));
}
function addShape() {
s.addShape(new Shape(40,40,50,50)); // The default is gray
}
init();
<canvas id="canvas1" width="400" height="300" style="border:1px solid #000000;">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<button onclick= "addShape()">click </button>
How do I make the shape disappear like the text does? I've gone through the code and they're practically identical except that one is created when the user spins the mouse wheel and the other is created when the user clicks on the screen, but the text disappears after time and the triangle does not. I feel like there's something small I must be missing. Here's the code:
<html>
<head>
<script>
var canvas;
var context;
var triangles = [];
var texts = [];
var timer;
var textSayings = ['Cool!', 'Nice!', 'Awesome!', 'Wow!', 'Whoa!', 'Super!', 'Woohoo!', 'Yay!', 'Yeah!', ':)', ':D'];
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext("2d");
//resize canvas to fit the window
resizeCanvas();
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
canvas.onwheel = function(event) {
handleWheel(event.clientX, event.clientY);
};
canvas.onclick = function(event) {
handleClick(event.clientX, event.clientY);
}
var timer = setInterval(resizeCanvas, 30);
}
function Triangle(x,y,triangleColor) {
this.x = x;
this.y = y;
this.triangleColor = triangleColor;
this.vx = Math.random() * 80 - 40;
this.vy = Math.random() * 80 - 40;
this.time = 250;
}
function Text(x,y,textColor,word) {
this.x = x;
this.y = y;
this.word = word;
this.textColor = textColor;
this.vx = Math.random() * 20 - 10;
this.vy = Math.random() * 20 - 10;
this.time = 300;
}
function handleWheel(x,y) {
var colors = [[255,0,0],[255,255,255],[0,0,255]];
var triangleColor = colors[Math.floor(Math.random()*colors.length)];
triangles.push(new Triangle(x,y,triangleColor));
for (var i=0; i<triangles.length; i++) {
drawTriangle(triangles[i]);
}
}
function handleClick(x,y) {
var colors = [[255,0,0],[255,255,0],[0,0,255]];
var textColor = colors[Math.floor(Math.random()*colors.length)];
texts.push(new Text(x,y,textColor,pickWord()));
for (var i=0; i<texts.length; i++) {
drawText(texts[i]);
}
}
function timeToFade(time) {
if(time > 100) {
return 1;
}
else {
return time / 100;
}
}
function pickWord() {
return textSayings[Math.floor(Math.random() * textSayings.length)];
}
function drawText(text) {
context.font = "bold 80px Verdana";
var gradient=context.createLinearGradient(0,0,canvas.width,0);
gradient.addColorStop("0","magenta");
gradient.addColorStop("0.25","yellow");
gradient.addColorStop("0.5","lime");
gradient.addColorStop("0.75","aqua");
gradient.addColorStop("1.0","magenta");
context.fillStyle = gradient;
context.fillText(text.word,text.x,text.y);
}
function drawTriangle(triangle) {
context.beginPath();
context.moveTo(triangle.x,triangle.y);
context.lineTo(triangle.x+25,triangle.y+25);
context.lineTo(triangle.x+25,triangle.y-25);
var gradient = context.createLinearGradient(0,0,canvas.width,0);
gradient.addColorStop("0","red");
gradient.addColorStop("0.25","salmon");
gradient.addColorStop("0.5","aqua");
gradient.addColorStop("0.75","lime");
gradient.addColorStop("1.0","orange");
context.fillStyle = gradient;
context.fill();
}
function resizeCanvas() {
canvas.width = window.innerWidth-20;
canvas.height = window.innerHeight-20;
fillBackgroundColor();
for (var i=0; i<triangles.length; i++) {
var t = triangles[i];
drawTriangle(t);
if (t.x + t.vx > canvas.width || t.x + t.vx < 0)
t.vx = -t.vx
if (t.y + t.vy > canvas.height || t.y + t.vy < 0)
t.vy = -t.vy
if (t.time === 0) {
triangles.splice(i,1);
}
t.time -= 3;
t.x += t.vx;
t.y += t.vy;
}
for (var i=0; i<texts.length; i++) {
var te = texts[i];
drawText(te);
if (te.x + te.vx > canvas.width || te.x + te.vx < 0)
te.vx = -te.vx
if (te.y + te.vy > canvas.height || te.y + te.vy < 0)
te.vy = -te.vy
if (te.time === 0) {
texts.splice(i,1);
}
te.time -= 3;
te.x += te.vx;
te.y += te.vy;
}
}
function fillBackgroundColor() {
context.globalCompositeOperation = 'source-over';
context.fillStyle = 'rgba(0, 0, 0, 1)';
context.fillRect(0,0,canvas.width,canvas.height);
context.globalCompositeOperation = 'lighter';
}
window.onload = init;
</script>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
</body>
</html>
It's because the triangle time isn't a multiple of 3, while the text time is so when you check this if statement:
if (t.time === 0) {
triangles.splice(i,1);
}
It's never true.
You can fix this by changing the if statement to:
if (t.time <= 0) {
triangles.splice(i,1);
}
This is actually my fault since it's a bug that was in my previous answer. Sorry about that.
jsfiddle:
https://jsfiddle.net/0rst8def/