You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular Pong游戏Canvas等比例响应式问题:高度适配及vmin新问题

Angular Canvas 等比例响应式适配方案(Pong游戏场景)

问题核心

Canvas的实际像素尺寸(width/height属性)和CSS显示尺寸是两个独立概念,单纯调整CSS单位容易出现比例失衡或适配异常。以下是针对你的Pong游戏场景的完整解决方案:


1. 调整HTML结构与基础样式

先重构外层容器,用Flex布局实现Canvas居中,并通过内边距/最大尺寸控制整体占比:

<div class="canvas-wrapper">
  <canvas #canvasContainer id="canvas-container" width="950" height="525"></canvas>
</div>

组件CSS样式:

.canvas-wrapper {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 15%; /* 对应原需求的70%可视占比,100%-15%-15%=70% */
  box-sizing: border-box;
  background-color: #000; /* 可选:游戏背景色 */
}

#canvas-container {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain; /* 核心:强制保持Canvas原始比例,避免拉伸 */
}

2. Angular组件逻辑适配(处理绘制缩放)

由于游戏绘制依赖Canvas像素坐标,需监听窗口resize事件计算缩放比例,让绘制逻辑沿用原始尺寸,自动适配显示:

import { Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';

@Component({
  selector: 'app-pong-game',
  templateUrl: './pong-game.component.html',
  styleUrls: ['./pong-game.component.css']
})
export class PongGameComponent implements OnInit {
  @ViewChild('canvasContainer') canvasRef!: ElementRef<HTMLCanvasElement>;
  private ctx!: CanvasRenderingContext2D;
  private originalWidth = 950;
  private originalHeight = 525;
  private scale = 1;

  ngOnInit(): void {
    this.ctx = this.canvasRef.nativeElement.getContext('2d')!;
    this.updateScale();
    this.startGameLoop(); // 启动游戏动画循环
  }

  @HostListener('window:resize')
  onWindowResize(): void {
    this.updateScale();
  }

  private updateScale(): void {
    const canvas = this.canvasRef.nativeElement;
    const wrapper = canvas.parentElement!;
    // 计算容器内可容纳的最大缩放比例,优先匹配宽高中的较小值
    const widthRatio = wrapper.clientWidth / this.originalWidth;
    const heightRatio = wrapper.clientHeight / this.originalHeight;
    this.scale = Math.min(widthRatio, heightRatio);
  }

  private startGameLoop(): void {
    requestAnimationFrame(() => this.gameLoop());
  }

  private gameLoop(): void {
    const canvas = this.canvasRef.nativeElement;
    // 清空画布
    this.ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 应用缩放:绘制时沿用原始坐标,自动适配显示尺寸
    this.ctx.save();
    this.ctx.scale(this.scale, this.scale);
    
    // --- 此处写入你的游戏绘制逻辑(示例)---
    // 左侧球拍
    this.ctx.fillStyle = 'white';
    this.ctx.fillRect(20, 200, 10, 125);
    // 右侧球拍
    this.ctx.fillRect(920, 200, 10, 125);
    // 球
    this.ctx.beginPath();
    this.ctx.arc(475, 262.5, 8, 0, Math.PI * 2);
    this.ctx.fill();
    
    this.ctx.restore();
    requestAnimationFrame(() => this.gameLoop());
  }
}

关键说明

  • 外层容器用100vw/100vh确保占满视口,Flex布局实现Canvas居中,padding控制整体可视占比;
  • object-fit: contain强制Canvas保持950:525的原始比例,无论窗口宽高如何变化都不会拉伸变形;
  • 通过scale变量统一处理绘制缩放,游戏逻辑无需修改原始坐标,自动适配所有窗口尺寸;
  • 若使用requestAnimationFrame实现动画,无需在resize时手动重绘,循环会自动更新画面。

内容的提问来源于stack exchange,提问作者user12356071

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:16:02