straker / kontra

A lightweight JavaScript gaming micro-library, optimized for js13kGames.
https://straker.github.io/kontra/
MIT License
963 stars 99 forks source link

Possibility of rotating an animation #20

Closed buehler closed 6 years ago

buehler commented 6 years ago

Hey there, very nice work!

We're currently making a hackday at our company and I was wondering if it's possible to rotate an animation by an angle.

It's (imo) cheaper (in case of filesize) to rotate the image than to import more sprites.

I'm trying with overwriting the draw methods and stuff, but so far, no luck.

Can you help me or provide any code sources where I can have a look?

Greetings Chris

straker commented 6 years ago

What a fun hackday! Now I'm jealous.

So off the top of my head, I would think you could rotate the canvas and then draw the animation to rotate the image. I used a similar technique in Asteroids to rotate the player ship. So a guess at the code would look something like this:

let sprite = kontra.sprite({
  // ...
  rotation: 0,  // rotation of the image
  render() {
    this.context.save();

    // transform the origin and rotate around it using the sprites rotation
    this.context.translate(this.x, this.y);
    this.context.rotate(degreesToRadians(this.rotation));

    this.draw();  // draw the animation as normal

    this.restore();
  }
});

I'm at work (not having an awesome hackday) so can't verify that will work, but hopefully it does!

buehler commented 6 years ago

Thanks! I'm at home right now, but I'm gonna try that tomorrow morning! I must say, it's a pretty neat lib you wrote here.

I'll report the success or fail tomorrow morning.

Have a nice evening

buehler commented 6 years ago

I just tried it while drinking my wake up coffee :-) Sadly, the animation itself does translate the whole context whilst using drawImage.

So this:

render() {
    this.context.save();

    // transform the origin and rotate around it using the sprites rotation
    //this.context.translate(this.x, this.y);
    this.context.rotate(radians(30));

    this.draw();  // draw the animation as normal

    this.context.restore();
  },

(edit: when I translate the element by the full X and Y, it's out of the screen) Ends up with this:

2018-08-22t07-28-44_c5a30111

Do you have any idea on how I need to translate the context so that the figure is centered? I'm not that skilled with context2d so I have like no idea on how to translate etc.

The other properties are:

x: 256 - 16,
  y: 256 - 16,

  width: 32,
  height: 32,
  animations: Spritesheet.animations,

Regards

straker commented 6 years ago

Ah, ya... I see what the problem is. this.draw() draws the spritesheet at the x, y position of the sprite even after transforming the origin. To make it work you'd need to draw the animation relative to the origin, so {0,0}. I see two options

  1. Set x and y to 0 before the draw and reset it after
  2. Use the "not public" this._ca.render() function which calls the current animations render() function and pass it 0 for x and y.

And now I see a use case to keep the current animation variable I had in the previous version, or at least a better way to rotate animations...

buehler commented 6 years ago

Perfect thanks, gonna try that.

A cool proposal could be: add a rotation (property) to sprites (or animations at least). In that way it would be "generic". You can rotate the whole sprite. So if it's drawing an animation, pass 0,0 and otherwise rotate the context and draw the image / rectangle then.

buehler commented 6 years ago

Alright, the _ca.render() function seems to be working. I need to "cheat" a little bit by offsetting the x and y depending on the rotation angle. but since I want to rotate into quarters, it a little issue.

render() {
      this.context.save();

      // transform the origin and rotate around it using the sprites rotation
      this.context.translate(this.x, this.y);
      //this.context.rotate(radians(90));
      this._ca.render({ x: 0, y: 0 });
      //this.draw();  // draw the animation as normal

      this.context.restore();
    },

(edit: pictures of the offset) before rotation:

2018-08-22t09-41-40_dd46c2cd

after rotation:

2018-08-22t09-41-47_38f074c6

Thanks for the help!

straker commented 6 years ago

Awesome! Glad it worked out. I'm going to leave this issue open as a reminder to make this better in the next update.

buehler commented 6 years ago

Perfect :) Maybe I find some time to work with it on my own. Maybe I try to translate it to TypeScript or WASM or something.. we'll see.

In case you want to see the results: https://js13k.smartive.ch/2018 Thanks for the help!

straker commented 6 years ago

Nice! I love 'em! Great job on the hackday projects.