javascript - 如何使球与画布上的三角形电源碰撞?
问题描述
我正在尝试为我的游戏创造能量。我已经让形状出现了,但是当球与形状碰撞时,它并没有像它应该做的那样加速。
<html>
<title>Level Selector</title>
<canvas id="myCanvas" width="750" height="400"></canvas>
<style type="text/css">
canvas { background: #eee; }
</style>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;//Ball is moving in x direction at a constant rate
var dy = -2;//Ball is moving in y direction at a constant rate
var ballRadius = 10;//To see if ball is colliding with brick/canvas
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;//This variable is false because the 'right arrow' key is not pressed.
var leftPressed = false;//This variable is false because the 'left arrow' key is not pressed.
var brickRowCount = 5;
var brickColumnCount = 8;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var paused = false;
var ballstartx = 10;
var ballstarty = 10;
var balllefttrix = 20;
var balllefttriy = 30;
var ballrighttrix = 30;
var ballrighttriy = 10;
var paddlestartx = 300;
var paddlestarty = 10;
var paddlelefttrix = 310;
var paddlelefttriy = 30;
var paddlerighttrix = 320;
var paddlerighttriy = 10;
var bricks = [];//this is an array holding all the bricks
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };//If status is '1' then draw it. However, is status is '0', fill in with background
}
}
document.addEventListener("keydown", keyDownHandler, false);//Functions only when key is pressed
document.addEventListener("keyup", keyUpHandler, false);//Functions only when key is not pressed
document.addEventListener("mousemove", mouseMoveHandler, false);//Functions only when mouse curcor moves
//keyCode(39) is the code for the 'right arrow' key and keyCode(37) is the code for the 'left arrow' key
function keyDownHandler(e) {
if(e.keyCode == 39) {
rightPressed = true;
}
else if(e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.keyCode == 39) {
rightPressed = false;
}
else if(e.keyCode == 37) {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;//This represents the hoizontal mouse movement.
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
window.addEventListener('keydown', pauseGameKeyHandler, false);
function pauseGameKeyHandler(e) {
var keyCode = e.keyCode;
switch(keyCode){
case 80: //p
togglePause();
break;
}
}
function togglePause() {
paused = !paused;
draw();
}
//Collisions only true when:
// -The x position of the ball is greater than the x position of the brick.
// -The x position of the ball is less than the x position of the brick plus its width.
// -The y position of the ball is greater than the y position of the brick.
// -The y position of the ball is less than the y position of the brick plus its height.
function collisionDetection() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("YOU WIN, CONGRATULATIONS!");
document.location.reload();
}
}
}
}
}
}
//this is the score variable of the game
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
//this is the lives variable of the game
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
//this is the ball power up
function drawBallpowerup() {
ctx.beginPath();
ctx.moveTo(ballstartx, ballstarty);
ctx.lineTo(balllefttrix, balllefttriy);
ctx.lineTo(ballrighttrix, ballrighttriy);
ctx.fillStyle = "#42f445";
ctx.fill();
ctx.closePath();
}
//ball power up collision
function ballpowerupDetection() {
if(ballstartx == x && ballstarty == y && balllefttrix == x && balllefttriy == y && ballrighttrix == x && ballrighttriy == y ) {
dy == -5;
dx == 5;
}
}
//this is the paddle power up
function drawPaddlepowerup() {
ctx.beginPath();
ctx.moveTo(paddlestartx, paddlestarty);
ctx.lineTo(paddlelefttrix, paddlelefttriy);
ctx.lineTo(paddlerighttrix, paddlerighttriy);
ctx.fillStyle = "#ce6210";
ctx.fill();
ctx.closePath();
}
//paddle power up collision
function paddlepowerupDetection() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("YOU WIN, CONGRATULATIONS!");
document.location.reload();
}
}
}
}
}
}
//this creates the ball
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
//this creates the paddle
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
//this creates the bricks
function drawBricks() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);//clears canvas content from previous frame
drawBall();//this code draws the ball onto the canvas
drawPaddle();//this code draws the paddle onto the canvas
collisionDetection();//this codes enables the collision detection for the ball and bricks
drawBricks();//this code draws the bricks onto the canvas
drawScore();//this code draws the score variable onto the canvas
drawLives();//this code draws the lives variable onto the canvas
drawBallpowerup();
drawPaddlepowerup();
ballpowerupDetection();
//Reverse Ball movement when the ball collides with wall in 'x' direction (Left/Right wall)
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
//Reverse Ball movement when the ball collides with wall in 'y' direction (Top/Bottom wall)
if(y + dy < ballRadius) {
dy = -dy;
} else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;//If the ball collides with the paddle, the ball is rebounded in the opposite direction.
}
else {
lives--;
if(!lives) {
alert("GAME OVER");
document.location.reload();
}
else {
x = canvas.width/2;
y = canvas.height-30;
dx = 2;
dy = -2;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {//limits paddle movement in between the canvas width
paddleX += 7;//Paddle shifts 7 pixels in the positive x direction
}
else if(leftPressed && paddleX > 0) {//limits paddle movement in between the canvas width
paddleX -= 7;//Paddle shifts 7 pixels in the negative x direction
}
x += dx;//Ball is updated by painting it over each position it moves in
y += dy;//Ball is updated by painting it over each position it moves in
if(!paused) {
requestAnimationFrame(draw);
}
}
draw();
</script>
<body onload="draw();>
</body>
</html>
加电功能不起作用,我不知道为什么。我希望球在基本接触三角形时加快速度。提前谢谢。
解决方案
我确实帮助了您遇到的大部分问题:
- 通电具有矩形碰撞边界,比三角形更容易数学
- 在画布内随机放置通电
- 评论在哪里以及如何添加效果以及如何在 X 秒后结束它
代码仍然有点混乱,但这是你的工作:将重复逻辑移动到单个函数,就像我对碰撞逻辑所做的那样,更好地查看和维护。
document.addEventListener('load', draw);
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;//Ball is moving in x direction at a constant rate
var dy = -2;//Ball is moving in y direction at a constant rate
var ballRadius = 10;//To see if ball is colliding with brick/canvas
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;//This variable is false because the 'right arrow' key is not pressed.
var leftPressed = false;//This variable is false because the 'left arrow' key is not pressed.
var brickRowCount = 5;
var brickColumnCount = 8;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var paused = false;
var ballstartx = 10;
var ballstarty = 10;
var balllefttrix = 20;
var balllefttriy = 30;
var ballrighttrix = 30;
var ballrighttriy = 10;
var paddlestartx = 300;
var paddlestarty = 10;
var paddlelefttrix = 310;
var paddlelefttriy = 30;
var paddlerighttrix = 320;
var paddlerighttriy = 10;
var bricks = [];//this is an array holding all the bricks
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };//If status is '1' then draw it. However, is status is '0', fill in with background
}
}
document.addEventListener("keydown", keyDownHandler, false);//Functions only when key is pressed
document.addEventListener("keyup", keyUpHandler, false);//Functions only when key is not pressed
document.addEventListener("mousemove", mouseMoveHandler, false);//Functions only when mouse curcor moves
//keyCode(39) is the code for the 'right arrow' key and keyCode(37) is the code for the 'left arrow' key
function keyDownHandler(e) {
if(e.keyCode == 39) {
rightPressed = true;
}
else if(e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.keyCode == 39) {
rightPressed = false;
}
else if(e.keyCode == 37) {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;//This represents the hoizontal mouse movement.
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
window.addEventListener('keydown', pauseGameKeyHandler, false);
function pauseGameKeyHandler(e) {
var keyCode = e.keyCode;
switch(keyCode){
case 80: //p
togglePause();
break;
}
}
function togglePause() {
paused = !paused;
draw();
}
/*************************************************************/
// my big changes start here
// PS! I commented out some annoying code
// from other places like game over alerts etc
// try to find a better way to debug
// your work, waiting all the time is bad
// NEW
const ballPowerupHalfWidth = 30;
const paddlePowerupHalfWidth = 30;
let ballPowerups = [];
let paddlePowerups = [];
// NEW: add powerup to random position
function addPowerups() {
// I check only if none exist, you could
// add more than 1 powerup if you want
if (ballPowerups.length < 1) {
// otherwise half the triangle could be outside canvas
const padding = 50;
const xMin = 0 + padding;
const xMax = canvas.width - padding;
const yMin = 0 + padding;
const yMax = canvas.height - padding;
ballPowerups.push({
x: Math.floor(Math.random()*(xMax-xMin+1)+xMin),
y: Math.floor(Math.random()*(yMax-yMin+1)+yMin),
});
}
// I check only if none exist, you could
// add more than 1 powerup if you want
if (paddlePowerups.length < 1) {
// otherwise half the triangle could be outside canvas
const padding = 50;
const xMin = 0 + padding;
const xMax = canvas.width - padding;
const yMin = 0 + padding;
const yMax = canvas.height - padding;
paddlePowerups.push({
x: Math.floor(Math.random()*(xMax-xMin+1)+xMin),
y: Math.floor(Math.random()*(yMax-yMin+1)+yMin),
});
}
}
// NEW: do all collision detections
function doCollisionDetection() {
// ball powerups
ballPowerups.forEach((powerup, i) => {
rectangleCollisionDetection(
{x: powerup.x, y: powerup.y},
{w: ballPowerupHalfWidth, h: ballPowerupHalfWidth},
() => {
console.log('BALL POWERUP COLLISION');
// remove powerup
ballPowerups.splice(i, 1);
// add your effect here
// to make effect last 10 seconds:
// 1. add effect
// 2. and setTimeout(() => { /* code that removes effect */ }, 10000);
});
});
// paddle powerups
paddlePowerups.forEach((powerup, i) => {
rectangleCollisionDetection(
{x: powerup.x, y: powerup.y},
{w: ballPowerupHalfWidth, h: ballPowerupHalfWidth},
() => {
console.log('PADDLE POWERUP COLLISION');
// remove powerup
paddlePowerups.splice(i, 1);
// add your effect here
});
});
// bricks
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
rectangleCollisionDetection(b, {w: brickWidth, h: brickHeight}, () => {
console.log('BRICK COLLISION');
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
//alert("YOU WIN, CONGRATULATIONS!");
//document.location.reload();
}
});
}
}
}
}
// NEW: collision detection between ball and rectangle shaped
// collision boundary (only need center(x, y) and half width)
function rectangleCollisionDetection(center, size, callback) {
if(
x > center.x &&
x < center.x+size.w &&
y > center.y &&
y < center.y+size.h
) {
callback && callback();
}
}
function drawBallpowerup() {
ballPowerups.forEach(powerup => {
ctx.beginPath();
ctx.moveTo(powerup.x, powerup.y);
ctx.lineTo(powerup.x+ballPowerupHalfWidth, powerup.y+ballPowerupHalfWidth);
ctx.lineTo(powerup.x+ballPowerupHalfWidth*2, powerup.y);
ctx.fillStyle = "#42f445";
ctx.fill();
ctx.closePath();
});
}
function drawPaddlepowerup() {
paddlePowerups.forEach(powerup => {
ctx.beginPath();
ctx.moveTo(powerup.x, powerup.y);
ctx.lineTo(powerup.x+paddlePowerupHalfWidth, powerup.y+paddlePowerupHalfWidth);
ctx.lineTo(powerup.x+paddlePowerupHalfWidth*2, powerup.y);
ctx.fillStyle = "#ce6210";
ctx.fill();
ctx.closePath();
});
}
// my big changes end here
/*************************************************************/
//this is the score variable of the game
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
//this is the lives variable of the game
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
//this creates the ball
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
//this creates the paddle
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
//this creates the bricks
function drawBricks() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function draw() {
// clears canvas content from previous frame
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();//this code draws the ball onto the canvas
drawPaddle();//this code draws the paddle onto the canvas
drawBricks();//this code draws the bricks onto the canvas
addPowerups();
doCollisionDetection();
drawScore();//this code draws the score variable onto the canvas
drawLives();//this code draws the lives variable onto the canvas
drawBallpowerup();
drawPaddlepowerup();
//Reverse Ball movement when the ball collides with wall in 'x' direction (Left/Right wall)
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
//Reverse Ball movement when the ball collides with wall in 'y' direction (Top/Bottom wall)
if(y + dy < ballRadius) {
dy = -dy;
} else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;//If the ball collides with the paddle, the ball is rebounded in the opposite direction.
}
else {
lives--;
if(!lives) {
//alert("GAME OVER");
//document.location.reload();
}
else {
x = canvas.width/2;
y = canvas.height-30;
dx = 2;
dy = -2;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {//limits paddle movement in between the canvas width
paddleX += 7;//Paddle shifts 7 pixels in the positive x direction
}
else if(leftPressed && paddleX > 0) {//limits paddle movement in between the canvas width
paddleX -= 7;//Paddle shifts 7 pixels in the negative x direction
}
x += dx;//Ball is updated by painting it over each position it moves in
y += dy;//Ball is updated by painting it over each position it moves in
if(!paused) {
requestAnimationFrame(draw);
}
}
draw();
canvas {
background: #eee;
}
<canvas id="myCanvas" width="750" height="400"></canvas>
推荐阅读
- python - 如何从他们的用户 ID 中获取不和谐服务器成员的用户名
- asp.net-mvc - nopcommerce 4.0 源代码是提取的 zip 文件,但在 NopCommerce sln 文件中未加载 Visual Studio 2015 问题
- c# - Unity collider OnTriggerEnter 没有被调用
- r - ggplot中多个组的密度图
- vue.js - Internet Explorer 11 使用随机值更新图表
- spring-boot - 春天云网关|| 需要配置全局和应用程序级别和api级别超时
- touch-event - 通过 HDMI 的触摸事件
- bulma - 非响应式布尔玛导航
- python - 如何根据文档类型验证特定的 jsonschema
- javascript - 如何停止添加到购物车按钮重定向用户