mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-05-28 08:41:30 +00:00
ecs: forward entity refs, deferred components, %binary
This commit is contained in:
parent
999aed9cb4
commit
fc0a43b9af
|
@ -19,6 +19,8 @@ npm i
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To use GitHub integration locally, download the Firebase config file, e.g. https://8bitworkshop.com/v[version]/config.js
|
||||||
|
|
||||||
### Start Server
|
### Start Server
|
||||||
|
|
||||||
Start a web server on http://localhost:8000/ while TypeScript compiles in the background:
|
Start a web server on http://localhost:8000/ while TypeScript compiles in the background:
|
||||||
|
@ -102,3 +104,4 @@ The IDE uses custom forks for many of these, found at https://github.com/sehugg?
|
||||||
* https://github.com/sehugg/8bitworkshop-compilers
|
* https://github.com/sehugg/8bitworkshop-compilers
|
||||||
* https://github.com/sehugg/8bit-tools
|
* https://github.com/sehugg/8bit-tools
|
||||||
* https://github.com/sehugg/awesome-8bitgamedev
|
* https://github.com/sehugg/awesome-8bitgamedev
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
import { mergeLocs, Tokenizer, TokenType } from "../tokenizer";
|
import { mergeLocs, Token, Tokenizer, TokenType } from "../tokenizer";
|
||||||
import { SourceLocated } from "../workertypes";
|
import { SourceLocated, SourceLocation } from "../workertypes";
|
||||||
import { newDecoder } from "./decoder";
|
import { newDecoder } from "./decoder";
|
||||||
import { Action, ActionWithJoin, ArrayType, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SELECT_TYPE, SourceFileExport, System } from "./ecs";
|
import { Action, ActionOwner, ActionNode, ActionWithJoin, ArrayType, CodeLiteralNode, CodePlaceholderNode, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SELECT_TYPE, SourceFileExport, System } from "./ecs";
|
||||||
|
|
||||||
export enum ECSTokenType {
|
export enum ECSTokenType {
|
||||||
Ellipsis = 'ellipsis',
|
Ellipsis = 'ellipsis',
|
||||||
|
@ -10,11 +10,18 @@ export enum ECSTokenType {
|
||||||
QuotedString = 'quoted-string',
|
QuotedString = 'quoted-string',
|
||||||
Integer = 'integer',
|
Integer = 'integer',
|
||||||
CodeFragment = 'code-fragment',
|
CodeFragment = 'code-fragment',
|
||||||
|
Placeholder = 'placeholder',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ForwardRef {
|
||||||
|
reftype: RefType | undefined
|
||||||
|
token: Token
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ECSCompiler extends Tokenizer {
|
export class ECSCompiler extends Tokenizer {
|
||||||
|
|
||||||
currentScope: EntityScope | null = null;
|
currentScope: EntityScope | null = null;
|
||||||
|
currentContext: ActionOwner | null = null;
|
||||||
debuginfo = false;
|
debuginfo = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -26,9 +33,10 @@ export class ECSCompiler extends Tokenizer {
|
||||||
{ type: ECSTokenType.Ellipsis, regex: /\.\./ },
|
{ type: ECSTokenType.Ellipsis, regex: /\.\./ },
|
||||||
{ type: ECSTokenType.QuotedString, regex: /".*?"/ },
|
{ type: ECSTokenType.QuotedString, regex: /".*?"/ },
|
||||||
{ type: ECSTokenType.CodeFragment, regex: /---.*?---/ },
|
{ type: ECSTokenType.CodeFragment, regex: /---.*?---/ },
|
||||||
{ type: ECSTokenType.Integer, regex: /[-]?0x[A-Fa-f0-9]+/ },
|
{ type: ECSTokenType.Integer, regex: /[-]?0[xX][A-Fa-f0-9]+/ },
|
||||||
{ type: ECSTokenType.Integer, regex: /[-]?\$[A-Fa-f0-9]+/ },
|
{ type: ECSTokenType.Integer, regex: /[-]?\$[A-Fa-f0-9]+/ },
|
||||||
{ type: ECSTokenType.Integer, regex: /[-]?\d+/ },
|
{ type: ECSTokenType.Integer, regex: /[-]?\d+/ },
|
||||||
|
{ type: ECSTokenType.Integer, regex: /[%][01]+/ },
|
||||||
{ type: ECSTokenType.Operator, regex: /[#=,:(){}\[\]\-]/ },
|
{ type: ECSTokenType.Operator, regex: /[#=,:(){}\[\]\-]/ },
|
||||||
{ type: TokenType.Ident, regex: /[A-Za-z_][A-Za-z0-9_]*/ },
|
{ type: TokenType.Ident, regex: /[A-Za-z_][A-Za-z0-9_]*/ },
|
||||||
{ type: TokenType.Ignore, regex: /\/\/.*?[\n\r]/ },
|
{ type: TokenType.Ignore, regex: /\/\/.*?[\n\r]/ },
|
||||||
|
@ -54,6 +62,7 @@ export class ECSCompiler extends Tokenizer {
|
||||||
this.annotate(() => t); // TODO? typescript bug?
|
this.annotate(() => t); // TODO? typescript bug?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.runDeferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
getImportFile: (path: string) => string;
|
getImportFile: (path: string) => string;
|
||||||
|
@ -108,6 +117,7 @@ export class ECSCompiler extends Tokenizer {
|
||||||
parseComponentDefinition(): ComponentType {
|
parseComponentDefinition(): ComponentType {
|
||||||
let name = this.expectIdent().str;
|
let name = this.expectIdent().str;
|
||||||
let fields = [];
|
let fields = [];
|
||||||
|
this.em.deferComponent(name);
|
||||||
while (this.peekToken().str != 'end') {
|
while (this.peekToken().str != 'end') {
|
||||||
fields.push(this.parseComponentField());
|
fields.push(this.parseComponentField());
|
||||||
}
|
}
|
||||||
|
@ -148,7 +158,7 @@ export class ECSCompiler extends Tokenizer {
|
||||||
this.compileError(`I expected a data type here.`); throw new Error();
|
this.compileError(`I expected a data type here.`); throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseDataValue(field: DataField) : DataValue {
|
parseDataValue(field: DataField) : DataValue | ForwardRef {
|
||||||
let tok = this.peekToken();
|
let tok = this.peekToken();
|
||||||
if (tok.type == 'integer') {
|
if (tok.type == 'integer') {
|
||||||
return this.expectInteger();
|
return this.expectInteger();
|
||||||
|
@ -158,20 +168,10 @@ export class ECSCompiler extends Tokenizer {
|
||||||
return new Uint8Array(this.parseDataArray());
|
return new Uint8Array(this.parseDataArray());
|
||||||
}
|
}
|
||||||
if (tok.str == '#') {
|
if (tok.str == '#') {
|
||||||
|
this.consumeToken();
|
||||||
let reftype = field.dtype == 'ref' ? field as RefType : undefined;
|
let reftype = field.dtype == 'ref' ? field as RefType : undefined;
|
||||||
let e = this.parseEntityRef();
|
let token = this.expectIdent();
|
||||||
let id = e.id;
|
return { reftype, token };
|
||||||
if (reftype) {
|
|
||||||
// TODO: make this a function? elo ehi etc?
|
|
||||||
if (!this.currentScope) {
|
|
||||||
this.compileError("This type can only exist inside of a scope."); throw new Error()
|
|
||||||
};
|
|
||||||
let atypes = this.em.archetypesMatching(reftype.query);
|
|
||||||
let entities = this.currentScope.entitiesMatching(atypes);
|
|
||||||
if (entities.length == 0) this.compileError(`This entitiy doesn't seem to fit the reference type.`);
|
|
||||||
id -= entities[0].id;
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
this.compileError(`I expected a ${field.dtype} here.`); throw new Error();
|
this.compileError(`I expected a ${field.dtype} here.`); throw new Error();
|
||||||
}
|
}
|
||||||
|
@ -185,8 +185,13 @@ export class ECSCompiler extends Tokenizer {
|
||||||
|
|
||||||
expectInteger(): number {
|
expectInteger(): number {
|
||||||
let s = this.consumeToken().str;
|
let s = this.consumeToken().str;
|
||||||
if (s.startsWith('$')) s = '0x' + s.substring(1);
|
let i : number;
|
||||||
let i = parseInt(s);
|
if (s.startsWith('$'))
|
||||||
|
i = parseInt(s.substring(1), 16); // hex $...
|
||||||
|
else if (s.startsWith('%'))
|
||||||
|
i = parseInt(s.substring(1), 2); // binary %...
|
||||||
|
else
|
||||||
|
i = parseInt(s); // default base 10 or 16 (0x...)
|
||||||
if (isNaN(i)) this.compileError('There should be an integer here.');
|
if (isNaN(i)) this.compileError('There should be an integer here.');
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +203,7 @@ export class ECSCompiler extends Tokenizer {
|
||||||
let cmd;
|
let cmd;
|
||||||
while ((cmd = this.expectTokens(['on','locals','end']).str) != 'end') {
|
while ((cmd = this.expectTokens(['on','locals','end']).str) != 'end') {
|
||||||
if (cmd == 'on') {
|
if (cmd == 'on') {
|
||||||
let action = this.annotate(() => this.parseAction());
|
let action = this.annotate(() => this.parseAction(system));
|
||||||
actions.push(action);
|
actions.push(action);
|
||||||
} else if (cmd == 'locals') {
|
} else if (cmd == 'locals') {
|
||||||
system.tempbytes = this.expectInteger();
|
system.tempbytes = this.expectInteger();
|
||||||
|
@ -216,13 +221,16 @@ export class ECSCompiler extends Tokenizer {
|
||||||
this.consumeToken();
|
this.consumeToken();
|
||||||
tempbytes = this.expectInteger();
|
tempbytes = this.expectInteger();
|
||||||
}
|
}
|
||||||
let text = this.parseCode();
|
let system : System = { name, tempbytes, actions: [] };
|
||||||
|
let context : ActionOwner = { scope: null, system };
|
||||||
|
let text = this.parseCode(context);
|
||||||
let select : SelectType = 'once';
|
let select : SelectType = 'once';
|
||||||
let action : Action = { text, event: name, select };
|
let action : Action = { text, event: name, select };
|
||||||
return { name, tempbytes, actions: [action] };
|
system.actions.push(action);
|
||||||
|
return system;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseAction(): Action {
|
parseAction(system: System): Action {
|
||||||
// TODO: unused events?
|
// TODO: unused events?
|
||||||
const event = this.expectIdent().str;
|
const event = this.expectIdent().str;
|
||||||
this.expectToken('do');
|
this.expectToken('do');
|
||||||
|
@ -245,7 +253,8 @@ export class ECSCompiler extends Tokenizer {
|
||||||
if (!query) { this.compileError(`A "${select}" query can't include a limit.`); }
|
if (!query) { this.compileError(`A "${select}" query can't include a limit.`); }
|
||||||
else query.limit = this.expectInteger();
|
else query.limit = this.expectInteger();
|
||||||
}
|
}
|
||||||
let text = this.parseCode();
|
let context : ActionOwner = { scope: null, system };
|
||||||
|
let text = this.parseCode(context);
|
||||||
let direction = undefined;
|
let direction = undefined;
|
||||||
if (modifiers['asc']) direction = 'asc';
|
if (modifiers['asc']) direction = 'asc';
|
||||||
else if (modifiers['desc']) direction = 'desc';
|
else if (modifiers['desc']) direction = 'desc';
|
||||||
|
@ -287,13 +296,20 @@ export class ECSCompiler extends Tokenizer {
|
||||||
return this.parseList(this.parseEventName, ",");
|
return this.parseList(this.parseEventName, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
parseCode(): string {
|
parseCode(context: ActionOwner): string { // TODOActionNode[] {
|
||||||
// TODO: add $loc
|
// TODO: add $loc
|
||||||
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||||
let code = tok.str.substring(3, tok.str.length-3);
|
let code = tok.str.substring(3, tok.str.length-3);
|
||||||
|
/*
|
||||||
let lines = code.split('\n');
|
let lines = code.split('\n');
|
||||||
|
// TODO: add after parsing maybe?
|
||||||
if (this.debuginfo) this.addDebugInfo(lines, tok.$loc.line);
|
if (this.debuginfo) this.addDebugInfo(lines, tok.$loc.line);
|
||||||
return lines.join('\n');
|
code = lines.join('\n');
|
||||||
|
*/
|
||||||
|
let acomp = new ECSActionCompiler(context);
|
||||||
|
let nodes = acomp.parseFile(code, this.path);
|
||||||
|
// TODO: return nodes
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
addDebugInfo(lines: string[], startline: number) {
|
addDebugInfo(lines: string[], startline: number) {
|
||||||
|
@ -342,6 +358,7 @@ export class ECSCompiler extends Tokenizer {
|
||||||
|
|
||||||
parseEntity() : Entity {
|
parseEntity() : Entity {
|
||||||
if (!this.currentScope) { this.internalError(); throw new Error(); }
|
if (!this.currentScope) { this.internalError(); throw new Error(); }
|
||||||
|
const scope = this.currentScope;
|
||||||
let entname = '';
|
let entname = '';
|
||||||
if (this.peekToken().type == TokenType.Ident) {
|
if (this.peekToken().type == TokenType.Ident) {
|
||||||
entname = this.expectIdent().str;
|
entname = this.expectIdent().str;
|
||||||
|
@ -349,17 +366,30 @@ export class ECSCompiler extends Tokenizer {
|
||||||
let etype = this.parseEntityArchetype();
|
let etype = this.parseEntityArchetype();
|
||||||
let entity = this.currentScope.newEntity(etype);
|
let entity = this.currentScope.newEntity(etype);
|
||||||
entity.name = entname;
|
entity.name = entname;
|
||||||
let cmd;
|
let cmd2 : string;
|
||||||
// TODO: remove init?
|
// TODO: remove init?
|
||||||
while ((cmd = this.expectTokens(['const', 'init', 'var', 'decode', 'end']).str) != 'end') {
|
while ((cmd2 = this.expectTokens(['const', 'init', 'var', 'decode', 'end']).str) != 'end') {
|
||||||
|
let cmd = cmd2; // put in scope
|
||||||
if (cmd == 'var') cmd = 'init';
|
if (cmd == 'var') cmd = 'init';
|
||||||
if (cmd == 'init' || cmd == 'const') {
|
if (cmd == 'init' || cmd == 'const') {
|
||||||
// TODO: check data types
|
// TODO: check data types
|
||||||
let name = this.expectIdent().str;
|
let name = this.expectIdent().str;
|
||||||
this.setEntityProperty(entity, name, cmd, (field) : DataValue => {
|
let { component, field } = this.getEntityField(entity, name);
|
||||||
this.expectToken('=');
|
let symtype = this.currentScope.isConstOrInit(component, name);
|
||||||
return this.parseDataValue(field);
|
if (symtype && symtype != cmd)
|
||||||
});
|
this.compileError(`I can't mix const and init values for a given field in a scope.`);
|
||||||
|
this.expectToken('=');
|
||||||
|
let valueOrRef = this.parseDataValue(field);
|
||||||
|
if ((valueOrRef as ForwardRef).token != null) {
|
||||||
|
this.deferred.push(() => {
|
||||||
|
let refvalue = this.resolveEntityRef(scope, valueOrRef as ForwardRef);
|
||||||
|
if (cmd == 'const') scope.setConstValue(entity, component, name, refvalue);
|
||||||
|
if (cmd == 'init') scope.setInitValue(entity, component, name, refvalue);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (cmd == 'const') scope.setConstValue(entity, component, name, valueOrRef as DataValue);
|
||||||
|
if (cmd == 'init') scope.setInitValue(entity, component, name, valueOrRef as DataValue);
|
||||||
|
}
|
||||||
} else if (cmd == 'decode') {
|
} else if (cmd == 'decode') {
|
||||||
let decoderid = this.expectIdent().str;
|
let decoderid = this.expectIdent().str;
|
||||||
let code = this.expectTokenTypes([ECSTokenType.CodeFragment]).str;
|
let code = this.expectTokenTypes([ECSTokenType.CodeFragment]).str;
|
||||||
|
@ -368,28 +398,23 @@ export class ECSCompiler extends Tokenizer {
|
||||||
if (!decoder) { this.compileError(`I can't find a "${decoderid}" decoder.`); throw new Error() }
|
if (!decoder) { this.compileError(`I can't find a "${decoderid}" decoder.`); throw new Error() }
|
||||||
let result = decoder.parse();
|
let result = decoder.parse();
|
||||||
for (let entry of Object.entries(result.properties)) {
|
for (let entry of Object.entries(result.properties)) {
|
||||||
this.setEntityProperty(entity, entry[0], 'const', (field) : DataValue => {
|
let { component, field } = this.getEntityField(entity, entry[0]);
|
||||||
return entry[1];
|
scope.setConstValue(entity, component, field.name, entry[1]);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
setEntityProperty(e: Entity, name: string, cmd: 'init' | 'const', valuefn: (field: DataField) => DataValue) {
|
getEntityField(e: Entity, name: string) {
|
||||||
if (!this.currentScope) { this.internalError(); throw new Error(); }
|
if (!this.currentScope) { this.internalError(); throw new Error(); }
|
||||||
let comps = this.em.componentsWithFieldName([e.etype], name);
|
let comps = this.em.componentsWithFieldName([e.etype], name);
|
||||||
if (comps.length == 0) this.compileError(`I couldn't find a field named "${name}" for this entity.`)
|
if (comps.length == 0) this.compileError(`I couldn't find a field named "${name}" for this entity.`)
|
||||||
if (comps.length > 1) this.compileError(`I found more than one field named "${name}" for this entity.`)
|
if (comps.length > 1) this.compileError(`I found more than one field named "${name}" for this entity.`)
|
||||||
let field = comps[0].fields.find(f => f.name == name);
|
let component = comps[0];
|
||||||
|
let field = component.fields.find(f => f.name == name);
|
||||||
if (!field) { this.internalError(); throw new Error(); }
|
if (!field) { this.internalError(); throw new Error(); }
|
||||||
let value = valuefn(field);
|
return { component, field };
|
||||||
let symtype = this.currentScope.isConstOrInit(comps[0], name);
|
|
||||||
if (symtype && symtype != cmd)
|
|
||||||
this.compileError(`I can't mix const and init values for a given field in a scope.`);
|
|
||||||
if (cmd == 'const') this.currentScope.setConstValue(e, comps[0], name, value);
|
|
||||||
if (cmd == 'init') this.currentScope.setInitValue(e, comps[0], name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parseEntityArchetype() : EntityArchetype {
|
parseEntityArchetype() : EntityArchetype {
|
||||||
|
@ -406,18 +431,25 @@ export class ECSCompiler extends Tokenizer {
|
||||||
return cref;
|
return cref;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseEntityRef(reftype?: RefType) : Entity {
|
resolveEntityRef(scope: EntityScope, ref: ForwardRef) : number {
|
||||||
if (!this.currentScope) { this.internalError(); throw new Error(); }
|
let name = ref.token.str;
|
||||||
this.expectToken('#');
|
let eref = scope.entities.find(e => e.name == name);
|
||||||
let name = this.expectIdent().str;
|
|
||||||
let eref = this.currentScope.entities.find(e => e.name == name);
|
|
||||||
if (!eref) {
|
if (!eref) {
|
||||||
this.compileError(`I couldn't find an entity named "${name}" in this scope.`)
|
this.compileError(`I couldn't find an entity named "${name}" in this scope.`, ref.token.$loc)
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
return eref;
|
let id = eref.id;
|
||||||
|
if (ref.reftype) {
|
||||||
|
// TODO: make this a function? elo ehi etc?
|
||||||
|
let atypes = this.em.archetypesMatching(ref.reftype.query);
|
||||||
|
let entities = scope.entitiesMatching(atypes);
|
||||||
|
if (entities.length == 0)
|
||||||
|
this.compileError(`This entity doesn't seem to fit the reference type.`, ref.token.$loc);
|
||||||
|
id -= entities[0].id;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseSystemRef() : System {
|
parseSystemRef() : System {
|
||||||
let name = this.expectIdent().str;
|
let name = this.expectIdent().str;
|
||||||
let sys = this.em.getSystemByName(name);
|
let sys = this.em.getSystemByName(name);
|
||||||
|
@ -438,3 +470,31 @@ export class ECSCompiler extends Tokenizer {
|
||||||
return src.toString();
|
return src.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ECSActionCompiler extends Tokenizer {
|
||||||
|
constructor(
|
||||||
|
public readonly context: ActionOwner)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.setTokenRules([
|
||||||
|
{ type: ECSTokenType.Placeholder, regex: /\{\{.*?\}\}/ },
|
||||||
|
{ type: TokenType.CatchAll, regex: /[^{\n]+\n*/ },
|
||||||
|
]);
|
||||||
|
this.errorOnCatchAll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseFile(text: string, path: string) {
|
||||||
|
this.tokenizeFile(text, path);
|
||||||
|
let nodes = [];
|
||||||
|
while (!this.isEOF()) {
|
||||||
|
let tok = this.consumeToken();
|
||||||
|
if (tok.type == ECSTokenType.Placeholder) {
|
||||||
|
let args = tok.str.substring(2, tok.str.length-2).split(/\s+/);
|
||||||
|
nodes.push(new CodePlaceholderNode(this.context, tok.$loc, args));
|
||||||
|
} else if (tok.type == TokenType.CatchAll) {
|
||||||
|
nodes.push(new CodeLiteralNode(this.context, tok.$loc, tok.str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,66 +1,3 @@
|
||||||
/*
|
|
||||||
|
|
||||||
entity scopes contain entities, and are nested
|
|
||||||
also contain segments (code, bss, rodata)
|
|
||||||
components and systems are global
|
|
||||||
component fields are stored in arrays, range of entities, can be bit-packed
|
|
||||||
some values can be constant, are stored in rodata (or loaded immediate)
|
|
||||||
optional components? on or off
|
|
||||||
union components? either X or Y or Z...
|
|
||||||
|
|
||||||
systems receive and send events, execute code on entities
|
|
||||||
systems are generated on a per-scope basis
|
|
||||||
system queries can only contain entities from self and parent scopes
|
|
||||||
starting from the 'init' event walk the event tree
|
|
||||||
include systems that have at least 1 entity in scope (except init?)
|
|
||||||
|
|
||||||
when entering scope, entities are initialized (zero or init w/ data)
|
|
||||||
to change scope, fire event w/ scope name
|
|
||||||
- how to handle bank-switching?
|
|
||||||
|
|
||||||
helps with:
|
|
||||||
- rapid prototyping w/ reasonable defaults
|
|
||||||
- deconstructing objects into arrays
|
|
||||||
- packing/unpacking bitfields
|
|
||||||
- initializing objects
|
|
||||||
- building lookup tables
|
|
||||||
- selecting and iterating objects
|
|
||||||
- managing events
|
|
||||||
- managing memory and scope
|
|
||||||
- converting assets to native formats?
|
|
||||||
- removing unused data
|
|
||||||
|
|
||||||
it's more convenient to have loops be zero-indexed
|
|
||||||
for page cross, temp storage, etc
|
|
||||||
should references be zero-indexed to a field, or global?
|
|
||||||
should we limit # of entities passed to systems? min-max
|
|
||||||
join thru a reference? load both x and y
|
|
||||||
|
|
||||||
code fragments can be parameterized like macros
|
|
||||||
if two fragments are identical, do a JSR
|
|
||||||
(do we have to look for labels?)
|
|
||||||
should events have parameters? e.g. addscore X Y Z
|
|
||||||
how are Z80 arrays working?
|
|
||||||
https://forums.nesdev.org/viewtopic.php?f=20&t=14691
|
|
||||||
https://www.cpcwiki.eu/forum/programming/trying-not-to-use-ix/msg133416/#msg133416
|
|
||||||
|
|
||||||
how to select two between two entities with once? like scoreboard
|
|
||||||
maybe stack-based interpreter?
|
|
||||||
|
|
||||||
can you query specific entities? merge with existing queries?
|
|
||||||
bigints?
|
|
||||||
source/if query?
|
|
||||||
|
|
||||||
only worry about intersection when non-contiguous ranges?
|
|
||||||
|
|
||||||
crazy idea -- full expansion, then relooper
|
|
||||||
|
|
||||||
how to avoid cycle crossing for critical code and data? bin packing
|
|
||||||
|
|
||||||
system define order, action order, entity order, using order?
|
|
||||||
what happens when a system must be nested inside another? like display kernels
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { SourceLocated, SourceLocation } from "../workertypes";
|
import { SourceLocated, SourceLocation } from "../workertypes";
|
||||||
import { Bin, Packer } from "./binpack";
|
import { Bin, Packer } from "./binpack";
|
||||||
|
@ -130,6 +67,39 @@ export class ActionStats {
|
||||||
callcount: number = 0;
|
callcount: number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ActionOwner {
|
||||||
|
system: System
|
||||||
|
scope: EntityScope | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ActionNode implements SourceLocated {
|
||||||
|
constructor(
|
||||||
|
public readonly owner: ActionOwner,
|
||||||
|
public readonly $loc: SourceLocation
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CodeLiteralNode extends ActionNode {
|
||||||
|
constructor(
|
||||||
|
owner: ActionOwner,
|
||||||
|
$loc: SourceLocation,
|
||||||
|
public readonly text: string
|
||||||
|
) {
|
||||||
|
super(owner, $loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CodePlaceholderNode extends ActionNode {
|
||||||
|
constructor(
|
||||||
|
owner: ActionOwner,
|
||||||
|
$loc: SourceLocation,
|
||||||
|
public readonly args: string[]
|
||||||
|
) {
|
||||||
|
super(owner, $loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ActionBase extends SourceLocated {
|
export interface ActionBase extends SourceLocated {
|
||||||
select: SelectType;
|
select: SelectType;
|
||||||
event: string;
|
event: string;
|
||||||
|
@ -532,6 +502,10 @@ class ActionCPUState {
|
||||||
yofs: number = 0;
|
yofs: number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ActionContext {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class ActionEval {
|
class ActionEval {
|
||||||
em : EntityManager;
|
em : EntityManager;
|
||||||
dialect : Dialect_CA65;
|
dialect : Dialect_CA65;
|
||||||
|
@ -1272,15 +1246,24 @@ export class EntityManager {
|
||||||
if (!parent) this.topScopes[name] = scope;
|
if (!parent) this.topScopes[name] = scope;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
deferComponent(name: string) {
|
||||||
|
this.components[name] = { name, fields: [] };
|
||||||
|
}
|
||||||
defineComponent(ctype: ComponentType) {
|
defineComponent(ctype: ComponentType) {
|
||||||
let existing = this.components[ctype.name];
|
let existing = this.components[ctype.name];
|
||||||
if (existing) throw new ECSError(`component ${ctype.name} already defined`, existing);
|
if (existing && existing.fields.length > 0)
|
||||||
|
throw new ECSError(`component ${ctype.name} already defined`, existing);
|
||||||
for (let field of ctype.fields) {
|
for (let field of ctype.fields) {
|
||||||
let list = this.name2cfpairs[field.name];
|
let list = this.name2cfpairs[field.name];
|
||||||
if (!list) list = this.name2cfpairs[field.name] = [];
|
if (!list) list = this.name2cfpairs[field.name] = [];
|
||||||
list.push({ c: ctype, f: field });
|
list.push({ c: ctype, f: field });
|
||||||
}
|
}
|
||||||
return this.components[ctype.name] = ctype;
|
if (existing) {
|
||||||
|
existing.fields = ctype.fields;
|
||||||
|
return existing;
|
||||||
|
} else {
|
||||||
|
return this.components[ctype.name] = ctype;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defineSystem(system: System) {
|
defineSystem(system: System) {
|
||||||
let existing = this.systems[system.name];
|
let existing = this.systems[system.name];
|
||||||
|
|
|
@ -69,6 +69,7 @@ export class Tokenizer {
|
||||||
curlabel: string;
|
curlabel: string;
|
||||||
eof: Token;
|
eof: Token;
|
||||||
errorOnCatchAll = false;
|
errorOnCatchAll = false;
|
||||||
|
deferred: (() => void)[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
|
@ -230,4 +231,9 @@ export class Tokenizer {
|
||||||
this.pushbackToken(sep);
|
this.pushbackToken(sep);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
runDeferred() {
|
||||||
|
while (this.deferred.length) {
|
||||||
|
this.deferred.shift()();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { execFileSync, spawnSync } from "child_process";
|
||||||
import { readdirSync, readFileSync, writeFileSync } from "fs";
|
import { readdirSync, readFileSync, writeFileSync } from "fs";
|
||||||
import { describe } from "mocha";
|
import { describe } from "mocha";
|
||||||
import { Bin, BoxConstraints, Packer } from "../common/ecs/binpack";
|
import { Bin, BoxConstraints, Packer } from "../common/ecs/binpack";
|
||||||
import { ECSCompiler } from "../common/ecs/compiler";
|
import { ECSActionCompiler, ECSCompiler } from "../common/ecs/compiler";
|
||||||
import { Dialect_CA65, EntityManager, SourceFileExport } from "../common/ecs/ecs";
|
import { Dialect_CA65, EntityManager, SourceFileExport } from "../common/ecs/ecs";
|
||||||
|
|
||||||
const TEMPLATE1 = `
|
const TEMPLATE1 = `
|
||||||
|
@ -344,6 +344,7 @@ end
|
||||||
c.exportToFile(src);
|
c.exportToFile(src);
|
||||||
// TODO: test?
|
// TODO: test?
|
||||||
//console.log(src.toString());
|
//console.log(src.toString());
|
||||||
|
return em;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
for (let err of c.errors) {
|
for (let err of c.errors) {
|
||||||
|
|
400
test/ecs/sprites1.ecs
Normal file
400
test/ecs/sprites1.ecs
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
|
||||||
|
//#resource "vcs-ca65.h"
|
||||||
|
|
||||||
|
import "vcslib.ecs"
|
||||||
|
|
||||||
|
component Bitmap
|
||||||
|
bitmapdata: array of 0..255 baseoffset 31
|
||||||
|
height: 0..255
|
||||||
|
end
|
||||||
|
|
||||||
|
component HasBitmap
|
||||||
|
bitmap: [Bitmap]
|
||||||
|
end
|
||||||
|
|
||||||
|
component Colormap
|
||||||
|
colormapdata: array of 0..255 baseoffset 31
|
||||||
|
end
|
||||||
|
|
||||||
|
component HasColormap
|
||||||
|
colormap: [Colormap]
|
||||||
|
end
|
||||||
|
|
||||||
|
component Sprite
|
||||||
|
plyrflags: 0..63
|
||||||
|
end
|
||||||
|
|
||||||
|
component HasXpos
|
||||||
|
xpos: 0..255
|
||||||
|
end
|
||||||
|
|
||||||
|
component HasYpos
|
||||||
|
ypos: 0..255
|
||||||
|
end
|
||||||
|
|
||||||
|
component SpriteSlot
|
||||||
|
sprite: [Sprite,HasBitmap,HasColormap,HasYpos]
|
||||||
|
end
|
||||||
|
|
||||||
|
component Missile
|
||||||
|
end
|
||||||
|
|
||||||
|
system Kernel2Sprite
|
||||||
|
locals 13
|
||||||
|
on preframe do with [KernelSection]
|
||||||
|
---
|
||||||
|
.define KLINES {{<lines}}
|
||||||
|
.define KPAD 32
|
||||||
|
---
|
||||||
|
on preframe do join
|
||||||
|
[SpriteSlot] with
|
||||||
|
[Sprite,HasBitmap,HasColormap,HasYpos] limit 2
|
||||||
|
---
|
||||||
|
; set player object flags
|
||||||
|
lda {{<plyrflags}}
|
||||||
|
sta NUSIZ0,y
|
||||||
|
sta REFP0,y
|
||||||
|
; calculate screen height - ypos
|
||||||
|
lda KLINES+KPAD
|
||||||
|
sec
|
||||||
|
sbc {{<ypos}}
|
||||||
|
sta {{$11}}
|
||||||
|
; calculate bitmap pointer
|
||||||
|
stx {{$12}} ; save X (Sprite index)
|
||||||
|
lda {{<bitmap}} ; deref bitmap
|
||||||
|
tax
|
||||||
|
lda {{<Bitmap:bitmapdata}},x
|
||||||
|
sec
|
||||||
|
sbc {{$11}}
|
||||||
|
sta {{$0}},y ; Y = sprite slot index
|
||||||
|
lda {{>Bitmap:bitmapdata}},x
|
||||||
|
sbc #0
|
||||||
|
sta {{$2}},y
|
||||||
|
; get bitmap height
|
||||||
|
lda {{<Bitmap:height}},x
|
||||||
|
sta {{$8}},y
|
||||||
|
; calculate colormap pointer
|
||||||
|
ldx {{$12}} ; restore X
|
||||||
|
lda {{<colormap}} ; deref colormap
|
||||||
|
tax
|
||||||
|
lda {{<Colormap:colormapdata}},x
|
||||||
|
sec
|
||||||
|
sbc {{$11}}
|
||||||
|
sta {{$4}},y
|
||||||
|
lda {{>Colormap:colormapdata}},x
|
||||||
|
sbc #0
|
||||||
|
sta {{$6}},y
|
||||||
|
; save ypos
|
||||||
|
ldx {{$12}} ; restore X
|
||||||
|
lda {{<ypos}}
|
||||||
|
sta {{$10}},y
|
||||||
|
---
|
||||||
|
on preframe do once
|
||||||
|
---
|
||||||
|
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||||
|
lda {{$1}}
|
||||||
|
ldy {{$2}}
|
||||||
|
sty {{$1}}
|
||||||
|
sta {{$2}}
|
||||||
|
lda {{$5}}
|
||||||
|
ldy {{$6}}
|
||||||
|
sty {{$5}}
|
||||||
|
sta {{$6}}
|
||||||
|
---
|
||||||
|
on preframe do if [BGColor]
|
||||||
|
---
|
||||||
|
lda {{<bgcolor}}
|
||||||
|
sta COLUBK
|
||||||
|
---
|
||||||
|
on preframe do if [Missile,HasYpos]
|
||||||
|
---
|
||||||
|
lda KLINES
|
||||||
|
sec
|
||||||
|
sbc {{<ypos}}
|
||||||
|
sta {{$12}}
|
||||||
|
---
|
||||||
|
on kernel do with [KernelSection]
|
||||||
|
---
|
||||||
|
ldy #0
|
||||||
|
sty VDELP0
|
||||||
|
iny
|
||||||
|
sta VDELP1
|
||||||
|
---
|
||||||
|
on kernel do with [KernelSection]
|
||||||
|
---
|
||||||
|
; define macro for each line
|
||||||
|
.macro @DrawLine do_wsync
|
||||||
|
.local DoDraw1
|
||||||
|
.local DoDraw2
|
||||||
|
; draw player 0
|
||||||
|
lda {{$8}} ; height
|
||||||
|
dcp {{$10}} ; ypos
|
||||||
|
bcs DoDraw1
|
||||||
|
lda #0
|
||||||
|
.byte $2C
|
||||||
|
DoDraw1:
|
||||||
|
lda ({{$0}}),y
|
||||||
|
.if do_wsync
|
||||||
|
sta WSYNC
|
||||||
|
.endif
|
||||||
|
sta GRP0
|
||||||
|
lda ({{$4}}),y
|
||||||
|
sta COLUP0
|
||||||
|
; draw player 1
|
||||||
|
lda {{$9}} ; height
|
||||||
|
dcp {{$11}} ; ypos
|
||||||
|
bcs DoDraw2
|
||||||
|
lda #0
|
||||||
|
.byte $2C
|
||||||
|
DoDraw2:
|
||||||
|
lda ({{$2}}),y
|
||||||
|
sta GRP1
|
||||||
|
lda ({{$6}}),y
|
||||||
|
sta COLUP1
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
ldy {{<lines}}
|
||||||
|
@LVScan:
|
||||||
|
{{!scanline1}}
|
||||||
|
@DrawLine 1 ; macro: draw scanline w/ WSYNC
|
||||||
|
dey ; next scanline
|
||||||
|
{{!scanline2}}
|
||||||
|
@DrawLine 0 ; macro: draw scanline no WSYNC
|
||||||
|
dey ; next scanline
|
||||||
|
bne @LVScan ; repeat until out of lines
|
||||||
|
---
|
||||||
|
on kernel do with [KernelSection]
|
||||||
|
---
|
||||||
|
lda #0
|
||||||
|
sta GRP0
|
||||||
|
sta GRP1
|
||||||
|
sta GRP0
|
||||||
|
sta GRP1
|
||||||
|
---
|
||||||
|
on scanline1 do if [Missile,HasYpos]
|
||||||
|
---
|
||||||
|
cpy {{$12}}
|
||||||
|
php
|
||||||
|
pla
|
||||||
|
sta ENAM0
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system VersatilePlayfield
|
||||||
|
locals 2
|
||||||
|
on preframe do with [VersatilePlayfield]
|
||||||
|
---
|
||||||
|
lda {{<data}}
|
||||||
|
sta {{$0}}
|
||||||
|
lda {{>data}}
|
||||||
|
sta {{$1}}
|
||||||
|
---
|
||||||
|
on scanline1 do with [VersatilePlayfield]
|
||||||
|
---
|
||||||
|
lda ({{local 0}}),y
|
||||||
|
tax
|
||||||
|
---
|
||||||
|
on scanline2 do with [VersatilePlayfield]
|
||||||
|
---
|
||||||
|
lda ({{local 0}}),y
|
||||||
|
sta $00,x
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system SetXPos
|
||||||
|
on preframe do once
|
||||||
|
---
|
||||||
|
sta HMCLR
|
||||||
|
---
|
||||||
|
on preframe do join [SpriteSlot] with [HasXpos]
|
||||||
|
limit 2
|
||||||
|
---
|
||||||
|
lda {{<xpos}}
|
||||||
|
{{!SetHorizPos}}
|
||||||
|
---
|
||||||
|
on preframe do if [Missile,HasXpos]
|
||||||
|
---
|
||||||
|
lda {{<xpos}}
|
||||||
|
ldx #2
|
||||||
|
{{!SetHorizPos}}
|
||||||
|
---
|
||||||
|
on preframe do once
|
||||||
|
---
|
||||||
|
sta WSYNC
|
||||||
|
sta HMOVE
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system MoveJoyX
|
||||||
|
on joyleft do with [HasXpos]
|
||||||
|
---
|
||||||
|
lda {{<xpos}}
|
||||||
|
sec
|
||||||
|
sbc #1
|
||||||
|
bcc @nomove
|
||||||
|
sta {{<xpos}}
|
||||||
|
@nomove:
|
||||||
|
---
|
||||||
|
on joyright do with [HasXpos]
|
||||||
|
---
|
||||||
|
lda {{<xpos}}
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
cmp #152
|
||||||
|
bcs @nomove
|
||||||
|
sta {{<xpos}}
|
||||||
|
@nomove:
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system MoveJoyY
|
||||||
|
on joyup do with [HasYpos]
|
||||||
|
---
|
||||||
|
lda {{<ypos}}
|
||||||
|
sec
|
||||||
|
sbc #1
|
||||||
|
bcc @nomove
|
||||||
|
sta {{<ypos}}
|
||||||
|
@nomove:
|
||||||
|
---
|
||||||
|
on joydown do with [HasYpos]
|
||||||
|
---
|
||||||
|
lda {{<ypos}}
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
cmp #220
|
||||||
|
bcs @nomove
|
||||||
|
sta {{<ypos}}
|
||||||
|
@nomove:
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system SpriteShuffler
|
||||||
|
locals 2
|
||||||
|
on postframe do select [SpriteSlot]
|
||||||
|
---
|
||||||
|
; load two sprite slots at left side of array
|
||||||
|
lda {{<SpriteSlot:sprite}}
|
||||||
|
sta {{$0}}
|
||||||
|
lda {{<SpriteSlot:sprite}}+1
|
||||||
|
sta {{$1}}
|
||||||
|
; move two slots to the left
|
||||||
|
ldx #0
|
||||||
|
@loop:
|
||||||
|
lda {{<SpriteSlot:sprite}}+2,x
|
||||||
|
sta {{<SpriteSlot:sprite}},x
|
||||||
|
inx
|
||||||
|
cpx #{{%ecount}}-2
|
||||||
|
bne @loop
|
||||||
|
; store two sprite slots at right side of array
|
||||||
|
lda {{$0}}
|
||||||
|
sta {{<SpriteSlot:sprite}}+{{%ecount}}-2
|
||||||
|
lda {{$1}}
|
||||||
|
sta {{<SpriteSlot:sprite}}+{{%ecount}}-1
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system SpriteHider
|
||||||
|
locals 1
|
||||||
|
on postframe do select [SpriteSlot]
|
||||||
|
---
|
||||||
|
lda #{{%efullcount}}-1
|
||||||
|
sta {{$0}}
|
||||||
|
---
|
||||||
|
on postframe do
|
||||||
|
join [SpriteSlot]
|
||||||
|
with [Sprite,HasYpos]
|
||||||
|
limit 2
|
||||||
|
---
|
||||||
|
lda {{<ypos}}
|
||||||
|
cmp #192
|
||||||
|
bcc @skip
|
||||||
|
; swap this sprite slot with slot at end of array
|
||||||
|
lda {{<SpriteSlot:sprite}},y
|
||||||
|
pha
|
||||||
|
ldx {{$0}} ; clobbers X, but no longer used
|
||||||
|
lda {{<SpriteSlot:sprite}},x
|
||||||
|
sta {{<SpriteSlot:sprite}},y
|
||||||
|
pla
|
||||||
|
sta {{<SpriteSlot:sprite}},x
|
||||||
|
dec {{$0}}
|
||||||
|
@skip:
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
demo Main
|
||||||
|
|
||||||
|
using FrameLoop, Kernel2Sprite
|
||||||
|
using Joystick, MoveJoyX, MoveJoyY
|
||||||
|
using SetXPos, SetHorizPos
|
||||||
|
using SpriteShuffler, SpriteHider
|
||||||
|
|
||||||
|
entity Kernel [KernelSection, BGColor]
|
||||||
|
const lines = 192
|
||||||
|
const bgcolor = 0xa2
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Bitmap1 [Bitmap]
|
||||||
|
const bitmapdata = [1, 1, 3, 7, 15, 31, 63, 127]
|
||||||
|
const height = 8
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Bitmap2 [Bitmap]
|
||||||
|
const bitmapdata = [$18,$3e,$ff,$ff,$ff,$ff,$3e,$18]
|
||||||
|
const height = 8
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Colormap1 [Colormap]
|
||||||
|
const colormapdata = [6, 3, 6, 9, 12, 14, 31, 63]
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Sprite0 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||||
|
init xpos = 50
|
||||||
|
init ypos = 150
|
||||||
|
init bitmap = #Bitmap2
|
||||||
|
const plyrflags = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Sprite1 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||||
|
init xpos = 100
|
||||||
|
init ypos = 60
|
||||||
|
init bitmap = #Bitmap1
|
||||||
|
const plyrflags = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Sprite2 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||||
|
init xpos = 80
|
||||||
|
init ypos = 90
|
||||||
|
init bitmap = #Bitmap2
|
||||||
|
const plyrflags = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
entity Sprite3 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||||
|
init xpos = 40
|
||||||
|
init ypos = 150
|
||||||
|
init bitmap = #Bitmap1
|
||||||
|
const plyrflags = 0
|
||||||
|
end
|
||||||
|
/*
|
||||||
|
entity [Missile,HasXpos,HasYpos]
|
||||||
|
init xpos = 70
|
||||||
|
init ypos = 70
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
entity Slot0 [SpriteSlot]
|
||||||
|
init sprite = #Sprite0
|
||||||
|
end
|
||||||
|
entity Slot1 [SpriteSlot]
|
||||||
|
init sprite = #Sprite1
|
||||||
|
end
|
||||||
|
entity Slot2 [SpriteSlot]
|
||||||
|
init sprite = #Sprite2
|
||||||
|
end
|
||||||
|
entity Slot3 [SpriteSlot]
|
||||||
|
init sprite = #Sprite3
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
515
test/ecs/sprites1.txt
Normal file
515
test/ecs/sprites1.txt
Normal file
|
@ -0,0 +1,515 @@
|
||||||
|
.scope Main
|
||||||
|
.zeropage
|
||||||
|
SpriteSlot_sprite_b0:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
HasYpos_ypos_b0:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
HasXpos_xpos_b0:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
HasColormap_colormap_b0:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
HasBitmap_bitmap_b0:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
TEMP:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
Kernel2Sprite__tmp = TEMP+0
|
||||||
|
Joystick__tmp = TEMP+0
|
||||||
|
SpriteShuffler__tmp = TEMP+1
|
||||||
|
SpriteHider__tmp = TEMP+3
|
||||||
|
.code
|
||||||
|
Bitmap_bitmapdata_e1_b0:
|
||||||
|
.byte 1
|
||||||
|
.byte 1
|
||||||
|
.byte 3
|
||||||
|
.byte 7
|
||||||
|
.byte 15
|
||||||
|
.byte 31
|
||||||
|
.byte 63
|
||||||
|
.byte 127
|
||||||
|
Bitmap_bitmapdata_b0:
|
||||||
|
.byte <(Bitmap_bitmapdata_e1_b0+31)
|
||||||
|
.byte <(Bitmap_bitmapdata_e2_b0+31)
|
||||||
|
Bitmap_bitmapdata_b8:
|
||||||
|
.byte >(Bitmap_bitmapdata_e1_b0+31)
|
||||||
|
.byte >(Bitmap_bitmapdata_e2_b0+31)
|
||||||
|
Bitmap_height_b0:
|
||||||
|
.byte 8
|
||||||
|
.byte 8
|
||||||
|
Bitmap_bitmapdata_e2_b0:
|
||||||
|
.byte 24
|
||||||
|
.byte 62
|
||||||
|
.byte 255
|
||||||
|
.byte 255
|
||||||
|
.byte 255
|
||||||
|
.byte 255
|
||||||
|
.byte 62
|
||||||
|
.byte 24
|
||||||
|
Colormap_colormapdata_e3_b0:
|
||||||
|
.byte 6
|
||||||
|
.byte 3
|
||||||
|
.byte 6
|
||||||
|
.byte 9
|
||||||
|
.byte 12
|
||||||
|
.byte 14
|
||||||
|
.byte 31
|
||||||
|
.byte 63
|
||||||
|
Colormap_colormapdata_b0:
|
||||||
|
.byte <(Colormap_colormapdata_e3_b0+31)
|
||||||
|
Colormap_colormapdata_b8:
|
||||||
|
.byte >(Colormap_colormapdata_e3_b0+31)
|
||||||
|
Sprite_plyrflags_b0:
|
||||||
|
.byte 0
|
||||||
|
.byte 3
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
Main__INITDATA:
|
||||||
|
.byte 0
|
||||||
|
.byte 1
|
||||||
|
.byte 2
|
||||||
|
.byte 3
|
||||||
|
.byte 150
|
||||||
|
.byte 60
|
||||||
|
.byte 90
|
||||||
|
.byte 150
|
||||||
|
.byte 50
|
||||||
|
.byte 100
|
||||||
|
.byte 80
|
||||||
|
.byte 40
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
.byte 1
|
||||||
|
.byte 0
|
||||||
|
.byte 1
|
||||||
|
.byte 0
|
||||||
|
__Start:
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Init main_init
|
||||||
|
|
||||||
|
.include "vcs-ca65.h"
|
||||||
|
.macpack longbranch
|
||||||
|
.define PAL 0
|
||||||
|
__NMI:
|
||||||
|
__Reset:
|
||||||
|
__BRK:
|
||||||
|
CLEAN_START
|
||||||
|
|
||||||
|
ldy #20
|
||||||
|
: lda Main__INITDATA-1,y
|
||||||
|
sta SpriteSlot_sprite_b0-1,y
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
; initialize data segment
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action FrameLoop start
|
||||||
|
|
||||||
|
FrameLoop__start__2__NextFrame:
|
||||||
|
FRAME_START
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
.define KLINES #192
|
||||||
|
.define KPAD 32
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
ldy #0
|
||||||
|
Kernel2Sprite__preframe__4____each:
|
||||||
|
ldx SpriteSlot_sprite_b0,y
|
||||||
|
|
||||||
|
; set player object flags
|
||||||
|
lda Sprite_plyrflags_b0,x
|
||||||
|
sta NUSIZ0,y
|
||||||
|
sta REFP0,y
|
||||||
|
; calculate screen height - ypos
|
||||||
|
lda KLINES+KPAD
|
||||||
|
sec
|
||||||
|
sbc HasYpos_ypos_b0,x
|
||||||
|
sta Kernel2Sprite__tmp+11
|
||||||
|
; calculate bitmap pointer
|
||||||
|
stx Kernel2Sprite__tmp+12 ; save X (Sprite index)
|
||||||
|
lda HasBitmap_bitmap_b0,x ; deref bitmap
|
||||||
|
tax
|
||||||
|
lda Bitmap_bitmapdata_b0,x
|
||||||
|
sec
|
||||||
|
sbc Kernel2Sprite__tmp+11
|
||||||
|
sta Kernel2Sprite__tmp+0,y ; Y = sprite slot index
|
||||||
|
lda Bitmap_bitmapdata_b8,x
|
||||||
|
sbc #0
|
||||||
|
sta Kernel2Sprite__tmp+2,y
|
||||||
|
; get bitmap height
|
||||||
|
lda Bitmap_height_b0,x
|
||||||
|
sta Kernel2Sprite__tmp+8,y
|
||||||
|
; calculate colormap pointer
|
||||||
|
ldx Kernel2Sprite__tmp+12 ; restore X
|
||||||
|
lda HasColormap_colormap_b0,x ; deref colormap
|
||||||
|
tax
|
||||||
|
lda Colormap_colormapdata_b0,x
|
||||||
|
sec
|
||||||
|
sbc Kernel2Sprite__tmp+11
|
||||||
|
sta Kernel2Sprite__tmp+4,y
|
||||||
|
lda Colormap_colormapdata_b8,x
|
||||||
|
sbc #0
|
||||||
|
sta Kernel2Sprite__tmp+6,y
|
||||||
|
; save ypos
|
||||||
|
ldx Kernel2Sprite__tmp+12 ; restore X
|
||||||
|
lda HasYpos_ypos_b0,x
|
||||||
|
sta Kernel2Sprite__tmp+10,y
|
||||||
|
|
||||||
|
iny
|
||||||
|
cpy #2
|
||||||
|
jne Kernel2Sprite__preframe__4____each
|
||||||
|
Kernel2Sprite__preframe__4____exit:
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||||
|
lda Kernel2Sprite__tmp+1
|
||||||
|
ldy Kernel2Sprite__tmp+2
|
||||||
|
sty Kernel2Sprite__tmp+1
|
||||||
|
sta Kernel2Sprite__tmp+2
|
||||||
|
lda Kernel2Sprite__tmp+5
|
||||||
|
ldy Kernel2Sprite__tmp+6
|
||||||
|
sty Kernel2Sprite__tmp+5
|
||||||
|
sta Kernel2Sprite__tmp+6
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
lda #162
|
||||||
|
sta COLUBK
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite preframe
|
||||||
|
|
||||||
|
;;; start action SetXPos preframe
|
||||||
|
|
||||||
|
sta HMCLR
|
||||||
|
|
||||||
|
;;; end action SetXPos preframe
|
||||||
|
|
||||||
|
;;; start action SetXPos preframe
|
||||||
|
|
||||||
|
ldy #0
|
||||||
|
SetXPos__preframe__8____each:
|
||||||
|
ldx SpriteSlot_sprite_b0,y
|
||||||
|
|
||||||
|
lda HasXpos_xpos_b0,x
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action SetHorizPos SetHorizPos
|
||||||
|
|
||||||
|
; SetHorizPos routine
|
||||||
|
; A = X coordinate
|
||||||
|
; Y = player number (0 or 1)
|
||||||
|
sta WSYNC ; start a new line
|
||||||
|
sec ; set carry flag
|
||||||
|
nop
|
||||||
|
SetHorizPos__SetHorizPos__9__DivideLoop:
|
||||||
|
sbc #15 ; subtract 15
|
||||||
|
bcs SetHorizPos__SetHorizPos__9__DivideLoop ; branch until negative
|
||||||
|
eor #7 ; calculate fine offset
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
sta RESP0,y ; fix coarse position
|
||||||
|
sta HMP0,y ; set fine offset
|
||||||
|
|
||||||
|
;;; end action SetHorizPos SetHorizPos
|
||||||
|
|
||||||
|
|
||||||
|
iny
|
||||||
|
cpy #2
|
||||||
|
jne SetXPos__preframe__8____each
|
||||||
|
SetXPos__preframe__8____exit:
|
||||||
|
|
||||||
|
;;; end action SetXPos preframe
|
||||||
|
|
||||||
|
;;; start action SetXPos preframe
|
||||||
|
|
||||||
|
;;; end action SetXPos preframe
|
||||||
|
|
||||||
|
;;; start action SetXPos preframe
|
||||||
|
|
||||||
|
sta WSYNC
|
||||||
|
sta HMOVE
|
||||||
|
|
||||||
|
;;; end action SetXPos preframe
|
||||||
|
|
||||||
|
KERNEL_START
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite kernel
|
||||||
|
|
||||||
|
ldy #0
|
||||||
|
sty VDELP0
|
||||||
|
iny
|
||||||
|
sta VDELP1
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite kernel
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite kernel
|
||||||
|
|
||||||
|
; define macro for each line
|
||||||
|
.macro Kernel2Sprite__kernel__12__DrawLine do_wsync
|
||||||
|
.local DoDraw1
|
||||||
|
.local DoDraw2
|
||||||
|
; draw player 0
|
||||||
|
lda Kernel2Sprite__tmp+8 ; height
|
||||||
|
dcp Kernel2Sprite__tmp+10 ; ypos
|
||||||
|
bcs DoDraw1
|
||||||
|
lda #0
|
||||||
|
.byte $2C
|
||||||
|
DoDraw1:
|
||||||
|
lda (Kernel2Sprite__tmp+0),y
|
||||||
|
.if do_wsync
|
||||||
|
sta WSYNC
|
||||||
|
.endif
|
||||||
|
sta GRP0
|
||||||
|
lda (Kernel2Sprite__tmp+4),y
|
||||||
|
sta COLUP0
|
||||||
|
; draw player 1
|
||||||
|
lda Kernel2Sprite__tmp+9 ; height
|
||||||
|
dcp Kernel2Sprite__tmp+11 ; ypos
|
||||||
|
bcs DoDraw2
|
||||||
|
lda #0
|
||||||
|
.byte $2C
|
||||||
|
DoDraw2:
|
||||||
|
lda (Kernel2Sprite__tmp+2),y
|
||||||
|
sta GRP1
|
||||||
|
lda (Kernel2Sprite__tmp+6),y
|
||||||
|
sta COLUP1
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
ldy #192
|
||||||
|
Kernel2Sprite__kernel__12__LVScan:
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite scanline1
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite scanline1
|
||||||
|
|
||||||
|
Kernel2Sprite__kernel__12__DrawLine 1 ; macro: draw scanline w/ WSYNC
|
||||||
|
dey ; next scanline
|
||||||
|
.code
|
||||||
|
|
||||||
|
Kernel2Sprite__kernel__12__DrawLine 0 ; macro: draw scanline no WSYNC
|
||||||
|
dey ; next scanline
|
||||||
|
bne Kernel2Sprite__kernel__12__LVScan ; repeat until out of lines
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite kernel
|
||||||
|
|
||||||
|
;;; start action Kernel2Sprite kernel
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta GRP0
|
||||||
|
sta GRP1
|
||||||
|
sta GRP0
|
||||||
|
sta GRP1
|
||||||
|
|
||||||
|
;;; end action Kernel2Sprite kernel
|
||||||
|
|
||||||
|
KERNEL_END
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Joystick postframe
|
||||||
|
|
||||||
|
; 2 control inputs share a single byte, 4 bits each
|
||||||
|
lda SWCHA
|
||||||
|
sta Joystick__tmp+0
|
||||||
|
|
||||||
|
;;; end action Joystick postframe
|
||||||
|
|
||||||
|
;;; start action Joystick postframe
|
||||||
|
|
||||||
|
ldx #0
|
||||||
|
Joystick__postframe__15____each:
|
||||||
|
|
||||||
|
asl Joystick__tmp+0
|
||||||
|
bcs Joystick__postframe__15__SkipMoveRight
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action MoveJoyX joyright
|
||||||
|
|
||||||
|
lda HasXpos_xpos_b0,x
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
cmp #152
|
||||||
|
bcs MoveJoyX__joyright__16__nomove
|
||||||
|
sta HasXpos_xpos_b0,x
|
||||||
|
MoveJoyX__joyright__16__nomove:
|
||||||
|
|
||||||
|
;;; end action MoveJoyX joyright
|
||||||
|
|
||||||
|
Joystick__postframe__15__SkipMoveRight:
|
||||||
|
asl Joystick__tmp+0
|
||||||
|
bcs Joystick__postframe__15__SkipMoveLeft
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action MoveJoyX joyleft
|
||||||
|
|
||||||
|
lda HasXpos_xpos_b0,x
|
||||||
|
sec
|
||||||
|
sbc #1
|
||||||
|
bcc MoveJoyX__joyleft__17__nomove
|
||||||
|
sta HasXpos_xpos_b0,x
|
||||||
|
MoveJoyX__joyleft__17__nomove:
|
||||||
|
|
||||||
|
;;; end action MoveJoyX joyleft
|
||||||
|
|
||||||
|
Joystick__postframe__15__SkipMoveLeft:
|
||||||
|
asl Joystick__tmp+0
|
||||||
|
bcs Joystick__postframe__15__SkipMoveDown
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action MoveJoyY joydown
|
||||||
|
|
||||||
|
lda HasYpos_ypos_b0,x
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
cmp #220
|
||||||
|
bcs MoveJoyY__joydown__18__nomove
|
||||||
|
sta HasYpos_ypos_b0,x
|
||||||
|
MoveJoyY__joydown__18__nomove:
|
||||||
|
|
||||||
|
;;; end action MoveJoyY joydown
|
||||||
|
|
||||||
|
Joystick__postframe__15__SkipMoveDown:
|
||||||
|
asl Joystick__tmp+0
|
||||||
|
bcs Joystick__postframe__15__SkipMoveUp
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action MoveJoyY joyup
|
||||||
|
|
||||||
|
lda HasYpos_ypos_b0,x
|
||||||
|
sec
|
||||||
|
sbc #1
|
||||||
|
bcc MoveJoyY__joyup__19__nomove
|
||||||
|
sta HasYpos_ypos_b0,x
|
||||||
|
MoveJoyY__joyup__19__nomove:
|
||||||
|
|
||||||
|
;;; end action MoveJoyY joyup
|
||||||
|
|
||||||
|
Joystick__postframe__15__SkipMoveUp:
|
||||||
|
|
||||||
|
inx
|
||||||
|
cpx #4
|
||||||
|
jne Joystick__postframe__15____each
|
||||||
|
Joystick__postframe__15____exit:
|
||||||
|
|
||||||
|
;;; end action Joystick postframe
|
||||||
|
|
||||||
|
;;; start action SpriteShuffler postframe
|
||||||
|
|
||||||
|
; load two sprite slots at left side of array
|
||||||
|
lda SpriteSlot_sprite_b0
|
||||||
|
sta SpriteShuffler__tmp+0
|
||||||
|
lda SpriteSlot_sprite_b0+1
|
||||||
|
sta SpriteShuffler__tmp+1
|
||||||
|
; move two slots to the left
|
||||||
|
ldx #0
|
||||||
|
SpriteShuffler__postframe__20__loop:
|
||||||
|
lda SpriteSlot_sprite_b0+2,x
|
||||||
|
sta SpriteSlot_sprite_b0,x
|
||||||
|
inx
|
||||||
|
cpx #4-2
|
||||||
|
bne SpriteShuffler__postframe__20__loop
|
||||||
|
; store two sprite slots at right side of array
|
||||||
|
lda SpriteShuffler__tmp+0
|
||||||
|
sta SpriteSlot_sprite_b0+4-2
|
||||||
|
lda SpriteShuffler__tmp+1
|
||||||
|
sta SpriteSlot_sprite_b0+4-1
|
||||||
|
|
||||||
|
;;; end action SpriteShuffler postframe
|
||||||
|
|
||||||
|
;;; start action SpriteHider postframe
|
||||||
|
|
||||||
|
lda #4-1
|
||||||
|
sta SpriteHider__tmp+0
|
||||||
|
|
||||||
|
;;; end action SpriteHider postframe
|
||||||
|
|
||||||
|
;;; start action SpriteHider postframe
|
||||||
|
|
||||||
|
ldy #0
|
||||||
|
SpriteHider__postframe__22____each:
|
||||||
|
ldx SpriteSlot_sprite_b0,y
|
||||||
|
|
||||||
|
lda HasYpos_ypos_b0,x
|
||||||
|
cmp #192
|
||||||
|
bcc SpriteHider__postframe__22__skip
|
||||||
|
; swap this sprite slot with slot at end of array
|
||||||
|
lda SpriteSlot_sprite_b0,y
|
||||||
|
pha
|
||||||
|
ldx SpriteHider__tmp+0 ; clobbers X, but no longer used
|
||||||
|
lda SpriteSlot_sprite_b0,x
|
||||||
|
sta SpriteSlot_sprite_b0,y
|
||||||
|
pla
|
||||||
|
sta SpriteSlot_sprite_b0,x
|
||||||
|
dec SpriteHider__tmp+0
|
||||||
|
SpriteHider__postframe__22__skip:
|
||||||
|
|
||||||
|
iny
|
||||||
|
cpy #2
|
||||||
|
jne SpriteHider__postframe__22____each
|
||||||
|
SpriteHider__postframe__22____exit:
|
||||||
|
|
||||||
|
;;; end action SpriteHider postframe
|
||||||
|
|
||||||
|
FRAME_END
|
||||||
|
.code
|
||||||
|
|
||||||
|
jmp FrameLoop__start__2__NextFrame ; loop to next frame
|
||||||
|
|
||||||
|
;;; end action FrameLoop start
|
||||||
|
; start main routine
|
||||||
|
.segment "VECTORS"
|
||||||
|
Return: .word $6060
|
||||||
|
VecNMI:
|
||||||
|
VecReset: .word Main::__Reset
|
||||||
|
VecBRK: .word Main::__BRK
|
||||||
|
|
||||||
|
;;; end action Init main_init
|
||||||
|
|
||||||
|
.endscope
|
||||||
|
Main__Start = Main::__Start
|
240
test/ecs/vcslib.ecs
Normal file
240
test/ecs/vcslib.ecs
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
|
||||||
|
//#resource "vcs-ca65.h"
|
||||||
|
|
||||||
|
system Init
|
||||||
|
on main_init do once
|
||||||
|
---
|
||||||
|
.include "vcs-ca65.h"
|
||||||
|
.macpack longbranch
|
||||||
|
.define PAL 0
|
||||||
|
__NMI:
|
||||||
|
__Reset:
|
||||||
|
__BRK:
|
||||||
|
CLEAN_START
|
||||||
|
{{bss_init}} ; initialize data segment
|
||||||
|
{{!start}} ; start main routine
|
||||||
|
.segment "VECTORS"
|
||||||
|
Return: .word $6060
|
||||||
|
VecNMI:
|
||||||
|
VecReset: .word Main::__Reset
|
||||||
|
VecBRK: .word Main::__BRK
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
component Player
|
||||||
|
end
|
||||||
|
|
||||||
|
component KernelSection
|
||||||
|
lines: 1..255
|
||||||
|
end
|
||||||
|
|
||||||
|
component BGColor
|
||||||
|
bgcolor: 0..255
|
||||||
|
end
|
||||||
|
|
||||||
|
component PFColor
|
||||||
|
pfcolor: 0..255
|
||||||
|
end
|
||||||
|
|
||||||
|
component Playfield
|
||||||
|
pf: 0..0xffffff
|
||||||
|
end
|
||||||
|
|
||||||
|
component AsymPlayfield
|
||||||
|
pfleft: 0..0xffffff
|
||||||
|
pfright: 0..0xffffff
|
||||||
|
end
|
||||||
|
|
||||||
|
component VersatilePlayfield
|
||||||
|
data: array of 0..255 baseoffset -1
|
||||||
|
end
|
||||||
|
|
||||||
|
system FrameLoop
|
||||||
|
on start do once
|
||||||
|
---
|
||||||
|
@NextFrame:
|
||||||
|
FRAME_START
|
||||||
|
{{emit preframe}}
|
||||||
|
KERNEL_START
|
||||||
|
{{emit kernel}}
|
||||||
|
KERNEL_END
|
||||||
|
{{emit postframe}}
|
||||||
|
FRAME_END
|
||||||
|
{{emit nextframe}}
|
||||||
|
jmp @NextFrame ; loop to next frame
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system ResetSwitch
|
||||||
|
on nextframe do once
|
||||||
|
---
|
||||||
|
lsr SWCHB ; test Game Reset switch
|
||||||
|
bcs @NoStart
|
||||||
|
{{!resetswitch}}
|
||||||
|
@NoStart:
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system ResetConsole
|
||||||
|
on resetswitch do once
|
||||||
|
---
|
||||||
|
jmp Main::__Reset ; jump to Reset handler
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system JoyButton
|
||||||
|
on postframe do foreach [Player]
|
||||||
|
---
|
||||||
|
lda {{index INPT4}} ;read button input
|
||||||
|
bmi @NotPressed
|
||||||
|
{{emit joybutton}}
|
||||||
|
@NotPressed:
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system Joystick
|
||||||
|
locals 1
|
||||||
|
on postframe do once
|
||||||
|
---
|
||||||
|
; 2 control inputs share a single byte, 4 bits each
|
||||||
|
lda SWCHA
|
||||||
|
sta {{$0}}
|
||||||
|
---
|
||||||
|
on postframe do foreach [Player]
|
||||||
|
---
|
||||||
|
asl {{$0}}
|
||||||
|
bcs @SkipMoveRight
|
||||||
|
{{!joyright}}
|
||||||
|
@SkipMoveRight:
|
||||||
|
asl {{$0}}
|
||||||
|
bcs @SkipMoveLeft
|
||||||
|
{{!joyleft}}
|
||||||
|
@SkipMoveLeft:
|
||||||
|
asl {{$0}}
|
||||||
|
bcs @SkipMoveDown
|
||||||
|
{{!joydown}}
|
||||||
|
@SkipMoveDown:
|
||||||
|
asl {{$0}}
|
||||||
|
bcs @SkipMoveUp
|
||||||
|
{{!joyup}}
|
||||||
|
@SkipMoveUp:
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
system SetHorizPos
|
||||||
|
on SetHorizPos do once
|
||||||
|
---
|
||||||
|
; SetHorizPos routine
|
||||||
|
; A = X coordinate
|
||||||
|
; Y = player number (0 or 1)
|
||||||
|
sta WSYNC ; start a new line
|
||||||
|
sec ; set carry flag
|
||||||
|
nop
|
||||||
|
@DivideLoop:
|
||||||
|
sbc #15 ; subtract 15
|
||||||
|
bcs @DivideLoop ; branch until negative
|
||||||
|
eor #7 ; calculate fine offset
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
sta RESP0,y ; fix coarse position
|
||||||
|
sta HMP0,y ; set fine offset
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
system StaticKernel
|
||||||
|
on preframe do foreach [KernelSection] limit 1
|
||||||
|
---
|
||||||
|
{{!kernelsetup}}
|
||||||
|
---
|
||||||
|
on kernel do foreach [KernelSection]
|
||||||
|
---
|
||||||
|
sta WSYNC
|
||||||
|
{{!kernelsetup}}
|
||||||
|
{{!kerneldraw}}
|
||||||
|
{{!kerneldone}}
|
||||||
|
---
|
||||||
|
on kerneldraw do with [KernelSection]
|
||||||
|
---
|
||||||
|
ldy {{<lines}}
|
||||||
|
@loop:
|
||||||
|
sta WSYNC
|
||||||
|
{{!scanline}}
|
||||||
|
dey
|
||||||
|
bne @loop
|
||||||
|
---
|
||||||
|
on kernelsetup do if [BGColor]
|
||||||
|
---
|
||||||
|
lda {{<bgcolor}}
|
||||||
|
sta COLUBK
|
||||||
|
---
|
||||||
|
on kernelsetup do if [PFColor]
|
||||||
|
---
|
||||||
|
lda {{get pfcolor}}
|
||||||
|
sta COLUPF
|
||||||
|
---
|
||||||
|
on kernelsetup do if [Playfield]
|
||||||
|
---
|
||||||
|
lda {{get pf 0}}
|
||||||
|
sta PF0
|
||||||
|
lda {{get pf 8}}
|
||||||
|
sta PF1
|
||||||
|
lda {{get pf 16}}
|
||||||
|
sta PF2
|
||||||
|
---
|
||||||
|
end
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
demo Main
|
||||||
|
using FrameLoop, ResetSwitch, ResetConsole
|
||||||
|
using StaticKernel, JoyButton
|
||||||
|
entity [Player]
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor]
|
||||||
|
const lines = 2
|
||||||
|
const bgcolor = $18
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor]
|
||||||
|
const lines = 2
|
||||||
|
const bgcolor = $16
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor]
|
||||||
|
const lines = 2
|
||||||
|
const bgcolor = $14
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor]
|
||||||
|
const lines = 2
|
||||||
|
const bgcolor = $12
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor,Playfield]
|
||||||
|
const lines = 10
|
||||||
|
const bgcolor = $14
|
||||||
|
const pf = 0x125244
|
||||||
|
end
|
||||||
|
entity Trees [KernelSection,BGColor,PFColor,Playfield]
|
||||||
|
const lines = 50
|
||||||
|
const bgcolor = $14
|
||||||
|
const pf = 0x112244
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor,PFColor,Playfield]
|
||||||
|
const lines = 50
|
||||||
|
const bgcolor = $16
|
||||||
|
const pf = 0x124
|
||||||
|
end
|
||||||
|
entity [KernelSection,BGColor,Playfield]
|
||||||
|
const lines = 10
|
||||||
|
const bgcolor = $18
|
||||||
|
const pf = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
system Local
|
||||||
|
locals 1
|
||||||
|
on joybutton do foreach [PFColor] limit 1 ---
|
||||||
|
inc {{$0}}
|
||||||
|
inc {{set Trees.pfcolor}}
|
||||||
|
---
|
||||||
|
end
|
||||||
|
end
|
250
test/ecs/vcslib.txt
Normal file
250
test/ecs/vcslib.txt
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
.scope Main
|
||||||
|
.zeropage
|
||||||
|
PFColor_pfcolor_b0:
|
||||||
|
.res 1
|
||||||
|
.res 1
|
||||||
|
TEMP:
|
||||||
|
.res 1
|
||||||
|
Local__tmp = TEMP+0
|
||||||
|
.code
|
||||||
|
KernelSection_lines_b0:
|
||||||
|
.byte 2
|
||||||
|
.byte 2
|
||||||
|
.byte 2
|
||||||
|
.byte 2
|
||||||
|
.byte 10
|
||||||
|
.byte 50
|
||||||
|
.byte 50
|
||||||
|
.byte 10
|
||||||
|
BGColor_bgcolor_b0:
|
||||||
|
.byte 24
|
||||||
|
.byte 22
|
||||||
|
.byte 20
|
||||||
|
.byte 18
|
||||||
|
.byte 20
|
||||||
|
.byte 20
|
||||||
|
.byte 22
|
||||||
|
.byte 24
|
||||||
|
Playfield_pf_b0:
|
||||||
|
.byte 68
|
||||||
|
.byte 68
|
||||||
|
.byte 36
|
||||||
|
.byte 0
|
||||||
|
Playfield_pf_b8:
|
||||||
|
.byte 82
|
||||||
|
.byte 34
|
||||||
|
.byte 1
|
||||||
|
.byte 0
|
||||||
|
Playfield_pf_b16:
|
||||||
|
.byte 18
|
||||||
|
.byte 17
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
Main__INITDATA:
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
__Start:
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Init main_init
|
||||||
|
|
||||||
|
.include "vcs-ca65.h"
|
||||||
|
.macpack longbranch
|
||||||
|
.define PAL 0
|
||||||
|
__NMI:
|
||||||
|
__Reset:
|
||||||
|
__BRK:
|
||||||
|
CLEAN_START
|
||||||
|
|
||||||
|
ldy #2
|
||||||
|
: lda Main__INITDATA-1,y
|
||||||
|
sta PFColor_pfcolor_b0-1,y
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
; initialize data segment
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action FrameLoop start
|
||||||
|
|
||||||
|
FrameLoop__start__2__NextFrame:
|
||||||
|
FRAME_START
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action StaticKernel preframe
|
||||||
|
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
lda #24
|
||||||
|
sta COLUBK
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
cpx #0+2
|
||||||
|
jcs StaticKernel__kernelsetup__5____skipxhi
|
||||||
|
|
||||||
|
cpx #0
|
||||||
|
jcc StaticKernel__kernelsetup__5____skipxlo
|
||||||
|
|
||||||
|
lda PFColor_pfcolor_b0,x
|
||||||
|
sta COLUPF
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__5____skipxlo:
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__5____skipxhi:
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
cpx #0+4
|
||||||
|
jcs StaticKernel__kernelsetup__6____skipxhi
|
||||||
|
|
||||||
|
cpx #0
|
||||||
|
jcc StaticKernel__kernelsetup__6____skipxlo
|
||||||
|
|
||||||
|
lda Playfield_pf_b0,x
|
||||||
|
sta PF0
|
||||||
|
lda Playfield_pf_b8,x
|
||||||
|
sta PF1
|
||||||
|
lda Playfield_pf_b16,x
|
||||||
|
sta PF2
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__6____skipxlo:
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__6____skipxhi:
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
|
||||||
|
;;; end action StaticKernel preframe
|
||||||
|
|
||||||
|
KERNEL_START
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernel
|
||||||
|
|
||||||
|
ldx #0
|
||||||
|
StaticKernel__kernel__7____each:
|
||||||
|
|
||||||
|
sta WSYNC
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
lda BGColor_bgcolor_b0,x
|
||||||
|
sta COLUBK
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
cpx #5+2
|
||||||
|
jcs StaticKernel__kernelsetup__9____skipxhi
|
||||||
|
|
||||||
|
cpx #5
|
||||||
|
jcc StaticKernel__kernelsetup__9____skipxlo
|
||||||
|
|
||||||
|
lda PFColor_pfcolor_b0-5,x
|
||||||
|
sta COLUPF
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__9____skipxlo:
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__9____skipxhi:
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
;;; start action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
cpx #4
|
||||||
|
jcc StaticKernel__kernelsetup__10____skipxlo
|
||||||
|
|
||||||
|
lda Playfield_pf_b0-4,x
|
||||||
|
sta PF0
|
||||||
|
lda Playfield_pf_b8-4,x
|
||||||
|
sta PF1
|
||||||
|
lda Playfield_pf_b16-4,x
|
||||||
|
sta PF2
|
||||||
|
|
||||||
|
StaticKernel__kernelsetup__10____skipxlo:
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernelsetup
|
||||||
|
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action StaticKernel kerneldraw
|
||||||
|
|
||||||
|
ldy KernelSection_lines_b0,x
|
||||||
|
StaticKernel__kerneldraw__11__loop:
|
||||||
|
sta WSYNC
|
||||||
|
|
||||||
|
dey
|
||||||
|
bne StaticKernel__kerneldraw__11__loop
|
||||||
|
|
||||||
|
;;; end action StaticKernel kerneldraw
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inx
|
||||||
|
cpx #8
|
||||||
|
jne StaticKernel__kernel__7____each
|
||||||
|
StaticKernel__kernel__7____exit:
|
||||||
|
|
||||||
|
;;; end action StaticKernel kernel
|
||||||
|
|
||||||
|
KERNEL_END
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action JoyButton postframe
|
||||||
|
|
||||||
|
lda INPT4 ;read button input
|
||||||
|
bmi JoyButton__postframe__12__NotPressed
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action Local joybutton
|
||||||
|
|
||||||
|
inc Local__tmp+0
|
||||||
|
inc PFColor_pfcolor_b0
|
||||||
|
|
||||||
|
;;; end action Local joybutton
|
||||||
|
|
||||||
|
JoyButton__postframe__12__NotPressed:
|
||||||
|
|
||||||
|
;;; end action JoyButton postframe
|
||||||
|
|
||||||
|
FRAME_END
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action ResetSwitch nextframe
|
||||||
|
|
||||||
|
lsr SWCHB ; test Game Reset switch
|
||||||
|
bcs ResetSwitch__nextframe__14__NoStart
|
||||||
|
.code
|
||||||
|
|
||||||
|
;;; start action ResetConsole resetswitch
|
||||||
|
|
||||||
|
jmp Main::__Reset ; jump to Reset handler
|
||||||
|
|
||||||
|
;;; end action ResetConsole resetswitch
|
||||||
|
|
||||||
|
ResetSwitch__nextframe__14__NoStart:
|
||||||
|
|
||||||
|
;;; end action ResetSwitch nextframe
|
||||||
|
|
||||||
|
jmp FrameLoop__start__2__NextFrame ; loop to next frame
|
||||||
|
|
||||||
|
;;; end action FrameLoop start
|
||||||
|
; start main routine
|
||||||
|
.segment "VECTORS"
|
||||||
|
Return: .word $6060
|
||||||
|
VecNMI:
|
||||||
|
VecReset: .word Main::__Reset
|
||||||
|
VecBRK: .word Main::__BRK
|
||||||
|
|
||||||
|
;;; end action Init main_init
|
||||||
|
|
||||||
|
.endscope
|
||||||
|
Main__Start = Main::__Start
|
Loading…
Reference in New Issue
Block a user