create-gamenative-app 0.1.5 → 0.1.7
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/bin/create.js +170 -37
- package/dist/scripts/Game.d.ts +11 -0
- package/dist/scripts/Game.d.ts.map +1 -0
- package/dist/scripts/Game.js +83 -0
- package/dist/scripts/Game.js.map +1 -0
- package/dist/scripts/Graphics.d.ts +12 -0
- package/dist/scripts/Graphics.d.ts.map +1 -0
- package/dist/scripts/Graphics.js +96 -0
- package/dist/scripts/Graphics.js.map +1 -0
- package/dist/scripts/Input.d.ts +55 -0
- package/dist/scripts/Input.d.ts.map +1 -0
- package/dist/scripts/Input.js +69 -0
- package/dist/scripts/Input.js.map +1 -0
- package/dist/scripts/Text.d.ts +50 -0
- package/dist/scripts/Text.d.ts.map +1 -0
- package/dist/scripts/Text.js +136 -0
- package/dist/scripts/Text.js.map +1 -0
- package/dist/scripts/UI.d.ts +6 -0
- package/dist/scripts/UI.d.ts.map +1 -0
- package/dist/scripts/UI.js +8 -0
- package/dist/scripts/UI.js.map +1 -0
- package/dist/scripts/config.d.ts +12 -0
- package/dist/scripts/config.d.ts.map +1 -0
- package/dist/scripts/config.js +14 -0
- package/dist/scripts/config.js.map +1 -0
- package/dist/scripts/icon.d.ts +7 -0
- package/dist/scripts/icon.d.ts.map +1 -0
- package/dist/scripts/icon.js +16 -0
- package/dist/scripts/icon.js.map +1 -0
- package/dist/scripts/index.d.ts +10 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +5 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/scripts/main.d.ts +2 -0
- package/dist/scripts/main.d.ts.map +1 -0
- package/dist/scripts/main.js +33 -0
- package/dist/scripts/main.js.map +1 -0
- package/dist/scripts/types.d.ts +33 -0
- package/dist/scripts/types.d.ts.map +1 -0
- package/dist/scripts/types.js +2 -0
- package/dist/scripts/types.js.map +1 -0
- package/dist/src/games/ExampleGame.d.ts +11 -0
- package/dist/src/games/ExampleGame.d.ts.map +1 -0
- package/dist/src/games/ExampleGame.js +36 -0
- package/dist/src/games/ExampleGame.js.map +1 -0
- package/package.json +15 -9
- package/{src → scripts}/Graphics.ts +24 -0
- package/scripts/Text.ts +159 -0
- package/scripts/UI.ts +8 -0
- package/{src → scripts}/config.ts +1 -1
- package/scripts/earcut.d.ts +4 -0
- package/{src → scripts}/index.ts +3 -0
- package/{src → scripts}/main.ts +1 -1
- package/scripts/opentype.d.ts +8 -0
- package/scripts/set-exe-icon.js +36 -0
- package/src/assets/icon.png +0 -0
- package/src/games/ExampleGame.ts +2 -2
- package/tsconfig.json +1 -1
- /package/{src → scripts}/Game.ts +0 -0
- /package/{src → scripts}/Input.ts +0 -0
- /package/{src → scripts}/icon.ts +0 -0
- /package/{src → scripts}/pngjs.d.ts +0 -0
- /package/{src → scripts}/types.ts +0 -0
package/bin/create.js
CHANGED
|
@@ -43,18 +43,28 @@ async function scaffold(projectName, parentDir) {
|
|
|
43
43
|
indexTs,
|
|
44
44
|
iconTs,
|
|
45
45
|
pngjsDts,
|
|
46
|
+
opentypeDts,
|
|
47
|
+
earcutDts,
|
|
48
|
+
textTs,
|
|
49
|
+
uiTs,
|
|
46
50
|
copyConfigJs,
|
|
51
|
+
setExeIconJs,
|
|
47
52
|
] = await Promise.all([
|
|
48
|
-
copyFrameworkFile('
|
|
49
|
-
copyFrameworkFile('
|
|
50
|
-
copyFrameworkFile('
|
|
51
|
-
copyFrameworkFile('
|
|
52
|
-
copyFrameworkFile('
|
|
53
|
-
copyFrameworkFile('
|
|
54
|
-
copyFrameworkFile('
|
|
55
|
-
copyFrameworkFile('
|
|
56
|
-
copyFrameworkFile('
|
|
53
|
+
copyFrameworkFile('scripts/main.ts'),
|
|
54
|
+
copyFrameworkFile('scripts/config.ts'),
|
|
55
|
+
copyFrameworkFile('scripts/Game.ts'),
|
|
56
|
+
copyFrameworkFile('scripts/Input.ts'),
|
|
57
|
+
copyFrameworkFile('scripts/Graphics.ts'),
|
|
58
|
+
copyFrameworkFile('scripts/types.ts'),
|
|
59
|
+
copyFrameworkFile('scripts/index.ts'),
|
|
60
|
+
copyFrameworkFile('scripts/icon.ts'),
|
|
61
|
+
copyFrameworkFile('scripts/pngjs.d.ts'),
|
|
62
|
+
readFile(join(FRAMEWORK_ROOT, 'scripts/opentype.d.ts'), 'utf-8'),
|
|
63
|
+
readFile(join(FRAMEWORK_ROOT, 'scripts/earcut.d.ts'), 'utf-8'),
|
|
64
|
+
copyFrameworkFile('scripts/Text.ts'),
|
|
65
|
+
copyFrameworkFile('scripts/UI.ts'),
|
|
57
66
|
readFile(join(FRAMEWORK_ROOT, 'scripts/copy-config.js'), 'utf-8'),
|
|
67
|
+
readFile(join(FRAMEWORK_ROOT, 'scripts/set-exe-icon.js'), 'utf-8'),
|
|
58
68
|
])
|
|
59
69
|
|
|
60
70
|
const gameConfig = {
|
|
@@ -72,29 +82,33 @@ async function scaffold(projectName, parentDir) {
|
|
|
72
82
|
version: '0.1.0',
|
|
73
83
|
description: `Game built with GameNative`,
|
|
74
84
|
type: 'module',
|
|
75
|
-
main: 'dist/main.js',
|
|
85
|
+
main: 'dist/scripts/main.js',
|
|
76
86
|
scripts: {
|
|
77
|
-
dev: 'cross-env NODE_ENV=development tsx
|
|
87
|
+
dev: 'cross-env NODE_ENV=development tsx scripts/main.ts',
|
|
78
88
|
build: 'tsc',
|
|
79
|
-
start: 'node dist/main.js',
|
|
80
|
-
'build:exe': 'npm run build && node scripts/copy-config.js && pkg . --output release/' + name + '.exe',
|
|
89
|
+
start: 'node dist/scripts/main.js',
|
|
90
|
+
'build:exe': 'npm run build && node scripts/copy-config.js && pkg . --output release/' + name + '.exe && node scripts/set-exe-icon.js release/' + name + '.exe',
|
|
81
91
|
},
|
|
82
92
|
dependencies: {
|
|
83
93
|
'@kmamal/gl': '^9.1.0',
|
|
84
94
|
'@kmamal/sdl': '^0.11.13',
|
|
95
|
+
earcut: '^3.0.0',
|
|
85
96
|
pngjs: '^7.0.0',
|
|
97
|
+
'opentype.js': '^1.3.4',
|
|
86
98
|
},
|
|
87
99
|
devDependencies: {
|
|
88
100
|
'@types/node': '^22.10.0',
|
|
89
101
|
'cross-env': '^7.0.3',
|
|
90
102
|
pkg: '^5.8.1',
|
|
103
|
+
rcedit: '^5.0.0',
|
|
91
104
|
tsx: '^4.19.2',
|
|
105
|
+
'to-ico': '^1.1.5',
|
|
92
106
|
typescript: '^5.7.0',
|
|
93
107
|
},
|
|
94
108
|
engines: { node: '>=18' },
|
|
95
109
|
pkg: {
|
|
96
|
-
scripts: 'dist/main.js',
|
|
97
|
-
assets: ['node_modules/@kmamal/sdl/**', 'node_modules/@kmamal/gl/**', 'dist/games/**'],
|
|
110
|
+
scripts: 'dist/scripts/main.js',
|
|
111
|
+
assets: ['node_modules/@kmamal/sdl/**', 'node_modules/@kmamal/gl/**', 'node_modules/opentype.js/**', 'node_modules/earcut/**', 'dist/src/games/**'],
|
|
98
112
|
targets: ['node18-win-x64'],
|
|
99
113
|
},
|
|
100
114
|
}
|
|
@@ -114,38 +128,151 @@ async function scaffold(projectName, parentDir) {
|
|
|
114
128
|
esModuleInterop: true,
|
|
115
129
|
forceConsistentCasingInFileNames: true,
|
|
116
130
|
},
|
|
117
|
-
include: ['src/**/*.ts'],
|
|
131
|
+
include: ['scripts/**/*.ts', 'src/**/*.ts'],
|
|
118
132
|
exclude: ['node_modules', 'dist'],
|
|
119
133
|
}
|
|
120
134
|
|
|
121
|
-
const gameTemplate = `import {
|
|
122
|
-
import type { GameContext, IGame } from '
|
|
135
|
+
const gameTemplate = `import { SCANCODE } from '../../scripts/index.js'
|
|
136
|
+
import type { GameContext, IGame } from '../../scripts/types.js'
|
|
137
|
+
|
|
138
|
+
const VERT = \`
|
|
139
|
+
attribute vec3 a_position;
|
|
140
|
+
uniform mat4 u_mvp;
|
|
141
|
+
void main() {
|
|
142
|
+
gl_Position = u_mvp * vec4(a_position, 1.0);
|
|
143
|
+
}
|
|
144
|
+
\`
|
|
145
|
+
|
|
146
|
+
const FRAG = \`
|
|
147
|
+
precision mediump float;
|
|
148
|
+
uniform vec3 u_color;
|
|
149
|
+
void main() {
|
|
150
|
+
gl_FragColor = vec4(u_color, 1.0);
|
|
151
|
+
}
|
|
152
|
+
\`
|
|
153
|
+
|
|
154
|
+
function mul4(a: number[], b: number[]): number[] {
|
|
155
|
+
const out: number[] = []
|
|
156
|
+
for (let col = 0; col < 4; col++) {
|
|
157
|
+
for (let row = 0; row < 4; row++) {
|
|
158
|
+
out[col * 4 + row] = a[0 * 4 + row] * b[col * 4 + 0] + a[1 * 4 + row] * b[col * 4 + 1] + a[2 * 4 + row] * b[col * 4 + 2] + a[3 * 4 + row] * b[col * 4 + 3]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return out
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function perspective(fovY: number, aspect: number, near: number, far: number): number[] {
|
|
165
|
+
const f = 1 / Math.tan(fovY / 2)
|
|
166
|
+
const nf = 1 / (near - far)
|
|
167
|
+
return [f / aspect, 0, 0, 0, 0, f, 0, 0, 0, 0, (far + near) * nf, -1, 0, 0, 2 * far * near * nf, 0]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function rotateY(t: number): number[] {
|
|
171
|
+
const c = Math.cos(t), s = Math.sin(t)
|
|
172
|
+
return [c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function rotateX(t: number): number[] {
|
|
176
|
+
const c = Math.cos(t), s = Math.sin(t)
|
|
177
|
+
return [1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function translate(x: number, y: number, z: number): number[] {
|
|
181
|
+
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1]
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const CUBE_POSITIONS = new Float32Array([
|
|
185
|
+
-0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5,
|
|
186
|
+
-0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
|
|
187
|
+
-0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5,
|
|
188
|
+
0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5,
|
|
189
|
+
-0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
|
|
190
|
+
-0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
|
|
191
|
+
])
|
|
123
192
|
|
|
124
193
|
interface Game extends IGame {
|
|
125
194
|
ctx: GameContext | null
|
|
126
|
-
|
|
195
|
+
gl: WebGLRenderingContext | null
|
|
196
|
+
program: WebGLProgram | null
|
|
197
|
+
buf: WebGLBuffer | null
|
|
198
|
+
uMvp: WebGLUniformLocation | null
|
|
199
|
+
uColor: WebGLUniformLocation | null
|
|
200
|
+
time: number
|
|
127
201
|
}
|
|
128
202
|
|
|
129
203
|
const game: Game = {
|
|
130
204
|
ctx: null,
|
|
131
|
-
|
|
205
|
+
gl: null,
|
|
206
|
+
program: null,
|
|
207
|
+
buf: null,
|
|
208
|
+
uMvp: null,
|
|
209
|
+
uColor: null,
|
|
210
|
+
time: 0,
|
|
132
211
|
|
|
133
212
|
async init(ctx: GameContext) {
|
|
134
213
|
this.ctx = ctx
|
|
135
|
-
|
|
214
|
+
const gl = ctx.gl
|
|
215
|
+
this.gl = gl
|
|
216
|
+
const vs = gl.createShader(gl.VERTEX_SHADER)!
|
|
217
|
+
gl.shaderSource(vs, VERT)
|
|
218
|
+
gl.compileShader(vs)
|
|
219
|
+
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(vs) ?? 'vert')
|
|
220
|
+
const fs = gl.createShader(gl.FRAGMENT_SHADER)!
|
|
221
|
+
gl.shaderSource(fs, FRAG)
|
|
222
|
+
gl.compileShader(fs)
|
|
223
|
+
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(fs) ?? 'frag')
|
|
224
|
+
const program = gl.createProgram()!
|
|
225
|
+
gl.attachShader(program, vs)
|
|
226
|
+
gl.attachShader(program, fs)
|
|
227
|
+
gl.linkProgram(program)
|
|
228
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(program) ?? 'link')
|
|
229
|
+
this.program = program
|
|
230
|
+
const buf = gl.createBuffer()!
|
|
231
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buf)
|
|
232
|
+
gl.bufferData(gl.ARRAY_BUFFER, CUBE_POSITIONS, gl.STATIC_DRAW)
|
|
233
|
+
this.buf = buf
|
|
234
|
+
this.uMvp = gl.getUniformLocation(program, 'u_mvp')!
|
|
235
|
+
this.uColor = gl.getUniformLocation(program, 'u_color')!
|
|
236
|
+
gl.enable(gl.DEPTH_TEST)
|
|
237
|
+
gl.depthFunc(gl.LEQUAL)
|
|
136
238
|
},
|
|
137
239
|
|
|
138
240
|
update(dt: number) {
|
|
241
|
+
this.time += dt
|
|
139
242
|
if (this.ctx?.input.isKeyDown(SCANCODE.Escape)) process.exit(0)
|
|
140
243
|
},
|
|
141
244
|
|
|
142
245
|
draw() {
|
|
143
|
-
|
|
144
|
-
|
|
246
|
+
const gl = this.gl!
|
|
247
|
+
const w = this.ctx!.width
|
|
248
|
+
const h = this.ctx!.height
|
|
249
|
+
gl.viewport(0, 0, w, h)
|
|
250
|
+
gl.clearColor(0.06, 0.06, 0.1, 1)
|
|
251
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
|
252
|
+
const aspect = w / h
|
|
253
|
+
const proj = perspective(Math.PI / 4, aspect, 0.1, 10)
|
|
254
|
+
const view = translate(0, 0, -2.5)
|
|
255
|
+
const model = mul4(rotateY(this.time), rotateX(this.time * 0.7))
|
|
256
|
+
const mvp = mul4(mul4(proj, view), model)
|
|
257
|
+
gl.useProgram(this.program!)
|
|
258
|
+
gl.uniformMatrix4fv(this.uMvp!, false, new Float32Array(mvp))
|
|
259
|
+
gl.uniform3f(this.uColor!, 0.25, 0.5, 0.9)
|
|
260
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.buf!)
|
|
261
|
+
const loc = gl.getAttribLocation(this.program!, 'a_position')
|
|
262
|
+
gl.enableVertexAttribArray(loc)
|
|
263
|
+
gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0)
|
|
264
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4)
|
|
265
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 4, 4)
|
|
266
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 8, 4)
|
|
267
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 12, 4)
|
|
268
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 16, 4)
|
|
269
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 20, 4)
|
|
145
270
|
},
|
|
146
271
|
|
|
147
272
|
dispose() {
|
|
148
|
-
this.
|
|
273
|
+
const gl = this.gl
|
|
274
|
+
if (gl && this.buf) gl.deleteBuffer(this.buf)
|
|
275
|
+
if (gl && this.program) gl.deleteProgram(this.program)
|
|
149
276
|
},
|
|
150
277
|
}
|
|
151
278
|
|
|
@@ -156,17 +283,22 @@ export default game
|
|
|
156
283
|
writeFile(join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2)),
|
|
157
284
|
writeFile(join(projectPath, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2)),
|
|
158
285
|
writeFile(join(projectPath, 'game.config.json'), JSON.stringify(gameConfig, null, 2)),
|
|
159
|
-
writeFile(join(
|
|
160
|
-
writeFile(join(
|
|
161
|
-
writeFile(join(
|
|
162
|
-
writeFile(join(
|
|
163
|
-
writeFile(join(
|
|
164
|
-
writeFile(join(
|
|
165
|
-
writeFile(join(
|
|
166
|
-
writeFile(join(
|
|
167
|
-
writeFile(join(
|
|
286
|
+
writeFile(join(scripts, 'main.ts'), mainTs),
|
|
287
|
+
writeFile(join(scripts, 'config.ts'), configTs),
|
|
288
|
+
writeFile(join(scripts, 'Game.ts'), gameTs),
|
|
289
|
+
writeFile(join(scripts, 'Input.ts'), inputTs),
|
|
290
|
+
writeFile(join(scripts, 'Graphics.ts'), graphicsTs),
|
|
291
|
+
writeFile(join(scripts, 'types.ts'), typesTs),
|
|
292
|
+
writeFile(join(scripts, 'index.ts'), indexTs),
|
|
293
|
+
writeFile(join(scripts, 'icon.ts'), iconTs),
|
|
294
|
+
writeFile(join(scripts, 'pngjs.d.ts'), pngjsDts),
|
|
295
|
+
writeFile(join(scripts, 'opentype.d.ts'), opentypeDts),
|
|
296
|
+
writeFile(join(scripts, 'earcut.d.ts'), earcutDts),
|
|
297
|
+
writeFile(join(scripts, 'Text.ts'), textTs),
|
|
298
|
+
writeFile(join(scripts, 'UI.ts'), uiTs),
|
|
168
299
|
writeFile(join(games, 'Game.ts'), gameTemplate),
|
|
169
300
|
writeFile(join(scripts, 'copy-config.js'), copyConfigJs),
|
|
301
|
+
writeFile(join(scripts, 'set-exe-icon.js'), setExeIconJs),
|
|
170
302
|
])
|
|
171
303
|
|
|
172
304
|
const iconSrc = join(FRAMEWORK_ROOT, 'src', 'assets', 'icon.png')
|
|
@@ -182,6 +314,7 @@ Game built with [GameNative](https://github.com/your-org/GameNative).
|
|
|
182
314
|
|
|
183
315
|
- \`npm run dev\` — run from source
|
|
184
316
|
- \`npm run build\` then \`npm start\` — run built app
|
|
317
|
+
- \`npm run build:exe\` — build Windows .exe (taskbar uses \`assets/icon.png\`; under \`npm run dev\` the taskbar shows Node’s icon)
|
|
185
318
|
- Edit \`game.config.json\` for window title, size, icon
|
|
186
319
|
- Edit \`src/games/Game.ts\` to build your game
|
|
187
320
|
|
|
@@ -191,16 +324,17 @@ See FRAMEWORK.md for 2D, 3D, lighting, sound, UI, and camera.
|
|
|
191
324
|
|
|
192
325
|
Your game has access to:
|
|
193
326
|
|
|
194
|
-
- **2D**: \`createDraw2D(ctx.gl)\` — \`clear()\`, \`fillRect()\`. Use \`ctx.gl\` (WebGL 1) for textures, sprites, batching.
|
|
327
|
+
- **2D**: \`createDraw2D(ctx.gl)\` — \`clear()\`, \`fillRect()\`, \`fillTriangles()\`, \`strokeRect()\`. Use \`ctx.gl\` (WebGL 1) for textures, sprites, batching.
|
|
328
|
+
- **Text**: \`loadFont(\'path/to/font.ttf\')\` (TTF/OTF), \`getTextTriangles(font, text, x, y, size)\` → triangles, \`drawText(draw2d, font, text, x, y, size, r, g, b, a)\`, \`measureText(font, text, size)\`. Any font, any size; draw with \`fillTriangles\` for full control.
|
|
195
329
|
- **3D**: Use \`ctx.gl\` directly: buffers, shaders, matrices. Implement camera (view/projection), meshes, and lighting in shaders.
|
|
196
330
|
- **Lighting**: In 3D shaders use uniforms for light position/color; in 2D use tint or custom fragment shaders.
|
|
197
331
|
- **Assets**: Load images (decode PNG with pngjs or similar), upload to \`ctx.gl\` textures; load audio (see sound).
|
|
198
332
|
- **Sound**: \`ctx.sdl.audio\` (SDL audio) — open device, enqueue buffers. Or add a small wrapper in your game.
|
|
199
333
|
- **Visuals**: Full WebGL — post-process by rendering to framebuffer, then to screen; particles, blur, etc. in shaders.
|
|
200
|
-
- **UI**:
|
|
334
|
+
- **UI / Buttons**: \`fillRect\` + \`strokeRect\` for panels/buttons, \`drawText\` for labels. \`isPointInRect(px, py, x, y, w, h)\` for hit-test. Track \`ctx.input.mouseX\`, \`mouseY\`, \`mouseLeft\` in \`update\` and draw any style in code.
|
|
201
335
|
- **Camera**: 2D: store \`offsetX, offsetY, scale\` and pass to your draw calls or a uniform. 3D: \`view\` and \`projection\` matrices from position/target/up and perspective.
|
|
202
336
|
|
|
203
|
-
All of this is done in your \`Game.ts\` using \`ctx.gl\`, \`ctx.input\`, and
|
|
337
|
+
All of this is done in your \`Game.ts\` using \`ctx.gl\`, \`ctx.input\`, and the exported helpers (createDraw2D, loadFont, drawText, isPointInRect, etc.).
|
|
204
338
|
`
|
|
205
339
|
await writeFile(join(projectPath, 'README.md'), readme)
|
|
206
340
|
await writeFile(join(projectPath, 'FRAMEWORK.md'), frameworkMd)
|
|
@@ -214,7 +348,6 @@ function npmInstall(cwd) {
|
|
|
214
348
|
const child = spawn(isWin ? 'npm.cmd' : 'npm', ['install'], {
|
|
215
349
|
cwd,
|
|
216
350
|
stdio: 'inherit',
|
|
217
|
-
shell: isWin,
|
|
218
351
|
})
|
|
219
352
|
child.on('close', (code) => (code === 0 ? resolve() : reject(new Error('npm install failed'))))
|
|
220
353
|
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import sdl from '@kmamal/sdl';
|
|
2
|
+
import type { IGame, GameConfig } from './types.js';
|
|
3
|
+
import { createInput } from './Input.js';
|
|
4
|
+
/**
|
|
5
|
+
* Runs an IGame: creates SDL window + WebGL context, drives update/draw loop, handles resize and close.
|
|
6
|
+
*/
|
|
7
|
+
export declare function run(game: IGame, config?: GameConfig): Promise<void>;
|
|
8
|
+
export type { IGame, GameConfig };
|
|
9
|
+
export { sdl, createInput };
|
|
10
|
+
export { SCANCODE } from './Input.js';
|
|
11
|
+
//# sourceMappingURL=Game.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Game.d.ts","sourceRoot":"","sources":["../../scripts/Game.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAG7B,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAe,MAAM,YAAY,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAaxC;;GAEG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAwE7E;AAED,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;AACjC,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAA;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import sdl from '@kmamal/sdl';
|
|
2
|
+
import glPkg from '@kmamal/gl';
|
|
3
|
+
import { createInput } from './Input.js';
|
|
4
|
+
const createGLContext = (typeof glPkg === 'function' ? glPkg : glPkg.default);
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
title: 'Game',
|
|
7
|
+
width: 800,
|
|
8
|
+
height: 600,
|
|
9
|
+
vsync: true,
|
|
10
|
+
resizable: true,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Runs an IGame: creates SDL window + WebGL context, drives update/draw loop, handles resize and close.
|
|
14
|
+
*/
|
|
15
|
+
export async function run(game, config = {}) {
|
|
16
|
+
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
17
|
+
const window = sdl.video.createWindow({
|
|
18
|
+
title: opts.title,
|
|
19
|
+
width: opts.width,
|
|
20
|
+
height: opts.height,
|
|
21
|
+
resizable: opts.resizable,
|
|
22
|
+
vsync: opts.vsync,
|
|
23
|
+
opengl: true,
|
|
24
|
+
});
|
|
25
|
+
if (opts.icon) {
|
|
26
|
+
try {
|
|
27
|
+
const { loadIcon } = await import('./icon.js');
|
|
28
|
+
await loadIcon(window, opts.icon);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// icon optional; ignore if loadIcon or file fails
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let width = window.pixelWidth;
|
|
35
|
+
let height = window.pixelHeight;
|
|
36
|
+
const gl = createGLContext(width, height, { window: window.native });
|
|
37
|
+
const input = createInput(sdl);
|
|
38
|
+
const ctx = {
|
|
39
|
+
gl,
|
|
40
|
+
input,
|
|
41
|
+
get width() {
|
|
42
|
+
return width;
|
|
43
|
+
},
|
|
44
|
+
get height() {
|
|
45
|
+
return height;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
if (game.init) {
|
|
49
|
+
await game.init(ctx, { ...opts, width, height });
|
|
50
|
+
}
|
|
51
|
+
window.on('resize', (e) => {
|
|
52
|
+
width = e.pixelWidth;
|
|
53
|
+
height = e.pixelHeight;
|
|
54
|
+
gl.viewport(0, 0, width, height);
|
|
55
|
+
});
|
|
56
|
+
let running = true;
|
|
57
|
+
window.on('close', () => {
|
|
58
|
+
running = false;
|
|
59
|
+
});
|
|
60
|
+
let lastTime = performance.now();
|
|
61
|
+
const maxDt = 0.1;
|
|
62
|
+
function loop() {
|
|
63
|
+
if (!running) {
|
|
64
|
+
if (game.dispose)
|
|
65
|
+
game.dispose();
|
|
66
|
+
window.destroy();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const now = performance.now();
|
|
70
|
+
let dt = (now - lastTime) / 1000;
|
|
71
|
+
lastTime = now;
|
|
72
|
+
if (dt > maxDt)
|
|
73
|
+
dt = maxDt;
|
|
74
|
+
game.update(dt);
|
|
75
|
+
game.draw();
|
|
76
|
+
gl.swap();
|
|
77
|
+
setImmediate(loop);
|
|
78
|
+
}
|
|
79
|
+
setImmediate(loop);
|
|
80
|
+
}
|
|
81
|
+
export { sdl, createInput };
|
|
82
|
+
export { SCANCODE } from './Input.js';
|
|
83
|
+
//# sourceMappingURL=Game.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Game.js","sourceRoot":"","sources":["../../scripts/Game.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WebGLRenderingContext as GLContext } from '@kmamal/gl';
|
|
2
|
+
export interface Draw2D {
|
|
3
|
+
clear(r: number, g: number, b: number, a?: number): void;
|
|
4
|
+
fillRect(x: number, y: number, w: number, h: number, r: number, g: number, b: number, a?: number): void;
|
|
5
|
+
/** Draw triangles in pixel space. verts: [x,y, x,y, x,y, ...] (3 verts per triangle). */
|
|
6
|
+
fillTriangles(verts: Float32Array, r: number, g: number, b: number, a?: number): void;
|
|
7
|
+
/** Draw rectangle outline (1px stroke). */
|
|
8
|
+
strokeRect(x: number, y: number, w: number, h: number, r: number, g: number, b: number, a?: number): void;
|
|
9
|
+
dispose(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createDraw2D(gl: GLContext): Draw2D;
|
|
12
|
+
//# sourceMappingURL=Graphics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graphics.d.ts","sourceRoot":"","sources":["../../scripts/Graphics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,IAAI,SAAS,EAAE,MAAM,YAAY,CAAA;AAwBpE,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxD,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvG,yFAAyF;IACzF,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrF,2CAA2C;IAC3C,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzG,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAkFlD"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal 2D helpers: clear, and draw solid-color quads with a simple shader.
|
|
3
|
+
* For anything else use the raw WebGL context.
|
|
4
|
+
*/
|
|
5
|
+
const VERT = `
|
|
6
|
+
attribute vec2 a_position;
|
|
7
|
+
uniform vec2 u_resolution;
|
|
8
|
+
void main() {
|
|
9
|
+
vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
|
|
10
|
+
gl_Position = vec4(clip * vec2(1, -1), 0, 1);
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
const FRAG = `
|
|
14
|
+
precision mediump float;
|
|
15
|
+
uniform vec4 u_color;
|
|
16
|
+
void main() {
|
|
17
|
+
gl_FragColor = u_color;
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
export function createDraw2D(gl) {
|
|
21
|
+
const vs = gl.createShader(gl.VERTEX_SHADER);
|
|
22
|
+
gl.shaderSource(vs, VERT);
|
|
23
|
+
gl.compileShader(vs);
|
|
24
|
+
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
|
|
25
|
+
throw new Error('vert: ' + gl.getShaderInfoLog(vs));
|
|
26
|
+
}
|
|
27
|
+
const fs = gl.createShader(gl.FRAGMENT_SHADER);
|
|
28
|
+
gl.shaderSource(fs, FRAG);
|
|
29
|
+
gl.compileShader(fs);
|
|
30
|
+
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
|
|
31
|
+
throw new Error('frag: ' + gl.getShaderInfoLog(fs));
|
|
32
|
+
}
|
|
33
|
+
const program = gl.createProgram();
|
|
34
|
+
gl.attachShader(program, vs);
|
|
35
|
+
gl.attachShader(program, fs);
|
|
36
|
+
gl.linkProgram(program);
|
|
37
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
38
|
+
throw new Error('link: ' + gl.getProgramInfoLog(program));
|
|
39
|
+
}
|
|
40
|
+
const aPosition = gl.getAttribLocation(program, 'a_position');
|
|
41
|
+
const uResolution = gl.getUniformLocation(program, 'u_resolution');
|
|
42
|
+
const uColor = gl.getUniformLocation(program, 'u_color');
|
|
43
|
+
const buffer = gl.createBuffer();
|
|
44
|
+
const verts = new Float32Array(8);
|
|
45
|
+
const strokeWidth = 1;
|
|
46
|
+
return {
|
|
47
|
+
clear(r, g, b, a = 1) {
|
|
48
|
+
gl.clearColor(r, g, b, a);
|
|
49
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
50
|
+
},
|
|
51
|
+
fillRect(x, y, w, h, r, g, b, a = 1) {
|
|
52
|
+
const x2 = x + w;
|
|
53
|
+
const y2 = y + h;
|
|
54
|
+
verts[0] = x;
|
|
55
|
+
verts[1] = y;
|
|
56
|
+
verts[2] = x2;
|
|
57
|
+
verts[3] = y;
|
|
58
|
+
verts[4] = x;
|
|
59
|
+
verts[5] = y2;
|
|
60
|
+
verts[6] = x2;
|
|
61
|
+
verts[7] = y2;
|
|
62
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
63
|
+
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.DYNAMIC_DRAW);
|
|
64
|
+
gl.useProgram(program);
|
|
65
|
+
gl.uniform2f(uResolution, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
66
|
+
gl.uniform4f(uColor, r, g, b, a);
|
|
67
|
+
gl.enableVertexAttribArray(aPosition);
|
|
68
|
+
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
|
|
69
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
70
|
+
},
|
|
71
|
+
fillTriangles(verts, r, g, b, a = 1) {
|
|
72
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
73
|
+
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.DYNAMIC_DRAW);
|
|
74
|
+
gl.useProgram(program);
|
|
75
|
+
gl.uniform2f(uResolution, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
76
|
+
gl.uniform4f(uColor, r, g, b, a);
|
|
77
|
+
gl.enableVertexAttribArray(aPosition);
|
|
78
|
+
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
|
|
79
|
+
gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2);
|
|
80
|
+
},
|
|
81
|
+
strokeRect(x, y, w, h, r, g, b, a = 1) {
|
|
82
|
+
const s = strokeWidth;
|
|
83
|
+
this.fillRect(x, y, w, s, r, g, b, a);
|
|
84
|
+
this.fillRect(x, y + h - s, w, s, r, g, b, a);
|
|
85
|
+
this.fillRect(x, y, s, h, r, g, b, a);
|
|
86
|
+
this.fillRect(x + w - s, y, s, h, r, g, b, a);
|
|
87
|
+
},
|
|
88
|
+
dispose() {
|
|
89
|
+
gl.deleteProgram(program);
|
|
90
|
+
gl.deleteShader(vs);
|
|
91
|
+
gl.deleteShader(fs);
|
|
92
|
+
gl.deleteBuffer(buffer);
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=Graphics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graphics.js","sourceRoot":"","sources":["../../scripts/Graphics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input state: keyboard and mouse. Read each frame in update().
|
|
3
|
+
* Keys use SDL scancode names; common ones: W, A, S, D, Up, Down, Left, Right, Space, Escape, etc.
|
|
4
|
+
*/
|
|
5
|
+
type SDL = any;
|
|
6
|
+
export interface InputState {
|
|
7
|
+
readonly mouseX: number;
|
|
8
|
+
readonly mouseY: number;
|
|
9
|
+
readonly mouseLeft: boolean;
|
|
10
|
+
readonly mouseRight: boolean;
|
|
11
|
+
readonly mouseMiddle: boolean;
|
|
12
|
+
isKeyDown(scancode: number): boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function createInput(sdl: SDL): InputState;
|
|
15
|
+
/** SDL scancode constants for use with input.isKeyDown(sdl.SCANCODE.X). Use the sdl instance from run(). */
|
|
16
|
+
export declare const SCANCODE: {
|
|
17
|
+
readonly A: 4;
|
|
18
|
+
readonly B: 5;
|
|
19
|
+
readonly C: 6;
|
|
20
|
+
readonly D: 7;
|
|
21
|
+
readonly E: 8;
|
|
22
|
+
readonly F: 9;
|
|
23
|
+
readonly G: 10;
|
|
24
|
+
readonly H: 11;
|
|
25
|
+
readonly I: 12;
|
|
26
|
+
readonly J: 13;
|
|
27
|
+
readonly K: 14;
|
|
28
|
+
readonly L: 15;
|
|
29
|
+
readonly M: 16;
|
|
30
|
+
readonly N: 17;
|
|
31
|
+
readonly O: 18;
|
|
32
|
+
readonly P: 19;
|
|
33
|
+
readonly Q: 20;
|
|
34
|
+
readonly R: 21;
|
|
35
|
+
readonly S: 22;
|
|
36
|
+
readonly T: 23;
|
|
37
|
+
readonly U: 24;
|
|
38
|
+
readonly V: 25;
|
|
39
|
+
readonly W: 26;
|
|
40
|
+
readonly X: 27;
|
|
41
|
+
readonly Y: 28;
|
|
42
|
+
readonly Z: 29;
|
|
43
|
+
readonly Space: 44;
|
|
44
|
+
readonly Escape: 41;
|
|
45
|
+
readonly Up: 82;
|
|
46
|
+
readonly Down: 81;
|
|
47
|
+
readonly Left: 80;
|
|
48
|
+
readonly Right: 79;
|
|
49
|
+
readonly Enter: 40;
|
|
50
|
+
readonly Shift: 225;
|
|
51
|
+
readonly Ctrl: 224;
|
|
52
|
+
readonly Tab: 43;
|
|
53
|
+
};
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=Input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../scripts/Input.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,KAAK,GAAG,GAAG,GAAG,CAAA;AAEd,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;CACrC;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU,CAyBhD;AAED,4GAA4G;AAC5G,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCX,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input state: keyboard and mouse. Read each frame in update().
|
|
3
|
+
* Keys use SDL scancode names; common ones: W, A, S, D, Up, Down, Left, Right, Space, Escape, etc.
|
|
4
|
+
*/
|
|
5
|
+
export function createInput(sdl) {
|
|
6
|
+
const keyboard = sdl.keyboard;
|
|
7
|
+
const mouse = sdl.mouse;
|
|
8
|
+
return {
|
|
9
|
+
get mouseX() {
|
|
10
|
+
return mouse.position.x;
|
|
11
|
+
},
|
|
12
|
+
get mouseY() {
|
|
13
|
+
return mouse.position.y;
|
|
14
|
+
},
|
|
15
|
+
get mouseLeft() {
|
|
16
|
+
return mouse.getButton(1);
|
|
17
|
+
},
|
|
18
|
+
get mouseRight() {
|
|
19
|
+
return mouse.getButton(3);
|
|
20
|
+
},
|
|
21
|
+
get mouseMiddle() {
|
|
22
|
+
return mouse.getButton(2);
|
|
23
|
+
},
|
|
24
|
+
isKeyDown(scancode) {
|
|
25
|
+
const state = keyboard.getState();
|
|
26
|
+
return !!(Array.isArray(state) ? state[scancode] : state[scancode]);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** SDL scancode constants for use with input.isKeyDown(sdl.SCANCODE.X). Use the sdl instance from run(). */
|
|
31
|
+
export const SCANCODE = {
|
|
32
|
+
A: 4,
|
|
33
|
+
B: 5,
|
|
34
|
+
C: 6,
|
|
35
|
+
D: 7,
|
|
36
|
+
E: 8,
|
|
37
|
+
F: 9,
|
|
38
|
+
G: 10,
|
|
39
|
+
H: 11,
|
|
40
|
+
I: 12,
|
|
41
|
+
J: 13,
|
|
42
|
+
K: 14,
|
|
43
|
+
L: 15,
|
|
44
|
+
M: 16,
|
|
45
|
+
N: 17,
|
|
46
|
+
O: 18,
|
|
47
|
+
P: 19,
|
|
48
|
+
Q: 20,
|
|
49
|
+
R: 21,
|
|
50
|
+
S: 22,
|
|
51
|
+
T: 23,
|
|
52
|
+
U: 24,
|
|
53
|
+
V: 25,
|
|
54
|
+
W: 26,
|
|
55
|
+
X: 27,
|
|
56
|
+
Y: 28,
|
|
57
|
+
Z: 29,
|
|
58
|
+
Space: 44,
|
|
59
|
+
Escape: 41,
|
|
60
|
+
Up: 82,
|
|
61
|
+
Down: 81,
|
|
62
|
+
Left: 80,
|
|
63
|
+
Right: 79,
|
|
64
|
+
Enter: 40,
|
|
65
|
+
Shift: 225,
|
|
66
|
+
Ctrl: 224,
|
|
67
|
+
Tab: 43,
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=Input.js.map
|