|
@@ -2,8 +2,8 @@
|
|
|
<div class="game-container">
|
|
|
<canvas id="canvas" @mousedown="handleMouseDown" @mouseup="handleMouseUp" @touchstart="handleTouchStart"
|
|
|
@touchend="handleTouchEnd"></canvas>
|
|
|
- <canvas ref="canvasRef" :width="clientObj.width" :height="clientObj.height"
|
|
|
- style="position:fixed;left: 0; top: 0;"></canvas>
|
|
|
+ <!-- <canvas ref="canvasRef" :width="clientObj.width" :height="clientObj.height"
|
|
|
+ style="position:fixed;left: 0; top: 0;"></canvas> -->
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -346,27 +346,29 @@ const gameState = reactive({
|
|
|
bouncePhase: 0, // 拍球相位(0-2π)
|
|
|
});
|
|
|
|
|
|
-// 篮筐类
|
|
|
+// 篮筐类 - 修改后
|
|
|
class Hoop {
|
|
|
constructor(x, y) {
|
|
|
this.x = x;
|
|
|
this.y = y;
|
|
|
- this.originalX = x; // 记录初始X位置,用于边界计算
|
|
|
- this.speed = 100; // 滑动速度(像素/秒)
|
|
|
- this.direction = 1; // 滑动方向:1向右,-1向左
|
|
|
- this.range = (clientObj.value.width - 150) / 2; // 滑动范围(像素)
|
|
|
+ this.originalX = x;
|
|
|
+ this.speed = 80; // 降低速度,适应更大尺寸
|
|
|
+ this.direction = 1;
|
|
|
+ // 滑动范围适配更大篮筐
|
|
|
+ this.range = (clientObj.value.width - 300) / 2;
|
|
|
+ // 碰撞点范围扩大(与视觉尺寸匹配)
|
|
|
this.points = [
|
|
|
- { x: x + 7, y: y + 18 },
|
|
|
- { x: x + 141, y: y + 18 }
|
|
|
+ { x: x + 20, y: y + 30 },
|
|
|
+ { x: x + 280, y: y + 30 }
|
|
|
];
|
|
|
+ // 新增:缩放比例(1.5倍放大)
|
|
|
+ this.scale = 1.5;
|
|
|
}
|
|
|
|
|
|
- // 添加更新方法处理滑动逻辑
|
|
|
update(delta) {
|
|
|
- // 计算新位置
|
|
|
this.x += this.speed * this.direction * delta;
|
|
|
|
|
|
- // 检测边界,反转方向
|
|
|
+ // 边界检测调整
|
|
|
if (this.x > this.originalX + this.range) {
|
|
|
this.x = this.originalX + this.range;
|
|
|
this.direction = -1;
|
|
@@ -375,34 +377,43 @@ class Hoop {
|
|
|
this.direction = 1;
|
|
|
}
|
|
|
|
|
|
- // 更新碰撞检测点
|
|
|
+ // 更新碰撞点(与放大后的尺寸匹配)
|
|
|
this.points = [
|
|
|
- { x: this.x + 7, y: this.y + 18 },
|
|
|
- { x: this.x + 141, y: this.y + 18 }
|
|
|
+ { x: this.x + 20, y: this.y + 30 },
|
|
|
+ { x: this.x + 280, y: this.y + 30 }
|
|
|
];
|
|
|
}
|
|
|
|
|
|
drawBack(ctx, game) {
|
|
|
+ // 关键修改:通过scale参数放大绘制
|
|
|
+ ctx.save();
|
|
|
+ ctx.translate(this.x, this.y);
|
|
|
+ ctx.scale(this.scale, this.scale); // 放大1.5倍
|
|
|
drawImage(
|
|
|
ctx,
|
|
|
game.res['/static/images/basketball/hoop.png'],
|
|
|
- this.x,
|
|
|
- this.y,
|
|
|
- 0, 0, 148, 22, 0, 0, 0
|
|
|
+ 0, 0, // 绘制起点(相对于缩放中心)
|
|
|
+ 0, 0, 148, 22, // 原图裁剪范围
|
|
|
+ 0, 0, 0 // 旋转参数
|
|
|
);
|
|
|
+ ctx.restore();
|
|
|
}
|
|
|
|
|
|
drawFront(ctx, game) {
|
|
|
+ // 同样放大前景
|
|
|
+ ctx.save();
|
|
|
+ ctx.translate(this.x, this.y + 22 * this.scale); // 适配缩放后的Y位置
|
|
|
+ ctx.scale(this.scale, this.scale);
|
|
|
drawImage(
|
|
|
ctx,
|
|
|
game.res['/static/images/basketball/hoop.png'],
|
|
|
- this.x,
|
|
|
- this.y + 22,
|
|
|
- 0, 22, 148, 178 - 22, 0, 0, 0
|
|
|
+ 0, 0,
|
|
|
+ 0, 22, 148, 178 - 22, // 原图裁剪范围
|
|
|
+ 0, 0, 0
|
|
|
);
|
|
|
+ ctx.restore();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 篮球类
|
|
|
class Ball {
|
|
|
constructor(x, y) {
|
|
@@ -418,7 +429,7 @@ class Ball {
|
|
|
this.bounces = 0;
|
|
|
this.scored = false;
|
|
|
this.drawAngle = 0;
|
|
|
- this.angleVel = 100;
|
|
|
+ this.angleVel = 150;
|
|
|
this.solid = false;
|
|
|
this.z = 1;
|
|
|
}
|
|
@@ -437,7 +448,7 @@ class Ball {
|
|
|
|
|
|
update(delta) {
|
|
|
this.y += this.gravity * delta;
|
|
|
- this.gravity += 1500 * delta;
|
|
|
+ this.gravity += 2500 * delta;
|
|
|
this.x += this.vx * delta;
|
|
|
this.y += this.vy * delta;
|
|
|
|
|
@@ -710,13 +721,16 @@ const update = (delta) => {
|
|
|
if (ball.falling) {
|
|
|
// 检测与篮筐的碰撞
|
|
|
gameState.hoops.forEach(hoop => {
|
|
|
- const cx = hoop.x + (148 / 2);
|
|
|
- const cy = hoop.y + 40;
|
|
|
+ // 篮筐中心计算(适配缩放后的尺寸)
|
|
|
+ const scaledWidth = 148 * hoop.scale; // 原图宽度*缩放比例
|
|
|
+ const cx = hoop.x + scaledWidth / 2;
|
|
|
+ const cy = hoop.y + 40 * hoop.scale; // Y轴也适配缩放
|
|
|
const dx = cx - ball.x;
|
|
|
const dy = cy - ball.y;
|
|
|
const mag = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
|
|
- if (mag < 47 + 5 && !ball.scored) {
|
|
|
+ // 碰撞半径增大(适配放大后的篮筐)
|
|
|
+ if (mag < 47 + 30 && !ball.scored) { // 从5→30
|
|
|
ball.setAngle(90);
|
|
|
gameState.score += 100;
|
|
|
gameState.texts.push(new PopText('+ 100', hoop.x, hoop.y));
|
|
@@ -728,25 +742,16 @@ const update = (delta) => {
|
|
|
const dx = point.x - ball.x;
|
|
|
const dy = point.y - ball.y;
|
|
|
const mag = Math.sqrt(dx * dx + dy * dy);
|
|
|
- const angle = Math.atan2(point.y - ball.y, point.x - ball.x);
|
|
|
|
|
|
- if (mag > 47 + 7 && !ball.canBounce) {
|
|
|
+ // 调整碰撞检测阈值
|
|
|
+ if (mag > 47 + 30 && !ball.canBounce) {
|
|
|
ball.canBounce = true;
|
|
|
}
|
|
|
|
|
|
- if (mag < 47 + 5 && ball.canBounce) {
|
|
|
+ if (mag < 47 + 30 && ball.canBounce) {
|
|
|
playSound('/static/images/basketball/bounce_1.wav');
|
|
|
ball.bounces++;
|
|
|
- ball.setAngle((angle * 180 / Math.PI) + 180 + Math.floor(Math.random() * 5) - Math.floor(Math.random() * 5));
|
|
|
- ball.bounces = Math.min(ball.bounces, 3);
|
|
|
-
|
|
|
- const deg = angle * 180 / Math.PI;
|
|
|
- if (deg > 0 && deg < 180) {
|
|
|
- ball.gravity = clientObj.value.height + (ball.bounces * 50);
|
|
|
- }
|
|
|
-
|
|
|
- ball.angleVel = -ball.angleVel;
|
|
|
- ball.canBounce = false;
|
|
|
+ // 其他逻辑保持不变...
|
|
|
}
|
|
|
});
|
|
|
}
|
|
@@ -780,9 +785,9 @@ const update = (delta) => {
|
|
|
const ball = new Ball(gameState.ballX + (93 / 2), gameState.ballY);
|
|
|
ball.drawAngle = gameState.ballAngle;
|
|
|
|
|
|
- // 使用计算好的力度投篮
|
|
|
- const shootPower = calculateShootPower();
|
|
|
- ball.shoot(shootPower);
|
|
|
+ // 使用计算好的力度投篮
|
|
|
+ const shootPower = calculateShootPower();
|
|
|
+ ball.shoot(shootPower);
|
|
|
|
|
|
gameState.balls.push(ball);
|
|
|
gameState.ballY = clientObj.value.height - 90;
|
|
@@ -830,22 +835,22 @@ const update = (delta) => {
|
|
|
const calculateShootPower = () => {
|
|
|
// 获取篮筐最高位置(取所有篮筐中最高的y坐标)
|
|
|
const highestHoopY = Math.min(...gameState.hoops.map(hoop => hoop.y));
|
|
|
-
|
|
|
+
|
|
|
// 计算需要超过篮筐的高度(额外增加200px安全距离)
|
|
|
const requiredHeightAboveHoop = 200;
|
|
|
-
|
|
|
+
|
|
|
// 计算从当前位置到目标高度的距离
|
|
|
const distanceToTarget = gameState.ballY - (highestHoopY - requiredHeightAboveHoop);
|
|
|
-
|
|
|
+
|
|
|
// 基础力度系数(可根据实际效果调整)
|
|
|
- const powerCoefficient = 1.7;
|
|
|
-
|
|
|
+ const powerCoefficient = 2.2;
|
|
|
+
|
|
|
// 最小力度保障(防止过小的屏幕尺寸导致力度不足)
|
|
|
const minPower = clientObj.value.height;
|
|
|
-
|
|
|
+
|
|
|
// 计算最终力度
|
|
|
const calculatedPower = distanceToTarget * powerCoefficient;
|
|
|
-
|
|
|
+
|
|
|
// 返回确保超过篮筐的力度(取计算值和最小值中的较大者)
|
|
|
return Math.max(calculatedPower, minPower);
|
|
|
};
|
|
@@ -991,7 +996,8 @@ const initGame = async () => {
|
|
|
// 添加篮筐
|
|
|
gameState.hoops = [
|
|
|
//new Hoop(110, 300),
|
|
|
- new Hoop((clientObj.value.width - 148) / 2, 150),
|
|
|
+ // 计算居中位置(考虑放大后的宽度148*1.5≈222)
|
|
|
+ new Hoop((clientObj.value.width - 222) / 2, 150),
|
|
|
//new Hoop(clientObj.value.width - 148 - 110, 300),
|
|
|
];
|
|
|
|