Skip to content

Commit 819ba3b

Browse files
author
gamedevgrunt
committed
Add mobile joystick support
1 parent 9767955 commit 819ba3b

19 files changed

Lines changed: 752 additions & 449 deletions

File tree

‎src/GLOBALS.js‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,21 @@ let SHADERS = {};
1515

1616
let GRID = {};
1717

18+
let MESH_LIBRARY = {};
19+
1820
let targetBaseOnCameraView = true; // if false target based on character rotation
1921
// use touch joystick for mobile options
2022

2123
let DYNAMIC_CAMERA = false;
2224
// Used for game controller on pc and shows joystick on mobile.
2325
// Emulates KOA smooth camera follow effect
26+
let ON_MOBILE = true
27+
let CANVASES = []; //One canvas For Game, one for Mobile Input Detection
28+
29+
// todo move this from global. used for mobile input
30+
let inputMap = {};
31+
32+
2433

2534

2635
// Graphics Settings

‎src/scene/SceneManager.js‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ class SceneManager {
4545
this.scenes.push(scene);
4646
this.guiTextures.set(scene, new BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI", true, scene));
4747
this.activeGUI = this.guiTextures.get(this.activeScene);
48-
4948
return scene;
5049
}
5150

@@ -78,25 +77,28 @@ class SceneManager {
7877
if (debugParam === 'true') { DEBUG = true; }
7978

8079
const sceneParam = urlParams.get('scene');
81-
const sceneCreator = this.sceneCreators[sceneParam] || this.sceneCreators.builder; // Default to builder if no valid scene parameter
80+
const defaultScene = this.sceneCreators[sceneParam] || this.sceneCreators.outdoor; // Default to outdoor if no valid scene parameter
8281

83-
await this.loadScene(sceneCreator);
82+
await this.loadScene(defaultScene);
8483
await this.switchToScene(0);
84+
8585
// this.loadScene(createBuilder).then(() => {
8686
// this.switchToScene(0);
8787
// });
8888

89-
89+
// Uncomment this for key based scene switching.
90+
// await this.loadScene(this.sceneCreators['inn']);
91+
// await this.loadScene(this.sceneCreators['builder']);
9092
// Setup scene switching logic, e.g., based on user input or game events
91-
window.addEventListener('keydown', (e) => {
92-
if (e.key === 'i') {
93-
this.switchToScene(0);
94-
} else if (e.key === 'o') {
95-
this.switchToScene(1);
96-
} else if (e.key === 'p') {
97-
this.switchToScene(2);
98-
}
99-
});
93+
// window.addEventListener('keydown', (e) => {
94+
// if (e.key === 'i') {
95+
// this.switchToScene(0);
96+
// } else if (e.key === 'o') {
97+
// this.switchToScene(1);
98+
// } else if (e.key === 'p') {
99+
// this.switchToScene(2);
100+
// }
101+
// });
100102

101103
window.addEventListener('resize', () => {
102104
this.engine.resize();

‎src/scene/gen/LLM.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ async function getLLMJSONDummyData() {
4545
return jsonObject;
4646
}
4747

48-
const groqApiKey = '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';
48+
//Use your own but be careful to not commit the key
49+
const groqApiKey = 'your_key_here';
4950
async function getLLMJSON(systemPrompt, userPrompt) {
5051
try {
5152
const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {

‎src/scene/gen/procedural/grid/animations.js‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function createClutter(scene, meshes, floor, cellSize) {
4242
return null;// don't place any clutter this turn
4343
}
4444
// let object = meshes['clutter'][clutterToPlace].clone("clutter_clone");
45-
let object = meshes['clutter'][clutterToPlace].clone("clutter_clone");
45+
let object = meshes['clutter'][clutterToPlace].createInstance("clutter_clone");
4646

4747
// clutter specific methods
4848
function getRandomPosition(cellSize, border) {
@@ -61,9 +61,14 @@ function createClutter(scene, meshes, floor, cellSize) {
6161

6262
object.parent = floor;
6363

64-
object.position.x = object.position.x + newPosition.x;
65-
object.position.y = object.position.y + newPosition.y;
66-
object.position.z = object.position.z + newPosition.z;
64+
object.position.x = 0;
65+
object.position.y = 0;
66+
object.position.z = 0;
67+
68+
// Nan when using instance, todo
69+
// object.position.x = object.position.x + newPosition.x;
70+
// object.position.y = object.position.y + newPosition.y;
71+
// object.position.z = object.position.z + newPosition.z;
6772

6873
object.rotation = getRandomYRotation();
6974

‎src/scene/gen/procedural/grid/grid.js‎

Lines changed: 102 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@ import { createHighlight, updateHighlight } from "./tools/visual/highlight.js";
66

77
export function createGrid(scene, meshes) {
88

9+
let options = { width: gridSize * cellSize, height: gridSize * cellSize, subdivisions: gridSize };
10+
const grid = BABYLON.MeshBuilder.CreateGround('grid', options, scene);
911

10-
const grid = BABYLON.MeshBuilder.CreateGround('grid', { width: gridSize * cellSize, height: gridSize * cellSize, subdivisions: gridSize }, scene);
12+
MESH_LIBRARY = meshes;
1113
GRID = grid;
14+
15+
// const body = new BABYLON.PhysicsBody(GRID, BABYLON.PhysicsMotionType.STATIC, false, scene);
16+
GRID.groundAggregate = new BABYLON.PhysicsAggregate(GRID, BABYLON.PhysicsShapeType.MESH, { mass: 0, restitution: 0.0, friction: 1000000000.8 }, scene);
17+
// body.shape = this.terrainShape;
18+
19+
// addNonTilingColor(grid);
1220
let gridMaterial = new BABYLON.StandardMaterial("Selection_Grid_Mat", scene);
1321
// Create an invisible grid
14-
// gridMaterial.alpha = 0;
15-
// gridMaterial.wireframe = true;
22+
gridMaterial.alpha = 0;
23+
gridMaterial.wireframe = true;
1624
if (DEBUG) {
1725
gridMaterial.alpha = 1;
1826
gridMaterial.wireframe = true;
@@ -34,64 +42,80 @@ export function createGrid(scene, meshes) {
3442
let tools = createTools(scene, meshes, gridTracker, grid);
3543

3644
// Player starts on this cell, the mesh is already filled in.
37-
gridTracker[Math.floor(gridSize / 2)][Math.floor(gridSize / 2)] = true; // Fill a cell
45+
// gridTracker[Math.floor(gridSize / 2)][Math.floor(gridSize / 2)] = true; // Fill a cell
3846

3947
function convert(x, z) {
4048
return { 'x': x + Math.floor(gridSize / 2), 'z': z + Math.floor(gridSize / 2) };
4149
}
4250

4351
// Grid Input Actions //
44-
grid.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, (evt) => {
45-
const pickedPoint = evt.additionalData.pickedPoint;
46-
if (!pickedPoint) return;
47-
48-
const xIndex = Math.round(pickedPoint.x / cellSize);
49-
const zIndex = Math.round(pickedPoint.z / cellSize);
50-
let gridTrackerIndex = convert(xIndex, zIndex);
51-
console.log(`Clicked gridTrackerIndex: (${gridTrackerIndex.x}, ${gridTrackerIndex.z})`);
52-
console.log(`Clicked cell center: (${xIndex}, ${zIndex})`);
53-
54-
// Create or remove the floor mesh based on click type
55-
if (evt.sourceEvent.button === 0) { // Left click
56-
// Do current Selected Tool
57-
tools.selectedTool.click(xIndex, zIndex, gridTrackerIndex, gridTracker, pickedPoint);
58-
59-
// let floor = scene.getMeshByName(`floor_${xIndex}_${zIndex}`);
60-
// if (!floor) {
61-
// let removeFunction = function () {
62-
// disposeAnimation(scene, floor);
63-
// gridTracker[gridTrackerIndex.x][gridTrackerIndex.z] = false;
64-
// removeAllWalls(gridTrackerIndex.x, gridTrackerIndex.z);
65-
// updateCellAndSurronding(gridTrackerIndex, meshes);
66-
// };
67-
// floor = createFloor(scene, xIndex, zIndex, cellSize, meshes, removeFunction);
68-
// // Position at the exact center of the cell
69-
// floor.position = new BABYLON.Vector3((xIndex + 0.5) * cellSize - cellSize / 2, 0.1, (zIndex + 0.5) * cellSize - cellSize / 2);
70-
71-
// let completeFunction = function () {
72-
// gridTracker[gridTrackerIndex.x][gridTrackerIndex.z] = true;
73-
// updateCellAndSurronding(gridTrackerIndex, meshes);
74-
// }
75-
// floor.completeFunction = completeFunction;
76-
// entryAnimationFloor(scene, floor, meshes);
77-
78-
79-
// }
80-
}// else if (evt.sourceEvent.button === 2) { // Right click
81-
// const floor = scene.getMeshByName(`floor_${x}_${z}`);
82-
// if (floor) {
83-
// // Scale down and remove
84-
// floor.scaling = new BABYLON.Vector3(0, 0, 0); // Animate this for a smoother effect
85-
// setTimeout(() => floor.dispose(), 300); // Delay to show scaling
86-
// }
87-
// }
88-
}));
52+
// grid.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, (evt) => {
53+
// if (ON_MOBILE) {
54+
// const { width, height } = scene.getEngine().getRenderingCanvas();
55+
// if (evt.pointerY >= height * 0.6) {
56+
// console.log("clicked bottom");
57+
// CANVASES[1].style.zIndex = 1;
58+
// return;
59+
// }
60+
// }
61+
// const pickedPoint = evt.additionalData.pickedPoint;
62+
// if (!pickedPoint) return;
63+
64+
// const xIndex = Math.round(pickedPoint.x / cellSize);
65+
// const zIndex = Math.round(pickedPoint.z / cellSize);
66+
// let gridTrackerIndex = convert(xIndex, zIndex);
67+
// // console.log(`Clicked gridTrackerIndex: (${gridTrackerIndex.x}, ${gridTrackerIndex.z})`);
68+
// // console.log(`Clicked cell center: (${xIndex}, ${zIndex})`);
69+
70+
// // Create or remove the floor mesh based on click type
71+
// if (evt.sourceEvent.button === 0) { // Left click
72+
// // Do current Selected Tool
73+
// tools.selectedTool.click(xIndex, zIndex, gridTrackerIndex, gridTracker, pickedPoint);
74+
75+
// // let floor = scene.getMeshByName(`floor_${xIndex}_${zIndex}`);
76+
// // if (!floor) {
77+
// // let removeFunction = function () {
78+
// // disposeAnimation(scene, floor);
79+
// // gridTracker[gridTrackerIndex.x][gridTrackerIndex.z] = false;
80+
// // removeAllWalls(gridTrackerIndex.x, gridTrackerIndex.z);
81+
// // updateCellAndSurronding(gridTrackerIndex, meshes);
82+
// // };
83+
// // floor = createFloor(scene, xIndex, zIndex, cellSize, meshes, removeFunction);
84+
// // // Position at the exact center of the cell
85+
// // floor.position = new BABYLON.Vector3((xIndex + 0.5) * cellSize - cellSize / 2, 0.1, (zIndex + 0.5) * cellSize - cellSize / 2);
86+
87+
// // let completeFunction = function () {
88+
// // gridTracker[gridTrackerIndex.x][gridTrackerIndex.z] = true;
89+
// // updateCellAndSurronding(gridTrackerIndex, meshes);
90+
// // }
91+
// // floor.completeFunction = completeFunction;
92+
// // entryAnimationFloor(scene, floor, meshes);
93+
94+
95+
// // }
96+
// }// else if (evt.sourceEvent.button === 2) { // Right click
97+
// // const floor = scene.getMeshByName(`floor_${x}_${z}`);
98+
// // if (floor) {
99+
// // // Scale down and remove
100+
// // floor.scaling = new BABYLON.Vector3(0, 0, 0); // Animate this for a smoother effect
101+
// // setTimeout(() => floor.dispose(), 300); // Delay to show scaling
102+
// // }
103+
// // }
104+
// }));
89105

90106

91107

92108
// Grid Pointer Held //
93109
let leftHeldDown = false;
94110
scene.onPointerObservable.add((pointerInfo) => {
111+
if (ON_MOBILE) {
112+
const { width, height } = scene.getEngine().getRenderingCanvas();
113+
if (pointerInfo.event.clientY >= height * 0.6) {
114+
console.log("clicked bottom");
115+
CANVASES[1].style.zIndex = 1;
116+
return;
117+
}
118+
}
95119
if (pointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
96120
if (pointerInfo.event.button == 0) leftHeldDown = true;
97121
}
@@ -110,8 +134,8 @@ export function createGrid(scene, meshes) {
110134
const zIndex = Math.round(pickedPoint.z / cellSize);
111135
let gridTrackerIndex = convert(xIndex, zIndex);
112136
if (gridTracker[gridTrackerIndex.x][gridTrackerIndex.z]) { return; } //don't place while already filling
113-
console.log(`Clicked gridTrackerIndex: (${gridTrackerIndex.x}, ${gridTrackerIndex.z})`);
114-
console.log(`Clicked cell center: (${xIndex}, ${zIndex})`);
137+
// console.log(`Clicked gridTrackerIndex: (${gridTrackerIndex.x}, ${gridTrackerIndex.z})`);
138+
// console.log(`Clicked cell center: (${xIndex}, ${zIndex})`);
115139

116140
// if (evt.sourceEvent.button === 0) { // Left click
117141
tools.selectedTool.click(xIndex, zIndex, gridTrackerIndex, gridTracker, pickedPoint);
@@ -147,7 +171,34 @@ export function createGrid(scene, meshes) {
147171

148172
}
149173

174+
function addNonTilingColor(grid) {
175+
// Access the vertex data
176+
const geometry = grid.getGeometry();
177+
const positions = geometry.getVerticesData(BABYLON.VertexBuffer.PositionKind);
178+
const indices = geometry.getIndices();
179+
180+
// Create an array to hold the colors
181+
const colors = new Array(positions.length / 3 * 4); // 4 color components per vertex (RGBA)
182+
183+
// Fill the colors array with random greyscale values
184+
for (let i = 0; i < positions.length / 3; i++) {
185+
// Generate a random greyscale value
186+
const grey = Math.random();
187+
188+
// Assign the same grey value to R, G, B channels, and set alpha to 1 (opaque)
189+
colors[i * 4] = grey; // Red
190+
colors[i * 4 + 1] = grey; // Green
191+
colors[i * 4 + 2] = grey; // Blue
192+
colors[i * 4 + 3] = 1; // Alpha
193+
}
194+
195+
// Set the colors to the geometry
196+
geometry.setVerticesData(BABYLON.VertexBuffer.ColorKind, colors, true);
150197

198+
// Apply the geometry to the mesh
199+
grid.refreshBoundingInfo();
200+
grid.computeWorldMatrix(true);
201+
}
151202

152203

153204

0 commit comments

Comments
 (0)