So I was about to make my final project on codehs. I use javascript and came across this problem, so I have a target that is always moving and I have a crosshair which I want to be deleted when I click on it through mouseClickMethod(); I tried getElementAt and getX and getY.
Can anyone help me?
this is my code:
var background;
var target;
var horizontalLine;
var verticalLine;
var x;
var y;
var redBall;
var dx = 5;
var dy = 0;
var count = 0;
function start(){
var play = readInt("Press 1 to start the game in easiest difficulty press 2 to play in normal difficulty and press 3 to play in hard difficulty ");
if(play == 1){
background();
target = new WebImage("https://codehs.com/uploads/09d10ce42020f57b62bb51edf4af52b1");
target.setPosition(-150,350);
target.setSize(140,140);
add(target);
setTimer(drawTarget,0);
mouseMoveMethod(crosshair);
}
}
function background(){
background = new WebImage("https://codehs.com/uploads/761ea7cf98a0159e6ab47e5f04194ce5");
background.setSize(400,500);
add(background);
}
function drawTarget(){
count++;
target.move(dx,dy);
println(count);
turnAround();
}
function turnAround(){
if(count == 100){
dx = -dx;
count = 0;
}
}
function crosshair(e){
x = e.getX();
y = e.getY();
remove(horizontalLine);
remove(verticalLine);
horizontalLine = new Line(e.getX(), 0, e.getX(), e.getY());
horizontalLine.setEndpoint(e.getX() - 0 ,e.getY() - 0);
horizontalLine.setLineWidth(1);
add(horizontalLine);
verticalLine = new Line(x, 0, x, getHeight());
verticalLine.setEndpoint(x - 0 ,y - 0);
verticalLine.setLineWidth(1);
add(verticalLine);
remove(horizontalLine);
remove(verticalLine);
horizontalLine = new Line(0, y, getWidth(), y);
horizontalLine.setLineWidth(1);
add(horizontalLine);
verticalLine = new Line(x, 0, x, getHeight());
verticalLine.setLineWidth(1);
add(verticalLine);
}
here how you can easily remove an element from the dom:
https://www.w3schools.com/jsref/met_element_remove.asp
const el = document.querySelector('#image');
const rmv = () => el.remove();
el.addEventListener('click', rmv)
<img src="" id="image" alt="i will be removed after click"/>
Related
I made this red line in JavaScript that goes to closest target (balloon 1 to 3) to the player but I need to make it so that it moves like a laser starting from player position into the target position. I thought about multiple ways of implementing this with no luck.
function Tick() {
// Erase the sprite from its current location.
eraseSprite();
for (var i = 0; i < lasers.length; i++) {
lasers[i].x += lasers[i].direction.x * laserSpeed;
lasers[i].y += lasers[i].direction.y * laserSpeed;
//Hit detection here
}
function detectCharClosest() {
var ballon1char = {
x: balloon1X,
y: balloon1Y
};
var ballon2char = {
x: balloon2X,
y: balloon2Y
};
var ballon3char = {
x: balloon3X,
y: balloon3Y,
};
ballon1char.distanceFromPlayer = Math.sqrt((CharX - balloon1X) ** 2 + (CharY - balloon1Y) ** 2);
ballon2char.distanceFromPlayer = Math.sqrt((CharX - balloon2X) ** 2 + (CharY - balloon2Y) ** 2);
ballon3char.distanceFromPlayer = Math.sqrt((CharX - balloon3X) ** 2 + (CharY - balloon3Y) ** 2);
var minDistance = Math.min(
ballon1char.distanceFromPlayer,
ballon2char.distanceFromPlayer,
ballon3char.distanceFromPlayer);
console.log(ballon1char);
console.log(ballon2char);
console.log(ballon3char);
for (let i = 0; i < 3; i++) {
if (minDistance == ballon1char.distanceFromPlayer)
return ballon1char
if (minDistance == ballon2char.distanceFromPlayer)
return ballon2char
if (minDistance == ballon3char.distanceFromPlayer)
return ballon3char
}
}
function loadComplete() {
console.log("Load is complete.");
canvas = document.getElementById("theCanvas");
ctx = canvas.getContext("2d");
myInterval = self.setInterval(function () { Tick() }, INTERVAL);
myInterval = self.setInterval(function () { laserTicker(detectCharClosest()) }, 2000);
function laserTicker(balloon) {
//gets the closest ballon to go to
laserDo(balloon);
}
function laserDo(balloon) {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "#F44336"; // "red";
ctx.moveTo(CharX + 16, CharY + 16);
ctx.lineTo(balloon.x, balloon.y);
// lasers.push({x: })
ctx.stroke();
}
I didn't put all of my code here so If something doesn't make sense please tell me. I'm still new to JavaScript and learning it. One way I thought I could make this work was by taking the distance between the player and the target and dividing it by the speed on the x and y axis then changing having it start from the player position and keeps on adding up on both axis until it reaches the target. That didn't work out though. If you have any suggestions then please tell me.
Thanks
I'm trying to convert one of the Paper.js library examples (http://paperjs.org/examples/smoothing/) from PaperScript to Javascript. Following the documentation, I have
Made the scope global
Installed the event handlers onFrame and onResize
Created a tool and installed the event handlers onMouseMove and onMouseDown
But the canvas is not shown. I only see a couple of small blue lines: AFAIK the problem lies in the view.onFrame() function, since commenting that out at least I can see the shape, but not interact with it. The JS console dosen't show any error. What is missing?
// Make the paper scope global, by injecting it into window
paper.install(window);
window.onload = function () {
// Setup directly from canvas id:
paper.setup('myCanvas');
// Create tool
tool = new Tool();
var width, height, center;
var points = 10;
var smooth = true;
var path = new Path();
var mousePos = view.center / 2;
var pathHeight = mousePos.y;
path.fillColor = 'black';
initializePath();
function initializePath() {
center = view.center;
width = view.size.width;
height = view.size.height / 2;
path.segments = [];
path.add(view.bounds.bottomLeft);
for (var i = 1; i < points; i++) {
var point = new Point(width / points * i, center.y);
path.add(point);
}
path.add(view.bounds.bottomRight);
path.fullySelected = true;
}
view.onFrame = function (event) {
pathHeight += (center.y - mousePos.y - pathHeight) / 10;
for (var i = 1; i < points; i++) {
var sinSeed = event.count + (i + i % 10) * 100;
var sinHeight = Math.sin(sinSeed / 200) * pathHeight;
var yPos = Math.sin(sinSeed / 100) * sinHeight + height;
path.segments[i].point.y = yPos;
}
if (smooth)
path.smooth({ type: 'continuous' });
}
tool.onMouseMove = function (event) {
mousePos = event.point;
}
tool.onMouseDown = function (event) {
smooth = !smooth;
if (!smooth) {
// If smooth has been turned off, we need to reset
// the handles of the path:
for (var i = 0, l = path.segments.length; i < l; i++) {
var segment = path.segments[i];
segment.handleIn = segment.handleOut = null;
}
}
}
// Reposition the path whenever the window is resized:
view.onResize = function (event) {
initializePath();
}
}
To try it: https://jsfiddle.net/1rtkbp9s/
Found the solution (credits to Stefan Krüger of the Paper.js Google Group):
var mousePos = view.center / 2;
Should have been:
var mousePos = view.center.divide(2);
The fact is that Math functions should be used instead of operators for Point and Size object... and I didn't realize that view.center IS a Point object: http://paperjs.org/reference/view/#center
Whenever I try to clear the canvas using clearRect(), at first it is cleared. But as soon as I start redrawing the old elements reappear. I even tried
context.width = context.width
but nothing seems to be working. The canvas is getting cleared initially but on clicking the clear button, it clears at first, but everything reappears. Please help me in debugging this error. The clearRect method is in the end of the code.
Below is the code
<script>
var canv = document.getElementById('canv'),
ctx = canv.getContext('2d'),
rect = [],
move = false;
var newRect;
var startX, startY, mouseX, mouseY;
var offsetX,offsetY;
function reOffset(){
var bound = canv.getBoundingClientRect();
offsetX = bound.left;
offsetY = bound.top;
}
reOffset();
function movement(){
canv.addEventListener('mousedown', mouseDown, false);
canv.addEventListener('mouseup', mouseUp, false);
canv.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(event){
startX=parseInt(event.clientX-offsetX);
startY=parseInt(event.clientY-offsetY);
move = true;
}
function mouseUp(event){
mouseX=parseInt(event.clientX-offsetX);
mouseY=parseInt(event.clientY-offsetY);
move = false;
if(!overlap(newRect)){
rect.push(newRect);
}
make();
//ctx.fillRect(q.left,q.top,q.right-q.left,q.bottom-q.top);
}
function make(){
for(var i = 0; i < rect.length; i++){
var q = rect[i];
ctx.fillStyle = randomColour();
ctx.fillRect(q.left, q.top, q.right - q.left, q.bottom - q.top);
}
}
function mouseMove(event){
if(move){
mouseX=parseInt(event.clientX - offsetX);
mouseY=parseInt(event.clientY - offsetY);
newRect = {
left : Math.min(startX , mouseX),
right : Math.max(startX , mouseX),
top : Math.min(startY , mouseY),
bottom : Math.max(startY , mouseY),
}
ctx.clearRect(0, 0, canv.width, canv.height);
ctx.strokeRect(startX, startY, mouseX-startX, mouseY-startY);
}
}
function randomColour() {
var colour = [];
for (var i = 0; i < 3; i++) {
colour.push(Math.floor(Math.random() * 256));
}
return 'rgb(' + colour.join(',') + ')';
}
function overlap(newRect){
var q1 = newRect;
//if one rect is completely inside another rect
var inside = function(rectx, recty){
return(recty.left >= rectx.left &&
recty.right <= rectx.right &&
recty.top >= rectx.top &&
recty.bottom <= rectx.bottom);
}
//if the new rect is overlapping any existing rect
var isOverlaping = false;
for(var i = 0; i < rect.length; i++){
var q2 = rect[i];
var isIntersecting = !(q1.left > q2.right ||
q1.right < q2.left ||
q1.top > q2.bottom ||
q1.bottom < q2.top);
var isContain = inside(q2, q1) || inside(q1, q2);
if(isIntersecting || isContain){
isOverlaping=true;
}
}
return(isOverlaping);
}
movement();
//clear the canvas for redrawing
document.getElementById('clear').addEventListener('click', function () {
ctx.clearRect(0, 0, canv.width, canv.height);
}, false);
</script>`
<head>
<title>Simple Paint App</title>
</head>
<body>
<canvas id ="canv" width="1000" height="600" ></canvas>
<div id="button" style="position: absolute;">
<input type="button" id="clear" value="Clear">
</div>
</body>
You need to reset the rect array as well.
Adding this to your clear callback function:
document.getElementById('clear').addEventListener('click', function () {
rect = [];
console.log(rect);
ctx.clearRect(0, 0, canv.width, canv.height);
}, false);
should work, while removing the reset of the rect array (as in your clear callback function), logs the old rectangles as well.
The Problem
I am creating a game using the HTML5 Canvas, the game has a main menu, the main menu has multiple buttons for you to choose. I am finding it difficult and confusing how I would, for example if the user presses the 'Play' button, to show the game. Here is an image of the main menu:
The Question
The question is how would I get from this page to another in my game?
I think you get the idea. I deliberately created the menu using the canvas, I know I could of made the menu using HTML for example but I cant as this is an example for students of what Canvas can do, whats good and bad etc.
The Code
<html>
<head>
<title>Sean Coyne</title>
</head>
<body onload="start_game()">
<body>
<div style id="canvas">
<canvas id="myCanvas" style="border:5px solid #410b11" height="320" width="480">
<p>Your browser does not support HTML5!</p>
</canvas>
<script type="text/javascript">
//Referencing the canvas
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var width = canvas.getAttribute('width');
var height = canvas.getAttribute('height');
//Finding the position of the mouse
var mouseX;
var mouseY;
//Images
var bgImage = new Image();
var logoImage = new Image();
var playImage = new Image();
var instructImage = new Image();
var settingsImage = new Image();
var aboutImage = new Image();
var peaceImage = new Image();
var backgroundY = 0;
var speed = 1;
//Arrays below used for mouse over function
var buttonX = [130,110,130,160];
var buttonY = [100,140,180,220];
var buttonWidth = [96,260,182,160];
var buttonHeight = [40,40,40,40];
var peaceX = [0,0];
var peaceY = [0,0];
var peaceWidth = 35;
var peaceHeight = 35;
var peaceVisible = false;
var peaceSize = peaceWidth;
var peaceRotate = 0;
var frames = 30;
var timerId = 0;
var fadeId = 0;
var time = 0.0;
peaceImage.src = "Images/peace.png";
bgImage.onload = function(){
context.drawImage(bgImage, 0, backgroundY);
};
bgImage.src = "Images/background.png";
logoImage.onload = function(){
context.drawImage(logoImage, 50, -10);
}
logoImage.src = "Images/logo.png";
playImage.onload = function(){
context.drawImage(playImage, buttonX[0], buttonY[0]);
}
playImage.src = "Images/play.png";
instructImage.onload = function(){
context.drawImage(instructImage, buttonX[1], buttonY[1]);
}
instructImage.src = "Images/instructions.png";
settingsImage.onload = function(){
context.drawImage(settingsImage, buttonX[2], buttonY[2]);
}
settingsImage.src = "Images/settings.png";
aboutImage.onload = function(){
context.drawImage(aboutImage, buttonX[3], buttonY[3]);
}
aboutImage.src = "Images/about.png";
timerId = setInterval("update()", 1000/frames);
canvas.addEventListener("mousemove", checkPos);
canvas.addEventListener("mouseup", checkClick);
function update() {
clear();
move();
draw();
}
function clear() {
context.clearRect(0, 0, width, height);
}
function move(){
backgroundY -= speed;
if(backgroundY == -1 * height){
backgroundY = 0;
}
if(peaceSize == peaceWidth){
peaceRotate = -1;
}
if(peaceSize == 0){
peaceRotate = 1;
}
peaceSize += peaceRotate;
}
function draw(){
context.drawImage(bgImage, 0, backgroundY);
context.drawImage(logoImage, 50,-10);
context.drawImage(playImage, buttonX[1], buttonY[0]);
context.drawImage(instructImage, buttonX[2], buttonY[1]);
context.drawImage(settingsImage, buttonX[2], buttonY[2]);
context.drawImage(aboutImage, buttonX[3], buttonY[3]);
if(peaceVisible == true){
context.drawImage(peaceImage, peaceX[0] - (peaceSize/2), peaceY[0], peaceSize, peaceHeight);
context.drawImage(peaceImage, peaceX[2] - (peaceSize/2), peaceY[2], peaceSize, peaceHeight);
}
}
function checkPos(mouseEvent){
if(mouseEvent.pageX || mouseEvent.pageY == 0){
mouseX = mouseEvent.pageX - this.offsetLeft;
mouseY = mouseEvent.pageY - this.offsetTop;
}else if(mouseEvent.offsetX || mouseEvent.offsetY == 0){
mouseX = mouseEvent.offsetX;
mouseY = mouseEvent.offsetY;
}
for(i = 0; i < buttonX.length; i++){
if(mouseX > buttonX[i] && mouseX < buttonX[i] + buttonWidth[i]){
if(mouseY > buttonY[i] && mouseY < buttonY[i] + buttonHeight[i]){
peaceVisible = true;
peaceX[0] = buttonX[i] - (peaceWidth/2) - 2;
peaceY[0] = buttonY[i] + 2;
peaceX[1] = buttonX[i] + buttonWidth[i] + (peaceWidth/2);
peaceY[1] = buttonY[i] + 2;
}
}else{
peaceVisible = false;
}
}
}
function checkClick(mouseEvent){
for(i = 0; i < buttonX.length; i++){
if(mouseX > buttonX[i] && mouseX < buttonX[i] + buttonWidth[i]){
if(mouseY > buttonY[i] && mouseY < buttonY[i] + buttonHeight[i]){
fadeId = setInterval("fadeOut()", 1000/frames);
clearInterval(timerId);
canvas.removeEventListener("mousemove", checkPos);
canvas.removeEventListener("mouseup", checkClick);
}
}
}
}
function fadeOut(){
context.fillStyle = "rgba(0,0,0, 0.2)";
context.fillRect (0, 0, width, height);
time += 0.1;
if(time >= 2){
clearInterval(fadeId);
time = 0;
timerId = setInterval("update()", 1000/frames);
canvas.addEventListener("mousemove", checkPos);
canvas.addEventListener("mouseup", checkClick);
}
}
</script>
</body>
</html>
What I usually do is have a switch statement inside the draw loop, and a state variable which holds the current game state (menu, playing, etc...).
Then, based on the current game state you only draw the objects required for the current scene.
Something like this:
var STATES = {
Menu: 0,
PauseMenu: 1,
Playing: 2
};
var currentState = STATES.Menu;
...
function draw() {
switch(currentState) {
case STATES.Menu:
// Draw buttons, etc..
break;
case STATES.Playing:
// Draw the game screen, the player, etc...
break;
}
}
When the user presses the Play button the only thing you have to do is:
function onPlayButtonClick() {
currentState = STATES.Playing;
// Starting the next frame the new state will be "magically" drawn
}
If you don't like the switch statement, you can create a State class that has a draw method. Then you can simply create new states, each with it's own drawing method and in the main draw loop only call the draw method of the current state.
Same goes for the update function, each state has it's own update function (in the main menu you update buttons or animate things, while playing the game you update the game world and run your physics). So, based on the current state your update function is actually different. It's up to you how you structure your code and how you call different functions based on the current state.
In each text option, you should create a smaller Canvas, only with the option text and add a 'click' event with the callbacks.
Tip: You don't need another page, just erase the main canvas and draw what you want.
I'm writing a simple game in javascript and I'm wondering what the best way to handle collisions between the player and the world objects.
<script>
var isJumping = false;
var isFalling = false;
var w = 1;
var recwidth = 400;
var recheight = 400;
var xpos = 50;
var ypos = 279;
window.onload = function() {
var FPS = 30;
var ground = new myObject();
setInterval(function() {
clear();
draw();
ground.draw(0, 325);
ground.draw(125,325)
}, 1000/FPS);
};
function myObject(){
this.draw = function drawground(groundx, groundy){
var canvas = document.getElementById('canvas')
var context = canvas.getContext('2d');
//context.fillRect(xpos,ypos,100,100);
var img=new Image()
img.src="ground.png"
img.onload = function() {
context.drawImage(img,groundx,groundy)}
}
};
function jump()
{
var t=.1;
isJumping=true;
var jumpint= setInterval(function() {
yup = 12*t-(5*t*t);
ypos= ypos - yup;
t = t + .1
if(yup < 0)
{
isJumping = false;
isFalling = true;
clearInterval(jumpint);
jumpint = 0;
fall();
return;
}
}, 20);
}
function fall()
{
t=.10
var fallint= setInterval(function() {
ydown = (5*t*t);
ypos= ypos + ydown;
t = t + .1
if(ypos > 275)
{
isFalling == false;
clearInterval(fallint);
fallint = 0;
return;
}
}, 20);
}
function changex(x){
xpos = xpos + (x);
//clear();
//draw();
}
function changey(y){
ypos = ypos + (y);
//clear();
//draw();
}
function draw(){
var canvas = document.getElementById('canvas')
var context = canvas.getContext('2d');
var img=new Image()
img.src="character.png"
img.onload = function() {
context.drawImage(img,xpos,ypos)}
}
function clear(){
var canvas = document.getElementById('canvas')
var context = canvas.getContext('2d');
context.clearRect(0,0, canvas.width, canvas.height);
}
document.onkeydown = function(event) {
var keyCode;
if(event == null)
{
keyCode = window.event.keyCode;
}
else
{
keyCode = event.keyCode;
}
switch(keyCode)
{
// left
case 37:
//left
changex(-5);
break;
// up
case 38:
// action when pressing up key
jump();
break;
// right
case 39:
// action when pressing right key
changex(5);
break;
// down
case 40:
// action when pressing down key
changey(5);
break;
default:
break;
}
}
</script>
So, as you can see I'm creating two objects so far, and the player stops falling at any arbitrary point. I feel collisions at this stage wont be too difficult, but once I start adding more I feel it's going to get more difficult. I'm not going to be using the instance of the object with the same image for each instance of the object, so at some point I'm going to change the myobject function to be able to accept the image as a parameter, and then checking for collisions will be a bit more tricky. I also plan on making this into a side scroller, so once one end the map is hit it changes into the next area, which is going to cause performance issues. If I'm checking for collisions on every single object in the entire game every interval I imagine things are going to get slow. What is going to be the best way to limit the number of collisions checked? Obviously, if the object isn't on screen there is no need to check it, but is there a way to limit that. I'm thinking of making an array for every frame of the game, and filling that array with it's objects. Then, only check the array the of the frame the player is currently in. Is this feasible or still going to cause too many issues? Any help is greatly appreciated.
If you want pixel perfect collisions, I have some plain javascript code that worked for me with canvas2d rendering context.
function collide(sprite, sprite2, minOpacity=1) {
// Rectangular bounding box collision
if (sprite.x < sprite2.x + sprite2.width && sprite.x + sprite.width > sprite2.x && sprite.y < sprite2.y + sprite2.height && sprite.y + sprite.height > sprite2.y) {
// Finds the x and width of the overlapping area
var overlapX = (this.rect.x > other.rect.x) ? [this.rect.x, (other.rect.x + other.rect.width) - this.rect.x + 1] : [other.rect.x, (this.rect.x + this.rect.width) - other.rect.x + 1];
// Finds the y and height of the overlapping area
var overlapY = (this.rect.y + this.rect.height > other.rect.y + other.rect.height) ? [this.rect.y, (other.rect.y + other.rect.height) - this.rect.y + 1] : [other.rect.y, (this.rect.y + this.rect.height) - other.rect.y + 1];
// Creates a canvas to draw sprite.image to
var spriteImageCanvas = new OffscreenCanvas(overlapX[0] + overlapX[1], overlapY[0] + overlapY[1]);
var spriteImageCanvasContext = spriteImageCanvas.getContext("2d");
// Draws sprite.image to spriteImageCanvasContext
spriteImageCanvasContext.drawImage(this.image, sprite.x, sprite.y, sprite.width, sprite.height);
// Creates a canvas to draw sprite2.image to
var sprite2ImageCanvas = new OffscreenCanvas(overlapX[0] + overlapX[1], overlapY[0] + overlapY[1]);
var sprite2ImageCanvasContext = otherImageCanvas.getContext("2d");
// Draws sprite2.image to sprite2ImageCanvasContext
sprite2ImageCanvasContext.drawImage(sprite2.image, sprite2.x, sprite2.y, sprite2.width, sprite2.height);
// Loops through the x coordinates in the overlapping area
for (var x = overlapX[0]; x <= overlapX[0] + overlapX[1]; x++) {
// Loops through the y coordinates in the overlapping area
for (var y = overlapY[0]; y <= overlapY[0] + overlapY[1]; y++) {
if (/* Checks if the pixel at [x, y] in the sprite image has an opacity over minOpacity input */ thisImageCanvasContext.getImageData(x, y, 1, 1).data[3] >= minOpacity && /* Checks if the pixel at [x, y] in the sprite2 image has an opacity over minOpacity input */ otherImageCanvasContext.getImageData(x, y, 1, 1).data[3] >= minOpacity) {
return true;
};
};
};
};
}
Or if you just want rectangular collision, use the first if statement in the function.