ChatGPT助力游戲創(chuàng)作:從零開始開發(fā)一個(gè)五子棋網(wǎng)頁小游戲
前言
今天和大家分享一些關(guān)于如何利用 ChatGPT 輔助游戲創(chuàng)作的想法。隨著人工智能技術(shù)的不斷發(fā)展,ChatGPT 的出現(xiàn)為游戲創(chuàng)作帶來了新的可能性。它可以幫助我們更快地生成游戲角色、場景和劇情,讓游戲開發(fā)變得更加高效和有趣。接下來,讓我們一起探索如何利用 ChatGPT 來輔助游戲創(chuàng)作吧!
游戲規(guī)則
這個(gè)完全可以交給 ChatGPT 完成。
五子棋是一種雙人對弈的棋類游戲,游戲規(guī)則如下:
棋盤為 15 行 15 列,黑方先行。
每個(gè)玩家輪流在棋盤上下棋子,黑方用黑色棋子,白方用白色棋子。
棋子下在空白的交叉點(diǎn)上,每個(gè)交叉點(diǎn)只能下一枚棋子。
玩家的目標(biāo)是在棋盤上形成五個(gè)同色棋子連成一條線(橫、豎、斜線均可)。
如果一方玩家在棋盤上形成了五個(gè)同色棋子連成一條線,則該玩家獲勝。
如果棋盤上所有的交叉點(diǎn)都下滿了棋子,但沒有任何一方玩家形成五個(gè)同色棋子連成一條線,則游戲結(jié)束,雙方平局。
游戲思路
如果你不知道怎么設(shè)計(jì)游戲,沒關(guān)系,交給 ChatGPT 完成。
給 ChatGPT 發(fā)送指令,讓它提供游戲的設(shè)計(jì)思路,內(nèi)容如下:
棋盤的繪制 首先需要繪制一個(gè)棋盤??梢允褂?HTML 的 canvas 標(biāo)簽來實(shí)現(xiàn)??梢栽O(shè)置棋盤大小、背景顏色、線條顏色等等。
棋子的放置 當(dāng)用戶點(diǎn)擊棋盤時(shí),需要判斷當(dāng)前這個(gè)位置是否已經(jīng)有了棋子。如果沒有,則根據(jù)當(dāng)前玩家的角色(黑子或白子),在這個(gè)位置上繪制一個(gè)棋子。
判斷輸贏 在每次棋子放置后,需要判斷當(dāng)前玩家是否獲勝??梢詮漠?dāng)前放置的棋子開始,向上下左右、斜著兩個(gè)方向檢查是否有連續(xù)五個(gè)相同顏色的棋子。如果有,則當(dāng)前玩家獲勝。
切換玩家 每次棋子放置后,需要切換當(dāng)前玩家的角色(黑子或白子)。
悔棋功能 如果用戶誤操作或者想要重新開始游戲,可以提供悔棋功能??梢杂涗浵滤衅遄拥穆潼c(diǎn),當(dāng)用戶點(diǎn)擊悔棋按鈕時(shí),回退到上一步棋的狀態(tài)。
重新開始 當(dāng)游戲結(jié)束后,可以提供重新開始游戲的按鈕,回到初始狀態(tài)。
有了以上游戲思路,我們就可以讓 ChatGPT 幫助我們一步步來實(shí)現(xiàn)完整的游戲。
界面設(shè)計(jì)
繪制棋盤
我們給 ChatGPT 發(fā)送指令,讓它繪制一個(gè) 15x15 的五子棋棋盤,輸出代碼如下:
<script>
? ?var canvas = document.getElementById("chessboard");
? ?var ctx = canvas.getContext("2d");
? ?// 設(shè)置棋盤顏色
? ?ctx.fillStyle = "#F9B87C";
? ?ctx.fillRect(0, 0, 750, 750);
? ?// 繪制棋盤線條
? ?ctx.strokeStyle = "#000";
? ?ctx.lineWidth = 1;
? ?for (var i = 0; i < 15; i++) {
? ? ? ?ctx.beginPath();
? ? ? ?ctx.moveTo(50 + i * 50, 50);
? ? ? ?ctx.lineTo(50 + i * 50, 700);
? ? ? ?ctx.stroke();
? ? ? ?ctx.beginPath();
? ? ? ?ctx.moveTo(50, 50 + i * 50);
? ? ? ?ctx.lineTo(700, 50 + i * 50);
? ? ? ?ctx.stroke();
? ?}
? ?// 繪制棋盤上的點(diǎn)
? ?ctx.fillStyle = "#000";
? ?for (var i = 0; i < 3; i++) {
? ? ? ?for (var j = 0; j < 3; j++) {
? ? ? ? ? ?ctx.beginPath();
? ? ? ? ? ?ctx.arc(200 + i * 300, 200 + j * 300, 5, 0, 2 * Math.PI);
? ? ? ? ? ?ctx.fill();
? ? ? ?}
? ?}
? ?ctx.beginPath();
? ?ctx.arc(350, 350, 5, 0, 2 * Math.PI);
? ?ctx.fill();
</script>
繪制棋子
我們給 ChatGPT 發(fā)送指令,讓它寫一個(gè)繪制棋子的函數(shù),輸出代碼如下:
function drawPiece(x, y, color) {
? ?ctx.beginPath();
? ?ctx.arc(x * gridSize, y * gridSize, pieceSize, 0, 2 * Math.PI);
? ?if (color === BLACK) {
? ? ctx.fillStyle = "#000";
? ?} else {
? ? ctx.fillStyle = "#fff";
? ?}
? ?ctx.fill();
}
其中,ctx是canvas上下文對象;gridSize是網(wǎng)格大?。籶ieceSize是棋子半徑大??;BLACK和WHITE分別表示黑色和白色棋子的常量。
代碼實(shí)現(xiàn)
初始化棋盤
初始化棋盤的代碼如下:
var chess = []; // 存儲(chǔ)棋盤狀態(tài)的二維數(shù)組,0表示空位,1表示黑子,2表示白子
// 初始化棋盤數(shù)組
for (var i = 0; i < 15; i++) {
?chess[i] = [];
?for (var j = 0; j < 15; j++) {
? ?chess[i][j] = 0;
?}
}
玩家下棋
放置棋子的代碼如下:
function playChess(x, y) {
? ?// 檢查是否可以下棋
? ?if (!canPlay) {
? ? return;
? ?}
? ?// 檢查該位置是否已經(jīng)下過棋
? ?if (board[x][y] !== 0) {
? ? return;
? ?}
? ?// 下棋
? ?board[x][y] = player;
? ?drawChess(x, y);
? ?// 檢查勝負(fù)
? ?var result = checkWin(x, y);
? ?if (result) {
? ? alert(player === 1 ? "黑方勝利!" : "白方勝利!");
? ? canPlay = false;
? ? return;
? ?}
? ?// 切換玩家
? ?player = player === 1 ? 2 : 1;
}
鼠標(biāo)事件
玩家下棋時(shí)觸發(fā)鼠標(biāo)事件的代碼如下:
//獲取棋盤元素
const chessboard = document.getElementById('chessboard');
//監(jiān)聽鼠標(biāo)點(diǎn)擊事件
chessboard.addEventListener('click', function(event) {
? ?//獲取點(diǎn)擊位置的坐標(biāo)
? ?const x = event.offsetX;
? ?const y = event.offsetY;
? ?//將坐標(biāo)轉(zhuǎn)換為棋盤上格子的行列數(shù)
? ?//將floor改成round,離交叉線最近的哪個(gè)落子點(diǎn)
? ?//CELL_SIZE指一個(gè)格子的像素大小
? ?const row = Math.round(y / CELL_SIZE);
? ?const col = Math.round(x / CELL_SIZE);
? ?//玩家落子
? ?playChess(row, col);
});
判斷輸贏
讓 ChatGPT 寫一個(gè)判斷勝負(fù)的函數(shù),代碼如下:
function checkWin(row, col, player, board) {
? ?let directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]];
? ?for (let i = 0; i < directions.length; i++) {
? ? ? ?let count = 0;
? ? ? ?let d = directions[i];
? ? ? ?let r = row + d[0];
? ? ? ?let c = col + d[1];
? ? ? ?while (r >= 0 && c >= 0 && r < board.length && c < board[0].length && board[r][c] === player) {
? ? ? ? ? ?count++;
? ? ? ? ? ?r += d[0];
? ? ? ? ? ?c += d[1];
? ? ? ? ? ?if (count >= 5) {
? ? ? ? ? ? return true;
? ? ? ? }
? ? }
? ?}
? ?return false;
}
//調(diào)用方法
if (checkWin(row, col, player, board)) {
console.log("player " + player + " wins!");
} else {
console.log("keep playing");
}
說明:
該函數(shù)接受四個(gè)參數(shù):row表示當(dāng)前下子的行號(hào),col表示當(dāng)前下子的列號(hào),player表示當(dāng)前下子的玩家(1或2),board表示當(dāng)前棋盤狀態(tài)。
將八個(gè)方向分別用一個(gè)二元數(shù)組表示,并遍歷八個(gè)方向,分別檢查當(dāng)前位置下的子是否能夠和同色棋子連成五子相連,如果能,則返回true。
如果循環(huán)完八個(gè)方向都沒有返回true,則代表當(dāng)前局面下仍然沒有勝者,返回false。
電腦下棋
如果是2人對戰(zhàn),就很簡單,只需要切換玩家就可以。如果是人機(jī)對戰(zhàn),就要復(fù)雜很多。
我們?nèi)宰?ChatGPT 寫一個(gè)函數(shù),代碼如下:
function computerPlay() {
? ?var maxScore = 0;
? ?var bestMove = [];
? ?for (var i = 0; i < BOARD_SIZE; i++) {
? ? ? ?for (var j = 0; j < BOARD_SIZE; j++) {
? ? ? ? ? ?if (board[i][j] === EMPTY) {
? ? ? ? ? ? ? ?var score = getScore(i, j);
? ? ? ? ? ? ? ?if (score > maxScore) {
? ? ? ? ? ? ? ? ? ?maxScore = score;
? ? ? ? ? ? ? ? ? ?bestMove = [i, j];
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ?}
? ?}
? ?board[bestMove[0]][bestMove[1]] = COMPUTER;
? ?updateBoard();
? ?checkWin();
? ?currentPlayer = HUMAN;
}
這段代碼只是給出了電腦方下棋的邏輯,缺少 getScore()
函數(shù)的實(shí)現(xiàn)。而 getScore()
這個(gè)函數(shù)才是人機(jī)對戰(zhàn)的核心代碼。我試著讓它給我這個(gè)函數(shù)的代碼,以下是它的回答:
抱歉,無法給出具體代碼。因?yàn)槲遄悠逵螒螂娔X方下棋的實(shí)現(xiàn)方式有很多種,而其中用于評估每個(gè)空位得分的算法也有很多。需要根據(jù)具體的實(shí)現(xiàn)方式和算法來編寫對應(yīng)的getScore()函數(shù)。
這個(gè)算法的核心是計(jì)算每一個(gè)空位的得分,得分最大的即為最佳落子點(diǎn)。試了很多提問方式,最終還是沒有得到算法的代碼,只能放棄。然而實(shí)在不想動(dòng)手寫這個(gè)代碼,于是從 Github 找了一個(gè)算法來實(shí)現(xiàn)。
結(jié)束語
本篇我們分享了一個(gè)用 ChatGPT 輔助游戲創(chuàng)作的案例。從構(gòu)思到完成創(chuàng)作,并修改代碼使其在瀏覽器中運(yùn)行,整個(gè)過程大概半天時(shí)間。以下是我的一些使用心得:
ChatGPT 的代碼編寫能力確實(shí)非常強(qiáng)大,很多代碼基本無需改動(dòng)就能直接使用;
提問的方式很重要,提問時(shí)盡量給出明確的關(guān)鍵詞,提問越準(zhǔn)確就越能得到我們想要的結(jié)果;
ChatGPT給出的代碼并不是完全正確的,需要我們在運(yùn)行環(huán)境中調(diào)試及修改完善;
如果是開發(fā)網(wǎng)頁類小游戲,使用者應(yīng)有一定的 html,canvas、javascript 技術(shù)的基礎(chǔ)。
總之,ChatGPT 是一個(gè)非常強(qiáng)大的生成式 AI 工具,如果掌握了提問技巧,能極大的提高我們的工作效率。