summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2024-05-18 15:49:24 +0200
committerDaniel Weipert <git@mail.dweipert.de>2024-05-18 15:49:24 +0200
commit9155752f861ae43e3534cdfa833d8c644cb0e5d3 (patch)
treefb1a0b115c1b23099796b56b30a04cb6fd1864d2
parent3e94dd0704d7b4005f17c1086796afdbbe36b1f5 (diff)
save/load
-rw-r--r--Objects/BuilderObject.gd8
-rw-r--r--Start.tscn6
-rw-r--r--Tray.gd45
-rw-r--r--Tray.tscn15
-rw-r--r--app.html217
-rw-r--r--export_presets.cfg2
-rw-r--r--project.godot4
7 files changed, 287 insertions, 10 deletions
diff --git a/Objects/BuilderObject.gd b/Objects/BuilderObject.gd
index 91465bc..fde2660 100644
--- a/Objects/BuilderObject.gd
+++ b/Objects/BuilderObject.gd
@@ -30,7 +30,7 @@ func _process(_delta):
func _on_area_2d_input_event(_viewport, event: InputEvent, _shape_idx):
if event.is_action_pressed("drag_start"):
drag_start()
- if event.is_action_released("drag_start"):
+ if is_dragging and event.is_action_released("drag_start"):
drag_end()
@@ -79,6 +79,6 @@ func _on_area_2d_area_entered(_area):
func _on_area_2d_area_exited(_area):
- #if $Area2D.get_overlapping_areas().size() == 0:
- is_colliding = false
- modulate = Color("fff")
+ if $Area2D.get_overlapping_areas().size() == 0:
+ is_colliding = false
+ modulate = Color("fff")
diff --git a/Start.tscn b/Start.tscn
index 69324fc..0c880ae 100644
--- a/Start.tscn
+++ b/Start.tscn
@@ -1,7 +1,6 @@
-[gd_scene load_steps=5 format=3 uid="uid://bdyngwtm3rowr"]
+[gd_scene load_steps=4 format=3 uid="uid://bdyngwtm3rowr"]
[ext_resource type="Script" path="res://Start.gd" id="1_k0odd"]
-[ext_resource type="PackedScene" uid="uid://p0ay1mp7v772" path="res://Objects/BuilderObject.tscn" id="3_skats"]
[ext_resource type="PackedScene" uid="uid://3vuctgbcjqi7" path="res://Tray.tscn" id="3_u4wpj"]
[ext_resource type="Texture2D" uid="uid://djasmoqj87h1r" path="res://icon.svg" id="4_kyq1e"]
@@ -39,9 +38,6 @@ texture = ExtResource("4_kyq1e")
[node name="DropTarget" type="Node2D" parent="Map"]
unique_name_in_owner = true
-[node name="BuilderObject" parent="Map/DropTarget" instance=ExtResource("3_skats")]
-position = Vector2(155, 109)
-
[node name="Viewport" type="Node2D" parent="."]
unique_name_in_owner = true
diff --git a/Tray.gd b/Tray.gd
index 9936ef1..3e117af 100644
--- a/Tray.gd
+++ b/Tray.gd
@@ -4,9 +4,15 @@ extends Control
var TrayItemScene = preload("res://TrayItem.tscn")
var is_open = true
+var _on_data_loaded_callback = null
func _ready():
+ if OS.get_name() == "Web":
+ _on_data_loaded_callback = JavaScriptBridge.create_callback(load_save)
+ var callbacks = JavaScriptBridge.get_interface("godotCallbacks")
+ callbacks.dataLoaded = _on_data_loaded_callback
+
for i in range(5):
add_item()
@@ -55,3 +61,42 @@ func _on_button_pressed():
close()
else:
open()
+
+
+func _on_save_pressed():
+ if OS.get_name() == "Web":
+ var to_save = []
+ var objects = get_tree().current_scene.get_node("%DropTarget").get_children()
+ for obj in objects:
+ to_save.append({
+ "position": {
+ "x": obj.position.x,
+ "y": obj.position.y,
+ },
+ "rotation": obj.rotation,
+ "object": "BuilderObject",
+ })
+
+ JavaScriptBridge.download_buffer(
+ JSON.stringify(to_save).to_utf8_buffer(),
+ "CityBuilder-save.json",
+ "application/json"
+ )
+
+
+func _on_load_pressed():
+ if OS.get_name() == "Web":
+ JavaScriptBridge.eval("openLoadDialog()")
+
+
+func load_save(data: Array):
+ var current_objects = get_tree().current_scene.get_node("%DropTarget").get_children()
+ for obj in current_objects:
+ obj.queue_free()
+
+ var objects = JSON.parse_string(data[0])
+ for obj in objects:
+ var scene = load("res://Objects/" + obj.object + ".tscn").instantiate()
+ scene.position = Vector2(obj.position.x, obj.position.y)
+ scene.rotation = obj.rotation
+ get_tree().current_scene.get_node("%DropTarget").add_child(scene)
diff --git a/Tray.tscn b/Tray.tscn
index 9a4765b..8a26d5e 100644
--- a/Tray.tscn
+++ b/Tray.tscn
@@ -38,6 +38,19 @@ layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+
+[node name="Save" type="Button" parent="VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Save"
+
+[node name="Load" type="Button" parent="VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Load"
+
[node name="Control" type="Control" parent="."]
layout_mode = 2
size_flags_horizontal = 0
@@ -60,4 +73,6 @@ collision_mask = 3
[node name="CollisionShape2D" type="CollisionShape2D" parent="TrayCollision"]
[connection signal="resized" from="." to="." method="_on_resized"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/Save" to="." method="_on_save_pressed"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/Load" to="." method="_on_load_pressed"]
[connection signal="pressed" from="Control/Button" to="." method="_on_button_pressed"]
diff --git a/app.html b/app.html
new file mode 100644
index 0000000..078d27d
--- /dev/null
+++ b/app.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
+ <title>$GODOT_PROJECT_NAME</title>
+ <style>
+ html, body, #canvas {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ }
+
+ body {
+ color: white;
+ background-color: black;
+ overflow: hidden;
+ touch-action: none;
+ }
+
+ #canvas {
+ display: block;
+ }
+
+ #canvas:focus {
+ outline: none;
+ }
+
+ #status, #status-splash, #status-progress {
+ position: absolute;
+ left: 0;
+ right: 0;
+ }
+
+ #status, #status-splash {
+ top: 0;
+ bottom: 0;
+ }
+
+ #status {
+ background-color: #242424;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ visibility: hidden;
+ }
+
+ #status-splash {
+ max-height: 100%;
+ max-width: 100%;
+ margin: auto;
+ }
+
+ #status-progress, #status-notice {
+ display: none;
+ }
+
+ #status-progress {
+ bottom: 10%;
+ width: 50%;
+ margin: 0 auto;
+ }
+
+ #status-notice {
+ background-color: #5b3943;
+ border-radius: 0.5rem;
+ border: 1px solid #9b3943;
+ color: #e0e0e0;
+ font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;
+ line-height: 1.3;
+ margin: 0 2rem;
+ overflow: hidden;
+ padding: 1rem;
+ text-align: center;
+ z-index: 1;
+ }
+ </style>
+ $GODOT_HEAD_INCLUDE
+ <script>
+ var godotCallbacks = {
+ dataLoaded: null
+ }
+
+ function openLoadDialog() {
+ var input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', '.json');
+ input.click();
+
+ input.addEventListener('change', (event) => {
+ var file = event.target.files[0];
+ var reader = new FileReader();
+
+ reader.readAsText(file);
+
+ reader.onloadend = () => {
+ if (godotCallbacks.dataLoaded) {
+ godotCallbacks.dataLoaded(reader.result);
+ }
+ }
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <canvas id="canvas">
+ Your browser does not support the canvas tag.
+ </canvas>
+
+ <noscript>
+ Your browser does not support JavaScript.
+ </noscript>
+
+ <div id="status">
+ <img id="status-splash" src="$GODOT_SPLASH" alt="">
+ <progress id="status-progress"></progress>
+ <div id="status-notice"></div>
+ </div>
+
+ <script src="$GODOT_URL"></script>
+ <script>
+ const GODOT_CONFIG = $GODOT_CONFIG;
+ // const GODOT_THREADS_ENABLED = $GODOT_THREADS_ENABLED;
+ const GODOT_THREADS_ENABLED = 'yes';
+ const engine = new Engine(GODOT_CONFIG);
+
+ (function () {
+ const statusOverlay = document.getElementById('status');
+ const statusProgress = document.getElementById('status-progress');
+ const statusNotice = document.getElementById('status-notice');
+
+ let initializing = true;
+ let statusMode = '';
+
+ function setStatusMode(mode) {
+ if (statusMode === mode || !initializing) {
+ return;
+ }
+ if (mode === 'hidden') {
+ statusOverlay.remove();
+ initializing = false;
+ return;
+ }
+ statusOverlay.style.visibility = 'visible';
+ statusProgress.style.display = mode === 'progress' ? 'block' : 'none';
+ statusNotice.style.display = mode === 'notice' ? 'block' : 'none';
+ statusMode = mode;
+ }
+
+ function setStatusNotice(text) {
+ while (statusNotice.lastChild) {
+ statusNotice.removeChild(statusNotice.lastChild);
+ }
+ const lines = text.split('\n');
+ lines.forEach((line) => {
+ statusNotice.appendChild(document.createTextNode(line));
+ statusNotice.appendChild(document.createElement('br'));
+ });
+ }
+
+ function displayFailureNotice(err) {
+ const msg = err.message || err;
+ console.error(msg);
+ setStatusNotice(msg);
+ setStatusMode('notice');
+ initializing = false;
+ }
+
+ const missing = Engine.getMissingFeatures({
+ threads: GODOT_THREADS_ENABLED,
+ });
+
+ if (missing.length !== 0) {
+ if (GODOT_CONFIG['serviceWorker'] && GODOT_CONFIG['ensureCrossOriginIsolationHeaders'] && 'serviceWorker' in navigator) {
+ // There's a chance that installing the service worker would fix the issue
+ Promise.race([
+ navigator.serviceWorker.getRegistration().then((registration) => {
+ if (registration != null) {
+ return Promise.reject(new Error('Service worker already exists.'));
+ }
+ return registration;
+ }).then(() => engine.installServiceWorker()),
+ // For some reason, `getRegistration()` can stall
+ new Promise((resolve) => {
+ setTimeout(() => resolve(), 2000);
+ }),
+ ]).catch((err) => {
+ console.error('Error while registering service worker:', err);
+ }).then(() => {
+ window.location.reload();
+ });
+ } else {
+ // Display the message as usual
+ const missingMsg = 'Error\nThe following features required to run Godot projects on the Web are missing:\n';
+ displayFailureNotice(missingMsg + missing.join('\n'));
+ }
+ } else {
+ setStatusMode('progress');
+ engine.startGame({
+ 'onProgress': function (current, total) {
+ if (current > 0 && total > 0) {
+ statusProgress.value = current;
+ statusProgress.max = total;
+ } else {
+ statusProgress.removeAttribute('value');
+ statusProgress.removeAttribute('max');
+ }
+ },
+ }).then(() => {
+ setStatusMode('hidden');
+ }, displayFailureNotice);
+ }
+ }());
+ </script>
+ </body>
+</html>
diff --git a/export_presets.cfg b/export_presets.cfg
index 542cb18..4deecb9 100644
--- a/export_presets.cfg
+++ b/export_presets.cfg
@@ -22,7 +22,7 @@ variant/extensions_support=false
vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=false
html/export_icon=true
-html/custom_html_shell=""
+html/custom_html_shell="res://app.html"
html/head_include=""
html/canvas_resize_policy=2
html/focus_canvas_on_start=true
diff --git a/project.godot b/project.godot
index 2f94abc..a703fc6 100644
--- a/project.godot
+++ b/project.godot
@@ -15,6 +15,10 @@ run/main_scene="res://Start.tscn"
config/features=PackedStringArray("4.2", "GL Compatibility")
config/icon="res://icon.svg"
+[audio]
+
+driver/mix_rate.web=44100
+
[input]
drag_start={