如何在画布中调整精灵表帧的大小?

huangapple go评论61阅读模式
英文:

How can I adjust a sprite sheet frame size within a canvas?

问题

我有一个画布元素,我正在上面绘制小鸭子精灵表,让它从屏幕的右侧飞到左侧。我现在的代码实现了这个效果。但我怎么也想不明白如何扩大鸭子所在的帧,而不影响它的动画。

目前看起来鸭子被限制在一个小盒子里,就像这样 | |,所以你只能看到动画的一部分,远远不足以让你看到它在屏幕上持续飞行。每次我试图调整帧的宽度或大小,它只会使鸭子变得更大。

我知道片段无法工作,因为它无法加载资源,但你可以看到JS部分,希望这有所帮助!

感谢你们!

鸭子精灵表: 如何在画布中调整精灵表帧的大小?

$(document).ready(function () {
  // Variables for IDs - getContext to draw and clear canvas
  const canvas = $("#game-canvas")[0];
  const context = canvas.getContext("2d");
  const startButton = $("#start-button");

  const backgroundImage = new Image();
  backgroundImage.src = "https://opengameart.org/sites/default/files/duck_spritesheet.png";

  // Onload function to pull the background image of the game
  $(backgroundImage).on("load", function () {
    context.drawImage(backgroundImage, 0, 0);
  });

  // On click function to change the crosshair and pull in the duck image
  startButton.on("click", function () {
    const spriteSheet = new Image();
    spriteSheet.src = "https://opengameart.org/sites/default/files/duck_spritesheet.png";

    $("#game-canvas").on("mouseenter", function () {
      $(this).addClass("canvas-cursor");
    });

    $("#game-canvas").on("mouseleave", function () {
      $(this).removeClass("canvas-cursor");
    });

    $(spriteSheet).on("load", function () {
      const totalFrames = 4; // 精灵表中的帧总数
      const scale = 3; // 尝试缩放,但没有成功...
      const duckSpeed = 10; // 鸭子在画布上移动的速度

      // 任何一个乘以这些都对我没用
      const duckWidth = spriteSheet.width / totalFrames;
      const duckHeight = spriteSheet.height / totalFrames;
      const frameWidth = duckWidth;
      const frameHeight = duckHeight;

      const animationSpeed = 200; // 每帧的毫秒数

      let currentFrame = 0; // 当前动画的帧
      let duckX = canvas.width; // 鸭子在画布右侧的起始位置
      let duckY = canvas.height / 2 - (frameHeight * scale) / 2; // 垂直居中鸭子

      function animateDuck() {
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(backgroundImage, 0, 0);

        const frameX = (currentFrame % totalFrames) * frameWidth;
        const frameY = Math.floor(currentFrame / totalFrames) * frameHeight;

        // 绘制鸭子图像的当前帧
        context.drawImage(
          spriteSheet,
          frameX,
          frameY,
          frameWidth,
          frameHeight,
          duckX,
          duckY,
          frameWidth * scale,
          frameHeight * scale
        );

        // 当前帧
        currentFrame = (currentFrame + 1) % (totalFrames * totalFrames);

        // 鸭子的位置
        duckX -= duckSpeed;

        // 如果鸭子已经到达画布的左侧
        if (duckX + frameWidth * scale * 2 < 0) {
          duckX = canvas.width;
        }

        setTimeout(animateDuck, animationSpeed);
      }

      animateDuck();
    });
  });
});
body {
  background-color: #eee;
  text-align: center;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
}

h1 {
  color: #333;
}

#game-container {
  position: relative;
}

#game-canvas {
  display: block;
  margin: 0 auto;
  border: 1px solid black;
  background-color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<body>
    <div id="game-container">
        <canvas id="game-canvas" width="400" height="100"></canvas>
    </div>
    <button id="start-button">Start Game</button>
</body>
英文:

I have a canvas element and i'm drawing on this little duck sprite sheet to fly across from the right hand side of the screen to the left. The code i have right now achieves that. But i can't for the life of me figure out how to make the frame the duck is in, bigger, without messing with the animations of it.

Right now it appears that the duck is confined into a little sliver of a box like this | | so you only see bits and pieces of the animation, not nearly enough to see it consistently flying across the screen. Every time i try to adjust the width or frame, its just making the duck much larger.

