@litecanvas/utils 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tween.js ADDED
@@ -0,0 +1,190 @@
1
+ (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // src/_global.js
9
+ globalThis.utils = globalThis.utils || {};
10
+ globalThis.utils.global = () => {
11
+ for (const key in globalThis.utils) {
12
+ if ("global" === key) continue;
13
+ globalThis[key] = globalThis.utils[key];
14
+ }
15
+ };
16
+
17
+ // src/tween/index.js
18
+ var tween_exports = {};
19
+ __export(tween_exports, {
20
+ BACK_IN: () => BACK_IN,
21
+ BACK_IN_OUT: () => BACK_IN_OUT,
22
+ BACK_OUT: () => BACK_OUT,
23
+ BOUNCE_IN: () => BOUNCE_IN,
24
+ BOUNCE_IN_OUT: () => BOUNCE_IN_OUT,
25
+ BOUNCE_OUT: () => BOUNCE_OUT,
26
+ EASE_IN: () => EASE_IN,
27
+ EASE_IN_OUT: () => EASE_IN_OUT,
28
+ EASE_OUT: () => EASE_OUT,
29
+ ELASTIC_IN: () => ELASTIC_IN,
30
+ ELASTIC_IN_OUT: () => ELASTIC_IN_OUT,
31
+ ELASTIC_OUT: () => ELASTIC_OUT,
32
+ LINEAR: () => LINEAR,
33
+ tween: () => tween
34
+ });
35
+
36
+ // node_modules/litecanvas/src/zzfx.js
37
+ globalThis.zzfxV = 1;
38
+
39
+ // src/tween/index.js
40
+ var HALF_PI = Math.PI / 2;
41
+ var tween = (object, prop, toValue, duration = 1, easing = LINEAR) => {
42
+ return new TweenController(object, prop, toValue, duration, easing);
43
+ };
44
+ var LINEAR = (n) => n;
45
+ var EASE_IN = (n) => n * n;
46
+ var EASE_OUT = (n) => -n * (n - 2);
47
+ var EASE_IN_OUT = (n) => {
48
+ if (n < 0.5) {
49
+ return 2 * n * n;
50
+ }
51
+ return -2 * n * n + 4 * n - 1;
52
+ };
53
+ var BACK_IN = (n) => n * n * n - n * Math.sin(n * Math.PI);
54
+ var BACK_OUT = (n) => {
55
+ let a = 1 - n;
56
+ return 1 - (a * a * a - a * Math.sin(a * Math.PI));
57
+ };
58
+ var BACK_IN_OUT = (n) => {
59
+ if (n < 0.5) {
60
+ let a2 = 2 * n;
61
+ return 0.5 * (a2 * a2 * a2 - a2 * Math.sin(a2 * Math.PI));
62
+ }
63
+ let a = 1 - (2 * n - 1);
64
+ return 0.5 * (1 - (a * a * a - a * Math.sin(n * Math.PI))) + 0.5;
65
+ };
66
+ var ELASTIC_IN = (n) => {
67
+ return Math.sin(13 * HALF_PI * n) * Math.pow(2, 10 * (n - 1));
68
+ };
69
+ var ELASTIC_OUT = (n) => {
70
+ return Math.sin(-13 * HALF_PI * (n + 1)) * Math.pow(2, -10 * n) + 1;
71
+ };
72
+ var ELASTIC_IN_OUT = (n) => {
73
+ if (n < 0.5) {
74
+ let a2 = Math.sin(13 * HALF_PI * (2 * n));
75
+ let b2 = Math.pow(2, 10 * (2 * n - 1));
76
+ return 0.5 * a2 * b2;
77
+ }
78
+ let a = Math.sin(-13 * HALF_PI * (2 * n - 1 + 1));
79
+ let b = Math.pow(2, -10 * (2 * n - 1));
80
+ return 0.5 * (a * b + 2);
81
+ };
82
+ var BOUNCE_IN = (n) => 1 - BOUNCE_OUT(1 - n);
83
+ var BOUNCE_OUT = (n) => {
84
+ if (n < 4 / 11) {
85
+ return 121 * n * n / 16;
86
+ } else if (n < 8 / 11) {
87
+ return 363 / 40 * n * n - 99 / 10 * n + 17 / 5;
88
+ } else if (n < 9 / 10) {
89
+ return 4356 / 361 * n * n - 35442 / 1805 * n + 16061 / 1805;
90
+ }
91
+ return 54 / 5 * n * n - 513 / 25 * n + 268 / 25;
92
+ };
93
+ var BOUNCE_IN_OUT = (n) => {
94
+ if (n < 0.5) {
95
+ return 0.5 * BOUNCE_IN(n * 2);
96
+ }
97
+ return 0.5 * BOUNCE_OUT(n * 2 - 1) + 0.5;
98
+ };
99
+ var TweenController = class {
100
+ /** @type {boolean} */
101
+ running = false;
102
+ /** @type {*} */
103
+ _o;
104
+ /** @type {string} */
105
+ _p;
106
+ /** @type {number} */
107
+ _x;
108
+ /** @type {number} */
109
+ _d;
110
+ /** @type {(x: number) => number} */
111
+ _e;
112
+ /** @type {Function[]} */
113
+ _cb = [];
114
+ /** @type {number} */
115
+ _t = 0;
116
+ /** @type {Function} */
117
+ _u = 0;
118
+ /** @type {LitecanvasInstance} */
119
+ _lc;
120
+ /**
121
+ * @param {*} object
122
+ * @param {string} prop
123
+ * @param {number} toValue
124
+ * @param {number} duration
125
+ * @param {(x: number) => number} easing
126
+ */
127
+ constructor(object, prop, toValue, duration, easing) {
128
+ this._o = object;
129
+ this._p = prop;
130
+ this._x = toValue;
131
+ this._d = duration;
132
+ this._e = easing;
133
+ }
134
+ /**
135
+ *
136
+ * @param {LitecanvasInstance} engine
137
+ */
138
+ start(engine = globalThis) {
139
+ if (!this.running) {
140
+ this.stop();
141
+ }
142
+ const fromValue = this._o[this._p] || 0;
143
+ this._lc = engine;
144
+ this._u = engine.listen("update", (dt) => {
145
+ this._o[this._p] = engine.lerp(
146
+ fromValue,
147
+ this._x,
148
+ this._e(this._t / this._d)
149
+ );
150
+ this._t += dt;
151
+ if (this._t >= this._d) {
152
+ this._o[this._p] = this._x;
153
+ this.stop();
154
+ }
155
+ });
156
+ this.running = true;
157
+ return this;
158
+ }
159
+ /**
160
+ * @param {Function} callback
161
+ */
162
+ onEnd(callback) {
163
+ this._cb.push(callback);
164
+ }
165
+ /**
166
+ * @param {boolean} completed if `false` don't call the `onEnd()` registered callbacks.
167
+ * @returns
168
+ */
169
+ stop(completed = true) {
170
+ if (!this.running || !this._u) return;
171
+ this.running = false;
172
+ this._u();
173
+ if (completed) {
174
+ for (const callback of this._cb) {
175
+ callback(this._o);
176
+ }
177
+ }
178
+ }
179
+ reset() {
180
+ this._cb.length = 0;
181
+ this.stop();
182
+ }
183
+ get progress() {
184
+ return this.running ? this._t / this._d : 0;
185
+ }
186
+ };
187
+
188
+ // src/tween/_web.js
189
+ globalThis.utils = Object.assign(globalThis.utils || {}, tween_exports);
190
+ })();
@@ -0,0 +1 @@
1
+ (()=>{var p=Object.defineProperty;var h=(t,e)=>{for(var o in e)p(t,o,{get:e[o],enumerable:!0})};globalThis.utils=globalThis.utils||{};globalThis.utils.global=()=>{for(let t in globalThis.utils)t!=="global"&&(globalThis[t]=globalThis.utils[t])};var l={};h(l,{BACK_IN:()=>x,BACK_IN_OUT:()=>m,BACK_OUT:()=>E,BOUNCE_IN:()=>f,BOUNCE_IN_OUT:()=>w,BOUNCE_OUT:()=>n,EASE_IN:()=>_,EASE_IN_OUT:()=>T,EASE_OUT:()=>g,ELASTIC_IN:()=>I,ELASTIC_IN_OUT:()=>y,ELASTIC_OUT:()=>b,LINEAR:()=>c,tween:()=>d});globalThis.zzfxV=1;var r=Math.PI/2,d=(t,e,o,s=1,i=c)=>new a(t,e,o,s,i),c=t=>t,_=t=>t*t,g=t=>-t*(t-2),T=t=>t<.5?2*t*t:-2*t*t+4*t-1,x=t=>t*t*t-t*Math.sin(t*Math.PI),E=t=>{let e=1-t;return 1-(e*e*e-e*Math.sin(e*Math.PI))},m=t=>{if(t<.5){let o=2*t;return .5*(o*o*o-o*Math.sin(o*Math.PI))}let e=1-(2*t-1);return .5*(1-(e*e*e-e*Math.sin(t*Math.PI)))+.5},I=t=>Math.sin(13*r*t)*Math.pow(2,10*(t-1)),b=t=>Math.sin(-13*r*(t+1))*Math.pow(2,-10*t)+1,y=t=>{if(t<.5){let s=Math.sin(13*r*(2*t)),i=Math.pow(2,10*(2*t-1));return .5*s*i}let e=Math.sin(-13*r*(2*t-1+1)),o=Math.pow(2,-10*(2*t-1));return .5*(e*o+2)},f=t=>1-n(1-t),n=t=>t<4/11?121*t*t/16:t<8/11?363/40*t*t-99/10*t+17/5:t<9/10?4356/361*t*t-35442/1805*t+16061/1805:54/5*t*t-513/25*t+268/25,w=t=>t<.5?.5*f(t*2):.5*n(t*2-1)+.5,a=class{running=!1;_o;_p;_x;_d;_e;_cb=[];_t=0;_u=0;_lc;constructor(e,o,s,i,u){this._o=e,this._p=o,this._x=s,this._d=i,this._e=u}start(e=globalThis){this.running||this.stop();let o=this._o[this._p]||0;return this._lc=e,this._u=e.listen("update",s=>{this._o[this._p]=e.lerp(o,this._x,this._e(this._t/this._d)),this._t+=s,this._t>=this._d&&(this._o[this._p]=this._x,this.stop())}),this.running=!0,this}onEnd(e){this._cb.push(e)}stop(e=!0){if(!(!this.running||!this._u)&&(this.running=!1,this._u(),e))for(let o of this._cb)o(this._o)}reset(){this._cb.length=0,this.stop()}get progress(){return this.running?this._t/this._d:0}};globalThis.utils=Object.assign(globalThis.utils||{},l);})();
package/dist/vector.js CHANGED
@@ -120,8 +120,8 @@
120
120
  if (isVector(x)) {
121
121
  return vecDiv(v, x.x, x.y);
122
122
  }
