Compare commits

...

17 Commits

Author SHA1 Message Date
32a67a6617 Update README.md !build 2025-07-20 06:57:22 +10:00
fb0c7a9e3b Merge branch 'master' of https://github.com/litruv/PNGTuber-Plus 2025-07-20 06:53:37 +10:00
f0ce00b23b Viewmode Panning 2025-07-20 06:53:34 +10:00
d4a9f5a0b0 scaled zooming 2025-07-20 06:36:07 +10:00
085d6a21a0 Update README.md !build 2025-07-20 06:33:37 +10:00
99d2d3f508 Update UI positions during zoom changes 2025-07-20 06:26:23 +10:00
dad22ece22 !build fixed opacity shader on open 2025-07-20 06:19:21 +10:00
52496df10e added panning to edit mode 2025-07-20 06:13:09 +10:00
29b903fadd Improve GitHub Actions build automation workflow
- Update build automation wording and descriptions
- Refine workflow trigger conditions
- Enhance build process testing and validation
- Consolidate multiple build automation improvements
2025-07-20 05:48:34 +10:00
e8191e2de8 Merge branch 'master' of https://github.com/litruv/PNGTuber-Plus 2025-07-20 05:34:26 +10:00
b7b7d7cdec test some build description stuff out !build 2025-07-20 05:34:24 +10:00
fc6e4a1028 Update README.md 2025-07-20 05:28:11 +10:00
1dfe21363b update wording 2025-07-20 04:42:36 +10:00
fde3f23ed5 build trigger 2025-07-20 04:17:21 +10:00
79e54c28da Merge branch 'master' of https://github.com/litruv/PNGTuber-Plus 2025-07-20 04:15:13 +10:00
a8f327ae5a Add opacity slider with shader-based rendering that preserves clip mask behavior
- Added opacity slider (0-100%) in sprite options with 'affect children' checkbox
- Implemented hierarchical opacity that affects entire sprite hierarchy when enabled
- Created shader-based opacity system that doesn't interfere with clip mask functionality
- Clip masks now work with original image pixels regardless of opacity settings
- Removed shadow effects from selected sprites to prevent visual conflicts
- Updated save/load system to persist opacity properties with backward compatibility

Fixes clipping behavior issues where opacity changes previously affected clip mask detection
2025-07-20 04:14:58 +10:00
1295bcbcba Add opacity slider with shader-based rendering that preserves clip mask behavior
- Added opacity slider (0-100%) in sprite options with 'affect children' checkbox
- Implemented hierarchical opacity that affects entire sprite hierarchy when enabled
- Created shader-based opacity system that doesn't interfere with clip mask functionality
- Clip masks now work with original image pixels regardless of opacity settings
- Removed shadow effects from selected sprites to prevent visual conflicts
- Updated save/load system to persist opacity properties with backward compatibility

Fixes clipping behavior issues where opacity changes previously affected clip mask detection
2025-07-20 04:07:41 +10:00
17 changed files with 405 additions and 57 deletions

View File

@@ -16,6 +16,7 @@ jobs:
export-windows:
name: Windows Export
runs-on: self-hosted
if: contains(github.event.head_commit.message, '!build')
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -124,11 +125,49 @@ jobs:
Write-Host "Generated tag: $tag"
Write-Host "Generated release name: $releaseName"
# Get the latest release tag to compare against
$latestTag = ""
try {
$latestTag = & git describe --tags --abbrev=0 2>$null
Write-Host "Latest tag found: $latestTag"
} catch {
Write-Host "No previous tags found, showing all commits"
}
# Generate commit history since last tag (or all commits if no tag)
$commitRange = if ($latestTag) { "$latestTag..HEAD" } else { "HEAD" }
# Get commits with format: short hash, subject, author
$commits = & git log $commitRange --pretty=format:"%h|%s|%an" --no-merges
# Build commit history as a single string
$commitHistory = ""
if ($commits) {
$commitHistory += "`n`n## Changes Since Last Release`n`n"
$commits | ForEach-Object {
$parts = $_ -split '\|', 3
$hash = $parts[0]
$subject = $parts[1] -replace '"', '""'
$author = $parts[2]
$commitUrl = "https://github.com/${{ github.repository }}/commit/$hash"
$commitHistory += "- [$hash]($commitUrl) $subject`n"
}
} else {
$commitHistory += "`n`n## Changes Since Last Release`n`nNo new commits since last release.`n"
}
# Set outputs for use in next steps
echo "tag=$tag" >> $env:GITHUB_OUTPUT
echo "release_name=$releaseName" >> $env:GITHUB_OUTPUT
echo "short_sha=$shortSha" >> $env:GITHUB_OUTPUT
echo "build_number=$buildNumber" >> $env:GITHUB_OUTPUT
# Use heredoc syntax for multiline commit history
Add-Content -Path $env:GITHUB_OUTPUT -Value "commit_history<<EOF"
Add-Content -Path $env:GITHUB_OUTPUT -Value $commitHistory
Add-Content -Path $env:GITHUB_OUTPUT -Value "EOF"
- name: Download Windows Build
uses: actions/download-artifact@v4
with:
@@ -145,15 +184,14 @@ jobs:
release_name: ${{ steps.release_info.outputs.release_name }}
body: |
Automated build of PNGTuber Plus
${{ steps.release_info.outputs.commit_history }}
## Installation
1. Download PNGTuber-Plus.exe from the assets below
2. Run the executable - no installation required!
3. For StreamDeck integration, download the plugin from [here](https://github.com/BoyneGames/streamdeck-godot-plugin/releases/tag/1.0.0)
## Credits
- Original project by [kaiakairos](https://github.com/kaiakairos/PNGTuber-Plus)
- Microphone improvements by [k0ffinz](https://github.com/k0ffinz/PNGTuber-Plus)
draft: false
prerelease: false

11
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build PNGTuber-Plus",
"type": "shell",
"command": "cd c:\\DEV\\Sync\\PNGTuber-Plus; .\\build-windows.bat",
"group": "build"
}
]
}

View File