I know the snippet doesn't work cuz it wont load in the assets but you can see the JS side of it so hopefully that helps!

Thank you guys

ducksprite sheet: 如何在画布中调整精灵表帧的大小?

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

$(document).ready(function () {
// Variables for IDs - getContext to draw and clear canvas
const canvas = $(&quot;#game-canvas&quot;)[0];
const context = canvas.getContext(&quot;2d&quot;);
const startButton = $(&quot;#start-button&quot;);
const backgroundImage = new Image();
backgroundImage.src = &quot;https://opengameart.org/sites/default/files/duck_spritesheet.png&quot;;
// Onload function to pull the background image of the game
$(backgroundImage).on(&quot;load&quot;, function () {
context.drawImage(backgroundImage, 0, 0);
});
// On click function to change the crosshair and pull in the duck image
startButton.on(&quot;click&quot;, function () {
const spriteSheet = new Image();
spriteSheet.src = &quot;https://opengameart.org/sites/default/files/duck_spritesheet.png&quot;;
$(&quot;#game-canvas&quot;).on(&quot;mouseenter&quot;, function () {
$(this).addClass(&quot;canvas-cursor&quot;);
});
$(&quot;#game-canvas&quot;).on(&quot;mouseleave&quot;, function () {
$(this).removeClass(&quot;canvas-cursor&quot;);
});
$(spriteSheet).on(&quot;load&quot;, function () {
const totalFrames = 4; // Total number of frames in the sprite sheet
const scale = 3; // Scale to TRY and scale it, didn&#39;t work...
const duckSpeed = 10; // ducks movement speed across the canvas
//multiplying any of these didn&#39;t work for me
const duckWidth = spriteSheet.width / totalFrames;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight; 
const animationSpeed = 200; // Milliseconds per frame
let currentFrame = 0; // Current frame of the animation
let duckX = canvas.width; // Starting position of the duck on the right side of the canvas
let duckY = canvas.height / 2 - (frameHeight * scale) / 2; // Center the duck vertically
function animateDuck() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(backgroundImage, 0, 0);
const frameX = (currentFrame % totalFrames) * frameWidth;
const frameY = Math.floor(currentFrame / totalFrames) * frameHeight;
// Draw the current frame of the duck image 
context.drawImage(
spriteSheet,
frameX,
frameY,
frameWidth,
frameHeight,
duckX,
duckY,
frameWidth * scale,
frameHeight * scale
);
// current frame
currentFrame = (currentFrame + 1) % (totalFrames * totalFrames);
// duck&#39;s position
duckX -= duckSpeed;
// if the duck has reached the left side of the canvas
if (duckX + frameWidth * scale * 2 &lt; 0) {
duckX = canvas.width;
}
setTimeout(animateDuck, animationSpeed);
}
animateDuck();
});
});
});

<!-- language: lang-css -->

body {
background-color: #eee;
text-align: center;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
h1 {
color: #333;
}
#game-container {
position: relative;
}
#game-canvas {
display: block;
margin: 0 auto;
border: 1px solid black;
background-color: #fff;
}

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;body&gt;
&lt;div id=&quot;game-container&quot;&gt;
&lt;canvas id=&quot;game-canvas&quot; width=&quot;400&quot; height=&quot;100&quot;&gt;&lt;/canvas&gt;
&lt;/div&gt;
&lt;button id=&quot;start-button&quot;&gt;Start Game&lt;/button&gt;
&lt;/body&gt;

<!-- end snippet -->

答案1

得分: 1

看看你的精灵图像:

如何在画布中调整精灵表帧的大小?

然后看你的代码:

      const duckWidth = spriteSheet.width / totalFrames;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight; 
...
const frameX = (currentFrame % totalFrames) * frameWidth;

这应该足够让你明白了... 用手算一下,这有助于理解。你得到了预期的帧值吗?

以下是我对你的代码的更正,挑战自己尝试修复你的代码,不看我的代码片段:

const canvas = $("#game-canvas")[0];
const context = canvas.getContext("2d");

const spriteSheet = new Image();
spriteSheet.src = "https://opengameart.org/sites/default/files/duck_spritesheet.png";
$(spriteSheet).on("load", function() {
  const totalFrames = 4; // 精灵表中的总帧数
  const scale = 3; // 尝试缩放的比例,但没有起作用...
  const duckSpeed = 2; // 鸭子在画布上的移动速度

  const duckWidth = spriteSheet.width;
  const duckHeight = spriteSheet.height / totalFrames;
  const frameWidth = duckWidth;
  const frameHeight = duckHeight;

  let currentFrame = 0; // 动画的当前帧
  let duckX = canvas.width;
  let duckY = canvas.height / 2 - (frameHeight * scale) / 2;

  function animateDuck() {
    context.clearRect(0, 0, canvas.width, canvas.height);

    const frameX = 0;
    const frameY = Math.floor(currentFrame / totalFrames) * frameHeight;

    context.drawImage(spriteSheet, frameX, frameY, frameWidth, frameHeight, duckX, duckY, frameWidth * scale, frameHeight * scale);
    currentFrame = (currentFrame + 1) % (totalFrames * totalFrames);
    duckX -= duckSpeed;
    if (duckX + frameWidth * scale * 2 < 0) {
      duckX = canvas.width;
    }

    setTimeout(animateDuck, 40);
  }
  animateDuck();
});

简而言之,你的精灵图像不是正方形而是矩形,鸭子的宽度不需要除以总帧数,而且frameX的值也不会随着你的精灵图像而改变,它始终是0。如果你想挑战自己,尝试使用其他精灵,比如这个:
https://opengameart.org/content/explosion-sheet

如何在画布中调整精灵表帧的大小?

英文:

Look at your sprite again:

如何在画布中调整精灵表帧的大小?

and then your code:

      const duckWidth = spriteSheet.width / totalFrames;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight; 
...
const frameX = (currentFrame % totalFrames) * frameWidth;

That should be enough clue to get you moving...
Do the math by hand, that helps, Do you get the expected values for the frames?

Below is my correction to your code, challenge yourself try to fix yours without looking at my snippet

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

  const canvas = $(&quot;#game-canvas&quot;)[0];
const context = canvas.getContext(&quot;2d&quot;);
const spriteSheet = new Image();
spriteSheet.src = &quot;https://opengameart.org/sites/default/files/duck_spritesheet.png&quot;;
$(spriteSheet).on(&quot;load&quot;, function() {
const totalFrames = 4; // Total number of frames in the sprite sheet
const scale = 3; // Scale to TRY and scale it, didn&#39;t work...
const duckSpeed = 2; // ducks movement speed across the canvas
const duckWidth = spriteSheet.width;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight;
let currentFrame = 0; // Current frame of the animation
let duckX = canvas.width;
let duckY = canvas.height / 2 - (frameHeight * scale) / 2;
function animateDuck() {
context.clearRect(0, 0, canvas.width, canvas.height);
const frameX = 0
const frameY = Math.floor(currentFrame / totalFrames) * frameHeight;
context.drawImage(spriteSheet, frameX, frameY, frameWidth, frameHeight, duckX, duckY, frameWidth * scale, frameHeight * scale );
currentFrame = (currentFrame + 1) % (totalFrames * totalFrames);
duckX -= duckSpeed;
if (duckX + frameWidth * scale * 2 &lt; 0) {
duckX = canvas.width;
}
setTimeout(animateDuck, 40);
}
animateDuck();
});

<!-- language: lang-css -->

body {
background-color: #eee;
text-align: center;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
h1 {
color: #333;
}
#game-container {
position: relative;
}
#game-canvas {
display: block;
margin: 0 auto;
border: 1px solid black;
background-color: #fff;
}

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;body&gt;
&lt;div id=&quot;game-container&quot;&gt;
&lt;canvas id=&quot;game-canvas&quot; width=&quot;400&quot; height=&quot;100&quot;&gt;&lt;/canvas&gt;
&lt;/div&gt;
&lt;/body&gt;

<!-- end snippet -->


In a nutshell the image of your sprite is not a square but a rectangle, the duck width does not need to be divided by the total frames and the framex is also not a value that changes for your sprite this is always 0.

If you want to challenge yourself try other sprites like this one:
https://opengameart.org/content/explosion-sheet

如何在画布中调整精灵表帧的大小?

huangapple
  • 本文由 发表于 2023年6月19日 09:12:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76503107.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定