123
- v.x /= x;
124
- v.y /= y;
123
+ v.x /= x || 1;
124
+ v.y /= y || 1;
125
125
  return v;
126
126
  };
127
127
  var vecRotate = (v, radians) => {
@@ -1 +1 @@
1
- (()=>{var A=Object.defineProperty;var C=(t,e)=>{for(var o in e)A(t,o,{get:e[o],enumerable:!0})};var h={};C(h,{DOWN:()=>K,LEFT:()=>Q,ONE:()=>k,RIGHT:()=>J,UP:()=>z,Vector:()=>s,ZERO:()=>q,vec:()=>c,vecAbs:()=>j,vecAdd:()=>i,vecAngle:()=>P,vecAngleBetween:()=>w,vecCeil:()=>B,vecClamp:()=>H,vecCross:()=>U,vecDist:()=>L,vecDist2:()=>N,vecDiv:()=>y,vecDot:()=>T,vecEq:()=>u,vecFloor:()=>F,vecIsZero:()=>W,vecLerp:()=>Z,vecLimit:()=>b,vecMag:()=>R,vecMag2:()=>D,vecMove:()=>V,vecMult:()=>x,vecNorm:()=>l,vecRand:()=>$,vecReflect:()=>O,vecRotate:()=>I,vecRound:()=>G,vecSet:()=>g,vecSetMag:()=>S,vecSub:()=>a});var p=Math.sqrt,f=Math.cos,d=Math.sin,E=2*Math.PI,s=class{x;y;constructor(e=0,o=e){this.x=e,this.y=o}toString(){return`Vector (${this.x}, ${this.y})`}},n=t=>t instanceof s,c=(t=0,e=t)=>(n(t)&&(e=t.y,t=t.x),new s(t,e)),u=(t,e,o=e)=>n(e)?u(t,e.x,e.y):t.x===e&&t.y===o,g=(t,e,o=e)=>(n(e)?g(t,e.x,e.y):(t.x=e,t.y=o),t),i=(t,e,o=e)=>n(e)?i(t,e.x,e.y):(t.x+=e,t.y+=o,t),a=(t,e,o=e)=>n(e)?a(t,e.x,e.y):(t.x-=e,t.y-=o,t),x=(t,e,o=e)=>n(e)?x(t,e.x,e.y):(t.x*=e,t.y*=o,t),y=(t,e,o=e)=>n(e)?y(t,e.x,e.y):(t.x/=e,t.y/=o,t),I=(t,e)=>{let o=f(e),r=d(e);return t.x=o*t.x-r*t.y,t.y=r*t.x+o*t.y,t},O=(t,e)=>{let o=l(c(e));return a(t,x(o,2*T(t,o)))},S=(t,e)=>(l(t),x(t,e),t),R=t=>p(t.x*t.x+t.y*t.y),D=t=>t.x*t.x+t.y*t.y,l=t=>{let e=R(t);return e>0&&y(t,e),t},b=(t,e=1)=>{let o=D(t);return o>e*e&&(y(t,p(o)),x(t,e)),t},L=(t,e)=>{let o=t.x-e.x,r=t.y-e.y;return p(o*o+r*r)},N=(t,e)=>{let o=t.x-e.x,r=t.y-e.y;return o*o+r*r},P=t=>Math.atan2(t.y,t.x),w=(t,e)=>Math.atan2(e.y-t.y,e.x-t.x),T=(t,e)=>t.x*e.x+t.y*e.y,U=(t,e)=>t.x*e.y-t.y*e.x,Z=(t,e,o)=>(t.x+=(e.x-t.x)*o||0,t.y+=(e.y-t.y)*o||0,t),$=(t=1,e=t,o=globalThis.rand||Math.random)=>{let r=o()*E,M=o()*(e-t)+t;return c(f(r)*M,d(r)*M)},j=t=>(t.x=Math.abs(t.x),t.y=Math.abs(t.y),t),B=t=>(t.x=Math.ceil(t.x),t.y=Math.ceil(t.y),t),F=t=>(t.x=Math.floor(t.x),t.y=Math.floor(t.y),t),G=t=>(t.x=Math.round(t.x),t.y=Math.round(t.y),t),H=(t,e,o)=>(t.x<e.x&&(t.x=e.x),t.x>o.x&&(t.x=o.x),t.y<e.y&&(t.y=e.y),t.y>o.y&&(t.y=o.y),t),V=(t,e,o=1)=>i(t,e.x*o,e.y*o),W=t=>u(t,q),q=c(0,0),k=c(1,1),z=c(0,-1),J=c(1,0),K=c(0,1),Q=c(-1,0);globalThis.utils=Object.assign(globalThis.utils||{},h);})();
1
+ (()=>{var A=Object.defineProperty;var C=(t,e)=>{for(var o in e)A(t,o,{get:e[o],enumerable:!0})};var h={};C(h,{DOWN:()=>K,LEFT:()=>Q,ONE:()=>k,RIGHT:()=>J,UP:()=>z,Vector:()=>s,ZERO:()=>q,vec:()=>c,vecAbs:()=>j,vecAdd:()=>i,vecAngle:()=>P,vecAngleBetween:()=>w,vecCeil:()=>B,vecClamp:()=>H,vecCross:()=>U,vecDist:()=>L,vecDist2:()=>N,vecDiv:()=>y,vecDot:()=>T,vecEq:()=>u,vecFloor:()=>F,vecIsZero:()=>W,vecLerp:()=>Z,vecLimit:()=>b,vecMag:()=>R,vecMag2:()=>D,vecMove:()=>V,vecMult:()=>x,vecNorm:()=>l,vecRand:()=>$,vecReflect:()=>O,vecRotate:()=>I,vecRound:()=>G,vecSet:()=>g,vecSetMag:()=>S,vecSub:()=>a});var p=Math.sqrt,f=Math.cos,d=Math.sin,E=2*Math.PI,s=class{x;y;constructor(e=0,o=e){this.x=e,this.y=o}toString(){return`Vector (${this.x}, ${this.y})`}},n=t=>t instanceof s,c=(t=0,e=t)=>(n(t)&&(e=t.y,t=t.x),new s(t,e)),u=(t,e,o=e)=>n(e)?u(t,e.x,e.y):t.x===e&&t.y===o,g=(t,e,o=e)=>(n(e)?g(t,e.x,e.y):(t.x=e,t.y=o),t),i=(t,e,o=e)=>n(e)?i(t,e.x,e.y):(t.x+=e,t.y+=o,t),a=(t,e,o=e)=>n(e)?a(t,e.x,e.y):(t.x-=e,t.y-=o,t),x=(t,e,o=e)=>n(e)?x(t,e.x,e.y):(t.x*=e,t.y*=o,t),y=(t,e,o=e)=>n(e)?y(t,e.x,e.y):(t.x/=e||1,t.y/=o||1,t),I=(t,e)=>{let o=f(e),r=d(e);return t.x=o*t.x-r*t.y,t.y=r*t.x+o*t.y,t},O=(t,e)=>{let o=l(c(e));return a(t,x(o,2*T(t,o)))},S=(t,e)=>(l(t),x(t,e),t),R=t=>p(t.x*t.x+t.y*t.y),D=t=>t.x*t.x+t.y*t.y,l=t=>{let e=R(t);return e>0&&y(t,e),t},b=(t,e=1)=>{let o=D(t);return o>e*e&&(y(t,p(o)),x(t,e)),t},L=(t,e)=>{let o=t.x-e.x,r=t.y-e.y;return p(o*o+r*r)},N=(t,e)=>{let o=t.x-e.x,r=t.y-e.y;return o*o+r*r},P=t=>Math.atan2(t.y,t.x),w=(t,e)=>Math.atan2(e.y-t.y,e.x-t.x),T=(t,e)=>t.x*e.x+t.y*e.y,U=(t,e)=>t.x*e.y-t.y*e.x,Z=(t,e,o)=>(t.x+=(e.x-t.x)*o||0,t.y+=(e.y-t.y)*o||0,t),$=(t=1,e=t,o=globalThis.rand||Math.random)=>{let r=o()*E,M=o()*(e-t)+t;return c(f(r)*M,d(r)*M)},j=t=>(t.x=Math.abs(t.x),t.y=Math.abs(t.y),t),B=t=>(t.x=Math.ceil(t.x),t.y=Math.ceil(t.y),t),F=t=>(t.x=Math.floor(t.x),t.y=Math.floor(t.y),t),G=t=>(t.x=Math.round(t.x),t.y=Math.round(t.y),t),H=(t,e,o)=>(t.x<e.x&&(t.x=e.x),t.x>o.x&&(t.x=o.x),t.y<e.y&&(t.y=e.y),t.y>o.y&&(t.y=o.y),t),V=(t,e,o=1)=>i(t,e.x*o,e.y*o),W=t=>u(t,q),q=c(0,0),k=c(1,1),z=c(0,-1),J=c(1,0),K=c(0,1),Q=c(-1,0);globalThis.utils=Object.assign(globalThis.utils||{},h);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litecanvas/utils",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "Utilities to help build litecanvas games",
5
5
  "author": "Luiz Bills <luizbills@pm.me>",
6
6
  "license": "MIT",
@@ -56,7 +56,7 @@ player.y = 200
56
56
 
57
57
  ## Actor#scale
58
58
 
59
- Set or get the actor scale/size
59
+ Set or get the actor scale vector
60
60
 
61
61
  ```js
62
62
  // twice bigger
@@ -64,6 +64,36 @@ player.scale.x = 2
64
64
  player.scale.y = 2
65
65
  ```
66
66
 
67
+ ## Actor#scaleBy(x, y = x)
68
+
69
+ ```js
70
+ // multiplies the scale (y is optional)
71
+ player.scaleBy(3)
72
+
73
+ // same as
74
+ player.scale.x *= 3
75
+ player.scale.y *= 3
76
+ ```
77
+
78
+ ## Actor#scaleTo(x, y = x)
79
+
80
+ ```js
81
+ // sets the scale (y is optional)
82
+ player.scaleTo(3)
83
+
84
+ // same as
85
+ player.scale.x = 3
86
+ player.scale.y = 3
87
+ ```
88
+
89
+ ## Actor#flipX
90
+
91
+ If `true` the actor sprite is flipped horizontally. Default is `false`.
92
+
93
+ ## Actor#flipY
94
+
95
+ If `true` the actor sprite is flipped vertically. Default is `false`.
96
+
67
97
  ## Actor#anchor
68
98
 
69
99
  Set or get the actor anchor (origin). By default, the anchor is a vector `(0, 0)` (meaning anchor Top Left).
@@ -1,11 +1,11 @@
1
1
  import { Vector, vec } from "../vector/index.js"
2
2
  import "litecanvas"
3
3
 
4
- export const ANCHOR_CENTER = vec(0.5, 0.5)
5
- export const ANCHOR_TOP_LEFT = vec(0, 0)
6
- export const ANCHOR_TOP_RIGHT = vec(1, 0)
7
- export const ANCHOR_BOT_LEFT = vec(0, 1)
8
- export const ANCHOR_BOT_RIGHT = vec(1, 1)
4
+ export const ANCHOR_CENTER = /** @__PURE__ */ vec(0.5, 0.5)
5
+ export const ANCHOR_TOP_LEFT = /** @__PURE__ */ vec(0, 0)
6
+ export const ANCHOR_TOP_RIGHT = /** @__PURE__ */ vec(1, 0)
7
+ export const ANCHOR_BOT_LEFT = /** @__PURE__ */ vec(0, 1)
8
+ export const ANCHOR_BOT_RIGHT = /** @__PURE__ */ vec(1, 1)
9
9
 
10
10
  export class Actor {
11
11
  /** @type {Image|HTMLCanvasElement|OffscreenCanvas} */
@@ -20,6 +20,12 @@ export class Actor {
20
20
  /** @type {Vector} The actor scale */
21
21
  _s
22
22
 
23
+ /** @type {boolean} */
24
+ flipX = false
25
+
26
+ /** @type {boolean} */
27
+ flipY = false
28
+
23
29
  /** @type {number} The actor angle (in radians) */
24
30
  angle = 0
25
31
 
@@ -105,6 +111,28 @@ export class Actor {
105
111
  return this._s
106
112
  }
107
113
 
114
+ /**
115
+ * Sets the actor scale
116
+ *
117
+ * @param {number} x
118
+ * @param {number} [y]
119
+ */
120
+ scaleTo(x, y = x) {
121
+ this._s.x = x
122
+ this._s.y = y
123
+ }
124
+
125
+ /**
126
+ * Multiplies the actor scale
127
+ *
128
+ * @param {number} x
129
+ * @param {number} [y]
130
+ */
131
+ scaleBy(x, y = x) {
132
+ this._s.x *= x
133
+ this._s.y *= y
134
+ }
135
+
108
136
  /**
109
137
  * @returns {number[]}
110
138
  */
@@ -117,19 +145,19 @@ export class Actor {
117
145
  }
118
146
 
119
147
  /**
120
- * Update the transformation matrix, sets the opacity and draw the actor sprite image.
148
+ * Draw the actor
121
149
  *
122
150
  * @param {LitecanvasInstance} [litecanvas]
123
151
  */
124
- draw(litecanvas = globalThis) {
152
+ draw(litecanvas = globalThis, saveContext = true) {
125
153
  if (this.hidden || this.opacity <= 0) return
126
154
 
127
- litecanvas.push()
155
+ if (saveContext) litecanvas.push()
128
156
 
129
157
  this.transform(litecanvas)
130
158
  this.drawImage(litecanvas)
131
159
 
132
- litecanvas.pop()
160
+ if (saveContext) litecanvas.pop()
133
161
  }
134
162
 
135
163
  /**
@@ -138,16 +166,21 @@ export class Actor {
138
166
  transform(litecanvas) {
139
167
  litecanvas.translate(this.pos.x, this.pos.y)
140
168
  litecanvas.rotate(this.angle)
141
- litecanvas.scale(this._s.x, this._s.y)
169
+ litecanvas.scale(
170
+ (this.flipX ? -1 : 1) * this._s.x,
171
+ (this.flipY ? -1 : 1) * this._s.y
172
+ )
142
173
  }
143
174
 
144
175
  /**
145
176
  * @param {LitecanvasInstance} litecanvas
146
177
  */
147
- drawImage(litecanvas) {
148
- const anchorX = this.sprite.width * this.anchor.x
149
- const anchorY = this.sprite.height * this.anchor.y
150
- litecanvas.alpha(this.opacity)
151
- litecanvas.image(-anchorX, -anchorY, this.sprite)
178
+ drawImage(litecanvas, alpha = true) {
179
+ const anchor = this.anchor
180
+ const x = -this.sprite.width * (this.flipX ? 1 - anchor.x : anchor.x)
181
+ const y = -this.sprite.height * (this.flipY ? 1 - anchor.y : anchor.y)
182
+
183
+ if (alpha) litecanvas.alpha(this.opacity)
184
+ litecanvas.image(x, y, this.sprite)
152
185
  }
153
186
  }
package/src/index.js CHANGED
@@ -5,3 +5,4 @@ export * from "./grid/index.js"
5
5
  export * from "./vector/index.js"
6
6
  export * from "./actor/index.js"
7
7
  export * from "./math/index.js"
8
+ export * from "./tween/index.js"
@@ -62,6 +62,41 @@ function draw() {
62
62
  }
63
63
  ```
64
64
 
65
+ [See in playground](https://litecanvas.js.org?c=eJwlyrEKwjAUheE9T3HGBKME0UVwEM0mIuqgY4ytBC6JNGlLKXl3bVwOP4evTY7i4k3haYgLRi5V1vjORD4ygEL4bDDi1ZgeWbIsGKtbb5MLvpxcYHKWIldiiuBjwoAtetNVfL5USqKMPu7OV30oyDW2dkR8r083fblL%2FOOBGQaJ9U%2BvBMtfqxAsyg%3D%3D)
66
+
67
+ ## advance
68
+
69
+ Returns a sequence of numbers from `0` to `size - 1`.
70
+
71
+ Syntax: `range(size: number): number[]`
72
+
73
+ ```js
74
+ import litecanvas from "litecanvas"
75
+ import { vec, advance } from "@litecanvas/utils"
76
+
77
+ litecanvas()
78
+
79
+ function init() {
80
+ pos = vec(0, CENTERY)
81
+ vel = vec(0, 0)
82
+ acc = vec(100, 0)
83
+ }
84
+
85
+ function update(dt) {
86
+ advance(pos, vel, acc, dt)
87
+ if (pos.x > WIDTH) {
88
+ pos.x = 0
89
+ }
90
+ }
91
+
92
+ function draw() {
93
+ cls(0)
94
+ circ(pos.x, pos.y, 48, 4)
95
+ }
96
+ ```
97
+
98
+ [See in playground](https://litecanvas.js.org?c=eJxVjjELwjAQhff%2BihtTCKWCg0tdtKCLgxTEMV5SCYS0NGlUpP%2FdS1NQhxvue7yPN3ptXHE33U0YlmdGe4XCBuHoydrRotedBW21Zzm8M4C%2Bc1BBUMhKDrv61NTna048KPPlZSQCcSGrMrHpRzn2UnjFpE9aIYOwqBjpeXTxWOdAMYW6hRgUT9jC5bhvDqkzjyFYQUnf9KeXg3gsi9E4Ng9CPWDy8Ln54rDe0NGwDwbOS1Q%3D)
99
+
65
100
  ## range
66
101
 
67
102
  Returns a sequence of numbers from `0` to `size - 1`.
@@ -0,0 +1,20 @@
1
+ import { Vector, vecMult, vecAdd } from "../vector"
2
+
3
+ /**
4
+ * Move a vector (position) using another vectors: velocity and acceleration (optional).
5
+ * Note: This function changes the position and velocity vectors.
6
+ *
7
+ * @param {Vector} position
8
+ * @param {Vector} velocity
9
+ * @param {Vector?} acceleration
10
+ * @param {number?} deltaTime
11
+ */
12
+ export default advance = (position, velocity, acceleration, deltaTime = 1) => {
13
+ if (acceleration) {
14
+ velocity.x += acceleration.x * deltaTime
15
+ velocity.y += acceleration.y * deltaTime
16
+ }
17
+
18
+ position.x += velocity.x * deltaTime
19
+ position.y += velocity.y * deltaTime
20
+ }
package/src/math/index.js CHANGED
@@ -2,3 +2,4 @@ export { default as diff } from "./diff.js"
2
2
  export { default as wave } from "./wave.js"
3
3
  export { default as fract } from "./fract.js"
4
4
  export { default as range } from "./range.js"
5
+ export { default as advance } from "./advance.js"
@@ -0,0 +1,181 @@
1
+ # Tween
2
+
3
+ You can animate object property using the `tween().`
4
+
5
+ **CDN**: https://unpkg.com/@litecanvas/utils/dist/tween.js
6
+
7
+ ## tween
8
+
9
+ Animate a object property over time.
10
+
11
+ Syntax:
12
+
13
+ ```ts
14
+ tween(
15
+ object: any,
16
+ prop: string,
17
+ toValue: number,
18
+ duration?: number, // default: 1
19
+ easing?: (n: number) => number // default: LINEAR (see below)
20
+ ): TweenController
21
+ ```
22
+
23
+ ```js
24
+ // basic example
25
+ // move the rect position x from 100 to 250 over 2 seconds
26
+ import litecanvas from "litecanvas"
27
+ import { tween } from "@litecanvas/utils"
28
+
29
+ let object
30
+
31
+ litecanvas()
32
+
33
+ function init() {
34
+ pos = {
35
+ x: 100,
36
+ y: CENTERY,
37
+ }
38
+
39
+ // create the animation
40
+ const animation = tween(pos, "x", 250, 2)
41
+
42
+ // start the animation
43
+ animation.start()
44
+
45
+ // or just
46
+ // tween(...).start()
47
+ }
48
+
49
+ function draw() {
50
+ cls(0)
51
+ // draw the animated rect
52
+ rectfill(pos.x, pos.y, 50, 50, 3)
53
+ }
54
+ ```
55
+
56
+ ## TweenController
57
+
58
+ ### TweenController#start()
59
+
60
+ Starts the animation
61
+
62
+ Syntax: `.start(engine?: LitecanvasInstance): TweenController`
63
+
64
+ ```js
65
+ // if your litecanvas has config.global = false
66
+ // you need to pass the engine instance to all animations
67
+ const engine = litecanvas({
68
+ global: false
69
+ })
70
+
71
+ function init () {
72
+ engine.tween(...).start(engine)
73
+ }
74
+ ```
75
+
76
+ ```js
77
+ // otherwhise, just call `start()` without arguments
78
+ const engine = litecanvas({
79
+ // global: true // default value
80
+ })
81
+
82
+ function init () {
83
+ // just call start
84
+ engine.tween(...).start()
85
+ }
86
+ ```
87
+
88
+ ### TweenController#onEnd()
89
+
90
+ Enqueues a callback to be executed when the animation finishes.
91
+
92
+ Syntax: `.onEnd(callback?: (object:any) => void): void`
93
+
94
+ ```js
95
+ // lets imagine a animation
96
+ let anim = tween(...)
97
+
98
+ // print in console when that tween finishes
99
+ anim.onEnd(() => {
100
+ console.log('FINISHED')
101
+ })
102
+ ```
103
+
104
+ ### TweenController#stop()
105
+
106
+ Stops the animation.
107
+
108
+ Syntax: `.stop(complete?: boolean): void`
109
+
110
+ ```js
111
+ // lets imagine a animation with 5 seconds of duration
112
+ let anim = tween(...)
113
+
114
+ // call `stop()` to interrumpt that animation
115
+ // and call all "onEnd" callbacks
116
+ anim.stop()
117
+
118
+ // or
119
+ // call `stop()` to interrumpt that animation
120
+ // and NOT call the "onEnd" callbacks
121
+ anim.stop(false)
122
+ ```
123
+
124
+ ### TweenController#reset()
125
+
126
+ Stops the animation and remove all `.onEnd()` registered callbacks.
127
+
128
+ ### TweenController#progress
129
+
130
+ Returns the percentage of the animation's progress, a number between `0.0` and `1.0`. Where `0` represents 0% and `1` represents 100%.
131
+
132
+ ### Easing Functions
133
+
134
+ We provide few easing functions:
135
+
136
+ - `LINEAR` (the default)
137
+ - `EASE_IN`
138
+ - `EASE_OUT`
139
+ - `EASE_IN_OUT`
140
+ - `ELASTIC_IN`
141
+ - `ELASTIC_OUT`
142
+ - `ELASTIC_IN_OUT`
143
+ - `BOUNCE_IN`
144
+ - `BOUNCE_OUT`
145
+ - `BOUNCE_IN_OUT`
146
+ - `BACK_IN`
147
+ - `BACK_OUT`
148
+ - `BACK_IN_OUT`
149
+
150
+ You should use the `tween()`'s fifth argument to choose a easing function.
151
+
152
+ ```js
153
+ import litecanvas from "litecanvas"
154
+ import { tween, BOUNCE_OUT } from "@litecanvas/utils"
155
+
156
+ let object
157
+
158
+ litecanvas()
159
+
160
+ function init() {
161
+ pos = {
162
+ x: 100,
163
+ y: CENTERY,
164
+ }
165
+
166
+ tween(pos, "x", 250, 2, BOUNCE_OUT).start()
167
+ }
168
+
169
+ function draw() {
170
+ cls(0)
171
+ rectfill(pos.x, pos.y, 50, 50, 3)
172
+ }
173
+ ```
174
+
175
+ [See all Easing Functions in action](https://litecanvas.js.org?c=eJylVEtvGjEQvvMrJpy8zXZD2vSCRCVKaYMaEakh6qGqKrM24Nax0a43sIry3zt%2BLSyQ9lCJRfP2fPONXRkhy2wp9ZxKknQ6uValAU5LoZYlDOCpA3AzmY6HX1OUxsO78c%2FJtBFv72d75ka9Gd7NJqMYGLQjZ7R8uL2fjmLZoBy6GsNw9CVGWrFt9upzC8SUPnDEcTv%2FxXOT%2FeZ1SQK6pBX3qVK5EVrtYh%2BprPhetOQxdlQVBVcGQ3vNxFCRwvCcqkdaEju2jWBm1Ye3vZ5tkVZGlzmVvA8LKkuOfeK4F%2FFUoYQhiRs3qwoaOrlEFX%2FaNRTYwFJKPLiIPqhKytQZt33oeakO0nMH%2F0pDC5v5yHNy2eslaOKKBcO3ycfZNbwGdKRwPZ58vp55LbGpTOfVA8LM5prVGV2vMXG0EpIRd0zjzgtODZ%2FxrZlqxkl3RtdgNOQrqpYczIrD2E0N4ojPuraNBIna4a%2FWDIsQZvwMxAKIR501aBMouKkK1Wkmkm0RiEOYbXfGJgGdZsO58v16rx9Rd9v1AkLKtl6MYw%2BO1lJ8b%2FH%2Bw3afuXMJTzonTs60GitGkNDB%2B0DaieYseZan%2FRJ1g6hG40vt13vt1%2F%2FZ%2Fj4LrKAbsmPg7G8U5LIkbp%2BkUNztOrlySC4uXB3HvF8%2FihtnNWzXJooiJ4G1NIJN8Z6k8C6Jfk9MABh9B8V9W5yF2YTUhZAy7g5WiHNN4c1REQrrQi8LXpYwpwV%2BpS2mwJYqMMuVwiz8%2Bavy6pjpWCGFq1M9Kvv86AXk4cnwTECcuOUYL4495BK%2F3ZN1QFmbJmMvIwtEtQLPzwN1Bw%2FVYHCwEpnkamlWSdjO43fNvh8v3cPTG40rpdck%2Bde2I5I%2FARL3JQ%3D%3D)
176
+
177
+ ## Useful links
178
+
179
+ - https://en.wikipedia.org/wiki/Linear_interpolation
180
+ - https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
181
+ - https://easings.net/
@@ -0,0 +1,4 @@
1
+ import "../_global.js"
2
+ import * as tweenUtils from "./index.js"
3
+
4
+ globalThis.utils = Object.assign(globalThis.utils || {}, tweenUtils)