game_start_event and console_log_action
This commit is contained in:
parent
4b00dbfc00
commit
b3ed15fa30
|
|
@ -0,0 +1,23 @@
|
|||
import * as Blockly from "blockly";
|
||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||
|
||||
Blockly.Blocks['console_log_action'] = {
|
||||
init(this: Blockly.Block) {
|
||||
this.appendValueInput('VALUE')
|
||||
.setAlign(Blockly.inputs.Align.RIGHT)
|
||||
.appendField('print');
|
||||
this.setInputsInline(false)
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setTooltip('Print value to console');
|
||||
this.setHelpUrl('');
|
||||
this.setColour(150);
|
||||
}
|
||||
};
|
||||
|
||||
javascriptGenerator.forBlock['console_log_action'] = function (block, generator) {
|
||||
const valueValue = generator.valueToCode(block, 'VALUE', Order.ATOMIC);
|
||||
return `console.log(${valueValue});\n`;
|
||||
};
|
||||
|
||||
export { };
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from './consoleLog';
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
export * from './events';
|
||||
export * from './values';
|
||||
export * from './actions';
|
||||
export * from './theme';
|
||||
export * from './generateCode';
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@ import { javascriptGenerator, Order } from "blockly/javascript";
|
|||
Blockly.Blocks['current_object_value'] = {
|
||||
init(this: Blockly.Block) {
|
||||
this.appendEndRowInput('NAME')
|
||||
.appendField('current object');
|
||||
.appendField('Current object');
|
||||
this.setInputsInline(false)
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip('asd');
|
||||
this.setHelpUrl('asd');
|
||||
this.setTooltip('Returns id of current object instance');
|
||||
this.setColour(315);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
import * as Blockly from "blockly";
|
||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||
|
||||
Blockly.Blocks['current_object_type_value'] = {
|
||||
init(this: Blockly.Block) {
|
||||
this.appendEndRowInput('NAME')
|
||||
.appendField('Current object type');
|
||||
this.setInputsInline(false)
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip('Returns id of current object type');
|
||||
this.setColour(315);
|
||||
}
|
||||
};
|
||||
|
||||
javascriptGenerator.forBlock['current_object_type_value'] = function (_block, _generator) {
|
||||
return ['objectType.id', Order.NONE];
|
||||
};
|
||||
|
||||
export { };
|
||||
|
|
@ -1 +1,2 @@
|
|||
export * from './currentObject';
|
||||
export * from './currentObjectType';
|
||||
|
|
|
|||
|
|
@ -9,15 +9,44 @@ import '../../blockly';
|
|||
import { gameTheme, generateCode } from '../../blockly';
|
||||
|
||||
const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
|
||||
kind: 'flyoutToolbox',
|
||||
kind: 'categoryToolbox',
|
||||
contents: [
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Events',
|
||||
colour: '180',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'text' },
|
||||
{ kind: 'block', type: 'text_print' },
|
||||
{ kind: 'block', type: 'game_start_event' },
|
||||
{ kind: 'block', type: 'object_touch_start_event' },
|
||||
{ kind: 'block', type: 'player_touch_start_event' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Values',
|
||||
colour: '260',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'current_object_value' },
|
||||
|
||||
{ kind: 'block', type: 'current_object_type_value' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Actions',
|
||||
colour: '20',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'console_log_action' },
|
||||
{ kind: 'block', type: 'text_print' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Text',
|
||||
colour: '160',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'text' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import type { Game, ObjectType, RuntimeGameScene, RuntimeObjectInstance, RuntimeScene, World } from "../types";
|
||||
import type { GameEventHandler, GameEventContext } from "../types/runtime/gameBus";
|
||||
import type { Game, RuntimeGameScene, RuntimeScene, World } from "../types";
|
||||
import type { GameEventHandler, GameEventContext, InternalGameEventBus } from "../types/runtime/gameBus";
|
||||
import { clone } from "../utils";
|
||||
import { populateRuntimeScene } from "../utils/runtime";
|
||||
|
||||
type OwnedGameEventHandler = {
|
||||
handler: GameEventHandler;
|
||||
}
|
||||
import { ObjectApi } from "../utils/runtime/objectApi";
|
||||
|
||||
export class GameEventBus {
|
||||
private handlers = new Map<string, OwnedGameEventHandler[]>();
|
||||
private handlers = new Map<string, GameEventHandler[]>();
|
||||
|
||||
on(event: string, handler: GameEventHandler): void {
|
||||
console.log('subscribing to ' + event, handler);
|
||||
|
|
@ -17,8 +14,8 @@ export class GameEventBus {
|
|||
set = [];
|
||||
this.handlers.set(event, set);
|
||||
}
|
||||
if (!set.some((h) => h.handler === handler))
|
||||
set.push({ handler });
|
||||
if (!set.includes(handler))
|
||||
set.push(handler);
|
||||
}
|
||||
|
||||
off(event: string, handler: GameEventHandler): void {
|
||||
|
|
@ -27,14 +24,14 @@ export class GameEventBus {
|
|||
if (!handlers)
|
||||
return;
|
||||
|
||||
this.handlers.set(event, handlers.filter((h) => h.handler !== handler));
|
||||
this.handlers.set(event, handlers.filter((h) => h !== handler));
|
||||
}
|
||||
|
||||
emit(event: string, context: GameEventContext): void {
|
||||
console.log('emitting ' + event);
|
||||
console.log(Array.from(this.handlers.entries()));
|
||||
this.handlers.get(event)
|
||||
?.forEach((h) => h.handler(context));
|
||||
?.forEach((handler) => handler(context));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,9 +67,10 @@ export class GameFactory {
|
|||
world: World,
|
||||
scene: RuntimeGameScene,
|
||||
eventBus: GameEventBus,
|
||||
|
||||
): void {
|
||||
|
||||
const internalBus = {
|
||||
const internalBus: InternalGameEventBus = {
|
||||
onGameEvent: eventBus.on.bind(eventBus),
|
||||
offGameEvent: eventBus.off.bind(eventBus),
|
||||
};
|
||||
|
|
@ -81,12 +79,13 @@ export class GameFactory {
|
|||
Object.values(world.objectTypes)
|
||||
.filter((ot) => ot.javascript)
|
||||
.forEach((ot) => {
|
||||
const otCode = eval(`(function gameScript({onGameEvent, offGameEvent}, object, objectType) {${ot.javascript}})`);
|
||||
const otCode = eval(`(function gameScript({onGameEvent, offGameEvent }, {api, object, objectType}) {${ot.javascript}})`);
|
||||
const api = new ObjectApi(o, ot, world, scene);
|
||||
|
||||
Object.values(scene.objects)
|
||||
.filter((o) => o.typeId == ot.id)
|
||||
.forEach((o) => {
|
||||
otCode(internalBus, o, ot);
|
||||
otCode(internalBus, { api, o, ot });
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import type { WorldState } from "./worldState";
|
|||
import type { Game, Pos3, V3, R3, RuntimeGameScene } from "../types";
|
||||
import type { CameraProps } from "@react-three/fiber";
|
||||
import { GameEventBus, GameFactory } from "../model/gameFactory";
|
||||
import type { GameEventContext } from "../types/runtime/gameBus";
|
||||
|
||||
export class GameState {
|
||||
private readonly world: WorldState;
|
||||
|
||||
public isPaused: boolean = false;
|
||||
public time: number = 0;
|
||||
public isFirstTick: boolean;
|
||||
public scene: RuntimeGameScene;
|
||||
|
||||
private eventBus: GameEventBus;
|
||||
|
|
@ -40,14 +40,13 @@ export class GameState {
|
|||
const game = GameFactory.create(rawWorld);
|
||||
this.isPaused = game.paused;
|
||||
this.time = game.time;
|
||||
this.isFirstTick = true;
|
||||
this.scene = game.scene;
|
||||
|
||||
const eventBus = new GameEventBus();
|
||||
this.eventBus = eventBus;
|
||||
GameFactory.evalGameScripts(rawWorld, game.scene, eventBus);
|
||||
|
||||
this.emitEvent('game_start');
|
||||
|
||||
this._stopAutoSave = this.startAutoSave();
|
||||
makeAutoObservable(
|
||||
this,
|
||||
|
|
@ -145,5 +144,10 @@ export class GameState {
|
|||
return;
|
||||
|
||||
this.time += deltaTime;
|
||||
|
||||
if (this.isFirstTick) {
|
||||
this.isFirstTick = false;
|
||||
this.emitEvent('game_start');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import type { V3 } from "../3d";
|
||||
import type { VoxelGroup } from "../runtime";
|
||||
import type { ObjectInstance } from "./object";
|
||||
|
||||
|
|
@ -6,6 +7,9 @@ export type ObjectInstanceRuntimeData = {
|
|||
voxelGroups: VoxelGroup[];
|
||||
colliderMesh: [Float32Array, Uint32Array] | null;
|
||||
};
|
||||
pendingActions: {
|
||||
impulse: { direction: V3, amplitude: number };
|
||||
}
|
||||
}
|
||||
|
||||
export type Runtime<T extends ObjectInstance> = T & ObjectInstanceRuntimeData;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
import type { Scene, World } from "../model";
|
||||
import type { ObjectType, RuntimeGameObjectInstance, Scene, World } from "../model";
|
||||
|
||||
export type GameEventContext = {
|
||||
world: World;
|
||||
scene: Scene;
|
||||
}
|
||||
|
||||
export type GameEventHandler = (context: GameEventContext) => void;
|
||||
// export type GameObjectEventContext = GameEventContext & {
|
||||
// object: RuntimeGameObjectInstance;
|
||||
// objectType: ObjectType;
|
||||
// }
|
||||
|
||||
export type GameBus = {
|
||||
onGameEvent: (
|
||||
event: string,
|
||||
params: Record<string, unknown>,
|
||||
callback: GameEventHandler,
|
||||
) => void;
|
||||
export type GameEventHandler = (context: GameEventContext) => void;
|
||||
// export type GameObjectEventHandler = (context: GameObjectEventContext) => void;
|
||||
|
||||
export type InternalGameEventBus = {
|
||||
onGameEvent: (event: string, handler: GameEventHandler) => void;
|
||||
offGameEvent: (event: string, handler: GameEventHandler) => void;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import type { ObjectType, RuntimeGameObjectInstance, RuntimeGameScene, V3, World } from "../../types";
|
||||
|
||||
export class ObjectApi {
|
||||
private object: RuntimeGameObjectInstance;
|
||||
private obectType: ObjectType;
|
||||
private world: World;
|
||||
private scene: RuntimeGameScene;
|
||||
|
||||
constructor(
|
||||
object: RuntimeGameObjectInstance,
|
||||
obectType: ObjectType,
|
||||
world: World,
|
||||
scene: RuntimeGameScene,
|
||||
) {
|
||||
this.object = object;
|
||||
this.obectType = obectType;
|
||||
this.world = world;
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
public applyImpulse(direction: V3, amplitude: number) {
|
||||
this.object.pendingActions.impulse = { direction, amplitude };
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue