1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-26 10:49:17 +00:00

ecs 1st compile

This commit is contained in:
Steven Hugg 2022-01-26 19:12:49 -06:00
parent 3f87b5dbb8
commit b00d43d1ea

View File

@ -15,6 +15,10 @@
// to change scope, fire event w/ scope name // to change scope, fire event w/ scope name
// - how to handle bank-switching? // - how to handle bank-switching?
function mksymbol(c: ComponentType, fieldName: string) {
return c.name + '_' + fieldName;
}
export interface Entity { export interface Entity {
id: number; id: number;
etype: EntityArchetype; etype: EntityArchetype;
@ -46,9 +50,9 @@ export interface Query {
export interface System { export interface System {
name: string; name: string;
actions: CodeFragment[];
query: Query; query: Query;
tempbytes?: number; tempbytes?: number;
actions: CodeFragment[];
emits?: string[]; emits?: string[];
live?: EntityArchetype[] | null; live?: EntityArchetype[] | null;
} }
@ -101,6 +105,11 @@ interface ConstByte {
bitofs: number; bitofs: number;
} }
interface ArchetypeMatch {
etype: EntityArchetype;
cmatch: ComponentType[];
}
class SourceFileExport { class SourceFileExport {
lines : string[] = []; lines : string[] = [];
@ -108,10 +117,13 @@ class SourceFileExport {
this.lines.push(';' + text); this.lines.push(';' + text);
} }
segment(seg: string, segtype: 'rodata' | 'bss') { segment(seg: string, segtype: 'rodata' | 'bss') {
if (segtype == 'bss') if (segtype == 'bss') {
this.lines.push(` seg.u ${seg}`); this.lines.push(` seg.u ${seg}`);
else this.lines.push(` org $80`); // TODO
} else {
this.lines.push(` seg ${seg}`); this.lines.push(` seg ${seg}`);
this.lines.push(` org $f000`); // TODO
}
} }
label(sym: string) { label(sym: string) {
this.lines.push(`${sym}:`); this.lines.push(`${sym}:`);
@ -123,9 +135,13 @@ class SourceFileExport {
if (b < 0 || b > 255) throw new Error(`out of range byte ${b}`); if (b < 0 || b > 255) throw new Error(`out of range byte ${b}`);
this.lines.push(` .byte ${b}`) this.lines.push(` .byte ${b}`)
} else { } else {
this.lines.push(` .byte (${b.symbol} >> ${b.bitofs}) & 0xff`) this.lines.push(` .byte (${b.symbol} >> ${b.bitofs})`)
} }
} }
text(s: string) {
for (let l of s.split('\n'))
this.lines.push(l);
}
toString() { toString() {
return this.lines.join('\n'); return this.lines.join('\n');
} }
@ -137,8 +153,13 @@ class Segment {
fieldranges: {[cfname: string]: FieldArray} = {}; fieldranges: {[cfname: string]: FieldArray} = {};
size: number = 0; size: number = 0;
initdata: (number | ConstByte | undefined)[] = []; initdata: (number | ConstByte | undefined)[] = [];
codefrags : string[] = [];
addCodeFragment(code: string) {
this.codefrags.push(code);
}
allocateBytes(name: string, bytes: number) { allocateBytes(name: string, bytes: number) {
if (this.symbols[name]) return this.symbols[name]; // TODO: check size
let ofs = this.size; let ofs = this.size;
this.symbols[name] = ofs; this.symbols[name] = ofs;
if (!this.ofs2sym.has(ofs)) if (!this.ofs2sym.has(ofs))
@ -155,6 +176,9 @@ class Segment {
} }
} }
dump(file: SourceFileExport) { dump(file: SourceFileExport) {
for (let code of this.codefrags) {
file.text(code);
}
for (let i=0; i<this.size; i++) { for (let i=0; i<this.size; i++) {
let syms = this.ofs2sym.get(i); let syms = this.ofs2sym.get(i);
if (syms) { if (syms) {
@ -163,6 +187,10 @@ class Segment {
file.byte(this.initdata[i]); file.byte(this.initdata[i]);
} }
} }
// TODO: move cfname functions in here too
getFieldRange(component: ComponentType, fieldName: string) {
return this.fieldranges[mksymbol(component, fieldName)];
}
} }
function getFieldBits(f: IntType) { function getFieldBits(f: IntType) {
@ -184,12 +212,12 @@ function getPackedFieldSize(f: DataType, constValue?: DataValue): number {
} }
const ASM_ITERATE_EACH = ` const ASM_ITERATE_EACH = `
ldx #%{elo} ldx #0
.loop: %{.loop}:
%{action} %{code}
inx inx
cpx #%{ehi}+1 cpx #%{ecount}
bne .loop bne %{.loop}
`; `;
export class EntityScope { export class EntityScope {
@ -199,6 +227,9 @@ export class EntityScope {
rodata = new Segment(); rodata = new Segment();
code = new Segment(); code = new Segment();
componentsInScope = new Set(); componentsInScope = new Set();
tempOffset = 0;
maxTempBytes = 0;
subroutines = new Set<string>();
constructor( constructor(
public readonly em: EntityManager, public readonly em: EntityManager,
@ -223,23 +254,17 @@ export class EntityScope {
let e = this.entities[i]; let e = this.entities[i];
for (let c of e.etype.components) { for (let c of e.etype.components) {
for (let f of c.fields) { for (let f of c.fields) {
yield {i, e, c, f, v:e.consts[c.name + '.' + f.name]}; yield {i, e, c, f, v:e.consts[mksymbol(c, f.name)]};
} }
} }
} }
} }
analyzeEntities() {
this.buildSegments();
this.allocateSegment(this.bss, false);
this.allocateSegment(this.rodata, true);
this.allocateROData(this.rodata);
}
buildSegments() { buildSegments() {
let iter = this.iterateFields(); let iter = this.iterateFields();
for (var o=iter.next(); o.value; o=iter.next()) { for (var o=iter.next(); o.value; o=iter.next()) {
let {i,e,c,f,v} = o.value; let {i,e,c,f,v} = o.value;
let segment = v === undefined ? this.bss : this.rodata; let segment = v === undefined ? this.bss : this.rodata;
let cfname = c.name + '.' + f.name; let cfname = mksymbol(c, f.name);
let array = segment.fieldranges[cfname]; let array = segment.fieldranges[cfname];
if (!array) { if (!array) {
array = segment.fieldranges[cfname] = {component:c, field:f, elo:i, ehi:i}; array = segment.fieldranges[cfname] = {component:c, field:f, elo:i, ehi:i};
@ -254,11 +279,11 @@ export class EntityScope {
fields.sort((a,b) => (a.ehi - a.elo + 1) * getPackedFieldSize(a.field)); fields.sort((a,b) => (a.ehi - a.elo + 1) * getPackedFieldSize(a.field));
let f; let f;
while (f = fields.pop()) { while (f = fields.pop()) {
let name = f.component.name + "_" + f.field.name; let name = mksymbol(f.component, f.field.name);
// TODO: doesn't work for packed arrays too well // TODO: doesn't work for packed arrays too well
let bits = getPackedFieldSize(f.field); let bits = getPackedFieldSize(f.field);
// variable size? make it a pointer // variable size? make it a pointer
if (bits == 0) bits = 16; if (bits == 0) bits = 16; // TODO?
let rangelen = (f.ehi - f.elo + 1); let rangelen = (f.ehi - f.elo + 1);
let bytesperelem = Math.ceil(bits/8) * rangelen; let bytesperelem = Math.ceil(bits/8) * rangelen;
// TODO: packing bits // TODO: packing bits
@ -277,13 +302,20 @@ export class EntityScope {
let iter = this.iterateFields(); let iter = this.iterateFields();
for (var o=iter.next(); o.value; o=iter.next()) { for (var o=iter.next(); o.value; o=iter.next()) {
let {i,e,c,f,v} = o.value; let {i,e,c,f,v} = o.value;
let cfname = c.name + '.' + f.name; let cfname = mksymbol(c, f.name);
let fieldrange = segment.fieldranges[cfname]; let fieldrange = segment.fieldranges[cfname];
if (v !== undefined) { if (v !== undefined) {
// is it a byte array? // is it a byte array?
if (v instanceof Uint8Array) { if (v instanceof Uint8Array) {
let sym = c.name + '_' + f.name; let datasym = `${c.name}_${f.name}_e${e.id}`;
segment.allocateInitData(sym, v); let ptrlosym = `${c.name}_${f.name}_b0`;
let ptrhisym = `${c.name}_${f.name}_b8`;
let entcount = fieldrange.ehi - fieldrange.elo + 1;
segment.allocateInitData(datasym, v);
let loofs = segment.allocateBytes(ptrlosym, entcount);
let hiofs = segment.allocateBytes(ptrhisym, entcount);
segment.initdata[loofs + e.id - fieldrange.elo] = {symbol:datasym, bitofs:0};
segment.initdata[hiofs + e.id - fieldrange.elo] = {symbol:datasym, bitofs:8};
} else if (fieldrange.ehi > fieldrange.elo) { } else if (fieldrange.ehi > fieldrange.elo) {
// more than one element, add an array // more than one element, add an array
// TODO // TODO
@ -295,71 +327,124 @@ export class EntityScope {
//console.log(segment.initdata) //console.log(segment.initdata)
} }
setConstValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) { setConstValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) {
e.consts[component.name + '.' + fieldName] = value; // TODO: check to make sure component exists
} e.consts[mksymbol(component, fieldName)] = value;
dump(file: SourceFileExport) {
file.segment(`${this.name}_CODE`, 'rodata');
this.rodata.dump(file);
file.segment(`${this.name}_DATA`, 'bss');
this.bss.dump(file);
}
generateCode() {
let code = this.generateCodeForEvent('init');
console.log(code);
} }
generateCodeForEvent(event: string): string { generateCodeForEvent(event: string): string {
// find systems that respond to event // find systems that respond to event
// and have entities in this scope // and have entities in this scope
let systems = this.getSystems([event]); let systems = this.getSystems([event]);
if (systems.length == 0) { if (systems.length == 0) {
console.log(`no system responds to ${event}`); // TODO: warning console.log(`; warning: no system responds to ${event}`); // TODO: warning
} }
let s = ''; let s = '';
//s += `\n; event ${event}\n`; //s += `\n; event ${event}\n`;
let emitcode : {[event: string] : string} = {}; let emitcode : {[event: string] : string} = {};
for (let sys of systems) { for (let sys of systems) {
if (sys.tempbytes) this.allocateTempBytes(sys.tempbytes);
if (sys.emits) { if (sys.emits) {
for (let emit of sys.emits) { for (let emit of sys.emits) {
if (emitcode[emit]) {
console.log(`already emitted for ${sys.name}:${event}`);
}
//console.log('>', emit); //console.log('>', emit);
// TODO: cycles // TODO: cycles
emitcode[emit] = this.generateCodeForEvent(emit); emitcode[emit] = this.generateCodeForEvent(emit);
//console.log('<', emit, emitcode[emit].length); //console.log('<', emit, emitcode[emit].length);
} }
} }
if (sys.tempbytes) this.allocateTempBytes(-sys.tempbytes);
for (let action of sys.actions) { for (let action of sys.actions) {
let code = action.text;
if (action.event == event) { if (action.event == event) {
// TODO: find loops let code = this.replaceCode(action.text, sys, action);
if (action.iterate == 'each') { s += `\n; <action ${sys.name}:${event}>\n`;
let ents = this.entitiesMatching(sys.query);
console.log(sys.name, action.event, ents);
//frag = this.iterateCode(frag);
}
// TODO: better parser of ${}
for (let [k,v] of Object.entries(emitcode)) {
let frag = v;
code = code.replace(`%{${k}}`, frag);
}
// anything not replaced?
let unused = /\%\{.+?\}/.exec(code);
if (unused) {
//throw new Error(`${sys.name}:${action.event} did not replace ${unused[0]}`);
}
// TODO: check that this happens once?
s += `\n; action ${sys.name}:${action.event}\n`;
s += code; s += code;
s += `\n; </action ${sys.name}:${event}>\n`;
// TODO: check that this happens once?
} }
} }
} }
return s; return s;
} }
entitiesMatching(q: Query) { allocateTempBytes(n: number) {
this.tempOffset += n;
this.maxTempBytes = Math.max(this.tempOffset, this.maxTempBytes);
}
replaceCode(code: string, sys: System, action: CodeFragment): string {
const re = /\%\{(.+?)\}/g;
let label = sys.name + '_' + action.event;
let atypes = this.em.archetypesMatching(sys.query);
let entities = this.entitiesMatching(atypes);
// TODO: find loops
if (action.iterate == 'each') {
code = this.wrapCodeInLoop(code, sys, action, entities);
//console.log(sys.name, action.event, ents);
//frag = this.iterateCode(frag);
}
return code.replace(re, (entire, group: string) => {
let cmd = group.charAt(0);
let rest = group.substring(1);
switch (cmd) {
case '!': // emit event
return this.generateCodeForEvent(rest);
case '.': // auto label
return `.${label}_${rest}`;
case '$': // temp byte
return `TEMP+${this.tempOffset}+${rest}`;
case '<': // low byte
return this.generateCodeForField(sys, action, atypes, entities, rest, 0);
case '>': // high byte
return this.generateCodeForField(sys, action, atypes, entities, rest, 8);
case '^': // reference
return this.includeSubroutine(rest);
default:
//throw new Error(`unrecognized command ${cmd} in ${entire}`);
console.log(`unrecognized command ${cmd} in ${entire}`);
return entire;
}
});
}
includeSubroutine(symbol: string): string {
this.subroutines.add(symbol);
return symbol;
}
wrapCodeInLoop(code: string, sys: System, action: CodeFragment, ents: Entity[]): string {
// TODO: check ents
// TODO: check segment bounds
let s = ASM_ITERATE_EACH;
s = s.replace('%{elo}', ents[0].id.toString());
s = s.replace('%{ehi}', ents[ents.length-1].id.toString());
s = s.replace('%{ecount}', ents.length.toString());
s = s.replace('%{code}', code);
return s;
}
generateCodeForField(sys: System, action: CodeFragment,
atypes: ArchetypeMatch[], entities: Entity[],
fieldName: string, bitofs: number): string {
// find archetypes
let component = this.em.componentWithFieldName(atypes, fieldName);
if (!component) {
throw new Error(`cannot find component with field "${fieldName}" in ${sys.name}:${action.event}`);
}
// see if all entities have the same constant value
let constValues = new Set();
for (let e of entities) {
let constVal = e.consts[fieldName];
if (constVal) constValues.add(constVal);
}
// TODO: offset > 0?
//let range = this.bss.getFieldRange(component, fieldName);
return `${component.name}_${fieldName}_b${bitofs},x`
}
entitiesMatching(atypes: ArchetypeMatch[]) {
let result = []; let result = [];
let atypes = this.em.archetypesMatching(q);
for (let e of this.entities) { for (let e of this.entities) {
for (let a of atypes) { for (let a of atypes) {
if (e.etype == a.etype) // TODO: what about subclasses?
if (e.etype == a.etype) {
result.push(e); result.push(e);
break;
}
} }
} }
return result; return result;
@ -390,6 +475,31 @@ export class EntityScope {
hasComponent(ctype: ComponentType) { hasComponent(ctype: ComponentType) {
return this.componentsInScope.has(ctype.name); return this.componentsInScope.has(ctype.name);
} }
analyzeEntities() {
this.buildSegments();
this.allocateSegment(this.bss, false);
this.allocateSegment(this.rodata, true);
this.allocateROData(this.rodata);
}
generateCode() {
this.tempOffset = this.maxTempBytes = 0;
let init = this.generateCodeForEvent('init');
this.code.addCodeFragment(init);
for (let sub of Array.from(this.subroutines.values())) {
let code = this.generateCodeForEvent(sub);
this.code.addCodeFragment(code);
}
}
dump(file: SourceFileExport) {
file.text(HEADER); // TODO
file.segment(`${this.name}_DATA`, 'bss');
if (this.maxTempBytes) this.bss.allocateBytes('TEMP', this.maxTempBytes);
this.bss.dump(file);
file.segment(`${this.name}_CODE`, 'rodata');
this.rodata.dump(file);
this.code.dump(file);
file.text(FOOTER); // TODO
}
} }
export class EntityManager { export class EntityManager {
@ -426,7 +536,7 @@ export class EntityManager {
return list; return list;
} }
archetypesMatching(q: Query) { archetypesMatching(q: Query) {
let result : {etype: EntityArchetype, cmatch: ComponentType[]}[] = []; let result : ArchetypeMatch[] = [];
this.archtypes.forEach(etype => { this.archtypes.forEach(etype => {
let cmatch = this.componentsMatching(q, etype); let cmatch = this.componentsMatching(q, etype);
if (cmatch.length > 0) { if (cmatch.length > 0) {
@ -435,106 +545,175 @@ export class EntityManager {
}); });
return result; return result;
} }
emitCode(root: System) { componentWithFieldName(atypes: ArchetypeMatch[], fieldName: string) {
// TODO???
for (let at of atypes) {
for (let c of at.cmatch) {
for (let f of c.fields) {
if (f.name == fieldName)
return c;
}
}
}
} }
} }
/// ///
const HEADER = `
processor 6502
include "vcs.h"
include "macro.h"
include "xmacro.h"
`
const FOOTER = `
org $fffc
.word Start ; reset vector
.word Start ; BRK vector
`
const TEMPLATE_INIT = ` const TEMPLATE_INIT = `
Start: Start:
CLEAN_START CLEAN_START
%{start} %{!start}
` `
const TEMPLATE1 = ` const TEMPLATE1 = `
.NextFrame: .NextFrame:
lsr SWCHB ; test Game Reset switch
bcc Start ; reset?
VERTICAL_SYNC VERTICAL_SYNC
TIMER_SETUP 37 sta CXCLR ; clear collision register
%{preframe} IFCONST PAL
TIMER_SETUP 44
ELSE
TIMER_SETUP 36
ENDIF
%{!preframe}
TIMER_WAIT TIMER_WAIT
TIMER_SETUP 192 lda #0
%{kernel} sta VBLANK
IFNCONST PAL
TIMER_SETUP 194
ENDIF
%{!kernel}
IFNCONST PAL
TIMER_WAIT TIMER_WAIT
TIMER_SETUP 29 ENDIF
%{postframe} lda #2
sta VBLANK
IFCONST PAL
TIMER_SETUP 36
ELSE
TIMER_SETUP 28
ENDIF
%{!postframe}
TIMER_WAIT TIMER_WAIT
lsr SWCHB ; test Game Reset switch
bcs .NoStart ; reset?
jmp Start
.NoStart:
jmp .NextFrame jmp .NextFrame
`; `;
// TODO: two sticks?
const TEMPLATE2 = ` const TEMPLATE2 = `
#ifdef EVENT_joyup ;#ifdef EVENT_joyleft
lda #%00100000 ;Up? lda #%01000000 ;Left?
bit SWCHA bit SWCHA
bne SkipMoveUp bne %{.SkipMoveLeft}
%{joyup} %{!joyleft}
.SkipMoveUp %{.SkipMoveLeft}
#endif ;#endif
`; `;
const TEMPLATE3 = ` const TEMPLATE3_L = `
lda %{ypos},x lda %{<xpos}
sec sec
sbc #1 sbc #1
bcc .noclip bcc %{.noclip}
sta %{ypos},x sta %{<xpos}
.noclip %{.noclip}
`;
const TEMPLATE3_R = `
lda %{<xpos}
clc
adc #1
cmp #160
bcc %{.noclip}
sta %{<xpos}
%{.noclip}
`; `;
const TEMPLATE4_S = ` const TEMPLATE4_S = `
lda %{@sprite.bitmap+0} ; bitmap address txa ; TODO
sta temp+0 ; temp space asl
lda %{@sprite.bitmap+1} ; bitmap address tya
sta temp+1 ; temp space lda %{<bitmap} ; bitmap address
tay
lda bitmap_bitmapdata_b0,y
sta %{$0},y
lda bitmap_bitmapdata_b8,y
sta %{$1},y
lda colormap_colormapdata_b0,y
sta %{$2},y
lda colormap_colormapdata_b0,y
sta %{$3},y
lda sprite_height_b0,y
sta %{$4},y
lda ypos_ypos_b0,y
sta %{$5},y
` `
const TEMPLATE4_K = ` const TEMPLATE4_K = `
ldx %{kernel.numlines} ; lines in kernel ldx #192 ; lines in kernel
LVScan LVScan
txa ; X -> A txa ; X -> A
sec ; set carry for subtract sec ; set carry for subtract
sbc YPos ; local coordinate sbc %{$5} ; local coordinate
cmp %{sprite.height} ; in sprite? cmp %{$4} ; in sprite? (height)
bcc InSprite ; yes, skip over next bcc InSprite ; yes, skip over next
lda #0 ; not in sprite, load 0 lda #0 ; not in sprite, load 0
InSprite InSprite
tay ; local coord -> Y tay ; local coord -> Y
lda (temp+0),y ; lookup color lda (%{$0}),y ; lookup color
sta WSYNC ; sync w/ scanline sta WSYNC ; sync w/ scanline
sta GRP0 ; store bitmap sta GRP0 ; store bitmap
lda (temp+2),y ; lookup color lda (%{$2}),y ; lookup color
sta COLUP0 ; store color sta COLUP0 ; store color
dex ; decrement X dex ; decrement X
bne LVScan ; repeat until 192 lines bne LVScan ; repeat until 192 lines
`; `;
const SET_XPOS = ` const SET_XPOS = `
lda %{sprite.xpos} lda %{<xpos}
ldx %(sprite.plyrindex} ldy %{<plyrindex}
jsr SetHorizPos jsr %{^SetHorizPos}
` `
const SETHORIZPOS = ` const SETHORIZPOS = `
SetHorizPos: subroutine ; SetHorizPos routine
; A = X coordinate
; Y = player number (0 or 1)
SetHorizPos
sta WSYNC ; start a new line sta WSYNC ; start a new line
SLEEP 3
sec ; set carry flag sec ; set carry flag
SetHorizPosLoop: DivideLoop
sbc #15 ; subtract 15 sbc #15 ; subtract 15
bcs SetHorizPosLoop ; branch until negative bcs DivideLoop ; branch until negative
SetHorizPosAfter:
ASSERT_SAME_PAGE SetHorizPosLoop, SetHorizPosAfter
eor #7 ; calculate fine offset eor #7 ; calculate fine offset
asl asl
asl asl
asl asl
asl asl
sta RESP0,x ; fix coarse position sta RESP0,y ; fix coarse position
sta HMP0,x ; set fine offset sta HMP0,y ; set fine offset
sta WSYNC
Return: ; for SLEEP macro, etc.
rts ; return to caller rts ; return to caller
` `
@ -559,10 +738,10 @@ function test() {
{name:'colormap', dtype:'ref', query:{include:['colormap']}}, {name:'colormap', dtype:'ref', query:{include:['colormap']}},
]}) ]})
let c_bitmap = em.defineComponent({name:'bitmap', fields:[ let c_bitmap = em.defineComponent({name:'bitmap', fields:[
{name:'data', dtype:'array', elem:{ dtype:'int', lo:0, hi:255 }} {name:'bitmapdata', dtype:'array', elem:{ dtype:'int', lo:0, hi:255 }}
]}) ]})
let c_colormap = em.defineComponent({name:'colormap', fields:[ let c_colormap = em.defineComponent({name:'colormap', fields:[
{name:'data', dtype:'array', elem:{ dtype:'int', lo:0, hi:255 }} {name:'colormapdata', dtype:'array', elem:{ dtype:'int', lo:0, hi:255 }}
]}) ]})
let c_xpos = em.defineComponent({name:'xpos', fields:[ let c_xpos = em.defineComponent({name:'xpos', fields:[
{name:'xpos', dtype:'int', lo:0, hi:255} {name:'xpos', dtype:'int', lo:0, hi:255}
@ -580,19 +759,20 @@ function test() {
// TODO: where is kernel numlines? // TODO: where is kernel numlines?
// temp between preframe + frame? // temp between preframe + frame?
// TODO: check names for identifierness
em.defineSystem({ em.defineSystem({
name:'kernel-simple', name:'kernel_simple',
tempbytes:4, tempbytes:8,
query:{ query:{
include:['sprite','bitmap','colormap','ypos'], include:['sprite','hasbitmap','hascolormap','ypos'],
}, },
actions:[ actions:[
{ text:TEMPLATE4_S, event:'preframe', iterate:'once' }, { text:TEMPLATE4_S, event:'preframe', iterate:'each' },
{ text:TEMPLATE4_K, event:'kernel', iterate:'once' }, { text:TEMPLATE4_K, event:'kernel', iterate:'once' },
] ]
}) })
em.defineSystem({ em.defineSystem({
name:'set-xpos', name:'set_xpos',
query:{ query:{
include:['sprite','xpos'] include:['sprite','xpos']
}, },
@ -637,12 +817,20 @@ function test() {
] ]
}); });
em.defineSystem({ em.defineSystem({
name:'simple-move', name:'simple_move',
query:{ query:{
include:['player','xpos','ypos'] include:['player','xpos']
}, },
actions:[ actions:[
{ text:TEMPLATE3, event:'joyup', iterate:'each' } { text:TEMPLATE3_L, event:'joyleft', iterate:'once' }, // TODO: event source?
{ text:TEMPLATE3_R, event:'joyright', iterate:'once' }, // TODO: event source?
]
});
em.defineSystem({
name:'SetHorizPos',
query:{ include:[] },
actions:[
{ text:SETHORIZPOS, event:'SetHorizPos', iterate:'once' }, // TODO: event source?
] ]
}); });
@ -653,10 +841,10 @@ function test() {
let e_bitmap0 = root.newEntity({components:[c_bitmap]}); let e_bitmap0 = root.newEntity({components:[c_bitmap]});
// TODO: store array sizes? // TODO: store array sizes?
root.setConstValue(e_bitmap0, c_bitmap, 'data', new Uint8Array([1,2,3,4,5])); root.setConstValue(e_bitmap0, c_bitmap, 'bitmapdata', new Uint8Array([0,2,4,6,8,15,0]));
let e_colormap0 = root.newEntity({components:[c_colormap]}); let e_colormap0 = root.newEntity({components:[c_colormap]});
root.setConstValue(e_colormap0, c_colormap, 'data', new Uint8Array([1,2,3,4,5])); root.setConstValue(e_colormap0, c_colormap, 'colormapdata', new Uint8Array([0,3,6,9,12,14,0]));
let ea_playerSprite = {components:[c_sprite,c_hasbitmap,c_hascolormap,c_xpos,c_ypos,c_player]}; let ea_playerSprite = {components:[c_sprite,c_hasbitmap,c_hascolormap,c_xpos,c_ypos,c_player]};
let e_player0 = root.newEntity(ea_playerSprite); let e_player0 = root.newEntity(ea_playerSprite);