突然發現前面雖然有提到,這次的程式是在HTML檔案中寫JS,但我沒有提過自己的開發環境以及如何執行程式,這邊就簡單補充一下握個人的習慣.
我自己常用的程式語言大概就三種,JS、Python以及Java,那我個人的習慣是會區分使用的IDE,Python我都使用PyCharm;Java使用IntelliJ;有關前端開發的我使用VSCode,這樣的區分是按我個人習慣.
如何執行這次撰寫的遊戲檔案呢,我這邊提供一種方法,方法有很多種,但我覺得找到一種自己覺得方便的即可.我自己常用的,是在VSCode中安裝Preview on Web Server
,想做畫面測試時,點選右鍵選擇Launch on browser
會直接以瀏覽器開啟,我比較常使用這方法,因為我習慣會搭配瀏覽器的開發者工具來看.
以上是我補充我自己開發時使用的工具.
拉回到遊戲內容,昨天的進度是到了畫面上呈現了一個紅磚還有小白球,並且小白球會移動了,只是目前會任性地離場.今天我們就先來解決這問題,教會小白球在規定的範圍內移動.
我們先專注於球的移動,所以先把紅磚給移除,為了後面操作上好做修改,我們把球的移動速度寫為兩個維度的變數ball_speed_x
以及ball_speed_y
.目前的code是這樣:
<script>
var canvas, canvasContext;
//球的參數
var ball_x = 300;
var ball_y = 300;
var ball_speed_x = 5;
var ball_speed_y = 5;
window.onload = () => {
canvas = document.getElementById('playground');
canvasContext = canvas.getContext('2d');
//一秒更新幾次畫面
var timesPerSec = 30;
setInterval(drawAll, 1000/timesPerSec);
}
// 負責繪製畫面
drawAll = () => {
// background
canvasContext.fillStyle = 'black';
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
ball_x += ball_speed_x;
ball_y += ball_speed_y;
canvasContext.fillStyle = 'white';
canvasContext.beginPath();
canvasContext.arc(ball_x, ball_y, 10, 0, Math.PI * 2);
canvasContext.fill();
}
</script>
好的,那麼我們先想一下白球的移動方式,先不考慮球低於畫面底部時GG的情況,正常球的移動是若球碰壁即反彈,一次只改變一種維度的速度,什麼意思??? 比如說球往右下移動,先碰到了右側邊界,那改變的會是ball_speed_x
水平方向速度要往反方向改變,垂直方向ball_speed_y
則保持不變.我們就按照這邏輯來寫一下觸動四個邊界時的動作.
drawAll = () => {
// background
canvasContext.fillStyle = 'black';
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
ball_x += ball_speed_x;
ball_y += ball_speed_y;
// 碰觸邊界動作
if(ball_x < 0) {
ball_speed_x *= -1;
}
if(ball_x > canvas.width) {
ball_speed_x *= -1;
}
if(ball_y < 0) {
ball_speed_y *= -1;
}
if(ball_y > canvas.height) {
ball_speed_y *= -1;
}
canvasContext.fillStyle = 'white';
canvasContext.beginPath();
canvasContext.arc(ball_x, ball_y, 10, 0, Math.PI * 2);
canvasContext.fill();
}
執行後會看到上面畫面,球在碰觸邊界後會反彈,只是有一個問題,因為球碰觸邊界的判斷我們是以球心作為判斷依據,這樣讓球在碰壁時,看起來會先埋一半在邊界外才反彈,我不太喜歡這樣的視覺效果,來做個小修改.先把球的半徑也以參數表示ball_r
,在考量碰觸邊界時的距離也把球的半徑考量在內,如下程式,就可以解決這問題.
<script>
var canvas, canvasContext;
//球的參數
var ball_x = 300;
var ball_y = 300;
var ball_r = 10;
var ball_speed_x = 5;
var ball_speed_y = 5;
window.onload = () => {
canvas = document.getElementById('playground');
canvasContext = canvas.getContext('2d');
//一秒更新幾次畫面
var timesPerSec = 30;
setInterval(drawAll, 1000/timesPerSec);
}
// 負責繪製畫面
drawAll = () => {
// background
canvasContext.fillStyle = 'black';
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
ball_x += ball_speed_x;
ball_y += ball_speed_y;
// 碰觸邊界動作
if(ball_x < (0 + ball_r)) {
ball_speed_x *= -1;
}
if(ball_x > (canvas.width - ball_r)) {
ball_speed_x *= -1;
}
if(ball_y < (0 + ball_r)) {
ball_speed_y *= -1;
}
if(ball_y > (canvas.height - ball_r)) {
ball_speed_y *= -1;
}
canvasContext.fillStyle = 'white';
canvasContext.beginPath();
canvasContext.arc(ball_x, ball_y, ball_r, 0, Math.PI * 2);
canvasContext.fill();
}
</script>
到了這邊,我們完成了球的移動還有反彈,目前只寫了球跟邊界的互動,drawall就已經不少行了,可以預見如果我們用這方法寫下去,加入玩家操作的橫版以及磚塊後,程式碼一定超級長,這樣會導致除錯不易.趁問題更大之前,先來拆解我們的程式吧!!
我們把drawall拆為兩部分:畫圖的都放到draw,處理移動的都放到move.
修改完成後就完成了今天的內容,處理球碰觸邊界的反彈,還有為了後續容易修改程式或除錯,進行分割.
以下附上完整程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<title>First Game</title>
<meta name="description" content="第一個遊戲">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<canvas id="playground" width="800" height="630"></canvas>
<script>
var canvas, canvasContext;
//球的參數
var ball_x = 300;
var ball_y = 300;
var ball_r = 10;
var ball_speed_x = 5;
var ball_speed_y = 5;
window.onload = () => {
canvas = document.getElementById('playground');
canvasContext = canvas.getContext('2d');
//一秒更新幾次畫面
var timesPerSec = 30;
setInterval(drawAll, 1000 / timesPerSec);
}
// 負責更新畫面
drawAll = () => {
move();
draw();
}
// 負責畫畫
draw = () => {
// background
canvasContext.fillStyle = 'black';
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
// 畫球
canvasContext.fillStyle = 'white';
canvasContext.beginPath();
canvasContext.arc(ball_x, ball_y, ball_r, 0, Math.PI * 2);
canvasContext.fill();
}
// 負責處理動作
move = () => {
ball_x += ball_speed_x;
ball_y += ball_speed_y;
// 碰觸邊界動作
if (ball_x < (0 + ball_r)) {
ball_speed_x *= -1;
}
if (ball_x > (canvas.width - ball_r)) {
ball_speed_x *= -1;
}
if (ball_y < (0 + ball_r)) {
ball_speed_y *= -1;
}
if (ball_y > (canvas.height - ball_r)) {
ball_speed_y *= -1;
}
}
</script>
</body>
</html>