VUE+Canvas 데스크 톱 당구 벽돌 제거 게임 의 예제 코드 구현
그러면 VUE+Canvas 로 어떻게 이 루어 질 까요?실현 방향 은 매우 간단 하 다.먼저 캔버스 에 그 려 야 할 내용 을 나 누 어 보 자.
(1)키보드 좌우 버튼 으로 이동 하 는 널 빤 지 를 제어 한다.
(2)캔버스 안에서 사방 으로 튀 는 작은 공;
(3)화면 위 에 고정 하고 공 에 부 딪 히 면 사라 지 는 벽돌 더미.
상기 세 가지 대상 을 requestAnimationFrame()함수 로 이동 시 킨 다음 에 각종 충돌 검 사 를 결합 하면 최종 결 과 를 얻 을 수 있다.
최종 효과 부터 살 펴 보 자.
1.좌우 로 평평 하 게 옮 긴 널빤지
맨 밑 에 있 는 널 빤 지 는 가장 간단 한 부분 입 니 다.널빤지 의 y 좌 표 는 고정 되 어 있 기 때문에 우 리 는 널빤지 의 초기 매개 변 수 를 설정 합 니 다.너비,높이,이동 속도 등 을 포함 하고 널빤지 의 함 수 를 실현 합 니 다.
pannel: {
x: 0,
y: 0,
height: 8,
width: 100,
speed: 8,
dx: 0
},
....
drawPannel() {
this.drawRoundRect(
this.pannel.x,
this.pannel.y,
this.pannel.width,
this.pannel.height,
5
);
},
drawRoundRect(x, y, width, height, radius) { //
this.ctx.beginPath();
this.ctx.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2);
this.ctx.lineTo(width - radius + x, y);
this.ctx.arc(
width - radius + x,
radius + y,
radius,
(Math.PI * 3) / 2,
Math.PI * 2
);
this.ctx.lineTo(width + x, height + y - radius);
this.ctx.arc(
width - radius + x,
height - radius + y,
radius,
0,
(Math.PI * 1) / 2
);
this.ctx.lineTo(radius + x, height + y);
this.ctx.arc(
radius + x,
height - radius + y,
radius,
(Math.PI * 1) / 2,
Math.PI
);
this.ctx.fillStyle = "#008b8b";
this.ctx.fill();
this.ctx.closePath();
}
프로그램 이 초기 화 되 었 을 때 키보드 의 좌우 방향 키 를 감청 하여 널 빤 지 를 이동 하고 길 이 를 통 해 좌우 경계 로 이동 하여 화면 을 계속 이동 할 수 없 는 지 판단 합 니 다.
document.onkeydown = function(e) {
let key = window.event.keyCode;
if (key === 37) {
//
_this.pannel.dx = -_this.pannel.speed;
} else if (key === 39) {
//
_this.pannel.dx = _this.pannel.speed;
}
};
document.onkeyup = function(e) {
_this.pannel.dx = 0;
};
....
movePannel() {
this.pannel.x += this.pannel.dx;
if (this.pannel.x > this.clientWidth - this.pannel.width) {
this.pannel.x = this.clientWidth - this.pannel.width;
} else if (this.pannel.x < 0) {
this.pannel.x = 0;
}
},
2.점프 하 는 작은 공 과 충돌 검 측작은 공의 운동 은 널빤지 와 유사 하지만 dx 의 오프셋 뿐만 아니 라 dy 의 오프셋 도 있다.
그리고 충돌 검사 도 있어 야 합 니 다.
(1)위,오른쪽,왼쪽 벽 과 널빤지 에 부 딪 혔 을 때 튕 겨 나온다.
(2)널빤지 이외 의 하 경계 에 부 딪 혔 을 때 게임 에서 진다.
(3)벽돌 에 부 딪 혔 을 때 부 딪 힌 벽돌 이 사라 지고 점수+1 로 작은 공이 튕 겨 나온다.
그래서 널빤지 와 마찬가지 로 작은 공 부분 을 작은 공 함수 drawBall()과 작은 공 운동 함수 moveBall()로 나 누 었 다.
drawBall() {
this.ctx.beginPath();
this.ctx.arc(this.ball.x, this.ball.y, this.ball.r, 0, 2 * Math.PI);
this.ctx.fillStyle = "#008b8b";
this.ctx.fill();
this.ctx.closePath();
},
moveBall() {
this.ball.x += this.ball.dx;
this.ball.y += this.ball.dy;
this.breaksHandle();
this.edgeHandle();
},
breaksHandle() {
//
this.breaks.forEach(item => {
if (item.show) {
if (
this.ball.x + this.ball.r > item.x &&
this.ball.x - this.ball.r < item.x + this.breaksConfig.width &&
this.ball.y + this.ball.r > item.y &&
this.ball.y - this.ball.r < item.y + this.breaksConfig.height
) {
item.show = false;
this.ball.dy *= -1;
this.score ++ ;
if(this.showBreaksCount === 0){
this.gameOver = true;
}
}
}
});
},
edgeHandle() {
//
//
if (this.ball.y - this.ball.r < 0) {
this.ball.dy = -this.ball.dy;
}
if (
//
this.ball.x - this.ball.r < 0 ||
this.ball.x + this.ball.r > this.clientWidth
) {
this.ball.dx = -this.ball.dx;
}
if (
this.ball.x >= this.pannel.x &&
this.ball.x <= this.pannel.x + this.pannel.width &&
this.ball.y + this.ball.r >= this.clientHeight - this.pannel.height
) {
// x
this.ball.dy *= -1;
} else if (
(this.ball.x < this.pannel.x ||
this.ball.x > this.pannel.x + this.pannel.width) &&
this.ball.y + this.ball.r >= this.clientHeight
) {
//
this.gameOver = true;
this.getCurshBreaks();
}
}
3.벽돌의 생 성벽돌의 생 성도 비교적 간단 하 다.여기 서 우 리 는 약간의 데 이 터 를 시작 했다.
breaksConfig: {
row: 6, //
height: 25, //
width: 130, //
radius: 5, //
space: 0, //
colunm: 6 //
}
이러한 배치 항목 과 캔버스 너비 에 따라 우 리 는 모든 벽돌 의 가로 간격 이 얼마 인지 계산 할 수 있다.
//
this.breaksConfig.space = Math.floor(
(this.clientWidth -
this.breaksConfig.width * this.breaksConfig.colunm) /
(this.breaksConfig.colunm + 1)
);
그래서 우 리 는 모든 벽돌 이 캔버스 에 있 는 x,y 좌 표를 얻 을 수 있다.
for (let i = 0; i < _this.breaksConfig.row; i++) {
for (let j = 0; j < _this.breaksConfig.colunm; j++) {
_this.breaks.push({
x: this.breaksConfig.space * (j + 1) + this.breaksConfig.width * j,
y: 10 * (i + 1) + this.breaksConfig.height * i,
show: true
});
}
}
게다가 벽돌 을 그 리 는 함수:
drawBreaks() {
let _this = this;
_this.breaks.forEach(item => {
if (item.show) {
_this.drawRoundRect(
item.x,
item.y,
_this.breaksConfig.width,
_this.breaksConfig.height,
_this.breaksConfig.radius
);
}
});
}
4.위의 세 부분 을 움 직 이게 합 니 다.
(function animloop() {
if (!_this.gameOver) {
_this.movePannel();
_this.moveBall();
_this.drawAll();
} else {
_this.drawCrushBreaks();
}
window.requestAnimationFrame(animloop);
})();
....
drawAll() {
this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight);
this.drawPannel();
this.drawBall();
this.drawScore();
this.drawBreaks();
}
5.게임 종료 후 효과처음에 움 직 이 는 그림 에서 볼 수 있 듯 이 게임 이 끝 난 후에 벽돌 은 몇 개의 작은 공 으로 갈 라 져 떨 어 졌 다.이것 은 사실은 단독 적 인 작은 공 을 그 리 는 것 과 비슷 하 다.생각 은 바로 남 은 벽돌 중심 좌표 에서 몇 개의 크기 가 다 르 고 운동 궤적 이 다 르 며 색깔 이 다른 작은 공 을 생산 한 다음 에 애니메이션 을 계속 하 는 것 이다.
getCurshBreaks() {
let _this = this;
this.breaks.forEach(item => {
if (item.show) {
item.show = false;
for (let i = 0; i < 8; i++) { // 8
this.crushBalls.push({
x: item.x + this.breaksConfig.width / 2,
y: item.y + this.breaksConfig.height / 2,
dx: _this.getRandomArbitrary(-6, 6),
dy: _this.getRandomArbitrary(-6, 6),
r: _this.getRandomArbitrary(1, 4),
color: _this.getRandomColor()
});
}
}
});
},
drawCrushBreaks() {
this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight);
this.crushBalls.forEach(item => {
this.ctx.beginPath();
this.ctx.arc(item.x, item.y, item.r, 0, 2 * Math.PI);
this.ctx.fillStyle = item.color;
this.ctx.fill();
this.ctx.closePath();
item.x += item.dx;
item.y += item.dy;
if (
//
item.x - item.r < 0 ||
item.x + item.r > this.clientWidth
) {
item.dx = -item.dx;
}
if (
//
item.y - item.r < 0 ||
item.y + item.r > this.clientHeight
) {
item.dy = -item.dy;
}
});
},
이상 은 바로 데스크 톱 에서 공 을 튕 기 고 벽돌 을 없 애 는 작은 게임 의 실현 방향 과 일부 코드 입 니 다.실현 하기 가 매우 간단 합 니 다.이 300 줄 의 코드 는 이 작은 게임 을 실현 할 수 있 습 니 다.작은 공의 운동 에 있어 서 지속 적 으로 최적화 할 수 있 고 난이도 옵션 조작 도 증가 할 수 있다.마지막 으로 모든 vue 파일 코드 를 첨부 하여 여러분 이 참고 하여 공부 할 수 있 도록 합 니 다.
<template>
<div class="break-ball">
<canvas id="breakBall" width="900" height="600"></canvas>
<div class="container" v-if="gameOver">
<div class="dialog">
<p class="once-again"> :{{score}} </p>
<p class="once-again"> !</p>
<p class="once-again"> ~~</p>
<el-button class="once-again-btn" @click="init"> </el-button>
</div>
</div>
</div>
</template>
<script>
const randomColor = [
"#FF95CA",
"#00E3E3",
"#00E3E3",
"#6F00D2",
"#6F00D2",
"#C2C287",
"#ECFFFF",
"#FFDC35",
"#93FF93",
"#d0d0d0"
];
export default {
name: "BreakBall",
data() {
return {
clientWidth: 0,
clientHeight: 0,
ctx: null,
crushBalls: [],
pannel: {
x: 0,
y: 0,
height: 8,
width: 100,
speed: 8,
dx: 0
},
ball: {
x: 0,
y: 0,
r: 8,
dx: -4,
dy: -4
},
score: 0,
gameOver: false,
breaks: [],
breaksConfig: {
row: 6, //
height: 25, //
width: 130, //
radius: 5, //
space: 0, //
colunm: 6 //
}
};
},
mounted() {
let _this = this;
let container = document.getElementById("breakBall");
this.ctx = container.getContext("2d");
this.clientHeight = container.height;
this.clientWidth = container.width;
_this.init();
document.onkeydown = function(e) {
let key = window.event.keyCode;
if (key === 37) {
//
_this.pannel.dx = -_this.pannel.speed;
} else if (key === 39) {
//
_this.pannel.dx = _this.pannel.speed;
}
};
document.onkeyup = function(e) {
_this.pannel.dx = 0;
};
(function animloop() {
if (!_this.gameOver) {
_this.movePannel();
_this.moveBall();
_this.drawAll();
} else {
_this.drawCrushBreaks();
}
window.requestAnimationFrame(animloop);
})();
},
computed:{
showBreaksCount(){
return this.breaks.filter(item=>{
return item.show;
}).length;
}
},
methods: {
init() {
let _this = this;
_this.gameOver = false;
this.pannel.y = this.clientHeight - this.pannel.height;
this.pannel.x = this.clientWidth / 2 - this.pannel.width / 2;
this.ball.y = this.clientHeight / 2;
this.ball.x = this.clientWidth / 2;
this.score = 0;
this.ball.dx = [-1,1][Math.floor(Math.random() * 2)]*4;
this.ball.dy = [-1,1][Math.floor(Math.random() * 2)]*4;
this.crushBalls = [];
this.breaks = [];
//
this.breaksConfig.space = Math.floor(
(this.clientWidth -
this.breaksConfig.width * this.breaksConfig.colunm) /
(this.breaksConfig.colunm + 1)
);
for (let i = 0; i < _this.breaksConfig.row; i++) {
for (let j = 0; j < _this.breaksConfig.colunm; j++) {
_this.breaks.push({
x: this.breaksConfig.space * (j + 1) + this.breaksConfig.width * j,
y: 10 * (i + 1) + this.breaksConfig.height * i,
show: true
});
}
}
},
drawAll() {
this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight);
this.drawPannel();
this.drawBall();
this.drawScore();
this.drawBreaks();
},
movePannel() {
this.pannel.x += this.pannel.dx;
if (this.pannel.x > this.clientWidth - this.pannel.width) {
this.pannel.x = this.clientWidth - this.pannel.width;
} else if (this.pannel.x < 0) {
this.pannel.x = 0;
}
},
moveBall() {
this.ball.x += this.ball.dx;
this.ball.y += this.ball.dy;
this.breaksHandle();
this.edgeHandle();
},
breaksHandle() {
//
this.breaks.forEach(item => {
if (item.show) {
if (
this.ball.x + this.ball.r > item.x &&
this.ball.x - this.ball.r < item.x + this.breaksConfig.width &&
this.ball.y + this.ball.r > item.y &&
this.ball.y - this.ball.r < item.y + this.breaksConfig.height
) {
item.show = false;
this.ball.dy *= -1;
this.score ++ ;
if(this.showBreaksCount === 0){
this.gameOver = true;
}
}
}
});
},
edgeHandle() {
//
//
if (this.ball.y - this.ball.r < 0) {
this.ball.dy = -this.ball.dy;
}
if (
//
this.ball.x - this.ball.r < 0 ||
this.ball.x + this.ball.r > this.clientWidth
) {
this.ball.dx = -this.ball.dx;
}
if (
this.ball.x >= this.pannel.x &&
this.ball.x <= this.pannel.x + this.pannel.width &&
this.ball.y + this.ball.r >= this.clientHeight - this.pannel.height
) {
// x
this.ball.dy *= -1;
} else if (
(this.ball.x < this.pannel.x ||
this.ball.x > this.pannel.x + this.pannel.width) &&
this.ball.y + this.ball.r >= this.clientHeight
) {
//
this.gameOver = true;
this.getCurshBreaks();
}
},
drawScore(){
this.ctx.beginPath();
this.ctx.font="14px Arial";
this.ctx.fillStyle = "#FFF";
this.ctx.fillText(" :"+this.score,10,this.clientHeight-14);
this.ctx.closePath();
},
drawCrushBreaks() {
this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight);
this.crushBalls.forEach(item => {
this.ctx.beginPath();
this.ctx.arc(item.x, item.y, item.r, 0, 2 * Math.PI);
this.ctx.fillStyle = item.color;
this.ctx.fill();
this.ctx.closePath();
item.x += item.dx;
item.y += item.dy;
if (
//
item.x - item.r < 0 ||
item.x + item.r > this.clientWidth
) {
item.dx = -item.dx;
}
if (
//
item.y - item.r < 0 ||
item.y + item.r > this.clientHeight
) {
item.dy = -item.dy;
}
});
},
getRandomColor() {
return randomColor[Math.floor(Math.random() * randomColor.length)];
},
getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
},
getCurshBreaks() {
let _this = this;
this.breaks.forEach(item => {
if (item.show) {
item.show = false;
for (let i = 0; i < 8; i++) {
this.crushBalls.push({
x: item.x + this.breaksConfig.width / 2,
y: item.y + this.breaksConfig.height / 2,
dx: _this.getRandomArbitrary(-6, 6),
dy: _this.getRandomArbitrary(-6, 6),
r: _this.getRandomArbitrary(1, 4),
color: _this.getRandomColor()
});
}
}
});
},
drawBall() {
this.ctx.beginPath();
this.ctx.arc(this.ball.x, this.ball.y, this.ball.r, 0, 2 * Math.PI);
this.ctx.fillStyle = "#008b8b";
this.ctx.fill();
this.ctx.closePath();
},
drawPannel() {
this.drawRoundRect(
this.pannel.x,
this.pannel.y,
this.pannel.width,
this.pannel.height,
5
);
},
drawRoundRect(x, y, width, height, radius) {
this.ctx.beginPath();
this.ctx.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2);
this.ctx.lineTo(width - radius + x, y);
this.ctx.arc(
width - radius + x,
radius + y,
radius,
(Math.PI * 3) / 2,
Math.PI * 2
);
this.ctx.lineTo(width + x, height + y - radius);
this.ctx.arc(
width - radius + x,
height - radius + y,
radius,
0,
(Math.PI * 1) / 2
);
this.ctx.lineTo(radius + x, height + y);
this.ctx.arc(
radius + x,
height - radius + y,
radius,
(Math.PI * 1) / 2,
Math.PI
);
this.ctx.fillStyle = "#008b8b";
this.ctx.fill();
this.ctx.closePath();
},
drawBreaks() {
let _this = this;
_this.breaks.forEach(item => {
if (item.show) {
_this.drawRoundRect(
item.x,
item.y,
_this.breaksConfig.width,
_this.breaksConfig.height,
_this.breaksConfig.radius
);
}
});
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.break-ball {
width: 900px;
height: 600px;
position: relative;
#breakBall {
background: #2a4546;
}
.container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.3);
text-align: center;
font-size: 0;
white-space: nowrap;
overflow: auto;
}
.container:after {
content: "";
display: inline-block;
height: 100%;
vertical-align: middle;
}
.dialog {
width: 400px;
height: 300px;
background: rgba(255, 255, 255, 0.5);
box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, 0.3);
display: inline-block;
vertical-align: middle;
text-align: left;
font-size: 28px;
color: #fff;
font-weight: 600;
border-radius: 10px;
white-space: normal;
text-align: center;
.once-again-btn {
background: #1f9a9a;
border: none;
color: #fff;
}
}
}
</style>
VUE+Canvas 가 데스크 톱 에서 공 을 튕 기 고 벽돌 을 없 애 는 작은 게임 을 실현 하 는 것 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.vue 공 을 튕 기 고 벽돌 을 없 애 는 작은 게임 에 관 한 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 읽 어 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Fastapi websocket 및 vue 3(Composition API)1부: FastAPI virtualenv 만들기(선택 사항) FastAPI 및 필요한 모든 것을 다음과 같이 설치하십시오. 생성main.py 파일 및 실행 - 브라우저에서 이 링크 열기http://127.0.0.1:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.