@@ -2,16 +2,67 @@
![Build Status](https://github.com/litruv/PNGTuber-Plus/workflows/Build%20Windows/badge.svg)
### Recent Updates by Litruv
- **GitHub Actions**: Automated Windows builds on every commit
- **StreamDeck Integration**: Add buttons to enable the streamdeck plugin that was built in
- **Rotation Wobble**: New sprite rotation effects with frequency and amplitude controls
- **Enhanced Modifier Keys**: Support for complex key combinations (Ctrl+Shift+Alt+Cmd)
- **Godot 4.4.1 Support**: Updated for latest Godot stable release
- **Microphone Improvements**: Audio delay fix & more *from [k0ffinz/PNGTuber-Plus](https://github.com/k0ffinz/PNGTuber-Plus)*
A fork of [kaiakairos/PNGTuber-Plus](https://github.com/kaiakairos/PNGTuber-Plus) with some quality-of-life upgrades, editor polish, and a few power-user toys.
## 🙏 Credits
---
- **Original Project**: [PNGTuber Plus by kaiakairos](https://github.com/kaiakairos/PNGTuber-Plus)
- **StreamDeck Plugin**: Based on [BoyneGames StreamDeck Godot Plugin](https://github.com/BoyneGames/streamdeck-godot-plugin)
- **Microphone Improvements**: k0ffinz - Experimental mic loudness detection, improved audio initialization, and audio delay fixes from [k0ffinz/PNGTuber-Plus](https://github.com/k0ffinz/PNGTuber-Plus)
## 🔧 Fork Changes (Litruv Edition)
### 🎛️ Opacity Controls
Added a proper opacity slider for sprites, with an "affect children" toggle. Clip masks still behave like they should.
![Opacity Demo](https://github.com/user-attachments/assets/d5a05508-1cb1-46e0-8c90-d0aac73398db)
### 🌀 Rotation Wobble
Sprites can now do a subtle (or chaotic) rotational wobble. Frequency + amplitude sliders included.
![Rotation Wobble](https://github.com/user-attachments/assets/f45c3cc8-98d8-48cf-8821-b015de0a2f78)
### ⌨️ Enhanced Modifier Keys
Supports combos like Ctrl+Shift+Alt+Cmd. For people with more keybinds than fingers.
![Modifier Keys](https://github.com/user-attachments/assets/6d492134-f929-4e3e-a6c6-a89cf16cd62f)
### ↗️ Editor Middle Mouse Button Panning
Hold MMB in the editor to pan around the scene, it'll reset when you go back to live.
![Panning](https://github.com/user-attachments/assets/b8687b69-fc84-43c9-950b-70395ae54820)
### ↗️ View Mode MMB Shake
Hold MMB in view mode to shake your character, Show off them physics!
![viewmodeshake](https://github.com/user-attachments/assets/536dc4ae-0562-494f-8cd0-2d2ef115f085)
### 🎤 Microphone Fixes
Merged in [k0ffinzs](https://github.com/k0ffinz/PNGTuber-Plus) audio tweaks:
* Reduced mic startup delay
* Better loudness detection
* General stability improvements
### 🧱 Engine Update
Updated to **Godot 4.4.1** — no more editor nags or compatibility weirdness.
### 🎚️ StreamDeck Integration
StreamDeck plugin was already in, this just wires up the buttons.
---
## 🧾 Credits
* Original project by [kaiakairos](https://github.com/kaiakairos/PNGTuber-Plus)
* StreamDeck plugin from [BoyneGames](https://github.com/BoyneGames/streamdeck-godot-plugin)
* Mic improvements by [k0ffinz](https://github.com/k0ffinz/PNGTuber-Plus)

View File

@@ -106,7 +106,7 @@ func _process(delta):
heldSprite.z += 1
heldSprite.setZIndex()
pushUpdate("Moved sprite layer.")
if main.editMode:
if main and main.editMode:
if Input.is_action_just_pressed("reparent"):
reparentMode = !reparentMode
Global.chain.enable(reparentMode)
@@ -115,7 +115,7 @@ func _process(delta):
reparentMode = false
Global.chain.enable(reparentMode)
if main.editMode:
if main and main.editMode:
if reparentMode:
RenderingServer.set_default_clear_color(Color.POWDER_BLUE)
else:
@@ -126,7 +126,7 @@ func _process(delta):
scrollSprites()
if !main.fileSystemOpen:
if !main or main.fileSystemOpen:
if Input.is_action_just_pressed("refresh"):
refresh()
@@ -222,7 +222,7 @@ func scrollSprites():
if Input.is_action_pressed("control"):
return
if !main.editMode:
if !main or !main.editMode:
return
if main.fileSystemOpen:

Binary file not shown.

View File

@@ -43,6 +43,18 @@ var bounceOnCostumeChange = false
#Zooming
var scaleOverall = 100
#Camera Panning
var isPanning = false
var initialPanPosition = Vector2.ZERO
var initialCameraOffset = Vector2.ZERO
var cameraOffset = Vector2.ZERO
#View Mode Panning
var viewModePanning = false
var initialViewPanPosition = Vector2.ZERO
var viewPanOffset = Vector2.ZERO
var viewPanLerpSpeed = 3.0
var bounceChange = 0.0
#IMPORTANT
@@ -130,7 +142,7 @@ func _ready():
var s = get_viewport().get_visible_rect().size
origin.position = s*0.5
camera.position = origin.position
updateCameraPosition()
func _process(delta):
var hold = origin.get_parent().position.y
@@ -142,6 +154,16 @@ func _process(delta):
yVel += bounceGravity*0.0166
# Handle view mode panning lerp back to center
if !editMode:
if !viewModePanning:
# Lerp back to center when not actively panning
viewPanOffset = viewPanOffset.lerp(Vector2.ZERO, viewPanLerpSpeed * delta)
# Apply view pan offset to the root character (affects physics)
origin.position = (get_viewport().get_visible_rect().size * 0.5) + viewPanOffset
updateCameraPosition()
if Input.is_action_just_pressed("openFolder"):
OS.shell_open(ProjectSettings.globalize_path("user://"))
@@ -152,18 +174,64 @@ func _process(delta):
followShadow()
func followShadow():
shadow.visible = is_instance_valid(Global.heldSprite)
if !shadow.visible:
return
## Handle input events, especially for camera panning
func _input(event):
# Handle middle mouse button for camera panning/reset
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_MIDDLE:
if editMode:
if event.pressed:
# Start panning in edit mode
isPanning = true
initialPanPosition = event.global_position
initialCameraOffset = cameraOffset
else:
# Stop panning
isPanning = false
else:
if event.pressed:
# Start view mode panning
viewModePanning = true
initialViewPanPosition = event.global_position
else:
# Stop view mode panning
viewModePanning = false
shadow.global_position = Global.heldSprite.sprite.global_position + Vector2(6,6)
shadow.global_rotation = Global.heldSprite.sprite.global_rotation
shadow.offset = Global.heldSprite.sprite.offset
# Handle mouse movement during edit mode panning
elif editMode and event is InputEventMouseMotion and isPanning:
var totalDelta = event.global_position - initialPanPosition
shadow.texture = Global.heldSprite.sprite.texture
shadow.hframes = Global.heldSprite.sprite.hframes
shadow.frame = Global.heldSprite.sprite.frame
# Scale pan distance based on zoom level for more intuitive panning
# Higher zoom (closer) = less movement, lower zoom (farther) = more movement
var zoomScale = 1.0 / camera.zoom.x
var scaledDelta = totalDelta * zoomScale
# Calculate new camera offset from initial position plus scaled movement
cameraOffset = initialCameraOffset - scaledDelta
# Update camera position immediately
var s = get_viewport().get_visible_rect().size
camera.position = origin.position + cameraOffset
# Update UI positions
controlPanel.position = camera.position + (s/(camera.zoom*2.0))
tutorial.position = controlPanel.position
editControls.position = camera.position - (s/(camera.zoom*2.0))
viewerArrows.position = editControls.position
pushUpdates.position.y = controlPanel.position.y
pushUpdates.position.x = editControls.position.x
# Handle mouse movement during view mode panning
elif !editMode and event is InputEventMouseMotion and viewModePanning:
var totalDelta = event.global_position - initialViewPanPosition
# Scale pan distance for view mode (less sensitive than edit mode)
# Invert the movement so dragging right moves character right (not left)
var panSensitivity = 0.5
viewPanOffset = -totalDelta * panSensitivity
func followShadow():
# Shadow disabled for selected sprites
shadow.visible = false
func isFileSystemOpen():
@@ -198,14 +266,8 @@ func onWindowSizeChange():
lines.position = s*0.5
lines.drawLine()
camera.position = origin.position
controlPanel.position = camera.position + (s/(camera.zoom*2.0))
tutorial.position = controlPanel.position
editControls.position = camera.position - (s/(camera.zoom*2.0))
viewerArrows.position = editControls.position
updateCameraPosition()
spriteList.position.x = s.x - 233
pushUpdates.position.y = controlPanel.position.y
pushUpdates.position.x = editControls.position.x
func zoomScene():
#Handles Zooming
@@ -233,11 +295,45 @@ func changeZoom():
pushUpdates.scale = newZoom
Global.mouse.scale = newZoom
# Update UI positions to account for new zoom level
# Force update even during panning since zoom affects UI positioning calculations
var s = get_viewport().get_visible_rect().size
controlPanel.position = camera.position + (s/(camera.zoom*2.0))
tutorial.position = controlPanel.position
editControls.position = camera.position - (s/(camera.zoom*2.0))
viewerArrows.position = editControls.position
pushUpdates.position.y = controlPanel.position.y
pushUpdates.position.x = editControls.position.x
$ControlPanel/ZoomLabel.modulate.a = 6.0
$ControlPanel/ZoomLabel.text = "Zoom : " + str(scaleOverall) + "%"
Global.pushUpdate("Set zoom to " + str(scaleOverall) + "%")
onWindowSizeChange()
## Update camera position with current offset
func updateCameraPosition():
var s = get_viewport().get_visible_rect().size
# Only update if not currently panning to avoid conflicts
if !isPanning:
camera.position = origin.position + cameraOffset
# Update UI element positions relative to new camera position
controlPanel.position = camera.position + (s/(camera.zoom*2.0))
tutorial.position = controlPanel.position
editControls.position = camera.position - (s/(camera.zoom*2.0))
viewerArrows.position = editControls.position
pushUpdates.position.y = controlPanel.position.y
pushUpdates.position.x = editControls.position.x
## Reset camera position to center
func resetCameraPosition():
cameraOffset = Vector2.ZERO
isPanning = false
viewPanOffset = Vector2.ZERO
viewModePanning = false
updateCameraPosition()
Global.pushUpdate("Camera reset to center.")
#When the user speaks!
func onSpeak():
@@ -252,6 +348,14 @@ func swapMode():
editMode = !editMode
Global.pushUpdate("Toggled editing mode.")
# Reset camera when entering view mode
if !editMode:
resetCameraPosition()
else:
# Reset view mode panning when entering edit mode
viewPanOffset = Vector2.ZERO
viewModePanning = false
get_viewport().transparent_bg = !editMode
if Global.backgroundColor.a != 0.0:
get_viewport().transparent_bg = false
@@ -362,6 +466,10 @@ func _on_load_dialog_file_selected(path):
sprite.clipped = data[item]["clipped"]
if data[item].has("toggle"):
sprite.toggle = data[item]["toggle"]
if data[item].has("spriteOpacity"):
sprite.spriteOpacity = data[item]["spriteOpacity"]
if data[item].has("affectChildrenOpacity"):
sprite.affectChildrenOpacity = data[item]["affectChildrenOpacity"]
origin.add_child(sprite)
sprite.position = str_to_var(data[item]["pos"])
@@ -370,6 +478,13 @@ func _on_load_dialog_file_selected(path):
Saving.settings["lastAvatar"] = path
Global.spriteList.updateData()
# Update opacity shaders for all loaded sprites after they're all created
await get_tree().process_frame # Wait for all sprites to be fully initialized
var allSprites = get_tree().get_nodes_in_group("saved")
for sprite in allSprites:
if sprite.has_method("updateOpacity"):
sprite.updateOpacity()
Global.pushUpdate("Loaded avatar at: " + path)
onWindowSizeChange()
@@ -424,6 +539,9 @@ func _on_save_dialog_file_selected(path):
data[id]["toggle"] = child.toggle
data[id]["spriteOpacity"] = child.spriteOpacity
data[id]["affectChildrenOpacity"] = child.affectChildrenOpacity
id += 1
Saving.settings["lastAvatar"] = path
@@ -500,9 +618,16 @@ func _on_duplicate_button_pressed():
sprite.costumeLayers = Global.heldSprite.costumeLayers
sprite.spriteOpacity = Global.heldSprite.spriteOpacity
sprite.affectChildrenOpacity = Global.heldSprite.affectChildrenOpacity
origin.add_child(sprite)
sprite.position = Global.heldSprite.position + Vector2(16,16)
# Update opacity shader for the duplicated sprite
await get_tree().process_frame # Wait for sprite to be fully initialized
sprite.updateOpacity()
Global.heldSprite = sprite
Global.spriteList.updateData()
@@ -547,7 +672,7 @@ func moveSpriteMenu(delta):
var size = get_viewport().get_visible_rect().size
var windowLength = 1400
var windowLength = 1500
$ViewerArrows/Arrows.position.y = size.y - 25
@@ -673,4 +798,3 @@ func _on_background_input_capture_bg_key_pressed(node, keys_pressed):
if i >= 0:
changeCostume(i+1)

View File

@@ -14358,6 +14358,7 @@ text = "Zoom : 100%"
horizontal_alignment = 2
[node name="VersionLabels" type="Node2D" parent="ControlPanel"]
position = Vector2(-205, 59)
[node name="Label" type="Label" parent="ControlPanel/VersionLabels"]
offset_left = -713.0
@@ -14378,10 +14379,11 @@ label_settings = SubResource("LabelSettings_qg0do")
[node name="versionNo" type="Label" parent="ControlPanel/VersionLabels/Label2"]
layout_mode = 0
offset_left = 144.0
offset_top = 40.0
offset_top = 17.0
offset_right = 282.0
offset_bottom = 74.0
text = "v1.4.5"
offset_bottom = 60.0
text = "v1.4.5
Litruv"
label_settings = SubResource("LabelSettings_xvf50")
[node name="EditControls" type="Node2D" parent="."]

View File

@@ -136,6 +136,11 @@ control={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
mouse_middle={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
saveImages={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":76,"key_label":0,"unicode":108,"location":0,"echo":false,"script":null)

View File

@@ -9,7 +9,7 @@ func _ready():
Global.mouse = self
func _process(delta):
if Global.main.editMode:
if Global.main and Global.main.editMode:
if text != "":
label.text = text
visible = true

View File

@@ -0,0 +1,8 @@
shader_type canvas_item;
uniform float opacity : hint_range(0.0, 1.0) = 1.0;
void fragment() {
COLOR = texture(TEXTURE, UV);
COLOR.a *= opacity;
}

View File

@@ -0,0 +1 @@
uid://byxs44vljsg2f

View File

@@ -28,6 +28,9 @@ var imageSize = Vector2.ZERO
@onready var wob = $WobbleOrigin
@onready var outlineScene = preload("res://ui_scenes/selectedSprite/outline.tscn")
@onready var opacityShader = preload("res://ui_scenes/selectedSprite/opacity.gdshader")
var opacityMaterial = null
#Visuals
var mouseOffset = Vector2.ZERO
@@ -83,6 +86,10 @@ var clipped = false
var tick = 0
#Opacity
var spriteOpacity = 1.0
var affectChildrenOpacity = false
#Vis toggle
var toggle = "null"
@@ -262,10 +269,27 @@ func setZIndex():
sprite.z_index = z
func talkBlink():
var faded = 0.2 * int(Global.main.editMode)
var faded = 0.2 * int(Global.main and Global.main.editMode)
var value = (showOnTalk + (showOnBlink*3)) + (int(Global.speaking)*10) + (int(Global.blink)*20)
var yes = [0,10,20,30,1,21,12,32,3,13,4,15,26,36,27,38].has(int(value))
sprite.self_modulate.a = max(int(yes),faded)
var baseAlpha = max(int(yes), faded)
# Only handle talk/blink/edit visibility with modulate
# Opacity slider effects are handled by shader
sprite.self_modulate.a = 1.0 # Always keep original texture alpha for clipping
sprite.modulate.a = baseAlpha # Only apply talk/blink/edit visibility
func calculateParentOpacityMultiplier():
var multiplier = 1.0
var currentParent = parentSprite
# Traverse up the entire parent hierarchy
while currentParent != null:
if currentParent.affectChildrenOpacity:
multiplier *= currentParent.spriteOpacity
currentParent = currentParent.parentSprite
return multiplier
func delete():
queue_free()
@@ -403,6 +427,39 @@ func getAllLinkedSprites():
linkedSprites.append(node)
return linkedSprites
func updateOpacity():
# Force a refresh of opacity for this sprite and its children
talkBlink()
updateShaderOpacity()
# Update all child sprites in the entire hierarchy if this sprite affects children
if affectChildrenOpacity:
updateChildrenOpacityRecursively()
func updateShaderOpacity():
# Calculate total opacity from user settings and parent hierarchy
var totalOpacity = spriteOpacity * calculateParentOpacityMultiplier()
if totalOpacity >= 1.0:
# No shader needed for 100% opacity
sprite.material = null
else:
# Create or update shader material for opacity less than 100%
if opacityMaterial == null:
opacityMaterial = ShaderMaterial.new()
opacityMaterial.shader = opacityShader
opacityMaterial.set_shader_parameter("opacity", totalOpacity)
sprite.material = opacityMaterial
func updateChildrenOpacityRecursively():
var linkedSprites = getAllLinkedSprites()
for child in linkedSprites:
child.talkBlink()
child.updateShaderOpacity()
# Always update the entire hierarchy below this child
child.updateChildrenOpacityRecursively()
func visToggle(keys):
if keys.has(toggle):
$WobbleOrigin/DragOrigin.visible = !$WobbleOrigin/DragOrigin.visible

View File

@@ -73,6 +73,10 @@ func setImage():
$Animation/animFramesLabel.text = "sprite frames: " + str(Global.heldSprite.frames)
$Animation/animFrames.value = Global.heldSprite.frames
$Opacity/opacityLabel.text = "opacity: " + str(int(Global.heldSprite.spriteOpacity * 100)) + "%"
$Opacity/opacitySlider.value = Global.heldSprite.spriteOpacity
$Opacity/affectChildrenCheck.button_pressed = Global.heldSprite.affectChildrenOpacity
$VisToggle/setToggle/Label.text = "toggle: \"" + Global.heldSprite.toggle + "\""
changeRotLimit()
@@ -369,3 +373,12 @@ func _on_set_toggle_pressed():
var key = keys[0]
Global.heldSprite.toggle = key
$VisToggle/setToggle/Label.text = "toggle: \"" + Global.heldSprite.toggle + "\""
func _on_opacity_slider_value_changed(value):
$Opacity/opacityLabel.text = "opacity: " + str(int(value * 100)) + "%"
Global.heldSprite.spriteOpacity = value
Global.heldSprite.updateOpacity()
func _on_affect_children_check_toggled(button_pressed):
Global.heldSprite.affectChildrenOpacity = button_pressed
Global.heldSprite.updateOpacity()

View File

@@ -29,7 +29,7 @@
[ext_resource type="Texture2D" uid="uid://gflmeocxfnrq" path="res://ui_scenes/settings/deleteHotkey.png" id="27_fgu6g"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_21kva"]
size = Vector2(245, 1341)
size = Vector2(245, 1455)
[sub_resource type="ShaderMaterial" id="ShaderMaterial_hxmah"]
shader = ExtResource("3_ky0lu")
@@ -14285,11 +14285,12 @@ script = ExtResource("1_hp0e3")
z_index = -2
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
position = Vector2(122.5, 670.5)
position = Vector2(122.5, 727.5)
shape = SubResource("RectangleShape2D_21kva")
[node name="Border" type="Sprite2D" parent="."]
scale = Vector2(1, 1.16)
position = Vector2(0, 2.22901)
scale = Vector2(1, 1.37547)
texture = ExtResource("1_b54o8")
centered = false
offset = Vector2(-9, -10.3448)
@@ -14349,13 +14350,13 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3.362)
fov = 36.5
[node name="Position" type="Node2D" parent="."]
position = Vector2(0, 10)
position = Vector2(0, 20)
[node name="fileTitle" type="Label" parent="Position"]
offset_left = 10.0
offset_top = 134.0
offset_top = 127.0
offset_right = 236.0
offset_bottom = 154.0
offset_bottom = 147.0
text = "user://greenThing/head1.png"
label_settings = SubResource("LabelSettings_6favr")
@@ -14381,7 +14382,7 @@ offset_bottom = 227.0
text = "layer : 0"
[node name="Buttons" type="Node2D" parent="."]
position = Vector2(0, 27)
position = Vector2(0, 141)
[node name="Speaking" type="Sprite2D" parent="Buttons"]
position = Vector2(42, 523)
@@ -14468,7 +14469,7 @@ scrollable = false
[node name="WobbleControl" type="Node2D" parent="."]
z_index = 1
position = Vector2(-3, 378)
position = Vector2(-3, 486)
[node name="animationBox" type="Sprite2D" parent="WobbleControl"]
position = Vector2(125, 384.5)
@@ -14612,7 +14613,7 @@ scrollable = false
[node name="RotationalLimits" type="Node2D" parent="."]
z_index = -1
position = Vector2(0, 325)
position = Vector2(0, 435)
[node name="RotBack" type="Sprite2D" parent="RotationalLimits"]
clip_children = 2
@@ -14725,8 +14726,43 @@ offset_bottom = 1068.0
theme = SubResource("Theme_mrbyn")
scrollable = false
[node name="Opacity" type="Node2D" parent="."]
position = Vector2(-2, -611)
[node name="opacityLabel" type="Label" parent="Opacity"]
offset_left = 11.0
offset_top = 1090.0
offset_right = 159.0
offset_bottom = 1116.0
text = "opacity: 100%"
[node name="opacitySlider" type="HSlider" parent="Opacity"]
offset_left = 10.0
offset_top = 1111.0
offset_right = 233.0
offset_bottom = 1131.0
theme = SubResource("Theme_mrbyn")
max_value = 1.0
step = 0.01
value = 1.0
scrollable = false
[node name="affectChildrenLabel" type="Label" parent="Opacity"]
offset_left = 11.0
offset_top = 1140.0
offset_right = 159.0
offset_bottom = 1166.0
text = "affect children:"
[node name="affectChildrenCheck" type="CheckBox" parent="Opacity"]
offset_left = 140.0
offset_top = 1140.0
offset_right = 200.0
offset_bottom = 1166.0
theme = SubResource("Theme_mrbyn")
[node name="Layers" type="Node2D" parent="."]
position = Vector2(0, 327)
position = Vector2(0, 443)
[node name="Layer1" type="Sprite2D" parent="Layers"]
position = Vector2(23, 878)
@@ -14863,7 +14899,7 @@ position = Vector2(23, 878)
texture = ExtResource("20_px0dt")
[node name="VisToggle" type="Node2D" parent="."]
position = Vector2(11, 1289)
position = Vector2(11, 1404)
[node name="setToggle" type="Button" parent="VisToggle"]
custom_minimum_size = Vector2(0, 37.125)
@@ -14929,6 +14965,8 @@ centered = false
[connection signal="value_changed" from="RotationalLimits/rotLimitMax" to="." method="_on_rot_limit_max_value_changed"]
[connection signal="value_changed" from="Animation/animFrames" to="." method="_on_anim_frames_value_changed"]
[connection signal="value_changed" from="Animation/animSpeed" to="." method="_on_anim_speed_value_changed"]
[connection signal="value_changed" from="Opacity/opacitySlider" to="." method="_on_opacity_slider_value_changed"]
[connection signal="toggled" from="Opacity/affectChildrenCheck" to="." method="_on_affect_children_check_toggled"]
[connection signal="pressed" from="Layers/Layer1/layerButton1" to="." method="_on_layer_button_1_pressed"]
[connection signal="pressed" from="Layers/Layer2/layerButton2" to="." method="_on_layer_button_2_pressed"]
[connection signal="pressed" from="Layers/Layer3/layerButton3" to="." method="_on_layer_button_3_pressed"]