object click event
This commit is contained in:
parent
3d518ce3f0
commit
9dbd8d607c
|
|
@ -5,6 +5,7 @@ Blockly.Blocks['console_log_action'] = {
|
||||||
init(this: Blockly.Block) {
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('VALUE')
|
this.appendValueInput('VALUE')
|
||||||
.setAlign(Blockly.inputs.Align.RIGHT)
|
.setAlign(Blockly.inputs.Align.RIGHT)
|
||||||
|
.setCheck('ObjectType')
|
||||||
.appendField('print');
|
.appendField('print');
|
||||||
this.setInputsInline(false)
|
this.setInputsInline(false)
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
export * from './consoleLog';
|
export * from './consoleLog';
|
||||||
|
export * from './physics';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
|
|
||||||
|
Blockly.Blocks['physics_apply_impulse_action'] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput('')
|
||||||
|
.appendField('Push me to');
|
||||||
|
this.appendValueInput('POSITION')
|
||||||
|
.setCheck('Pos');
|
||||||
|
this.appendDummyInput('')
|
||||||
|
.appendField('with force')
|
||||||
|
.appendField(new Blockly.FieldNumber(1, -10, 10, 2), 'FORCE');
|
||||||
|
|
||||||
|
|
||||||
|
this.setInputsInline(true)
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip('Push me to a position');
|
||||||
|
this.setColour(150);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
javascriptGenerator.forBlock['physics_apply_impulse_action'] = function (block, generator) {
|
||||||
|
const positionValue = generator.valueToCode(block, 'POSITION', Order.ATOMIC);
|
||||||
|
const forceValue = block.getFieldValue('FORCE');
|
||||||
|
return `api.applyImpulse(${positionValue}, ${forceValue});\n`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { };
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './applyImpulse';
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator } from "blockly/javascript";
|
||||||
|
|
||||||
|
Blockly.Blocks['object_clicked_event'] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField('When I\'m clicked');
|
||||||
|
this.setStyle('event_hat');
|
||||||
|
this.setNextStatement(true);
|
||||||
|
this.setTooltip('Fires when an object is clicked');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
javascriptGenerator.forBlock['object_clicked_event'] = function (_block, _generator) {
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
export { };
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './gameStart';
|
export * from './gameStart';
|
||||||
export * from './objectTouchedMe';
|
export * from './objectTouchedMe';
|
||||||
export * from './playerTouchedMe';
|
export * from './playerTouchedMe';
|
||||||
|
export * from './imClicked';
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
import { javascriptGenerator } from "blockly/javascript";
|
||||||
import { getObjectTypeDropDownOptions } from "../fieldTypes/objectType";
|
|
||||||
|
|
||||||
Blockly.Blocks['object_touch_start_event'] = {
|
Blockly.Blocks['object_touch_start_event'] = {
|
||||||
init(this: Blockly.Block) {
|
init(this: Blockly.Block) {
|
||||||
this.appendDummyInput()
|
this.appendDummyInput('NAME')
|
||||||
.appendField('When')
|
.appendField('When');
|
||||||
.appendField(
|
this.appendValueInput('NAME')
|
||||||
new Blockly.FieldDropdown(getObjectTypeDropDownOptions),
|
.setCheck('Object');
|
||||||
'OBJECT_TYPE',
|
this.appendDummyInput('NAME')
|
||||||
)
|
|
||||||
.appendField('touches me');
|
.appendField('touches me');
|
||||||
this.setStyle('event_hat');
|
this.setStyle('event_hat');
|
||||||
this.setNextStatement(true);
|
this.setNextStatement(true);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './objectType';
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { state } from "../../state/rootState";
|
import * as Blockly from "blockly";
|
||||||
import { toJS } from "mobx";
|
|
||||||
|
|
||||||
export function getObjectTypeDropDownOptions(): [string, string][] {
|
export class ObjecTypeField extends Blockly.Field {
|
||||||
const types = Object.values(toJS(state.world.data.objectTypes));
|
constructor(value: any, validator: any) {
|
||||||
const values: [string, string][] = [
|
super(value, validator);
|
||||||
['Any object', '*'],
|
|
||||||
...types.map(t => [t.name, t.id] as [string, string]),
|
this.SERIALIZABLE = true;
|
||||||
];
|
}
|
||||||
return values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Blockly.fieldRegistry.register('field_object_type', ObjecTypeField);
|
||||||
|
|
@ -21,7 +21,16 @@ export function generateCode(workspace: Blockly.WorkspaceSvg): string {
|
||||||
|
|
||||||
//TODO use args
|
//TODO use args
|
||||||
|
|
||||||
result += `onGameEvent('${block.type.replace(/_event$/, '')}', function(context) {\n${body}});\n`;
|
result += `onGameEvent(
|
||||||
|
'${block.type.replace(/_event$/, '')}',
|
||||||
|
function(context) {
|
||||||
|
// console.dir({context, api, object, objectType});
|
||||||
|
if (context.object && (context.object.id !== object.id))
|
||||||
|
return;
|
||||||
|
${body}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@ export * from './values';
|
||||||
export * from './actions';
|
export * from './actions';
|
||||||
export * from './theme';
|
export * from './theme';
|
||||||
export * from './generateCode';
|
export * from './generateCode';
|
||||||
|
export * from './fieldTypes';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
|
|
||||||
|
Blockly.Blocks['any_object_of_type_value'] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput('NAME')
|
||||||
|
.appendField('Any object of type');
|
||||||
|
this.appendValueInput('NAME')
|
||||||
|
.setCheck('ObjectType');
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setOutput(true, 'Object');
|
||||||
|
this.setTooltip('Any object of type');
|
||||||
|
this.setColour(315);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
javascriptGenerator.forBlock['any_object_of_type_value'] = function (_block, _generator) {
|
||||||
|
return ['123', Order.NONE];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { };
|
||||||
|
|
@ -4,16 +4,16 @@ import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
Blockly.Blocks['current_object_value'] = {
|
Blockly.Blocks['current_object_value'] = {
|
||||||
init(this: Blockly.Block) {
|
init(this: Blockly.Block) {
|
||||||
this.appendEndRowInput('NAME')
|
this.appendEndRowInput('NAME')
|
||||||
.appendField('Current object');
|
.appendField('Me');
|
||||||
this.setInputsInline(false)
|
this.setInputsInline(false)
|
||||||
this.setOutput(true, 'String');
|
this.setOutput(true, 'Object');
|
||||||
this.setTooltip('Returns id of current object instance');
|
this.setTooltip('Returns current object instance');
|
||||||
this.setColour(315);
|
this.setColour(315);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['current_object_value'] = function (_block, _generator) {
|
javascriptGenerator.forBlock['current_object_value'] = function (_block, _generator) {
|
||||||
return ['object.id', Order.NONE];
|
return ['object', Order.NONE];
|
||||||
};
|
};
|
||||||
|
|
||||||
export { };
|
export { };
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
Blockly.Blocks['current_object_type_value'] = {
|
Blockly.Blocks['current_object_type_value'] = {
|
||||||
init(this: Blockly.Block) {
|
init(this: Blockly.Block) {
|
||||||
this.appendEndRowInput('NAME')
|
this.appendEndRowInput('NAME')
|
||||||
.appendField('Current object type');
|
.appendField('My type');
|
||||||
this.setInputsInline(false)
|
this.setInputsInline(false)
|
||||||
this.setOutput(true, 'String');
|
this.setOutput(true, 'ObjectType');
|
||||||
this.setTooltip('Returns id of current object type');
|
this.setTooltip('Returns current object type');
|
||||||
this.setColour(315);
|
this.setColour(315);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['current_object_type_value'] = function (_block, _generator) {
|
javascriptGenerator.forBlock['current_object_type_value'] = function (_block, _generator) {
|
||||||
return ['objectType.id', Order.NONE];
|
return ['objectType', Order.NONE];
|
||||||
};
|
};
|
||||||
|
|
||||||
export { };
|
export { };
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,6 @@
|
||||||
export * from './currentObject';
|
export * from './currentObject';
|
||||||
export * from './currentObjectType';
|
export * from './currentObjectType';
|
||||||
|
export * from './anyObjectOfType';
|
||||||
|
export * from './objectType';
|
||||||
|
export * from './positionOfObject';
|
||||||
|
export * from './position';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
|
import { toJS } from "mobx";
|
||||||
|
import { state } from "../../state";
|
||||||
|
|
||||||
|
export function getObjectTypeDropDownOptions(): [string, string][] {
|
||||||
|
const types = Object.values(toJS(state.world.data.objectTypes));
|
||||||
|
const values: [string, string][] = [
|
||||||
|
['Any object', '*'],
|
||||||
|
...types.map(t => [t.name, t.id] as [string, string]),
|
||||||
|
];
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
Blockly.Blocks['object_type_value'] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendEndRowInput('NAME')
|
||||||
|
.appendField(
|
||||||
|
new Blockly.FieldDropdown(getObjectTypeDropDownOptions),
|
||||||
|
'OBJECT_TYPE',
|
||||||
|
);
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setOutput(true, 'ObjectType');
|
||||||
|
this.setTooltip('Object type');
|
||||||
|
this.setColour(315);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
javascriptGenerator.forBlock['current_object_type_value'] = function (_block, _generator) {
|
||||||
|
return ['objectType', Order.NONE];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { };
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
|
|
||||||
|
Blockly.Blocks['pos_value'] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput('POSITION')
|
||||||
|
.appendField('[')
|
||||||
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 2), 'X')
|
||||||
|
.appendField(',')
|
||||||
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 2), 'Y')
|
||||||
|
.appendField(',')
|
||||||
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 2), 'Z');
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(']');
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setOutput(true, 'Pos');
|
||||||
|
this.setTooltip('Position [x,y,z]');
|
||||||
|
this.setColour(315);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
javascriptGenerator.forBlock['pos_value'] = function (block, _generator) {
|
||||||
|
const xValue = block.getFieldValue('X');
|
||||||
|
const yValue = block.getFieldValue('Y');
|
||||||
|
const zValue = block.getFieldValue('Z');
|
||||||
|
return [`[${xValue},${yValue},${zValue}]`, Order.ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { };
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator, Order } from "blockly/javascript";
|
||||||
|
|
||||||
|
Blockly.Blocks['position_of_object_value'] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput('NAME')
|
||||||
|
.appendField('Position of');
|
||||||
|
this.appendValueInput('NAME')
|
||||||
|
.setCheck('Object');
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setOutput(true, 'Pos');
|
||||||
|
this.setTooltip('Position of an object');
|
||||||
|
this.setColour(315);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
javascriptGenerator.forBlock['position_of_object_value'] = function (_block, _generator) {
|
||||||
|
return ['123', Order.NONE];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { };
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import type { ObjectInstance, Runtime, RuntimeGameObjectInstance } from "../types";
|
import type { RuntimeGameObjectInstance } from "../types";
|
||||||
import { state } from "../state";
|
import { state } from "../state";
|
||||||
import { ObjectViewInternal } from "./ObjectViewInternal";
|
import { ObjectViewInternal } from "./ObjectViewInternal";
|
||||||
import { PlayerObjectView } from "./CharacterView";
|
import { PlayerObjectView } from "./CharacterView";
|
||||||
|
|
||||||
export type GameObjectViewProps = {
|
export type GameObjectViewProps = {
|
||||||
object: Runtime<ObjectInstance>;
|
object: RuntimeGameObjectInstance;
|
||||||
isPlayer: boolean;
|
isPlayer: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,5 +17,13 @@ export const GameObjectView = observer(function (props: GameObjectViewProps) {
|
||||||
if (props.isPlayer)
|
if (props.isPlayer)
|
||||||
return <PlayerObjectView object={props.object as RuntimeGameObjectInstance} objectType={objectType} />;
|
return <PlayerObjectView object={props.object as RuntimeGameObjectInstance} objectType={objectType} />;
|
||||||
|
|
||||||
return <ObjectViewInternal {...props} objectType={objectType} />;
|
function handleClick(): void {
|
||||||
|
state.game?.emitEvent('object_clicked', { object: props.object });
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ObjectViewInternal
|
||||||
|
{...props}
|
||||||
|
objectType={objectType}
|
||||||
|
onClick={handleClick}
|
||||||
|
/>;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -60,15 +60,14 @@ export const ObjectEditorView = observer(function ({ object, isPlayer }: ObjectE
|
||||||
if (!objectType)
|
if (!objectType)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
function handleClick(e: ThreeEvent<MouseEvent>) {
|
function handleClick() {
|
||||||
if (e.delta > 5) return;
|
if (state.worldEditor.isEnabled) {
|
||||||
e.stopPropagation();
|
// Reading selection state inside an event handler: not tracked by observer.
|
||||||
// Reading selection state inside an event handler: not tracked by observer.
|
const currentMode = state.worldEditor.selection?.type === 'object' && state.worldEditor.selection?.id === object.id
|
||||||
const currentMode = state.worldEditor.isEnabled &&
|
? state.worldEditor.selection?.editMode
|
||||||
state.worldEditor.selection?.type === 'object' && state.worldEditor.selection?.id === object.id
|
: undefined;
|
||||||
? state.worldEditor.selection?.editMode
|
state.worldEditor.setSelectedObject({ id: object.id, editMode: nextObjectEditMode(currentMode) });
|
||||||
: undefined;
|
}
|
||||||
state.worldEditor.setSelectedObject({ id: object.id, editMode: nextObjectEditMode(currentMode) });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTransformEnd() {
|
function handleTransformEnd() {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ type ObjectViewInternalProps = {
|
||||||
objectType: ObjectType;
|
objectType: ObjectType;
|
||||||
isEditor?: boolean;
|
isEditor?: boolean;
|
||||||
isPlayer?: boolean;
|
isPlayer?: boolean;
|
||||||
onClick?: (e: ThreeEvent<MouseEvent>) => void;
|
onClick?: () => void;
|
||||||
ref?: Ref<ObjectViewInternalHandle>;
|
ref?: Ref<ObjectViewInternalHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,6 +56,37 @@ export const ObjectViewInternal = function ({ object, objectType, ref, ...props
|
||||||
[object.id]
|
[object.id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
const gameObj = object as RuntimeGameObjectInstance;
|
||||||
|
|
||||||
|
return reaction(
|
||||||
|
() => gameObj.pendingActions.impulse,
|
||||||
|
(impulse) => {
|
||||||
|
if (!impulse) return;
|
||||||
|
if (!rbRef.current) { console.warn('applyImpulse: rbRef is null for', gameObj.id); return; }
|
||||||
|
|
||||||
|
const { direction, amplitude } = impulse;
|
||||||
|
const v = { x: direction[0] * amplitude, y: direction[1] * amplitude, z: direction[2] * amplitude };
|
||||||
|
console.log('applyImpulse', gameObj.id, v, 'bodyType', rbRef.current.bodyType());
|
||||||
|
rbRef.current.applyImpulse(v, true);
|
||||||
|
runInAction(() => {
|
||||||
|
gameObj.pendingActions.impulse = undefined;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[object.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
function handleClick(e: ThreeEvent<MouseEvent>) {
|
||||||
|
if (e.delta > 5)
|
||||||
|
return;
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
props.onClick?.();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SyncRigidBody
|
<SyncRigidBody
|
||||||
ref={rbRef}
|
ref={rbRef}
|
||||||
|
|
@ -80,7 +111,7 @@ export const ObjectViewInternal = function ({ object, objectType, ref, ...props
|
||||||
ref={groupRef}
|
ref={groupRef}
|
||||||
name={`${object.id} (${objectType.id} instance)`}
|
name={`${object.id} (${objectType.id} instance)`}
|
||||||
scale={object.scale}
|
scale={object.scale}
|
||||||
onClick={props.onClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
object.cache.voxelGroups.map((vg) =>
|
object.cache.voxelGroups.map((vg) =>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
|
||||||
{ kind: 'block', type: 'game_start_event' },
|
{ kind: 'block', type: 'game_start_event' },
|
||||||
{ kind: 'block', type: 'object_touch_start_event' },
|
{ kind: 'block', type: 'object_touch_start_event' },
|
||||||
{ kind: 'block', type: 'player_touch_start_event' },
|
{ kind: 'block', type: 'player_touch_start_event' },
|
||||||
|
{ kind: 'block', type: 'object_clicked_event' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +29,10 @@ const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
|
||||||
contents: [
|
contents: [
|
||||||
{ kind: 'block', type: 'current_object_value' },
|
{ kind: 'block', type: 'current_object_value' },
|
||||||
{ kind: 'block', type: 'current_object_type_value' },
|
{ kind: 'block', type: 'current_object_type_value' },
|
||||||
|
{ kind: 'block', type: 'object_type_value' },
|
||||||
|
{ kind: 'block', type: 'any_object_of_type_value' },
|
||||||
|
{ kind: 'block', type: 'position_of_object_value' },
|
||||||
|
{ kind: 'block', type: 'pos_value' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -37,6 +42,7 @@ const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
|
||||||
contents: [
|
contents: [
|
||||||
{ kind: 'block', type: 'console_log_action' },
|
{ kind: 'block', type: 'console_log_action' },
|
||||||
{ kind: 'block', type: 'text_print' },
|
{ kind: 'block', type: 'text_print' },
|
||||||
|
{ kind: 'block', type: 'physics_apply_impulse_action' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -79,13 +79,13 @@ export class GameFactory {
|
||||||
Object.values(world.objectTypes)
|
Object.values(world.objectTypes)
|
||||||
.filter((ot) => ot.javascript)
|
.filter((ot) => ot.javascript)
|
||||||
.forEach((ot) => {
|
.forEach((ot) => {
|
||||||
const otCode = eval(`(function gameScript({onGameEvent, offGameEvent }, {api, object, objectType}) {${ot.javascript}})`);
|
const gameScript = eval(`(function gameScript({onGameEvent, offGameEvent }, {api, object, objectType}) {${ot.javascript}})`);
|
||||||
|
|
||||||
Object.values(scene.objects)
|
Object.values(scene.objects)
|
||||||
.filter((o) => o.typeId == ot.id)
|
.filter((o) => o.typeId == ot.id)
|
||||||
.forEach((o) => {
|
.forEach((o) => {
|
||||||
const api = new ObjectApi(o, ot, world, scene);
|
const api = new ObjectApi(o, ot, world, scene);
|
||||||
otCode(internalBus, { api, o, ot });
|
gameScript(internalBus, { api, object: o, objectType: ot });
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import type { WorldState } from "./worldState";
|
||||||
import type { Game, Pos3, RuntimeGameScene } from "../types";
|
import type { Game, Pos3, RuntimeGameScene } from "../types";
|
||||||
import type { CameraProps } from "@react-three/fiber";
|
import type { CameraProps } from "@react-three/fiber";
|
||||||
import { GameEventBus, GameFactory } from "../model/gameFactory";
|
import { GameEventBus, GameFactory } from "../model/gameFactory";
|
||||||
|
import type { GameEventContext } from "../types/runtime/gameBus";
|
||||||
|
|
||||||
export class GameState {
|
export class GameState {
|
||||||
private readonly world: WorldState;
|
private readonly world: WorldState;
|
||||||
|
|
@ -45,18 +46,18 @@ export class GameState {
|
||||||
|
|
||||||
const eventBus = new GameEventBus();
|
const eventBus = new GameEventBus();
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
GameFactory.evalGameScripts(rawWorld, game.scene, eventBus);
|
|
||||||
|
|
||||||
this._stopAutoSave = this.startAutoSave();
|
this._stopAutoSave = this.startAutoSave();
|
||||||
makeAutoObservable(
|
makeAutoObservable(this);
|
||||||
this,
|
|
||||||
);
|
GameFactory.evalGameScripts(rawWorld, this.scene, eventBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public emitEvent(event: string) {
|
public emitEvent(event: string, context: Omit<GameEventContext, 'world' | 'scene'> = {}) {
|
||||||
this.eventBus.emit(
|
this.eventBus.emit(
|
||||||
event,
|
event,
|
||||||
{
|
{
|
||||||
|
...context,
|
||||||
world: this.world.data,
|
world: this.world.data,
|
||||||
scene: this.scene,
|
scene: this.scene,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
import type { ObjectType, RuntimeGameObjectInstance, Scene, World } from "../model";
|
import type { RuntimeGameObjectInstance, Scene, World } from "../model";
|
||||||
|
|
||||||
export type GameEventContext = {
|
export type GameEventContext = {
|
||||||
world: World;
|
world: World;
|
||||||
scene: Scene;
|
scene: Scene;
|
||||||
|
object?: RuntimeGameObjectInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// export type GameObjectEventContext = GameEventContext & {
|
|
||||||
// object: RuntimeGameObjectInstance;
|
|
||||||
// objectType: ObjectType;
|
|
||||||
// }
|
|
||||||
|
|
||||||
export type GameEventHandler = (context: GameEventContext) => void;
|
export type GameEventHandler = (context: GameEventContext) => void;
|
||||||
// export type GameObjectEventHandler = (context: GameObjectEventContext) => void;
|
|
||||||
|
|
||||||
export type InternalGameEventBus = {
|
export type InternalGameEventBus = {
|
||||||
onGameEvent: (event: string, handler: GameEventHandler) => void;
|
onGameEvent: (event: string, handler: GameEventHandler) => void;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,14 @@ export class ObjectApi {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyImpulse(direction: V3, amplitude: number) {
|
public applyImpulse(targetPosition: V3, amplitude: number) {
|
||||||
|
const [px, py, pz] = this.object.position;
|
||||||
|
const dx = targetPosition[0] - px;
|
||||||
|
const dy = targetPosition[1] - py;
|
||||||
|
const dz = targetPosition[2] - pz;
|
||||||
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
if (len < 1e-6) return;
|
||||||
|
const direction: V3 = [dx / len, dy / len, dz / len];
|
||||||
this.object.pendingActions.impulse = { direction, amplitude };
|
this.object.pendingActions.impulse = { direction, amplitude };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue