Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for a Graphics Tiling Effect #2744

Open
eonarheim opened this issue Aug 29, 2023 Discussed in #2621 · 9 comments
Open

Allow for a Graphics Tiling Effect #2744

eonarheim opened this issue Aug 29, 2023 Discussed in #2621 · 9 comments
Labels
proposal Applied to issues that are a proposal for an implementation stale This issue or PR has not had any activity recently

Comments

@eonarheim
Copy link
Member

See comment

#2621 (reply in thread)

Discussed in #2621

Originally posted by KokoDoko April 15, 2023
In CSS and in javascript canvas, there's an option to create an infinitely repeating pattern. See this link.

I struggled a while to find out how to apply this in Excalibur, I eventually came up with this solution!

export class InfiniteAnimation extends Actor {

    offsetx = 0
    pattern

    constructor(pos) {
        super({ width: 300, height: 300 })
        this.pos = new Vector(10,10)
    }

    onInitialize(engine) {
        const img = Resources.YourImage.data
        const canvas = new Canvas({
            cache: false,
            draw: (ctx) => this.drawPattern(ctx)
        })
        this.pattern = canvas.ctx.createPattern(img, "repeat")
        this.graphics.use(canvas)
    }

    drawPattern(ctx) {
        this.offsetx--
        const matrix = new DOMMatrix().translate(this.offsetx, 0)
        this.pattern.setTransform(matrix)
        ctx.fillStyle = this.pattern
        ctx.fillRect(0, 0, 300, 300)
    }
}
```</div>
@eonarheim eonarheim added the proposal Applied to issues that are a proposal for an implementation label Aug 29, 2023
@eonarheim
Copy link
Member Author

It's not 100% clear yet what the API would look like

@github-actions
Copy link

This issue hasn't had any recent activity lately and is being marked as stale automatically.

@github-actions github-actions bot added the stale This issue or PR has not had any activity recently label Oct 29, 2023
@mattjennings
Copy link
Contributor

For reference on possible API, PixiJS has a TilingSprite component

@github-actions github-actions bot removed the stale This issue or PR has not had any activity recently label Dec 24, 2023
@eonarheim
Copy link
Member Author

@mattjennings Thanks, this is a great reference. I might be able to sneak tiling into the existing API into the option bag constructor? Potentially if the repeat flag is set on a dimension, it will tile if the destSize is greater than the sourceView's corresponding dimension?

export interface SpriteOptions {
  /**
   * Image to create a sprite from
   */
  image: ImageSource;
  /**
   * By default the source is the entire dimension of the [[ImageSource]]
   */
  sourceView?: { x: number; y: number; width: number; height: number };
  /**
   * By default the size of the final sprite is the size of the [[ImageSource]]
   */
  destSize?: { width: number; height: number };

  repeatX: boolean;
  repeatY: boolean;
}

@eonarheim
Copy link
Member Author

eonarheim commented Dec 26, 2023

Perhaps a new type would be best tho... tileScale and tilePosition seem pretty useful.

@mattjennings
Copy link
Contributor

Hmm. To be honest I'm not entirely sure what tileScale is as opposed to regular scale, and what tilePosition would do as opposed to changing the sprite origin. This is the rendering logic for those properties if that sheds any light.

My thinking is if you had repeatX and repeatY properties, I could manipulate the sprite scale & origin to achieve the same effect as tileScale and tilePosition... but it's probably not the most intuitive. Also not sure if origin wraps in Excalibur? tilePosition would have that behaviour if not, and could justify that property.

Copy link

This issue hasn't had any recent activity lately and is being marked as stale automatically.

@github-actions github-actions bot added the stale This issue or PR has not had any activity recently label Feb 25, 2024
@eonarheim
Copy link
Member Author

eonarheim commented Apr 25, 2024

We accidentally implemented this feature (see discord conversation for full context https://discord.com/channels/1195771303215513671/1229051072027562074)

20240414-1430-04.2978303.mp4

The gist for sprites, is if the ImageWrapping.Repeat is set AND you have a source view bigger than the natural width/height of the image source it will tile!

var game = new ex.Engine({
  canvasElementId: 'game',
  width: 600,
  height: 400,
  displayMode: ex.DisplayMode.FitScreenAndFill,
  pixelArt: true
  // antialiasing: false
});

var tex = new ex.ImageSource('https://cdn.rawgit.com/excaliburjs/Excalibur/7dd48128/assets/sword.png', {
  wrapping: ex.ImageWrapping.Repeat
});

var loader = new ex.Loader([tex]);

var sprite = new ex.Sprite({
  image: tex,
  sourceView: {
    x: 0,
    y: 0,
    width: 500,
    height: 500
  },
  destSize: {
    width: 1000,
    height: 1000
  }
});
var actor = new ex.Actor({ 
  x: 0, y: 0, 
  anchor: ex.vec(0, 0),
  coordPlane: ex.CoordPlane.Screen,
  z: -10
});
actor.onInitialize = () => {
  actor.graphics.add(sprite);
};
actor.onPostUpdate = (engine, delta) => {
  sprite.sourceView.x += .05 * delta;
}
game.add(actor);
game.start(loader);

game.currentScene.camera.pos = actor.pos;

Current hack for animation tiling

this.backgroundAnim = Resources.Background.getAnimation('default')!;
  // Terrible terrible to enable animation tiling
  for (let frame of this.backgroundAnim.frames) {
      const sprite = (frame.graphic as Sprite);
      sprite.image.wrapping = { x: ImageWrapping.Repeat, y: ImageWrapping.Repeat };
      sprite.image.image.setAttribute('wrapping-x', ImageWrapping.Repeat);
      sprite.image.image.setAttribute('wrapping-y', ImageWrapping.Repeat);
      sprite.image.image.setAttribute('forceUpload', 'true');
      sprite.sourceView.width *= 5;
      sprite.sourceView.height *= 5;
      sprite.destSize.width *= 5;
      sprite.destSize.height *= 5;
  }

@github-actions github-actions bot removed the stale This issue or PR has not had any activity recently label Apr 26, 2024
Copy link

This issue hasn't had any recent activity lately and is being marked as stale automatically.

@github-actions github-actions bot added the stale This issue or PR has not had any activity recently label Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal Applied to issues that are a proposal for an implementation stale This issue or PR has not had any activity recently
Projects
None yet
Development

No branches or pull requests

2 participants