@nixia/2d 0.0.2 → 0.0.3
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/LICENSE +1 -1
- package/README.md +90 -4
- package/cli.js +69 -53
- package/index.html +1 -1
- package/package.json +8 -4
- package/publish.js +0 -0
- package/src/core/Actor.ts +7 -1
- package/src/core/Application.ts +56 -2
- package/src/core/ITickable.ts +5 -0
- package/src/core/Level.ts +15 -2
- package/src/core/RenderBuffer.ts +13 -0
- package/src/core/Renderer.ts +26 -0
- package/src/index.ts +2 -0
- package/src/main.ts +7 -3
- package/cli.json +0 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,92 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🎮 NIXIA 2D Game Engine
|
|
2
|
+
> A lightning-fast, lightweight 2D game engine written entirely in TypeScript, engineered from the ground up to run seamlessly on low-power machines and resource-constrained devices.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 🚀 Getting Started
|
|
7
|
+
|
|
8
|
+
Getting your first Nixia project up and running takes less than a minute. Follow these simple steps:
|
|
9
|
+
|
|
10
|
+
### 1. Initialize your workspace
|
|
11
|
+
Create a new directory for your game and step into it:
|
|
4
12
|
```bash
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
mkdir my-game
|
|
14
|
+
cd my-game
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. Install the core package
|
|
18
|
+
Install the NIXIA package as a development dependency (this automatically pulls in Vite and all other required toolchain dependencies):
|
|
19
|
+
```bash
|
|
20
|
+
npm install -D @nixia/2d
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 3. Initialize your project structure
|
|
24
|
+
Run the built-in CLI tool to scaffold your configuration files and entry point:
|
|
25
|
+
```bash
|
|
26
|
+
nixia init
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Once initialization is complete, you are ready to write code! Your application's main entry point is located at `src/main.ts`
|
|
30
|
+
|
|
31
|
+
## 🏗️ Creating Your First Level
|
|
32
|
+
Levels represent the scenes or stages of your game. To create a new level, generate a new TypeScript file inside `src/levels/MyLevel.ts`, extend the core `Nixia.Level` class, and configure it:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// src/levels/MyLevel.ts
|
|
36
|
+
import * as Nixia from '@nixia/2d';
|
|
37
|
+
|
|
38
|
+
export class MyLevel extends Nixia.Level {
|
|
39
|
+
constructor() {
|
|
40
|
+
super("MyLevel");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Then in your `src/main.ts`, you can make this your default level by using the following code:
|
|
46
|
+
```ts
|
|
47
|
+
// src/main.ts
|
|
48
|
+
import * as Nixia from '@nixia/2d';
|
|
49
|
+
import { MyLevel } from './levels/MyLevel';
|
|
50
|
+
|
|
51
|
+
// Preload your level
|
|
52
|
+
const myLevel = new MyLevel();
|
|
53
|
+
|
|
54
|
+
// Create a new Application
|
|
55
|
+
const app = new Nixia.Application();
|
|
56
|
+
|
|
57
|
+
// Set the default level to our custom level
|
|
58
|
+
app.setDefaultLevel(myLevel);
|
|
59
|
+
|
|
60
|
+
// Start the application
|
|
61
|
+
app.start();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 👾 Creating Your First Actor
|
|
65
|
+
Actors represent game objects—or more specifically, active entities living inside a level. They handle components, custom game logic, rendering, physics, and more. You can create one like this:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// src/actors/MyActor.ts
|
|
69
|
+
import * as Nixia from '@nixia/2d';
|
|
70
|
+
|
|
71
|
+
export class MyActor extends Nixai.Actor {
|
|
72
|
+
constructor() {
|
|
73
|
+
super("MyActor");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
You can add your Actor to your Level like this:
|
|
79
|
+
```ts
|
|
80
|
+
// src/levels/MyLevel.ts
|
|
81
|
+
import * as Nixia from '@nixia/2d';
|
|
82
|
+
import { MyActor } from './actors/MyActor';
|
|
83
|
+
|
|
84
|
+
export class MyLevel extends Nixia.Level {
|
|
85
|
+
constructor() {
|
|
86
|
+
super("MyLevel");
|
|
87
|
+
|
|
88
|
+
// This both adds the actor to the scene and registers it with
|
|
89
|
+
// the game lifecycle.
|
|
90
|
+
this.root.add(new MyActor(this, this.app));
|
|
91
|
+
}
|
|
92
|
+
}
|
package/cli.js
CHANGED
|
@@ -2,31 +2,6 @@
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
|
|
5
|
-
const BASE_URL = "https://nixia-2d-cli.nakoyasoftware.com/components/";
|
|
6
|
-
|
|
7
|
-
// Define all components in a single configuration array to maintain DRY principles
|
|
8
|
-
const COMPONENTS = [
|
|
9
|
-
{ name: "index.html", dest: "index.html" },
|
|
10
|
-
{ name: "vite.config.ts", dest: "vite.config.ts" },
|
|
11
|
-
{ name: "tsconfig.json", dest: "tsconfig.json" },
|
|
12
|
-
{ name: "main.ts", dest: path.join("src", "main.ts") }
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Generic helper function to download any file from the remote components repository.
|
|
17
|
-
*/
|
|
18
|
-
async function downloadFile(filename) {
|
|
19
|
-
try {
|
|
20
|
-
const response = await fetch(`${BASE_URL}${filename}`);
|
|
21
|
-
if (!response.ok) {
|
|
22
|
-
throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
|
|
23
|
-
}
|
|
24
|
-
return await response.text();
|
|
25
|
-
} catch (e) {
|
|
26
|
-
throw new Error(`Failed to download '${filename}': ${e.message}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
5
|
async function runCli() {
|
|
31
6
|
console.log('🔍 Running pre-flight environment checks...');
|
|
32
7
|
|
|
@@ -44,38 +19,79 @@ async function runCli() {
|
|
|
44
19
|
}
|
|
45
20
|
console.log('✅ Pre-flight checks passed successfully!');
|
|
46
21
|
|
|
47
|
-
console.log('
|
|
48
|
-
const downloadedContent = {};
|
|
49
|
-
|
|
50
|
-
// Loop through our configuration array instead of writing duplicate functions
|
|
51
|
-
for (let i = 0; i < COMPONENTS.length; i++) {
|
|
52
|
-
const component = COMPONENTS[i];
|
|
53
|
-
console.log(`📥 Downloading component ${i + 1} of ${COMPONENTS.length}: ${component.name}...`);
|
|
54
|
-
downloadedContent[component.name] = await downloadFile(component.name);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log('💾 Writing files to disk...');
|
|
22
|
+
console.log('💾 Creating project structure and writing files locally...');
|
|
58
23
|
|
|
59
24
|
// Ensure the src directory exists before writing nested files
|
|
60
25
|
fs.mkdirSync("src", { recursive: true });
|
|
61
26
|
|
|
62
|
-
// Write
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
27
|
+
// 1. Write index.html
|
|
28
|
+
const indexHtmlContent = `<!DOCTYPE html>
|
|
29
|
+
<html lang="en">
|
|
30
|
+
<head>
|
|
31
|
+
<meta charset="utf-8">
|
|
32
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
33
|
+
<title>Nixia Engine Default Game</title>
|
|
34
|
+
</head>
|
|
35
|
+
<body>
|
|
36
|
+
<script type="module" src="./src/main.ts"></script>
|
|
37
|
+
</body>
|
|
38
|
+
</html>`;
|
|
39
|
+
fs.writeFileSync("index.html", indexHtmlContent);
|
|
40
|
+
console.log('📄 Created index.html successfully!');
|
|
41
|
+
|
|
42
|
+
// 2. Write tsconfig.json (Fixed the missing filename bug!)
|
|
43
|
+
const tsConfigData = {
|
|
44
|
+
"compilerOptions": {
|
|
45
|
+
"target": "ESNext",
|
|
46
|
+
"useDefineForClassFields": true,
|
|
47
|
+
"module": "ESNext",
|
|
48
|
+
"moduleResolution": "bundler",
|
|
49
|
+
"isolatedModules": true,
|
|
50
|
+
"strict": true,
|
|
51
|
+
"noUnusedLocals": true,
|
|
52
|
+
"noUnusedParameters": true,
|
|
53
|
+
"noImplicitReturns": true,
|
|
54
|
+
"skipLibCheck": true,
|
|
55
|
+
"resolveJsonModule": true,
|
|
56
|
+
"esModuleInterop": true,
|
|
57
|
+
"allowSyntheticDefaultImports": true,
|
|
58
|
+
"types": ["vite/client"]
|
|
59
|
+
},
|
|
60
|
+
"include": ["src/**/*", "vite.config.ts"]
|
|
61
|
+
};
|
|
62
|
+
fs.writeFileSync("tsconfig.json", JSON.stringify(tsConfigData, null, 2));
|
|
63
|
+
console.log('📄 Created tsconfig.json successfully!');
|
|
64
|
+
|
|
65
|
+
// 3. Write vite.config.ts
|
|
66
|
+
const viteConfigContent = `import { defineConfig } from 'vite';
|
|
67
|
+
import { viteSingleFile } from 'vite-plugin-singlefile';
|
|
68
|
+
|
|
69
|
+
export default defineConfig({
|
|
70
|
+
plugins: [viteSingleFile()],
|
|
71
|
+
build: {
|
|
72
|
+
target: 'esnext',
|
|
73
|
+
assetsInlineLimit: 100000000,
|
|
74
|
+
chunkSizeWarningLimit: 100000000,
|
|
75
|
+
cssCodeSplit: false,
|
|
76
|
+
rollupOptions: {
|
|
77
|
+
output: {
|
|
78
|
+
inlineDynamicImports: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});`;
|
|
83
|
+
fs.writeFileSync("vite.config.ts", viteConfigContent);
|
|
84
|
+
console.log('📄 Created vite.config.ts successfully!');
|
|
85
|
+
|
|
86
|
+
// 4. Write src/main.ts
|
|
87
|
+
const mainTsContent = `// This is the entry point for your game.
|
|
88
|
+
import * as Nixia from '@nixia/2d';
|
|
89
|
+
|
|
90
|
+
// Hello, world!`;
|
|
91
|
+
fs.writeFileSync(path.join("src", "main.ts"), mainTsContent);
|
|
92
|
+
console.log('📄 Created src/main.ts successfully!');
|
|
93
|
+
|
|
94
|
+
console.log('✅ All project components written to disk successfully!');
|
|
79
95
|
|
|
80
96
|
console.log('📦 Updating package.json configuration...');
|
|
81
97
|
const packageJsonPath = path.join("package.json");
|
package/index.html
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nixia/2d",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Aedan Maki",
|
|
6
6
|
"email": "aedanmaki@gmail.com"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "./src/index.ts",
|
|
12
12
|
"module": "./src/index.ts",
|
|
13
|
+
"keywords": ["game-engine", "2d"],
|
|
13
14
|
"exports": {
|
|
14
15
|
".": {
|
|
15
16
|
"import": "./src/index.ts",
|
|
@@ -19,11 +20,14 @@
|
|
|
19
20
|
"scripts": {
|
|
20
21
|
"dev": "vite",
|
|
21
22
|
"build": "vite build",
|
|
22
|
-
"preview": "vite preview"
|
|
23
|
+
"preview": "vite preview",
|
|
24
|
+
"publish": "nixia publish"
|
|
23
25
|
},
|
|
24
|
-
"
|
|
26
|
+
"devDependencies": {
|
|
25
27
|
"fs": "^0.0.1-security",
|
|
26
|
-
"path": "^0.12.7"
|
|
28
|
+
"path": "^0.12.7"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
27
31
|
"typescript": "^7.0.2",
|
|
28
32
|
"vite": "^8.3.5",
|
|
29
33
|
"vite-plugin-singlefile": "^2.3.4"
|
package/publish.js
ADDED
|
File without changes
|
package/src/core/Actor.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
// src/core/Actor.ts
|
|
2
2
|
import { Base } from "./Base";
|
|
3
|
+
import { ITickable } from "./ITickable";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Represents an Actor.
|
|
6
7
|
*/
|
|
7
|
-
export class Actor extends Base {
|
|
8
|
+
export class Actor extends Base implements ITickable {
|
|
8
9
|
/**
|
|
9
10
|
* Creates a new Actor.
|
|
10
11
|
*/
|
|
11
12
|
constructor() {
|
|
12
13
|
super();
|
|
13
14
|
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Called on tick.
|
|
18
|
+
*/
|
|
19
|
+
tick(dt: number): void {}
|
|
14
20
|
}
|
package/src/core/Application.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/core/Application.ts
|
|
2
2
|
import { Base } from "./Base";
|
|
3
|
+
import { ITickable } from "./ITickable";
|
|
4
|
+
import { Renderer } from "./Renderer";
|
|
5
|
+
import { Level } from "./Level";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Represents an Application.
|
|
@@ -10,17 +13,44 @@ export class Application extends Base {
|
|
|
10
13
|
*/
|
|
11
14
|
private wasInitialized: boolean = false;
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* If the game is ready.
|
|
18
|
+
*/
|
|
19
|
+
private isReady: boolean = false;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Previous tick time.
|
|
23
|
+
*/
|
|
24
|
+
private previousTickTime: number = Date.now();
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* An array of every tickable instance.
|
|
28
|
+
*/
|
|
29
|
+
private tickableInstances: ITickable[] = [];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The renderer instance.
|
|
33
|
+
*/
|
|
34
|
+
private renderer: Renderer;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The default level.
|
|
38
|
+
*/
|
|
39
|
+
private defaultLevel!: Level;
|
|
40
|
+
|
|
13
41
|
/**
|
|
14
42
|
* Creates a new Application.
|
|
15
43
|
*/
|
|
16
44
|
constructor() {
|
|
17
45
|
super();
|
|
46
|
+
|
|
47
|
+
this.renderer = new Renderer();
|
|
18
48
|
}
|
|
19
49
|
|
|
20
50
|
/**
|
|
21
|
-
*
|
|
51
|
+
* Starts the Application.
|
|
22
52
|
*/
|
|
23
|
-
|
|
53
|
+
start() {
|
|
24
54
|
if (this.wasInitialized) throw new Error('Application is already initialized.');
|
|
25
55
|
this.wasInitialized = true;
|
|
26
56
|
|
|
@@ -37,6 +67,8 @@ export class Application extends Base {
|
|
|
37
67
|
* Called when the game is ready.
|
|
38
68
|
*/
|
|
39
69
|
private _ready() {
|
|
70
|
+
this.isReady = true;
|
|
71
|
+
if (!this.defaultLevel) throw new Error("No default level was assigned, cannot create game.");
|
|
40
72
|
this.fire('ready');
|
|
41
73
|
|
|
42
74
|
requestAnimationFrame(this._tick);
|
|
@@ -46,6 +78,28 @@ export class Application extends Base {
|
|
|
46
78
|
* Called on tick.
|
|
47
79
|
*/
|
|
48
80
|
private _tick = () => {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
const delta = now - this.previousTickTime;
|
|
83
|
+
|
|
84
|
+
const len = this.tickableInstances.length;
|
|
85
|
+
for (let i = 0; i < len; i++) {
|
|
86
|
+
const inst = this.tickableInstances[i];
|
|
87
|
+
inst.tick(delta);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.renderer.clear();
|
|
91
|
+
this.renderer.draw();
|
|
92
|
+
|
|
93
|
+
this.previousTickTime = now;
|
|
94
|
+
|
|
49
95
|
requestAnimationFrame(this._tick);
|
|
50
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Sets the default level.
|
|
100
|
+
*/
|
|
101
|
+
setDefaultLevel(defaultLevel: Level) {
|
|
102
|
+
if (this.isReady) throw new Error("Cannot assign a default level when the game is already running.");
|
|
103
|
+
this.defaultLevel = defaultLevel;
|
|
104
|
+
}
|
|
51
105
|
}
|
package/src/core/Level.ts
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
// src/core/Level.ts
|
|
2
2
|
import { Base } from "./Base";
|
|
3
|
+
import { ITickable } from "./ITickable";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Represents a Level.
|
|
6
7
|
*/
|
|
7
|
-
export class Level extends Base {
|
|
8
|
+
export class Level extends Base implements ITickable {
|
|
9
|
+
/**
|
|
10
|
+
* The level name.
|
|
11
|
+
*/
|
|
12
|
+
private name: string;
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* Creates a new Level.
|
|
10
16
|
*/
|
|
11
|
-
constructor() {
|
|
17
|
+
constructor(name: string) {
|
|
12
18
|
super();
|
|
19
|
+
|
|
20
|
+
this.name = name;
|
|
13
21
|
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Called on tick.
|
|
25
|
+
*/
|
|
26
|
+
tick(dt: number): void {}
|
|
14
27
|
}
|
package/src/core/Renderer.ts
CHANGED
|
@@ -5,10 +5,36 @@ import { Base } from "./Base";
|
|
|
5
5
|
* Represents a Renderer.
|
|
6
6
|
*/
|
|
7
7
|
export class Renderer extends Base {
|
|
8
|
+
/**
|
|
9
|
+
* The canvas element.
|
|
10
|
+
*/
|
|
11
|
+
private canvas: HTMLCanvasElement;
|
|
12
|
+
|
|
8
13
|
/**
|
|
9
14
|
* Creates a new Renderer.
|
|
10
15
|
*/
|
|
11
16
|
constructor() {
|
|
12
17
|
super();
|
|
18
|
+
|
|
19
|
+
const canvas = document.createElement("canvas") as HTMLCanvasElement;
|
|
20
|
+
this.canvas = canvas;
|
|
21
|
+
this.canvas.width = 600;
|
|
22
|
+
this.canvas.height = 400;
|
|
23
|
+
this.canvas.style.border = "1px solid black";
|
|
24
|
+
document.body.appendChild(this.canvas);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Completely clears the canvas.
|
|
29
|
+
*/
|
|
30
|
+
clear() {
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Draws the buffers onto the canvas.
|
|
36
|
+
*/
|
|
37
|
+
draw() {
|
|
38
|
+
|
|
13
39
|
}
|
|
14
40
|
}
|
package/src/index.ts
CHANGED
package/src/main.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as Nixia from './index';
|
|
2
|
+
import { MyLevel } from './test/MyLevel';
|
|
2
3
|
|
|
3
|
-
const app = new
|
|
4
|
-
|
|
4
|
+
const app = new Nixia.Application();
|
|
5
|
+
|
|
6
|
+
app.setDefaultLevel(new MyLevel());
|
|
7
|
+
|
|
8
|
+
app.start();
|
package/cli.json
DELETED