kippy 0.2.1 → 0.3.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/README.md +60 -20
- package/dist/entity.d.ts +3 -4
- package/dist/entity.js +4 -5
- package/dist/input.d.ts +8 -8
- package/dist/input.js +40 -20
- package/dist/physics.d.ts +5 -8
- package/dist/physics.js +13 -12
- package/dist/vector.d.ts +26 -0
- package/dist/vector.js +64 -0
- package/index.d.ts +2 -1
- package/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,8 +64,7 @@ import { Entity } from "kippy";
|
|
|
64
64
|
|
|
65
65
|
const entity = new Entity({
|
|
66
66
|
sprite, // Entity's sprite to be rendered, type Sprite
|
|
67
|
-
|
|
68
|
-
y, // Entity's y position (centered), type number
|
|
67
|
+
position, // Entity's position (centered), type Vector2
|
|
69
68
|
rotation, // Entity's rotation in radians, type number
|
|
70
69
|
body, // Entity's physical body, type EntityBody
|
|
71
70
|
});
|
|
@@ -76,8 +75,10 @@ scene.addEntity(entity);
|
|
|
76
75
|
scene.removeEntity(entity);
|
|
77
76
|
|
|
78
77
|
// These props contain movement info and you can mutate them to edit its position
|
|
79
|
-
entity.
|
|
80
|
-
|
|
78
|
+
entity.position; // Initialized from the "position" param above, Vector2(0, 0) if not specified
|
|
79
|
+
// You can mutate these directly:
|
|
80
|
+
entity.position.x;
|
|
81
|
+
entity.position.y;
|
|
81
82
|
entity.rotation; // Initialized from the "rotation" param above, 0 if not specified
|
|
82
83
|
```
|
|
83
84
|
|
|
@@ -99,7 +100,7 @@ entity.sprite = sprite;
|
|
|
99
100
|
|
|
100
101
|
### Add controls
|
|
101
102
|
|
|
102
|
-
Game controls like mouse presses, key presses, and
|
|
103
|
+
Game controls like mouse presses, key presses, touch, and cursor traking (in the game canvas, not the web window) can be done by using the input handler from your `game` instance:
|
|
103
104
|
```js
|
|
104
105
|
const input = game.input;
|
|
105
106
|
```
|
|
@@ -110,12 +111,50 @@ Then in a scene's `update` method, you can use these utilities to check for key
|
|
|
110
111
|
input.isKeyDown(/* Character/key here */); // true if key is held, false otherwise
|
|
111
112
|
input.isKeyPressed(/* Character/key here */); // true if key is pressed, false otherwise
|
|
112
113
|
input.isKeyReleased(/* Character/key here */); // true if key is released, false otherwise
|
|
113
|
-
// Mouse
|
|
114
|
-
input.
|
|
115
|
-
input.
|
|
116
|
-
input.
|
|
117
|
-
input.
|
|
118
|
-
input.
|
|
114
|
+
// Mouse/touch
|
|
115
|
+
input.isPointerDown(/* 0 for left, 1 for right, 2 for touch */); // true if held, false otherwise
|
|
116
|
+
input.isPointerPressed(/* 0 for left, 1 for right, 2 for touch */); // true if pressed, false otherwise
|
|
117
|
+
input.isPointerReleased(/* 0 for left, 1 for right, 2 for touch */); // true if released, false otherwise
|
|
118
|
+
input.pointerX; // Current X position of mouse/touch
|
|
119
|
+
input.pointerY; // Current Y position of mouse/touch
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Vectors
|
|
123
|
+
|
|
124
|
+
To work with positions and movements in Kippy, it is best to know about `Vector2` first. Positions, velocities, forces, etc are all represented as vectors in Kippy. And here is how you can create a 2D vector and some vector math utilities that comes along with it:
|
|
125
|
+
```js
|
|
126
|
+
import { Vector2 } from "kippy";
|
|
127
|
+
|
|
128
|
+
const vect = new Vector2(/* x coordinate, number */, /*y coordinate, number */);
|
|
129
|
+
|
|
130
|
+
// Props
|
|
131
|
+
vect.x; // X coordinate
|
|
132
|
+
vect.y; // Y coordinate
|
|
133
|
+
|
|
134
|
+
// Utilities
|
|
135
|
+
vect.add(otherVect); // Add another vector and return the result vector
|
|
136
|
+
vect.sub(otherVect); // Subtract another vector and return the result vector
|
|
137
|
+
vect.scale(scale); // Multiply with scale and return the result vector
|
|
138
|
+
vect.magnitude(); // Return the magnitude/length of vector
|
|
139
|
+
vect.normalize(); // Return the normalized vector by magnitude
|
|
140
|
+
vect.dot(otherVect); // Return dot product with another vector
|
|
141
|
+
vect.distance(otherVect); // Return distance to another vector
|
|
142
|
+
vect.copy(); // Return a copy (same coordinates, different reference)
|
|
143
|
+
vect.lerp(otherVect, scale); // Apply linear interpolation and return
|
|
144
|
+
vect.clamp(maxLength); // Clamp vector to have length below maxLength
|
|
145
|
+
vect.rotate(angle); // Return rotated vector by provided angle
|
|
146
|
+
vect.angle(); // Return angle of vector.
|
|
147
|
+
vect.angleTo(otherVec); // Return angle between this and another vector
|
|
148
|
+
vect.reflect(otherVect); // Return reflection/bounce back vector
|
|
149
|
+
vect.equals(otherVect); // Check if two vectors are equal
|
|
150
|
+
|
|
151
|
+
// Useful constants
|
|
152
|
+
Vector2.ZERO; // Vector2(0, 0)
|
|
153
|
+
Vector2.ONE; // Vector2(1, 1);
|
|
154
|
+
Vector2.UP; // Vector2(0, -1);
|
|
155
|
+
Vector2.DOWN; // Vector2(0, 1);
|
|
156
|
+
Vector2.LEFT; // Vector2(-1, 0);
|
|
157
|
+
Vector2.RIGHT; // Vector2(1, 0);
|
|
119
158
|
```
|
|
120
159
|
|
|
121
160
|
### Physics
|
|
@@ -124,13 +163,11 @@ For movements, currently you can create a `RigidBody`:
|
|
|
124
163
|
```js
|
|
125
164
|
// Create a rigid body
|
|
126
165
|
const rigidBody = new RigidBody({
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
rotationVelocity, // Angular/rotation velocity, type number
|
|
166
|
+
velocity, // Entity's velocity vector, type Vector2
|
|
167
|
+
rotationVelocity, // Entity's ngular/rotation velocity, type number
|
|
130
168
|
mass, // Entity's mass, type number
|
|
131
169
|
inertia, // Entity's inertia, type number
|
|
132
|
-
|
|
133
|
-
forceY, // Entity's force on Y axis, type number
|
|
170
|
+
force, // Entity's force vector, type Vector2
|
|
134
171
|
torque, // Entity's torque/rotational force, type number
|
|
135
172
|
});
|
|
136
173
|
|
|
@@ -138,13 +175,12 @@ const rigidBody = new RigidBody({
|
|
|
138
175
|
entity.body = rigidBody;
|
|
139
176
|
|
|
140
177
|
// And you can mutate these props to update movement every frame
|
|
141
|
-
entity.body.
|
|
142
|
-
entity.body.velocityY; // Set with the matching parameter above, default is 0
|
|
178
|
+
entity.body.velocity; // Set with the matching parameter above, default is Vector2(0, 0)
|
|
143
179
|
entity.body.rotationVelocity; // Set with the matching parameter above, default is 0
|
|
144
180
|
entity.body.mass; // Set with the matching parameter above, default is 1
|
|
145
181
|
entity.body.inertia; // Set with the matching parameter above, default is 1
|
|
146
|
-
|
|
147
|
-
entity.body.
|
|
182
|
+
// Note that forces are reset after every frame
|
|
183
|
+
entity.body.force; // Set with the matching parameter above, default is Vector2(0, 0)
|
|
148
184
|
entity.body.torque; // Set with the matching parameter above, default is 0
|
|
149
185
|
```
|
|
150
186
|
|
|
@@ -158,6 +194,10 @@ To be added, for now mutate `entity.sprite` to swap sprites and create animation
|
|
|
158
194
|
|
|
159
195
|
To be added, for now use web's built-in `Audio` class.
|
|
160
196
|
|
|
197
|
+
### Asset management
|
|
198
|
+
|
|
199
|
+
To be added.
|
|
200
|
+
|
|
161
201
|
## Copyrights and License
|
|
162
202
|
|
|
163
203
|
Copyrights © 2026 Nguyen Phu Minh.
|
package/dist/entity.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { EntityBody } from "./physics.js";
|
|
2
2
|
import { Sprite } from "./sprite.js";
|
|
3
|
+
import { Vector2 } from "./vector.js";
|
|
3
4
|
export interface EntityOptions {
|
|
4
5
|
sprite?: Sprite;
|
|
5
|
-
|
|
6
|
-
y?: number;
|
|
6
|
+
position?: Vector2;
|
|
7
7
|
rotation?: number;
|
|
8
8
|
body?: EntityBody;
|
|
9
9
|
}
|
|
10
10
|
export declare class Entity {
|
|
11
11
|
sprite?: Sprite;
|
|
12
|
-
|
|
13
|
-
y: number;
|
|
12
|
+
position: Vector2;
|
|
14
13
|
rotation: number;
|
|
15
14
|
body?: EntityBody;
|
|
16
15
|
constructor(options?: EntityOptions);
|
package/dist/entity.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
import { Vector2 } from "./vector.js";
|
|
1
2
|
export class Entity {
|
|
2
3
|
sprite;
|
|
3
|
-
|
|
4
|
-
y;
|
|
4
|
+
position;
|
|
5
5
|
rotation;
|
|
6
6
|
body;
|
|
7
7
|
constructor(options = {}) {
|
|
8
8
|
this.sprite = options.sprite;
|
|
9
|
-
this.
|
|
10
|
-
this.y = options.y ?? 0;
|
|
9
|
+
this.position = options.position ?? new Vector2(0, 0);
|
|
11
10
|
this.rotation = options.rotation ?? 0;
|
|
12
11
|
this.body = options.body;
|
|
13
12
|
}
|
|
14
13
|
render(ctx) {
|
|
15
14
|
if (this.sprite) {
|
|
16
15
|
ctx.save();
|
|
17
|
-
ctx.translate(this.x, this.y);
|
|
16
|
+
ctx.translate(this.position.x, this.position.y);
|
|
18
17
|
ctx.rotate(this.rotation);
|
|
19
18
|
ctx.drawImage(this.sprite.texture, -this.sprite.width / 2, -this.sprite.height / 2);
|
|
20
19
|
ctx.restore();
|
package/dist/input.d.ts
CHANGED
|
@@ -6,17 +6,17 @@ export declare class Input {
|
|
|
6
6
|
keys: Set<string>;
|
|
7
7
|
keysPressed: Set<string>;
|
|
8
8
|
keysReleased: Set<string>;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
pointerX: number;
|
|
10
|
+
pointerY: number;
|
|
11
|
+
pointers: Set<number>;
|
|
12
|
+
pointersPressed: Set<number>;
|
|
13
|
+
pointersReleased: Set<number>;
|
|
14
14
|
constructor(options: InputOptions);
|
|
15
15
|
update(): void;
|
|
16
16
|
isKeyDown(key: string): boolean;
|
|
17
17
|
isKeyPressed(key: string): boolean;
|
|
18
18
|
isKeyReleased(key: string): boolean;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
isPointerDown(button?: number): boolean;
|
|
20
|
+
isPointerPressed(button?: number): boolean;
|
|
21
|
+
isPointerReleased(button?: number): boolean;
|
|
22
22
|
}
|
package/dist/input.js
CHANGED
|
@@ -3,11 +3,11 @@ export class Input {
|
|
|
3
3
|
keys = new Set(); // Key on hold
|
|
4
4
|
keysPressed = new Set(); // Key pressed
|
|
5
5
|
keysReleased = new Set(); // Key released
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
pointerX = 0; // Mouse/touch coord x in canvas
|
|
7
|
+
pointerY = 0; // Mouse/touch coord y in canvas
|
|
8
|
+
pointers = new Set(); // Mouse/touch on hold
|
|
9
|
+
pointersPressed = new Set(); // Mouse/touch pressed
|
|
10
|
+
pointersReleased = new Set(); // Mouse/touch released
|
|
11
11
|
constructor(options) {
|
|
12
12
|
this.canvas = options.canvas;
|
|
13
13
|
// Keyboard
|
|
@@ -21,21 +21,40 @@ export class Input {
|
|
|
21
21
|
this.keys.delete(e.key);
|
|
22
22
|
this.keysReleased.add(e.key);
|
|
23
23
|
});
|
|
24
|
-
// Mouse
|
|
24
|
+
// Mouse and touch
|
|
25
25
|
this.canvas.addEventListener("mousemove", (e) => {
|
|
26
26
|
const rect = this.canvas.getBoundingClientRect();
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
27
|
+
this.pointerX = e.clientX - rect.left;
|
|
28
|
+
this.pointerY = e.clientY - rect.top;
|
|
29
29
|
});
|
|
30
30
|
this.canvas.addEventListener("mousedown", (e) => {
|
|
31
|
-
if (!this.
|
|
32
|
-
this.
|
|
31
|
+
if (!this.pointers.has(e.button)) {
|
|
32
|
+
this.pointersPressed.add(e.button);
|
|
33
33
|
}
|
|
34
|
-
this.
|
|
34
|
+
this.pointers.add(e.button);
|
|
35
35
|
});
|
|
36
36
|
this.canvas.addEventListener("mouseup", (e) => {
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
37
|
+
this.pointers.delete(e.button);
|
|
38
|
+
this.pointersReleased.add(e.button);
|
|
39
|
+
});
|
|
40
|
+
this.canvas.addEventListener("touchmove", (e) => {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
43
|
+
const touch = e.touches[0];
|
|
44
|
+
this.pointerX = touch.clientX - rect.left;
|
|
45
|
+
this.pointerY = touch.clientY - rect.top;
|
|
46
|
+
});
|
|
47
|
+
this.canvas.addEventListener("touchstart", (e) => {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
if (!this.pointers.has(2)) {
|
|
50
|
+
this.pointersPressed.add(2);
|
|
51
|
+
}
|
|
52
|
+
this.pointers.add(2);
|
|
53
|
+
});
|
|
54
|
+
this.canvas.addEventListener("touchend", (e) => {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
this.pointers.delete(2);
|
|
57
|
+
this.pointersReleased.add(2);
|
|
39
58
|
});
|
|
40
59
|
// Prevent right-click menu
|
|
41
60
|
this.canvas.addEventListener("contextmenu", (e) => {
|
|
@@ -46,7 +65,8 @@ export class Input {
|
|
|
46
65
|
update() {
|
|
47
66
|
this.keysPressed.clear();
|
|
48
67
|
this.keysReleased.clear();
|
|
49
|
-
this.
|
|
68
|
+
this.pointersPressed.clear();
|
|
69
|
+
this.pointersReleased.clear();
|
|
50
70
|
}
|
|
51
71
|
// Helper methods
|
|
52
72
|
isKeyDown(key) {
|
|
@@ -58,13 +78,13 @@ export class Input {
|
|
|
58
78
|
isKeyReleased(key) {
|
|
59
79
|
return this.keysReleased.has(key);
|
|
60
80
|
}
|
|
61
|
-
|
|
62
|
-
return this.
|
|
81
|
+
isPointerDown(button = 0) {
|
|
82
|
+
return this.pointers.has(button);
|
|
63
83
|
}
|
|
64
|
-
|
|
65
|
-
return this.
|
|
84
|
+
isPointerPressed(button = 0) {
|
|
85
|
+
return this.pointersPressed.has(button);
|
|
66
86
|
}
|
|
67
|
-
|
|
68
|
-
return this.
|
|
87
|
+
isPointerReleased(button = 0) {
|
|
88
|
+
return this.pointersReleased.has(button);
|
|
69
89
|
}
|
|
70
90
|
}
|
package/dist/physics.d.ts
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import { Entity } from "./entity";
|
|
2
|
+
import { Vector2 } from "./vector";
|
|
2
3
|
export interface RigidBodyOptions {
|
|
3
|
-
|
|
4
|
-
velocityY?: number;
|
|
4
|
+
velocity?: Vector2;
|
|
5
5
|
rotationVelocity?: number;
|
|
6
6
|
mass?: number;
|
|
7
7
|
inertia?: number;
|
|
8
|
-
|
|
9
|
-
forceY?: number;
|
|
8
|
+
force?: Vector2;
|
|
10
9
|
torque?: number;
|
|
11
10
|
}
|
|
12
11
|
export declare class RigidBody {
|
|
13
|
-
|
|
14
|
-
velocityY: number;
|
|
12
|
+
velocity: Vector2;
|
|
15
13
|
rotationVelocity: number;
|
|
16
14
|
mass: number;
|
|
17
15
|
inertia: number;
|
|
18
|
-
|
|
19
|
-
forceY: number;
|
|
16
|
+
force: Vector2;
|
|
20
17
|
torque: number;
|
|
21
18
|
constructor(options?: RigidBodyOptions);
|
|
22
19
|
}
|
package/dist/physics.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
+
import { Vector2 } from "./vector";
|
|
1
2
|
export class RigidBody {
|
|
2
|
-
|
|
3
|
-
velocityY;
|
|
3
|
+
velocity;
|
|
4
4
|
rotationVelocity;
|
|
5
5
|
mass;
|
|
6
6
|
inertia;
|
|
7
|
-
|
|
8
|
-
forceY;
|
|
7
|
+
force;
|
|
9
8
|
torque;
|
|
10
9
|
constructor(options = {}) {
|
|
11
|
-
this.
|
|
12
|
-
this.velocityY = options.velocityY ?? 0;
|
|
10
|
+
this.velocity = options.velocity ?? new Vector2(0, 0);
|
|
13
11
|
this.rotationVelocity = options.rotationVelocity ?? 0;
|
|
14
12
|
this.mass = options.mass ?? 1;
|
|
15
13
|
this.inertia = options.inertia ?? 1;
|
|
16
|
-
this.
|
|
17
|
-
this.forceY = options.forceY ?? 0;
|
|
14
|
+
this.force = options.force ?? new Vector2(0, 0);
|
|
18
15
|
this.torque = options.torque ?? 0;
|
|
19
16
|
}
|
|
20
17
|
}
|
|
@@ -23,13 +20,17 @@ export class Physics {
|
|
|
23
20
|
for (const entity of entities) {
|
|
24
21
|
if (entity.body instanceof RigidBody) {
|
|
25
22
|
// Acceleration/apply force
|
|
26
|
-
entity.body.
|
|
27
|
-
entity.body.
|
|
23
|
+
entity.body.velocity.x += entity.body.force.x / entity.body.mass;
|
|
24
|
+
entity.body.velocity.y += entity.body.force.y / entity.body.mass;
|
|
28
25
|
entity.body.rotationVelocity += entity.body.torque / entity.body.inertia;
|
|
29
26
|
// Positional update
|
|
30
|
-
entity.x += entity.body.
|
|
31
|
-
entity.y += entity.body.
|
|
27
|
+
entity.position.x += entity.body.velocity.x;
|
|
28
|
+
entity.position.y += entity.body.velocity.y;
|
|
32
29
|
entity.rotation += entity.body.rotationVelocity;
|
|
30
|
+
// Clear force
|
|
31
|
+
entity.body.force.x = 0;
|
|
32
|
+
entity.body.force.y = 0;
|
|
33
|
+
entity.body.torque = 0;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
}
|
package/dist/vector.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class Vector2 {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
static ZERO: Vector2;
|
|
5
|
+
static ONE: Vector2;
|
|
6
|
+
static UP: Vector2;
|
|
7
|
+
static DOWN: Vector2;
|
|
8
|
+
static LEFT: Vector2;
|
|
9
|
+
static RIGHT: Vector2;
|
|
10
|
+
constructor(x: number, y: number);
|
|
11
|
+
add(other: Vector2): Vector2;
|
|
12
|
+
sub(other: Vector2): Vector2;
|
|
13
|
+
scale(scale: number): Vector2;
|
|
14
|
+
magnitude(): number;
|
|
15
|
+
normalize(): Vector2;
|
|
16
|
+
dot(other: Vector2): number;
|
|
17
|
+
distance(other: Vector2): number;
|
|
18
|
+
copy(): Vector2;
|
|
19
|
+
lerp(other: Vector2, scale: number): Vector2;
|
|
20
|
+
clamp(maxLength: number): Vector2;
|
|
21
|
+
rotate(angle: number): Vector2;
|
|
22
|
+
angle(): number;
|
|
23
|
+
angleTo(other: Vector2): number;
|
|
24
|
+
reflect(normal: Vector2): Vector2;
|
|
25
|
+
equals(other: Vector2): boolean;
|
|
26
|
+
}
|
package/dist/vector.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class Vector2 {
|
|
2
|
+
x;
|
|
3
|
+
y;
|
|
4
|
+
static ZERO = new Vector2(0, 0);
|
|
5
|
+
static ONE = new Vector2(1, 1);
|
|
6
|
+
static UP = new Vector2(0, -1);
|
|
7
|
+
static DOWN = new Vector2(0, 1);
|
|
8
|
+
static LEFT = new Vector2(-1, 0);
|
|
9
|
+
static RIGHT = new Vector2(1, 0);
|
|
10
|
+
constructor(x, y) {
|
|
11
|
+
this.x = x;
|
|
12
|
+
this.y = y;
|
|
13
|
+
}
|
|
14
|
+
add(other) {
|
|
15
|
+
return new Vector2(this.x + other.x, this.y + other.y);
|
|
16
|
+
}
|
|
17
|
+
sub(other) {
|
|
18
|
+
return new Vector2(this.x - other.x, this.y - other.y);
|
|
19
|
+
}
|
|
20
|
+
scale(scale) {
|
|
21
|
+
return new Vector2(this.x * scale, this.y * scale);
|
|
22
|
+
}
|
|
23
|
+
magnitude() {
|
|
24
|
+
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
25
|
+
}
|
|
26
|
+
normalize() {
|
|
27
|
+
const mag = this.magnitude();
|
|
28
|
+
return mag > 0 ? new Vector2(this.x / mag, this.y / mag) : new Vector2(0, 0);
|
|
29
|
+
}
|
|
30
|
+
dot(other) {
|
|
31
|
+
return this.x * other.x + this.y * other.y;
|
|
32
|
+
}
|
|
33
|
+
distance(other) {
|
|
34
|
+
return Math.sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2);
|
|
35
|
+
}
|
|
36
|
+
copy() {
|
|
37
|
+
return new Vector2(this.x, this.y);
|
|
38
|
+
}
|
|
39
|
+
lerp(other, scale) {
|
|
40
|
+
return this.add(other.sub(this).scale(scale));
|
|
41
|
+
}
|
|
42
|
+
clamp(maxLength) {
|
|
43
|
+
const mag = this.magnitude();
|
|
44
|
+
return mag > maxLength ? this.scale(maxLength / mag) : this.copy();
|
|
45
|
+
}
|
|
46
|
+
rotate(angle) {
|
|
47
|
+
const cos = Math.cos(angle);
|
|
48
|
+
const sin = Math.sin(angle);
|
|
49
|
+
return new Vector2(this.x * cos - this.y * sin, this.x * sin + this.y * cos);
|
|
50
|
+
}
|
|
51
|
+
angle() {
|
|
52
|
+
return Math.atan2(this.y, this.x);
|
|
53
|
+
}
|
|
54
|
+
angleTo(other) {
|
|
55
|
+
return Math.atan2(other.y - this.y, other.x - this.x);
|
|
56
|
+
}
|
|
57
|
+
reflect(normal) {
|
|
58
|
+
const d = this.dot(normal);
|
|
59
|
+
return this.sub(normal.scale(2 * d));
|
|
60
|
+
}
|
|
61
|
+
equals(other) {
|
|
62
|
+
return this.x === other.x && this.y === other.y;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/index.d.ts
CHANGED
package/index.js
CHANGED