Skip to content

Commit

Permalink
fix: #2848 Sprite tint respected in constructor (#2852)
Browse files Browse the repository at this point in the history
Closes #2848 

## Changes:

- Fixes sprite tint constructor value passing
- Fixes sprite tint on cloned sprites
- Fixes width/height inconsistency discovered in new tests
- New tests
  • Loading branch information
eonarheim authored Dec 21, 2023
1 parent cbb287a commit 410647a
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

- Sprite tint was not respected when supplied in the constructor, this has been fixed!
- Adjusted the `FontCache` font timeout to 400 ms and makes it configurable as a static `FontCache.FONT_TIMEOUT`. This is to help prevent a downward spiral on mobile devices that might take a long while to render a few starting frames causing the cache to repeatedly clear and never recover.

### Updates
Expand Down
26 changes: 19 additions & 7 deletions sandbox/tests/sprite-tint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var actor = new ex.Actor({x: game.halfDrawWidth, y: game.halfDrawHeight, width:
game.add(actor);

var sprite: ex.Sprite;
var shadow: ex.Graphic;
actor.onInitialize = () => {
sprite = new ex.Sprite({
image: tex,
Expand All @@ -21,17 +22,28 @@ actor.onInitialize = () => {
}
});
actor.graphics.add(sprite);
shadow = actor.graphics.add(
"shadow",
new ex.Sprite({
image: sprite.image,
origin: ex.vec(1, 1),
sourceView: sprite.sourceView, // sourceView needs to be cloned if it exists
destSize: {
width: 500,
height: 500
},
tint: ex.Color.fromRGB(0, 0, 0), // Semi-transparent black for shadow
opacity: 0.5,
scale: ex.vec(1.2, 1), // Stretched horizontally and squashed vertically to look like a shadow
})
);

actor.graphics.show(shadow, {offset: ex.vec(10, 10)});
actor.graphics.show(sprite);
};










let currentHue = 0;
let currentColor = ex.Color.fromHSL(currentHue, 0.6, 0.6);
actor.onPostUpdate = () => {
Expand Down
6 changes: 5 additions & 1 deletion src/engine/Graphics/Graphic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,21 @@ export abstract class Graphic {
this.rotation = options.rotation ?? this.rotation;
this.opacity = options.opacity ?? this.opacity;
this.scale = options.scale ?? this.scale;
this.tint = options.tint ?? this.tint;
}
}

public cloneGraphicOptions(): GraphicOptions {
return {
width: this.width / this.scale.x,
height: this.height / this.scale.y,
origin: this.origin ? this.origin.clone() : null,
flipHorizontal: this.flipHorizontal,
flipVertical: this.flipVertical,
rotation: this.rotation,
opacity: this.opacity,
scale: this.scale ? this.scale.clone() : null
scale: this.scale ? this.scale.clone() : null,
tint: this.tint ? this.tint.clone(): null
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/engine/Graphics/Raster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Vector } from '../Math/vector';
import { BoundingBox } from '../Collision/BoundingBox';
import { watch } from '../Util/Watch';
import { ImageFiltering } from './Filtering';
import { omit } from '../Util/Util';

export interface RasterOptions {
/**
Expand Down Expand Up @@ -75,7 +76,7 @@ export abstract class Raster extends Graphic {
private _dirty: boolean = true;

constructor(options?: GraphicOptions & RasterOptions) {
super(options);
super(omit(options, ['width', 'height'])); // rasters do some special sauce with width/height
if (options) {
this.quality = options.quality ?? this.quality;
this.color = options.color ?? Color.Black;
Expand Down
15 changes: 15 additions & 0 deletions src/engine/Util/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,18 @@ export function delay(milliseconds: number, clock?: Clock): Promise<void> {
}, milliseconds);
return future.promise;
}

/**
* Remove keys from object literals
* @param object
* @param keys
*/
export function omit<TObject extends Object, Keys extends (keyof TObject)>(object: TObject, keys: Keys[]) {
const newObj: Omit<TObject, Keys> = {} as any;
for (const key in object) {
if (!keys.includes(key as any)) {
(newObj as any)[key] = object[key];
}
}
return newObj;
}
31 changes: 27 additions & 4 deletions src/spec/GraphicSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { ExcaliburAsyncMatchers, ExcaliburMatchers } from 'excalibur-jasmine';
class TestGraphic extends ex.Graphic {
constructor(options?: ex.GraphicOptions) {
super(options ?? {});
this.width = 50;
this.height = 50;
this.width = options?.width ?? 50;
this.height = options?.height ?? 50;
}
private _rect1 = new ex.Rectangle({
width: 25,
Expand Down Expand Up @@ -66,14 +66,37 @@ describe('A Graphic', () => {
expect(graphic1.id).not.toBe(graphic2.id);
});

it('can provide all graphic options', () => {
const options: Required<ex.GraphicOptions> = {
width: 100,
height: 100,
origin: ex.vec(1, 1),
flipHorizontal: true,
flipVertical: true,
rotation: Math.PI / 8,
opacity: 0.25,
tint: ex.Color.fromRGB(0, 0, 0),
scale: ex.vec(1, 1)
};

const sut = new TestGraphic(options);

for (const prop in options) {
expect(sut[prop]).toEqual(options[prop]);
}
});

it('can clone all graphic options', () => {
const originalOptions: ex.GraphicOptions = {
const originalOptions: Required<ex.GraphicOptions> = {
width: 100,
height: 100,
origin: ex.vec(1, 1),
flipHorizontal: true,
flipVertical: true,
rotation: Math.PI / 8,
opacity: 0.25,
scale: ex.vec(0.5, 0.75)
tint: ex.Color.fromRGB(0, 0, 0),
scale: ex.vec(1, 1)
};

const sut = new TestGraphic(originalOptions);
Expand Down

0 comments on commit 410647a

Please sign in to comment.