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

Canvas JavaScript:带方向指向的三角形Jack键盘移动功能实现求助

实现带方向控制的Canvas角色Jack

嘿,作为HTML和JavaScript初学者,这个Canvas小项目真的很适合入门!我给你写了完整的实现代码,每部分都加了注释,方便你一步步理解~

完整实现代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Jack the Triangle</title>
    <style>
        canvas {
            border: 2px solid #333;
            background-color: #f0f0f0;
        }
        button {
            margin-top: 10px;
            padding: 8px 16px;
            font-size: 16px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="400" height="400"></canvas>
    <button id="resetBtn">重置Jack到中心</button>

    <script>
        // 获取Canvas和上下文
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');

        // Jack的属性
        let jack = {
            x: canvas.width / 2,
            y: canvas.height / 2,
            size: 40, // 身体三角形的边长
            direction: 'up', // 默认朝上
            speed: 5 // 移动速度
        };

        // 绘制Jack的函数
        function drawJack() {
            // 清空画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // 保存当前画布状态(避免旋转影响其他绘制)
            ctx.save();

            // 把画布原点移到Jack的位置,方便旋转
            ctx.translate(jack.x, jack.y);

            // 根据方向旋转画布
            switch(jack.direction) {
                case 'up':
                    ctx.rotate(0);
                    break;
                case 'right':
                    ctx.rotate(Math.PI / 2);
                    break;
                case 'down':
                    ctx.rotate(Math.PI);
                    break;
                case 'left':
                    ctx.rotate(-Math.PI / 2);
                    break;
            }

            // 绘制身体(大三角形)
            ctx.beginPath();
            ctx.moveTo(0, -jack.size/2); // 顶部(鼻子方向)
            ctx.lineTo(-jack.size/2, jack.size/2); // 左下
            ctx.lineTo(jack.size/2, jack.size/2); // 右下
            ctx.closePath();
            ctx.fillStyle = '#8B4513'; // 棕色身体
            ctx.fill();

            // 绘制红色鼻子(小三角形)
            ctx.beginPath();
            ctx.moveTo(0, -jack.size/2); // 和身体顶部重合
            ctx.lineTo(-jack.size/8, -jack.size/4);
            ctx.lineTo(jack.size/8, -jack.size/4);
            ctx.closePath();
            ctx.fillStyle = '#FF0000';
            ctx.fill();

            // 绘制眼睛(两个圆形)
            ctx.beginPath();
            ctx.arc(-jack.size/6, -jack.size/6, jack.size/12, 0, Math.PI*2);
            ctx.arc(jack.size/6, -jack.size/6, jack.size/12, 0, Math.PI*2);
            ctx.fillStyle = '#FFFFFF';
            ctx.fill();
            // 瞳孔
            ctx.beginPath();
            ctx.arc(-jack.size/6, -jack.size/6, jack.size/24, 0, Math.PI*2);
            ctx.arc(jack.size/6, -jack.size/6, jack.size/24, 0, Math.PI*2);
            ctx.fillStyle = '#000000';
            ctx.fill();

            // 恢复画布原始状态
            ctx.restore();
        }

        // 键盘控制移动
        document.addEventListener('keydown', (e) => {
            switch(e.key) {
                case 'ArrowUp':
                    jack.y -= jack.speed;
                    jack.direction = 'up';
                    break;
                case 'ArrowRight':
                    jack.x += jack.speed;
                    jack.direction = 'right';
                    break;
                case 'ArrowDown':
                    jack.y += jack.speed;
                    jack.direction = 'down';
                    break;
                case 'ArrowLeft':
                    jack.x -= jack.speed;
                    jack.direction = 'left';
                    break;
            }
            // 重新绘制Jack
            drawJack();
        });

        // 重置按钮功能
        document.getElementById('resetBtn').addEventListener('click', () => {
            jack.x = canvas.width / 2;
            jack.y = canvas.height / 2;
            jack.direction = 'up';
            drawJack();
        });

        // 初始绘制Jack
        drawJack();
    </script>
</body>
</html>

功能拆解

  • 绘制Jack角色:

    • 用ctx.beginPath()和lineTo()绘制棕色大三角形作为身体,红色小三角形作为鼻子,嵌套白色+黑色圆形实现眼睛效果
    • 利用ctx.save()和ctx.restore()管理画布状态,避免旋转操作影响后续绘制
  • 键盘方向控制:

    • 监听keydown事件,根据方向键修改Jack的坐标位置,同时更新当前方向
    • 通过ctx.translate()将画布原点移到Jack中心,再根据方向旋转画布,让鼻子始终指向移动方向
  • 重置按钮功能:

    • 给按钮绑定点击事件,将Jack的坐标重置为画布中心,方向设为默认朝上,然后重新绘制

关于未表述的特殊功能

你提到还有一处特殊功能没表述完整,比如可以扩展这些方向:

  • 碰撞边界检测:不让Jack移出画布范围
  • 移动动画:添加脚步或身体晃动的效果
  • 交互功能:点击画布让Jack移动到点击位置
  • 状态变化:比如按空格键让Jack变色或做出表情

如果之后补充具体需求,我可以帮你进一步完善这部分功能~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:25:54