前言
彈球消磚塊游戲想必大家都玩過,很簡單的小游戲,通過移動擋板反彈下落的小球,然后撞擊磚塊將其消除。本文使用QML來簡單實現這個小游戲。
效果圖:
正文
代碼目錄結構如下:
首先是小球部分,邏輯比較麻煩一點,需要檢查與磚塊的碰撞以及與擋板的碰撞,還要更新小球的軌跡位置,代碼如下:
Ball.qml
import QtQuick 2.12Rectangle {id: ballwidth: 15height: 15radius: width / 2color: "#FFFFFF"border.color: "#DDDDDD"border.width: 1// 引用游戲區域和擋板property var gameAreaproperty var paddle// 球的速度和方向property real speedX: 0property real speedY: 0property real baseSpeed: 3// 信號:球丟失signal ballLost()// 重置球的位置和狀態function reset() {x = gameArea.width / 2 - width / 2;y = gameArea.height / 2;speedX = 0;speedY = 0;}// 開始移動球function start() {if (speedX === 0 && speedY === 0) {// 隨機初始方向,但確保向下var angle = (Math.random() * Math.PI / 2) + Math.PI / 4; // 45-135度之間speedX = Math.cos(angle) * baseSpeed;speedY = Math.sin(angle) * baseSpeed;}}// 檢查與磚塊的碰撞function checkBrickCollision() {for (var i = 0; i < gameArea.bricksRepeater.count; i++) {var brick = gameArea.bricksRepeater.itemAt(i);if (brick && !brick.destroyed) {var brickPos = brick.mapToItem(gameArea, 0, 0);if (x + width > brickPos.x && x < brickPos.x + brick.width &&y + height > brickPos.y && y < brickPos.y + brick.height) {// 確定碰撞方向并反彈var centerX = x + width / 2;var centerY = y + height / 2;var brickCenterX = brickPos.x + brick.width / 2;var brickCenterY = brickPos.y + brick.height / 2;var dx = centerX - brickCenterX;var dy = centerY - brickCenterY;if (Math.abs(dx / brick.width) > Math.abs(dy / brick.height)) {// 水平碰撞speedX = -speedX;} else {// 垂直碰撞speedY = -speedY;}// 擊中磚塊,立即消除當前碰撞的磚塊brick.hit();return true;}}}return false;}// 檢查與擋板的碰撞function checkPaddleCollision() {if (y + height >= paddle.y && y <= paddle.y + paddle.height &&x + width >= paddle.x && x <= paddle.x + paddle.width) {// 根據擊中擋板的位置調整反彈角度var paddleCenter = paddle.x + paddle.width / 2;var ballCenter = x + width / 2;var relativePosition = (ballCenter - paddleCenter) / (paddle.width / 2);// 計算新的速度向量var angle = relativePosition * (Math.PI / 3); // 最大±60度var speed = Math.sqrt(speedX * speedX + speedY * speedY);speedX = Math.sin(angle) * speed;speedY = -Math.abs(Math.cos(angle) * speed); // 確保向上反彈// 稍微增加速度speedX *= 1.05;speedY *= 1.05;return true;}return false;}// 更新球的位置Timer {interval: 16 // 約60fpsrunning: gameArea.gameRunningrepeat: trueonTriggered: {// 移動球x += speedX;y += speedY;// 檢查墻壁碰撞if (x <= 0 || x + width >= gameArea.width) {speedX = -speedX;x = Math.max(0, Math.min(x, gameArea.width - width));}if (y <= 0) {speedY = -speedY;y = 0;}// 檢查是否掉落if (y + height >= gameArea.height - 20 && !checkPaddleCollision()) {ballLost();return;}// 檢查磚塊碰撞checkBrickCollision();// 檢查擋板碰撞checkPaddleCollision();}}
}
其次是磚塊 Brick.qml
import QtQuick 2.12Rectangle {id: brickradius: 3// 磚塊狀態property bool destroyed: falseproperty int colorIndex: 0// 磚塊顏色數組readonly property var colors: ["#FF5252", // 紅色"#FFAB40", // 橙色"#FFEB3B", // 黃色"#66BB6A", // 綠色"#42A5F5" // 藍色]// 磚塊被銷毀的信號signal brickDestroyed()// 設置磚塊顏色color: colors[colorIndex % colors.length]border.color: Qt.darker(color, 1.2)border.width: 1visible: !destroyed// 磚塊被擊中function hit() {if (!destroyed) {destroyed = true;visible = false;brickDestroyed();}}
}
磚塊擊中后要銷毀。
接著是擋板 Paddle.qml, 擋板可以通過鍵盤左右鍵進行移動,也可以直接使用鼠標進行左右拖動,代碼如下:
import QtQuick 2.12Rectangle {id: paddlewidth: 120height: 20radius: 10color: "#2196F3"border.color: "#1976D2"border.width: 1Component.onCompleted: {// 初始化時設置擋板居中x = (gameArea.width - width) / 2}// 引用游戲區域property var gameArea// 移動速度property int speed: 15property bool movingLeft: falseproperty bool movingRight: false// 處理鍵盤按下事件function handleKeyPress(key) {if (key === Qt.Key_Left) {movingLeft = true;} else if (key === Qt.Key_Right) {movingRight = true;}}// 處理鍵盤釋放事件function handleKeyRelease(key) {if (key === Qt.Key_Left) {movingLeft = false;} else if (key === Qt.Key_Right) {movingRight = false;}}// 鼠標控制MouseArea {anchors.fill: parentdrag.target: parentdrag.axis: Drag.XAxisdrag.minimumX: 0drag.maximumX: gameArea.width - parent.width}// 定時器更新擋板位置Timer {interval: 16 // 約60fpsrunning: (movingLeft || movingRight) && gameArea.gameRunningrepeat: trueonTriggered: {if (movingLeft) {paddle.x = Math.max(0, paddle.x - speed);}if (movingRight) {paddle.x = Math.min(gameArea.width - paddle.width, paddle.x + speed);}}}
}
以上是核心控件的完整代碼。
本文Demo下載