Initial commit: Unity WordConnect project

This commit is contained in:
2025-08-01 19:12:05 +08:00
commit f14db75802
3503 changed files with 448337 additions and 0 deletions

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 39a42cf101c74e4e8bb70b2958dad72c
timeCreated: 1726205143

View File

@ -0,0 +1,34 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.GUI;
using WordsToolkit.Scripts.GUI.Buttons;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class CallButtonMethod : StateMachineBehaviour
{
[SerializeField]
private string exitMethod;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
base.OnStateEnter(animator, stateInfo, layerIndex);
var component = animator.gameObject.GetComponent<CustomButton>();
if (component != null)
{
component.Invoke(exitMethod, 0.3f);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f1c162818dc149328fa1dcb096a8f7ff
timeCreated: 1730970355

View File

@ -0,0 +1,32 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.Popups;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class CallPopupMethod : StateMachineBehaviour
{
[SerializeField]
private string methodName;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
var component = animator.gameObject.GetComponent<Popup>();
if (component != null)
{
component.Invoke(methodName, 0f);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 23b520ef875a4cd1bbf46b02714dfcce
timeCreated: 1729076432

View File

@ -0,0 +1,54 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using UnityEngine.Serialization;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class DelayBeforeStart : StateMachineBehaviour
{
private float delay;
private bool hasStartedOnce;
[FormerlySerializedAs("randomMax")]
[SerializeField]
private float delayMax;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (!hasStartedOnce)
{
delay = delayMax;
animator.speed = 0;
}
else
{
animator.speed = 1;
}
}
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (!hasStartedOnce)
{
delay -= Time.deltaTime;
if (delay <= 0)
{
animator.speed = 1;
hasStartedOnce = true;
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c20ba3464f284bed8370fcefe71e9b5d
timeCreated: 1694162792

View File

@ -0,0 +1,52 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class RandomDelayBeforeStart : StateMachineBehaviour
{
private float delay;
private bool hasStartedOnce;
[SerializeField]
private float randomMax;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (!hasStartedOnce)
{
delay = Random.Range(0.0f, randomMax);
animator.speed = 0;
}
else
{
animator.speed = 1;
}
}
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (!hasStartedOnce)
{
delay -= Time.deltaTime;
if (delay <= 0)
{
animator.speed = 1;
hasStartedOnce = true;
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed32b723e2bb24e4598e155511c98198
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,47 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Collections.Generic;
using UnityEngine;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class RandomTransitionBehaviour : StateMachineBehaviour
{
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
// Get all parameters of the animator
var parameters = animator.parameters;
// Filter and store trigger parameters
var triggerParams = new List<AnimatorControllerParameter>();
foreach (var param in parameters)
{
if (param.type == AnimatorControllerParameterType.Trigger)
{
triggerParams.Add(param);
}
}
// Check if there are any trigger parameters
if (triggerParams.Count > 0)
{
// Select a random trigger
var randomIndex = Random.Range(0, triggerParams.Count);
var randomTriggerName = triggerParams[randomIndex].name;
// Set the random trigger
animator.SetTrigger(randomTriggerName);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5f71eb9df3f54f26a7fca082f2b165bc
timeCreated: 1726207741

View File

@ -0,0 +1,39 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class RandomWaitTime : StateMachineBehaviour
{
public float minWaitTime = 2f;
public float maxWaitTime = 5f;
private float nextChangeTime;
private bool isPlaying;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
nextChangeTime = Time.time + Random.Range(minWaitTime, maxWaitTime);
}
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (Time.time >= nextChangeTime)
{
isPlaying = !isPlaying;
animator.speed = isPlaying ? 1 : 0;
nextChangeTime = Time.time + Random.Range(minWaitTime, maxWaitTime);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8d28431513d24508bed75d96f343e797
timeCreated: 1694366333

View File

@ -0,0 +1,52 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
namespace WordsToolkit.Scripts.AnimationBehaviours
{
public class RandomizedState : StateMachineBehaviour
{
[Header("Add RandomFinished trigger to transition to next state")]
[SerializeField]
private float minTime = 2f;
[SerializeField]
private float maxTime = 4f;
[SerializeField]
private string randomfinishedStr = "RandomFinished";
private float currentTimeBeforeBlink;
private float timeElapsed;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Randomize();
}
private void Randomize()
{
currentTimeBeforeBlink = Random.Range(minTime, maxTime);
timeElapsed = 0f;
}
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
timeElapsed += Time.deltaTime;
if (timeElapsed >= currentTimeBeforeBlink)
{
animator.SetTrigger(Animator.StringToHash(randomfinishedStr));
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 92be39a43ff94817ad00fc3b7349e4a8
timeCreated: 1692957436

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7b5a765a4e4e498f8339b0006e9cc463
timeCreated: 1727507629

View File

@ -0,0 +1,20 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
namespace WordsToolkit.Scripts.Attributes
{
public class IconPreviewAttribute : PropertyAttribute
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 22d780b37ddb46cda7134ff6c7f360e9
timeCreated: 1727507608

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 878126e0c4d34bbba257d00faf5b79b6
timeCreated: 1725685907

View File

@ -0,0 +1,22 @@
using UnityEngine;
namespace WordsToolkit.Scripts.Audio
{
public interface IAudioService
{
void PlaySound(AudioClip clip);
void PlayDelayed(AudioClip clip, float delay);
void PlaySoundsRandom(AudioClip[] clips);
void PlayPopupShow();
void PlayPopupClose();
void PlayClick(AudioClip overrideClickSound);
void PlayCoins();
void PlayIncremental(int selectedLettersCount);
void PlayOpenWord();
void PlayBonus();
void PlayWrong();
void PlayWin();
void PlayBonusGetting();
void PlaySoundExclusive(AudioClip sound);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a6c574fa191a41adbc3fc0eebaebc90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using UnityEngine.Audio;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.Audio
{
[RequireComponent(typeof(AudioSource))]
public class MusicBase : MonoBehaviour
{
[SerializeField]
private AudioMixer mixer;
[SerializeField]
private string musicParameter = "musicVolume";
private void Start()
{
mixer.SetFloat(musicParameter, PlayerPrefs.GetInt("Music", 1) == 0 ? -80 : 0);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 948bdbeeb220479ba6e36947c8f043f6
timeCreated: 1704217383

View File

@ -0,0 +1,173 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.Audio;
using WordsToolkit.Scripts.System;
using Random = UnityEngine.Random;
namespace WordsToolkit.Scripts.Audio
{
[RequireComponent(typeof(AudioSource))]
public class SoundBase : MonoBehaviour, IAudioService
{
[SerializeField]
private AudioMixer mixer;
[SerializeField]
private string soundParameter = "soundVolume";
[SerializeField]
public AudioClip click;
public AudioClip[] swish;
public AudioClip coins;
public AudioClip coinsSpend;
public AudioClip luckySpin;
public AudioClip warningTime;
public AudioClip bonus;
public AudioClip gemSound;
public AudioClip[] combo;
private AudioSource audioSource;
private readonly HashSet<AudioClip> clipsPlaying = new();
[SerializeField]
private AudioClip openWord;
[SerializeField]
private AudioClip wrong;
[SerializeField]
private AudioClip win;
private void Awake()
{
audioSource = GetComponent<AudioSource>();
}
private void Start()
{
mixer.SetFloat(soundParameter, PlayerPrefs.GetInt("Sound", 1) == 0 ? -80 : 0);
}
public void PlaySound(AudioClip clip)
{
if (clip != null)
{
audioSource.PlayOneShot(clip);
}
}
public void PlayDelayed(AudioClip clip, float delay)
{
StartCoroutine(PlayDelayedCoroutine(clip, delay));
}
private IEnumerator PlayDelayedCoroutine(AudioClip clip, float delay)
{
yield return new WaitForSeconds(delay);
PlaySound(clip);
}
public void PlaySoundsRandom(AudioClip[] clip)
{
PlaySound(clip[Random.Range(0, clip.Length)]);
}
public void PlayPopupShow()
{
// PlaySound(swish[0]);
}
public void PlayPopupClose()
{
// PlaySound(swish[1]);
}
public void PlayClick(AudioClip overrideClickSound)
{
PlaySound(overrideClickSound != null ? overrideClickSound : click);
}
public void PlayCoins()
{
PlaySound(coins);
}
public void PlayBonusGetting()
{
PlaySound(gemSound);
}
public void PlaySoundExclusive([NotNull] AudioClip sound)
{
if (sound == null)
{
return;
}
if (clipsPlaying.Add(sound))
{
audioSource.PlayOneShot(sound);
StartCoroutine(WaitForCompleteSound(sound, 1));
}
}
public void PlayIncremental(int selectedLettersCount)
{
if (selectedLettersCount > 0 && selectedLettersCount <= combo.Length)
{
PlaySound(combo[selectedLettersCount - 1]);
}
}
public void PlayOpenWord()
{
PlayLimitSound(openWord, 1);
}
public void PlayBonus()
{
PlaySound(bonus);
}
public void PlayWrong()
{
PlaySound(wrong);
}
public void PlayWin()
{
PlaySound(win);
}
public void PlayLimitSound(AudioClip clip, int sec)
{
if (clipsPlaying.Add(clip))
{
PlaySound(clip);
StartCoroutine(WaitForCompleteSound(clip, sec));
}
}
private IEnumerator WaitForCompleteSound(AudioClip clip, int sec)
{
yield return new WaitForSeconds(sec);
clipsPlaying.Remove(clip);
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2dcae87cba276d84da88cca70d5ab1cc
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,45 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
namespace WordsToolkit.Scripts.Audio
{
public class UISoundSequence : MonoBehaviour
{
[SerializeField]
private AudioClip[] clips;
private int _index;
private IAudioService _audioService;
public void Construct(IAudioService audioService)
{
_audioService = audioService;
}
public void PlaySound()
{
if (clips.Length == 0 || _audioService == null)
{
return;
}
_audioService.PlaySound(clips[_index]);
_index++;
if (_index >= clips.Length)
{
_index = 0;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ec4f308c3c4449aead46df19c04c56fe
timeCreated: 1704730324

View File

@ -0,0 +1,25 @@
{
"name": "CandySmith.WordsToolkit.Main",
"rootNamespace": "",
"references": [
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:75bdbcf23199f4cfb86c610d1d946666",
"GUID:ac6e78962cfc743b9a5fc5f5a808aa72",
"GUID:60bfecf5cb232594891bc622f40d6bed",
"GUID:00dd4a7ac8c24c898083910c81898ecc",
"GUID:b25ad8286798741e3b2cc3883283e669",
"GUID:c98377141161c7746a178fb5cb1af075",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
"jp.hadashikick.vcontainer"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d3bf71b33c0c04eb9bc1a8d6513d76bb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2fa9ea523ff2490a9050e80bfb5df323
timeCreated: 1725686211

View File

@ -0,0 +1,27 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.Data
{
public class Coins : ResourceObject
{
public override int DefaultValue => Resources.Load<GameSettings>("Settings/GameSettings").coins;
public override void ResetResource()
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a3dd04ed239d4e27911d5c626b268895
timeCreated: 1725686242

View File

@ -0,0 +1,28 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.Data
{
// create scriptable
[CreateAssetMenu(fileName = "Gems", menuName = "WordConnectGameToolkit/Resources/Gems")]
public class Gems : ResourceObject
{
public override int DefaultValue => Resources.Load<GameSettings>("Settings/GameSettings").gems;
public override void ResetResource()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86c305bdfc261450db83ed12db7fb719
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
namespace WordsToolkit.Scripts.Data
{
[CreateAssetMenu(fileName = "Resource", menuName = "WordConnectGameToolkit/Resources/ResourceItem", order = 1)]
public class ResourceItem : ResourceObject
{
public int defaultValue;
public override int DefaultValue => defaultValue;
public override void ResetResource()
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 566ab6ec3d8843e3977f686e450580af
timeCreated: 1725686242

View File

@ -0,0 +1,99 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.System;
using VContainer;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.Infrastructure.Factories;
namespace WordsToolkit.Scripts.Data
{
public class ResourceManager : MonoBehaviour
{
[Inject] private ICoinsFactory coinsFactory;
[Inject] private MenuManager menuManager;
private ResourceObject[] resources;
public ResourceObject[] Resources
{
get
{
if (resources == null || resources.Length == 0)
{
Init();
}
return resources;
}
set => resources = value;
}
public void Awake()
{
Init();
}
private void Init()
{
Resources = UnityEngine.Resources.LoadAll<ResourceObject>("Variables");
foreach (var resource in Resources)
{
resource.LoadPrefs();
}
}
public bool Consume(ResourceObject resource, int amount)
{
return resource.Consume(amount);
}
private void ShowShop(Popup shopPopup)
{
menuManager.ShowPopup(shopPopup);
}
public void PlaySpendEffect(GameObject fxPrefab)
{
if (fxPrefab != null)
{
coinsFactory.CreateCoins(fxPrefab);
}
}
public bool ConsumeWithEffects(ResourceObject resource, int amount)
{
if (resource.Consume(amount))
{
PlaySpendEffect(resource.GetSpendEffectPrefab());
return true;
}
ShowShop(resource.shopPopup);
return false;
}
public ResourceObject GetResource(string resourceName)
{
foreach (var resource in Resources)
{
if (resource.name == resourceName)
{
return resource;
}
}
return null;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6063e6d1a0bd47d196d930f0ed77c99c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -10
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,139 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Threading.Tasks;
using UnityEngine;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.GUI.Labels;
namespace WordsToolkit.Scripts.Data
{
public abstract class ResourceObject : ScriptableObject
{
public ResourceValue ResourceValue;
//name of the resource
private string ResourceName => name;
public abstract int DefaultValue { get; }
//value of the resource
private int Resource;
public AudioClip sound;
public Popup shopPopup;
// Reference to the coins effect prefab
[SerializeField]
private GameObject fxSpendPrefab;
public GameObject GetSpendEffectPrefab() => fxSpendPrefab;
//delegate for resource update
public delegate void ResourceUpdate(int count);
//event for resource update
public event ResourceUpdate OnResourceUpdate;
//runs when the object is created
private void OnEnable()
{
Task.Run(async () =>
{
await Task.Delay(1000);
await LoadPrefs();
});
}
//loads prefs from player prefs and assigns to resource variable
public Task LoadPrefs()
{
Resource = LoadResource();
return Task.CompletedTask;
}
public int LoadResource()
{
return PlayerPrefs.GetInt(ResourceName, DefaultValue);
}
//adds amount to resource and saves to player prefs
public void Add(int amount)
{
Resource += amount;
PlayerPrefs.SetInt(ResourceName, Resource);
OnResourceChanged();
}
public void AddAnimated(int amount, Vector3 startPosition, GameObject animationSourceObject = null, Action callback = null)
{
callback += () => Add(amount);
ResourceAnimationController.AnimateForResource(this,animationSourceObject, startPosition, "+" + amount, sound, callback);
}
//sets resource to amount and saves to player prefs
public void Set(int amount)
{
Resource = amount;
PlayerPrefs.SetInt(ResourceName, Resource);
PlayerPrefs.Save();
OnResourceChanged();
}
//consumes amount from resource and saves to player prefs if there is enough
public bool Consume(int amount)
{
if (IsEnough(amount))
{
Resource -= amount;
PlayerPrefs.SetInt(ResourceName, Resource);
PlayerPrefs.Save();
OnResourceChanged();
return true;
}
return false;
}
//callback for ui elements
private void OnResourceChanged()
{
OnResourceUpdate?.Invoke(Resource);
}
//get the resource
public int GetValue()
{
return Resource;
}
//check if there is enough of the resource
public bool IsEnough(int targetAmount)
{
if (GetValue() < targetAmount)
{
Debug.Log("Not enough " + ResourceName);
}
return GetValue() >= targetAmount;
}
public abstract void ResetResource();
}
[Serializable]
public class ResourceValue
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c7823bdd74084b37a9c7f6f3dcd28abe
timeCreated: 1725686242

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 910ab0bde73e7394ebbdf4dfee9a9232
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,167 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using WordsToolkit.Scripts.Gameplay.Managers;
using WordsToolkit.Scripts.Levels;
using WordsToolkit.Scripts.System;
using VContainer;
namespace WordsToolkit.Scripts.Debugger
{
public class CrosswordWordsDebug : MonoBehaviour
{
[SerializeField] private bool showDebugButton = true;
[SerializeField] private bool showWordsList = false;
private LevelManager levelManager;
private StateManager stateManager;
private Vector2 scrollPosition = Vector2.zero;
[Inject]
public void Construct(LevelManager levelManager, StateManager stateManager)
{
this.levelManager = levelManager;
this.stateManager = stateManager;
}
private void OnGUI()
{
#if !UNITY_ANDROID && !UNITY_IOS
if (!showDebugButton)
return;
// Only show debug button when in Game state
if (stateManager == null || stateManager.CurrentState != EScreenStates.Game)
return;
// Debug button in the bottom-right corner - scale with screen width
float buttonWidth = Screen.width * 0.16f; // 12% of screen width
float buttonHeight = Screen.width * 0.06f; // 3% of screen width for proportional height
float margin = Screen.width * 0.01f; // 1% of screen width for margin
// Create scaled button style
int buttonFontSize = Mathf.RoundToInt(buttonHeight * 0.4f); // 40% of button height
GUIStyle buttonStyle = new GUIStyle(UnityEngine.GUI.skin.button);
buttonStyle.fontSize = buttonFontSize;
if (UnityEngine.GUI.Button(new Rect(Screen.width - buttonWidth - margin, Screen.height - buttonHeight - margin, buttonWidth, buttonHeight), "Show Words", buttonStyle))
{
showWordsList = !showWordsList;
}
// Words list panel along the bottom border
if (showWordsList)
{
// Scale everything based on screen width
float panelWidth = Screen.width * 0.85f; // 85% of screen width
float panelHeight = Screen.width * 0.15f; // 15% of screen width for consistent proportions
float minPanelWidth = Screen.width * 0.3f; // Minimum 30% of screen width
float minPanelHeight = Screen.width * 0.08f; // Minimum 8% of screen width
panelWidth = Mathf.Max(panelWidth, minPanelWidth);
panelHeight = Mathf.Max(panelHeight, minPanelHeight);
// Position the panel down and to the left
float panelX = (Screen.width - panelWidth) * 0.3f; // Move left (30% from left instead of centered)
float panelY = Screen.height - panelHeight - (Screen.width * 0.02f); // Move down (smaller bottom margin)
// Ensure panel doesn't go off screen
panelX = Mathf.Clamp(panelX, Screen.width * 0.005f, Screen.width - panelWidth - Screen.width * 0.005f);
panelY = Mathf.Clamp(panelY, Screen.width * 0.005f, Screen.height - panelHeight - Screen.width * 0.005f);
// Background panel
UnityEngine.GUI.Box(new Rect(panelX, panelY, panelWidth, panelHeight), "");
float padding = Screen.width * 0.005f; // Padding scaled to screen width
GUILayout.BeginArea(new Rect(panelX + padding, panelY + padding, panelWidth - padding * 2, panelHeight - padding * 2));
// Compact header with close button - font sizes based on panel height
GUILayout.BeginHorizontal();
int headerFontSize = Mathf.RoundToInt(panelHeight * 0.15f); // 15% of panel height
GUILayout.Label("Words", new GUIStyle(UnityEngine.GUI.skin.label)
{
fontSize = headerFontSize,
fontStyle = FontStyle.Bold
});
GUILayout.FlexibleSpace();
float closeButtonSize = panelHeight * 0.2f; // Close button size based on panel height
if (GUILayout.Button("X", GUILayout.Width(closeButtonSize), GUILayout.Height(closeButtonSize)))
{
showWordsList = false;
}
GUILayout.EndHorizontal();
// Get current level and display words
Level currentLevel = levelManager.GetCurrentLevel();
if (currentLevel != null)
{
var languageData = currentLevel.GetLanguageData(levelManager.GetCurrentLanguage());
if (languageData != null && languageData.crosswordData != null && languageData.crosswordData.placements != null)
{
// Get words from crossword placements
var words = languageData.crosswordData.placements
.Where(p => !string.IsNullOrEmpty(p.word))
.Select(p => p.word.ToUpper())
.Distinct()
.OrderBy(w => w)
.ToList();
// Responsive scrollable word list
float scrollViewHeight = panelHeight - (Screen.width * 0.04f); // Adjust based on panel height minus header, scaled
scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Height(scrollViewHeight));
// Display words in horizontal rows, dynamically fitting the width
int wordFontSize = Mathf.RoundToInt(panelHeight * 0.12f); // 12% of panel height
// Calculate approximate character width for font size estimation
float charWidth = wordFontSize * 0.6f; // Approximate character width
float separatorWidth = charWidth * 3; // Width for " • " separator
string currentLine = "";
float currentLineWidth = 0;
foreach (var word in words)
{
float wordWidth = word.Length * charWidth;
float totalWidth = currentLineWidth + (currentLine.Length > 0 ? separatorWidth : 0) + wordWidth;
// Check if adding this word would exceed the panel width
if (currentLine.Length > 0 && totalWidth > panelWidth - 40) // 40px padding buffer
{
// Display current line and start new one
GUILayout.Label(currentLine, new GUIStyle(UnityEngine.GUI.skin.label) { fontSize = wordFontSize });
currentLine = word;
currentLineWidth = wordWidth;
}
else
{
// Add word to current line
if (currentLine.Length > 0)
{
currentLine += " • " + word;
currentLineWidth += separatorWidth + wordWidth;
}
else
{
currentLine = word;
currentLineWidth = wordWidth;
}
}
}
// Display the last line if it has content
if (currentLine.Length > 0)
{
GUILayout.Label(currentLine, new GUIStyle(UnityEngine.GUI.skin.label) { fontSize = wordFontSize });
}
GUILayout.EndScrollView();
}
}
GUILayout.EndArea();
}
#endif
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea38205d5b4fd1b468379715158c7e54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6119684e075748458b7e22bb7a5a5e68
timeCreated: 1725694444

View File

@ -0,0 +1,43 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.IO;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace WordsToolkit.Scripts.Editor
{
[InitializeOnLoad]
public class Autorun
{
static Autorun()
{
EditorApplication.update += InitProject;
}
private static void InitProject()
{
EditorApplication.update -= InitProject;
if (EditorApplication.timeSinceStartup < 10 || !EditorPrefs.GetBool(Application.dataPath + "AlreadyOpened"))
{
if (SceneManager.GetActiveScene().name != "game" && Directory.Exists("Assets/WordConnectGameToolkit/Scenes"))
{
EditorSceneManager.OpenScene("Assets/WordConnectGameToolkit/Scenes/main.unity");
}
EditorPrefs.SetBool(Application.dataPath + "AlreadyOpened", true);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c10bf1643144c3398f97f61968329b4
timeCreated: 1725765484

View File

@ -0,0 +1,24 @@
{
"name": "CandySmith.BlockPuzzle.Drawers",
"rootNamespace": "",
"references": [
"GUID:2bafac87e7f4b9b418d9448d219b01ab",
"GUID:d3bf71b33c0c04eb9bc1a8d6513d76bb",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
"GUID:00dd4a7ac8c24c898083910c81898ecc",
"GUID:ac6e78962cfc743b9a5fc5f5a808aa72",
"GUID:b25ad8286798741e3b2cc3883283e669",
"GUID:75bdbcf23199f4cfb86c610d1d946666"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c912612fdd262440c8671324bf615a5d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 02cd75ced4a647a6b2dcece605b128db
timeCreated: 1725704655

View File

@ -0,0 +1,65 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEditor;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Attributes;
using WordsToolkit.Scripts.Gameplay;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.Editor.Drawers
{
// Custom attribute
// Drawer for the custom attribute
[CustomPropertyDrawer(typeof(IconPreviewAttribute))]
public class IconDrawer : PropertyDrawer
{
private Label m_Icon;
private ScriptableData m_IconScriptable;
private SerializedProperty m_property;
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
m_property = property;
m_Icon = new Label();
m_Icon.style.width = 200;
m_Icon.style.height = 200;
// get parent of the property
m_IconScriptable = property.serializedObject.targetObject as ScriptableData;
if (m_IconScriptable != null)
{
m_IconScriptable.OnChange += UpdatePreview;
}
UpdatePreview();
return m_Icon;
}
private void UpdatePreview()
{
EditorApplication.delayCall += () =>
{
var itemTemplate = m_IconScriptable as ColorsTile;
if (itemTemplate != null && itemTemplate.HasCustomPrefab())
{
// m_Icon.style.backgroundImage = EditorUtils.GetPrefabPreview(itemTemplate.customItemPrefab.gameObject);
}
else
{
m_Icon.style.backgroundImage = EditorUtils.GetCanvasPreviewVisualElement(m_IconScriptable.prefab, obj => obj.FillIcon(m_IconScriptable));
}
};
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 170ab4d5b40704f788163abb29cc0bd8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEditor;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Data;
namespace WordsToolkit.Scripts.Editor.Drawers
{
[CustomPropertyDrawer(typeof(ResourceValue))]
public class ResourceValueDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var root = new VisualElement();
root.Add(new Label("Resource Value: " + ((ResourceObject)property.serializedObject.targetObject).LoadResource()));
return root;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cf9081abd17a4ace8aaf39202c8b18da
timeCreated: 1712217714

View File

@ -0,0 +1,175 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Utils;
namespace WordsToolkit.Scripts.Editor.Drawers
{
[CustomPropertyDrawer(typeof(SerializableDictionary<,>))]
public class SerializableDictionaryDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var container = new VisualElement();
var foldout = new Foldout();
foldout.text = property.displayName;
container.Add(foldout);
var listView = new ListView();
foldout.Add(listView);
var dictionaryType = fieldInfo.FieldType;
var keyType = dictionaryType.GetGenericArguments()[0];
listView.makeItem = () => new PackElementDictionaryItemElement(keyType);
listView.bindItem = (element, index) =>
{
var itemElement = (PackElementDictionaryItemElement)element;
var keysProp = property.FindPropertyRelative("keys");
var valuesProp = property.FindPropertyRelative("values");
itemElement.BindProperties(keysProp.GetArrayElementAtIndex(index), valuesProp.GetArrayElementAtIndex(index), property, index);
};
listView.showAddRemoveFooter = true;
listView.showFoldoutHeader = false;
listView.showBorder = true;
listView.showBoundCollectionSize = false;
listView.reorderable = true;
void RefreshList()
{
var keysProp = property.FindPropertyRelative("keys");
listView.itemsSource = new List<int>(Enumerable.Range(0, keysProp.arraySize));
listView.RefreshItems();
}
RefreshList();
listView.itemsAdded += indexes =>
{
var keysProp = property.FindPropertyRelative("keys");
var valuesProp = property.FindPropertyRelative("values");
property.serializedObject.Update();
foreach (var index in indexes)
{
keysProp.InsertArrayElementAtIndex(index);
valuesProp.InsertArrayElementAtIndex(index);
var keyProp = keysProp.GetArrayElementAtIndex(index);
keyProp.objectReferenceValue = null;
var valueProp = valuesProp.GetArrayElementAtIndex(index);
// Reset the value based on its type
ResetValue(valueProp);
}
property.serializedObject.ApplyModifiedProperties();
RefreshList();
};
listView.itemsRemoved += indexes =>
{
var keysProp = property.FindPropertyRelative("keys");
var valuesProp = property.FindPropertyRelative("values");
property.serializedObject.Update();
foreach (var index in indexes.OrderByDescending(i => i))
{
keysProp.DeleteArrayElementAtIndex(index);
valuesProp.DeleteArrayElementAtIndex(index);
}
property.serializedObject.ApplyModifiedProperties();
RefreshList();
};
return container;
}
private void ResetValue(SerializedProperty valueProp)
{
switch (valueProp.propertyType)
{
case SerializedPropertyType.Integer:
valueProp.intValue = 0;
break;
case SerializedPropertyType.Boolean:
valueProp.boolValue = false;
break;
case SerializedPropertyType.Float:
valueProp.floatValue = 0f;
break;
case SerializedPropertyType.String:
valueProp.stringValue = string.Empty;
break;
case SerializedPropertyType.ObjectReference:
valueProp.objectReferenceValue = null;
break;
// Add more cases as needed for other types
}
}
}
public class PackElementDictionaryItemElement : VisualElement
{
private readonly ObjectField keyField;
private readonly PropertyField valueField;
public PackElementDictionaryItemElement(Type keyType)
{
style.flexDirection = FlexDirection.Row;
style.flexGrow = 1;
style.width = Length.Percent(100);
keyField = new ObjectField
{
style =
{
flexGrow = 1,
flexBasis = 0,
marginRight = 5,
marginLeft = 5
}
};
keyField.objectType = keyType;
Add(keyField);
valueField = new PropertyField
{
style =
{
flexGrow = 1,
flexBasis = 0,
marginRight = 5
}
};
Add(valueField);
}
public void BindProperties(SerializedProperty keyProp, SerializedProperty valueProp, SerializedProperty parentProp, int index)
{
keyField.BindProperty(keyProp);
valueField.BindProperty(valueProp);
keyField.label = string.Empty;
valueField.label = string.Empty;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 79fbdca59d1e412280be81efe1abef0b
timeCreated: 1723101447

View File

@ -0,0 +1,51 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Collections.Generic;
namespace WordsToolkit.Scripts.Editor.Drawers
{
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
[CustomPropertyDrawer(typeof(TagFieldUIAttribute))]
public class TagFieldUIPropertyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var container = new VisualElement();
if (property.propertyType == SerializedPropertyType.String)
{
var dropdown = new DropdownField(property.displayName);
dropdown.choices = new List<string>(UnityEditorInternal.InternalEditorUtility.tags);
dropdown.value = property.stringValue;
dropdown.RegisterValueChangedCallback(evt =>
{
property.stringValue = evt.newValue;
property.serializedObject.ApplyModifiedProperties();
});
container.Add(dropdown);
}
else
{
var propertyField = new PropertyField(property);
container.Add(propertyField);
}
return container;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6919d8875d47445b8a6d10d54e7cd8b2
timeCreated: 1747970167

View File

@ -0,0 +1,166 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using WordsToolkit.Scripts.Gameplay.Managers;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.Editor
{
public static class EditorMenu
{
public static string WordConnect = "WordConnect";
private static string WordConnectPath = "Assets/WordConnectGameToolkit";
[MenuItem( nameof(WordConnect) + "/Settings/Shop settings")]
public static void IAPProducts()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/CoinsShopSettings.asset");
}
[MenuItem( nameof(WordConnect) + "/Settings/Ads settings")]
public static void AdsSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/AdsSettings.asset");
}
//DailyBonusSettings
[MenuItem( nameof(WordConnect) + "/Settings/Daily bonus settings")]
public static void DailyBonusSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/DailyBonusSettings.asset");
}
//GameSettings
[MenuItem( nameof(WordConnect) + "/Settings/Game settings")]
public static void GameSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/GameSettings.asset");
}
//SpinSettings
[MenuItem( nameof(WordConnect) + "/Settings/Spin settings")]
public static void SpinSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/SpinSettings.asset");
}
//DebugSettings
[MenuItem( nameof(WordConnect) + "/Settings/Debug settings")]
public static void DebugSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/DebugSettings.asset");
}
[MenuItem( nameof(WordConnect) + "/Settings/Crossword config")]
public static void CrosswordConfig()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/CrosswordConfig.asset");
}
[MenuItem( nameof(WordConnect) + "/Settings/Tutorial settings")]
public static void TutorialSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/TutorialSettings.asset");
}
[MenuItem( nameof(WordConnect) + "/Settings/Language configuration")]
public static void LanguageConfiguration()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/LanguageConfiguration.asset");
}
[MenuItem( nameof(WordConnect) + "/Settings/Gift settings")]
public static void GiftSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/GiftSettings.asset");
}
[MenuItem( nameof(WordConnect) + "/Scenes/Main scene &1", priority = 0)]
public static void MainScene()
{
EditorSceneManager.OpenScene(WordConnectPath + "/Scenes/main.unity");
var stateManager = Object.FindObjectOfType<StateManager>();
if (stateManager != null)
{
stateManager.CurrentState = EScreenStates.MainMenu;
}
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
[MenuItem( nameof(WordConnect) + "/Scenes/Game scene &2")]
public static void GameScene()
{
var stateManager = Object.FindObjectOfType<StateManager>();
stateManager.CurrentState = EScreenStates.Game;
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
[MenuItem( nameof(WordConnect) + "/Editor/Tile editor", priority = 1)]
public static void ColorEditor()
{
string folderPath = WordConnectPath + "/Resources/ColorsTile";
// Get all tile assets in the folder
string[] guids = AssetDatabase.FindAssets("t:Object", new[] { folderPath });
if (guids.Length == 0)
{
Debug.LogWarning($"No tile assets found in: {folderPath}");
return;
}
// Select a random tile asset
string randomGuid = guids[Random.Range(0, guids.Length)];
string assetPath = AssetDatabase.GUIDToAssetPath(randomGuid);
var tileAsset = AssetDatabase.LoadAssetAtPath<Object>(assetPath);
// Select and ping the tile asset in the Project window
Selection.activeObject = tileAsset;
EditorGUIUtility.PingObject(tileAsset);
}
[MenuItem( nameof(WordConnect) + "/Documentation/Main", priority = 2)]
public static void MainDoc()
{
Application.OpenURL("https://candy-smith.gitbook.io/main");
}
[MenuItem( nameof(WordConnect) + "/Documentation/ADS/Setup ads")]
public static void UnityadsDoc()
{
Application.OpenURL("https://candy-smith.gitbook.io/bubble-shooter-toolkit/tutorials/ads-setup/");
}
[MenuItem( nameof(WordConnect) + "/Documentation/Unity IAP (in-apps)")]
public static void Inapp()
{
Application.OpenURL("https://candy-smith.gitbook.io/main/block-puzzle-game-toolkit/setting-up-in-app-purchase-products");
}
[MenuItem( nameof(WordConnect) + "/NLP/Training Language Model")]
public static void TrainingModel()
{
Application.OpenURL("https://colab.research.google.com/drive/199zNcB3FPfnrD6E7OiwmwCcf27jMnY1b?usp=sharing");
}
[MenuItem( nameof(WordConnect) + "/Reset PlayerPrefs &e")]
private static void ResetPlayerPrefs()
{
GameDataManager.ClearALlData();
PlayerPrefs.DeleteKey("GameState");
Debug.Log("PlayerPrefs are reset");
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c84cc4add82c408ab2fbbd7d25c01ba6
timeCreated: 1725699029

View File

@ -0,0 +1,255 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Gameplay;
using WordsToolkit.Scripts.System;
using WordsToolkit.Scripts.Utils;
using Object = UnityEngine.Object;
namespace WordsToolkit.Scripts.Editor
{
public static class EditorUtils
{
public static Texture2D GetPrefabPreview(GameObject prefab)
{
var previewRender = new PreviewRenderUtility();
previewRender.camera.backgroundColor = Color.black;
previewRender.camera.clearFlags = CameraClearFlags.SolidColor;
previewRender.camera.cameraType = CameraType.Game;
previewRender.camera.farClipPlane = 1000f;
previewRender.camera.nearClipPlane = 0.1f;
var obj = previewRender.InstantiatePrefabInScene(prefab);
var rect = obj.GetComponent<RectTransform>().rect;
previewRender.BeginStaticPreview(new Rect(0.0f, 0.0f, rect.width*1.5f, rect.height*1.5f));
SetupPreviewCanvas(obj, previewRender.camera);
previewRender.Render();
var texture = previewRender.EndStaticPreview();
previewRender.camera.targetTexture = null;
previewRender.Cleanup();
return texture;
}
private static void SetupPreviewCanvas(GameObject obj, Camera camera)
{
var canvasInstance = obj.AddComponent<Canvas>();
canvasInstance.renderMode = RenderMode.ScreenSpaceCamera;
canvasInstance.worldCamera = camera;
var canvasScaler = obj.AddComponent<CanvasScaler>();
canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ConstantPixelSize;
canvasScaler.referenceResolution = new Vector2(1920, 1080);
var scaleFactorX = Screen.width / canvasScaler.referenceResolution.x;
var scaleFactorY = Screen.height / canvasScaler.referenceResolution.y;
canvasScaler.scaleFactor = Mathf.Min(scaleFactorX, scaleFactorY) * 7;
}
public static SerializedProperty GetPropertyFromValue(Object targetObject)
{
var serializedObject = new SerializedObject(targetObject);
var property = serializedObject.GetIterator();
// Go through each property in the object
while (property.Next(true))
{
// Skip properties with child properties (e.g., arrays, structs)
if (property.hasVisibleChildren)
{
continue;
}
// Check if the property value matches the desired field value
// if (fieldValue.Equals(GetFieldValue(targetObject, property.name)))
{
// Create a copy of the property
var copiedProperty = property.Copy();
// Make sure the serializedObject is up to date
copiedProperty.serializedObject.Update();
// Apply the modified properties
copiedProperty.serializedObject.ApplyModifiedProperties();
return copiedProperty;
}
}
return null; // Field value not found
}
private static object GetFieldValue(Object targetObject, string fieldName)
{
var field = targetObject.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
return field.GetValue(targetObject);
}
Debug.LogError($"Field {fieldName} not found in object {targetObject.GetType().Name}");
return null;
}
public static VisualElement GetObjectFields(SerializedObject serializedObject, Action<SerializedProperty> onChange = null)
{
var visualElement = new VisualElement();
// Iterate through the fields of the Icon class
var iterator = serializedObject.GetIterator();
var enterChildren = true;
while (iterator.NextVisible(enterChildren))
{
// Exclude the "m_Script" field
if (iterator.name == "m_Script")
{
continue;
}
// Create a PropertyField for each field
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(serializedObject);
propertyField.style.flexShrink = 0;
propertyField.style.flexGrow = 0;
propertyField.style.width = 400;
propertyField.RegisterValueChangeCallback(evt => { onChange?.Invoke(evt.changedProperty); });
visualElement.Add(propertyField);
enterChildren = false;
}
return visualElement;
}
public static VisualElement GetPropertyFields(SerializedProperty property, bool children, Action<SerializedProperty> onChange = null)
{
var visualElement = new VisualElement();
var methods = TypeCache.GetMethodsWithAttribute<CustomSerializeTypePropertyAttribute>();
foreach (var m in methods)
{
foreach (var customAttributeData in m.CustomAttributes)
{
foreach (var customAttributeTypedArgument in customAttributeData.ConstructorArguments)
{
if (property.managedReferenceValue != null && (Type)customAttributeTypedArgument.Value != property.managedReferenceValue.GetType())
{
continue;
}
if (m.IsStatic)
{
return m.Invoke(null, new object[] { property }) as VisualElement;
}
var instance = Activator.CreateInstance(m.DeclaringType);
return m.Invoke(instance, new object[] { property }) as VisualElement;
}
}
}
// Iterate through the fields of the Icon class
var iterator = property.Copy();
while (iterator.NextVisible(children))
{
// Exclude the "m_Script" field
if (iterator.name == "m_Script")
{
continue;
}
if (iterator.depth == property.depth + 1)
{
// Create a PropertyField for each field
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(property.serializedObject);
propertyField.style.flexShrink = 0;
propertyField.style.flexGrow = 0;
propertyField.style.width = 400;
propertyField.RegisterValueChangeCallback(evt => { onChange?.Invoke(evt.changedProperty); });
visualElement.Add(propertyField);
}
children = false;
}
return visualElement;
}
public static DropdownField GetTypesDropdown(SerializedProperty property)
{
var fieldInfo = TypeCache.GetFieldsWithAttribute<SerializeTypePropertyAttribute>()[0];
var typesDerivedFrom = TypeCache.GetTypesDerivedFrom(fieldInfo.FieldType);
var typeNames = typesDerivedFrom.Select(t => t.Name).ToList();
var typeNamesFormatted = typesDerivedFrom.Select(t => t.Name.CamelCaseSplit()).ToList();
var parentTypeName = fieldInfo.Name.CamelCaseSplit();
// get the index of the current type
var currentIndex = Mathf.Max(typeNames.IndexOf(property.managedReferenceValue?.GetType().Name), 0);
var dropdown = new DropdownField(parentTypeName, typeNamesFormatted, typeNamesFormatted[currentIndex]);
dropdown.RegisterCallback<ChangeEvent<string>>(evt =>
{
var selectedTypeIndex = typeNamesFormatted.IndexOf(evt.newValue);
if (selectedTypeIndex >= 0 && selectedTypeIndex < typesDerivedFrom.Count)
{
property.managedReferenceValue = Activator.CreateInstance(typesDerivedFrom[selectedTypeIndex]);
property.serializedObject.ApplyModifiedProperties();
}
else
{
Debug.LogError($"Selected type index {selectedTypeIndex} is out of range.");
}
});
return dropdown;
}
public static Vector2 GetAbsolutePosition(List<VisualElement> elements, VisualElement parent)
{
var position = Vector2.zero;
foreach (var element in elements)
{
position += element.LocalToWorld(element.layout.position);
}
return parent.WorldToLocal(position / elements.Count);
}
public static Texture2D GetCanvasPreviewVisualElement<T>(T prefab, Action<T> action) where T : FillAndPreview
{
var previewRender = new PreviewRenderUtility();
previewRender.camera.backgroundColor = Color.black;
previewRender.camera.clearFlags = CameraClearFlags.SolidColor;
previewRender.camera.cameraType = CameraType.Game;
previewRender.camera.farClipPlane = 1000f;
previewRender.camera.nearClipPlane = 0.1f;
var obj = previewRender.InstantiatePrefabInScene(prefab.gameObject);
action.Invoke(obj.GetComponent<T>());
var rect = obj.GetComponent<RectTransform>().rect;
previewRender.BeginStaticPreview(new Rect(0.0f, 0.0f, rect.width, rect.height));
SetupPreviewCanvas(obj, previewRender.camera);
previewRender.Render();
var texture = previewRender.EndStaticPreview();
previewRender.camera.targetTexture = null;
previewRender.Cleanup();
return texture;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 21dbac26e1b24752a2671933b2f10f85
timeCreated: 1727422844

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af35eb4a48054f31955ec1854a3992f8
timeCreated: 1725694446

View File

@ -0,0 +1,86 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Reflection;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.GUI.Buttons;
namespace WordsToolkit.Scripts.Editor.GUI
{
[CustomEditor(typeof(CustomButton), true)]
internal class CustomButtonDrawer : UnityEditor.Editor
{
private CustomButtonEditor customButtonEditor;
private void OnEnable()
{
customButtonEditor = new CustomButtonEditor();
}
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
root.Add(new PropertyField(serializedObject.FindProperty("noSound")));
root.Add(new PropertyField(serializedObject.FindProperty("overrideClickSound")));
root.Add(new PropertyField(serializedObject.FindProperty("overrideAnimatorController")));
var foldout = new Foldout { text = "Custom Button Settings", value = false };
foldout.Add(customButtonEditor.CreateInspectorGUI(serializedObject));
root.Add(foldout);
// Draw default inspector for inherited fields
var iterator = serializedObject.GetIterator();
iterator.NextVisible(true); // Skip Script field
var customButtonType = typeof(CustomButton);
while (iterator.NextVisible(false))
{
var field = iterator.serializedObject.targetObject.GetType().GetField(iterator.name);
if (field != null)
{
// Show fields from parent classes AND child classes, but not from CustomButton itself
if (field.DeclaringType != customButtonType)
{
root.Add(new PropertyField(serializedObject.FindProperty(iterator.name)));
}
}
}
// Draw fields from derived class if any
var targetType = serializedObject.targetObject.GetType();
if (targetType != customButtonType)
{
var derivedFields = targetType.GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
foreach (var field in derivedFields)
{
if (field.IsPrivate && !field.IsDefined(typeof(SerializeField), false))
continue;
var property = serializedObject.FindProperty(field.Name);
if (property != null)
{
root.Add(new PropertyField(property));
}
}
}
return root;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5ef7a07874d4973a9672a27bb8b024e
timeCreated: 1748678361

View File

@ -0,0 +1,156 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UI;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.GUI;
using WordsToolkit.Scripts.Popups.Reward;
namespace WordsToolkit.Scripts.Editor.GUI
{
public class CustomButtonEditor
{
public VisualElement CreateInspectorGUI(SerializedObject serializedObject)
{
var root = new VisualElement();
root.Add(new VisualElement { name = "space", style = { height = 10 } });
// Add the Interactable field
root.Add(GetBindPropertyField(serializedObject, "m_Interactable", "Interactable"));
// Add the Transition field
var transition = GetPropertyField(serializedObject, "m_Transition", "Transition");
transition.Bind(serializedObject);
root.Add(transition);
var onClickProperty = GetBindPropertyField(serializedObject, "m_OnClick", "On Click");
var spriteProperty = GetPropertyField(serializedObject, "m_SpriteState", "Sprites");
var colorProperty = GetPropertyField(serializedObject, "m_Colors", "Colors");
var animations = GetPropertyField(serializedObject, "m_AnimationTriggers", "Animations");
transition.RegisterValueChangeCallback(evt =>
{
Transition(serializedObject, root, spriteProperty, animations, colorProperty);
root.Remove(onClickProperty);
root.Add(onClickProperty);
});
Transition(serializedObject, root, spriteProperty, animations, colorProperty);
root.Add(onClickProperty);
colorProperty.Bind(serializedObject);
spriteProperty.Bind(serializedObject);
animations.Bind(serializedObject);
return root;
}
private static void Transition(SerializedObject serializedObject, VisualElement root, PropertyField spriteProperty, PropertyField animations, PropertyField colorProperty)
{
var transitionProperty = serializedObject.FindProperty("m_Transition");
// Add transition details based on the selected type
if (transitionProperty.enumValueIndex == (int)Selectable.Transition.ColorTint)
{
if (root.Contains(spriteProperty))
{
root.Remove(spriteProperty);
}
if (root.Contains(animations))
{
root.Remove(animations);
}
root.Add(colorProperty);
}
else if (transitionProperty.enumValueIndex == (int)Selectable.Transition.SpriteSwap)
{
if (root.Contains(colorProperty))
{
root.Remove(colorProperty);
}
if (root.Contains(animations))
{
root.Remove(animations);
}
root.Add(spriteProperty);
}
else if (transitionProperty.enumValueIndex == (int)Selectable.Transition.Animation)
{
if (root.Contains(colorProperty))
{
root.Remove(colorProperty);
}
if (root.Contains(spriteProperty))
{
root.Remove(spriteProperty);
}
root.Add(animations);
}
else if (transitionProperty.enumValueIndex == (int)Selectable.Transition.None)
{
if (root.Contains(colorProperty))
{
root.Remove(colorProperty);
}
if (root.Contains(spriteProperty))
{
root.Remove(spriteProperty);
}
if (root.Contains(animations))
{
root.Remove(animations);
}
}
}
private VisualElement GetBindPropertyField(SerializedObject serializedObject, string propertyName, string label)
{
var propertyField = GetPropertyField(serializedObject, propertyName, label);
propertyField.Bind(serializedObject);
return propertyField;
}
private PropertyField GetPropertyField(SerializedObject serializedObject, string propertyName, string label)
{
return new PropertyField(serializedObject.FindProperty(propertyName), label);
}
}
[CustomEditor(typeof(RewardedButton))]
internal class RewardedButtonEditor : UnityEditor.Editor
{
private CustomButtonEditor customButtonEditor;
private void OnEnable()
{
customButtonEditor = new CustomButtonEditor();
}
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
// Add a property field for placement
var placementField = new PropertyField(serializedObject.FindProperty("placement"), "Placement");
root.Add(placementField);
root.Add(customButtonEditor.CreateInspectorGUI(serializedObject));
return root;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e393e17f265f4314be795dcbc434ac2a
timeCreated: 1709550126

View File

@ -0,0 +1,132 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
using WordsToolkit.Scripts.Utils;
namespace WordsToolkit.Scripts.Editor
{
public class PostImporting : AssetPostprocessor
{
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
CheckDefines("Assets/GoogleMobileAds", "ADMOB");
CheckDefines("Assets/FacebookSDK", "FACEBOOK");
CheckDefines("Assets/PlayFabSDK", "PLAYFAB");
CheckDefines("Assets/GameSparks", "GAMESPARKS");
CheckDefines("Assets/Appodeal", "APPODEAL");
}
private static void CheckDefines(string path, string symbols)
{
if (Directory.Exists(path))
{
DefineSymbolsUtils.AddSymbol(symbols);
}
else
{
DefineSymbolsUtils.DeleteSymbol(symbols);
}
}
public static void CheckIronsourceFolder()
{
var str = "Assets/LevelPlay";
if (Directory.Exists(str))
{
var asmdefPath = Path.Combine(str, "IronsourceAssembly.asmdef");
if (!File.Exists(asmdefPath))
{
CreateAsmdefIronSource(asmdefPath);
}
// get GUID of the IronsourceAssembly.asmdef
var guid = AssetDatabase.AssetPathToGUID(asmdefPath);
// assign asmdef to the Scripts/Ads/CandySmith.Ads.asmdef
var adsAsmdefPath = Path.Combine("Assets/WordConnectGameToolkit/Scripts/Ads", "CandySmith.Ads.asmdef");
if (File.Exists(adsAsmdefPath))
{
var asmdef = JsonUtility.FromJson<AssemblyDefinition>(File.ReadAllText(adsAsmdefPath));
// check references and add IronsourceAssembly if not exists
if (asmdef.references == null)
{
asmdef.references = new[] { "IronsourceAssembly" };
}
else
{
if (Array.IndexOf(asmdef.references, "IronsourceAssembly") == -1 && Array.IndexOf(asmdef.references, "GUID:" + guid) == -1)
{
Array.Resize(ref asmdef.references, asmdef.references.Length + 1);
asmdef.references[asmdef.references.Length - 1] = "IronsourceAssembly";
}
}
File.WriteAllText(adsAsmdefPath, JsonUtility.ToJson(asmdef, true));
AssetDatabase.Refresh();
}
}
}
private static void CreateAsmdefIronSource(string path)
{
var assemblyDefinition = new AssemblyDefinition
{
name = "IronsourceAssembly",
references = new string[0],
includePlatforms = new string[0],
excludePlatforms = new string[0],
allowUnsafeCode = false,
overrideReferences = false,
precompiledReferences = new string[0],
autoReferenced = true,
defineConstraints = new string[0],
versionDefines = new VersionDefine[]
{
new()
{
name = "com.unity.services.levelplay",
define = "IRONSOURCE"
}
}
};
File.WriteAllText(path, JsonUtility.ToJson(assemblyDefinition, true));
AssetDatabase.Refresh();
}
}
[Serializable]
public class AssemblyDefinition
{
public string name;
public string[] references;
public string[] includePlatforms;
public string[] excludePlatforms;
public bool allowUnsafeCode;
public bool overrideReferences;
public string[] precompiledReferences;
public bool autoReferenced;
public string[] defineConstraints;
public VersionDefine[] versionDefines;
}
[Serializable]
public class VersionDefine
{
public string name;
public string expression;
public string define;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c79109d6925a4967a20c2e24d466dcc7
timeCreated: 1725699029

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a0c8d60edd0e408f850eb5f0e1701d16
timeCreated: 1725698231

View File

@ -0,0 +1,33 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
namespace WordsToolkit.Scripts.Enums
{
public enum EGameEvent
{
LevelLoaded,
Win,
Play,
Uncover,
WaitForTutorial,
WordOpened,
RestartLevel,
ExtraWordFound,
SpecialItemCollected,
LanguageChanged,
TileSelected,
PurchaseSucceeded,
ButtonClicked,
WordAnimated,
ExtraWordClaimed
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42261fb2e5a54e46825eb80cf7661ad9
timeCreated: 1725698136

View File

@ -0,0 +1,20 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
namespace WordsToolkit.Scripts.Enums
{
public enum EGameMode
{
Classic,
Adventure
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7782e85ac5a84ba1b2f68cb896802e91
timeCreated: 1728897127

View File

@ -0,0 +1,28 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
namespace WordsToolkit.Scripts.Enums
{
public enum EGameState
{
PrepareGame=0,
Tutorial,
Pause,
Playing,
PreFailed,
Win,
PreWin,
Loaded,
Failed,
WinWaiting
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d4eb535e8299408eb17560a0aead30fe
timeCreated: 1712744615

View File

@ -0,0 +1,21 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
namespace WordsToolkit.Scripts.Enums
{
public enum ELevelType
{
Score,
CollectItems,
Classic
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 74df175815a44c3eb71157db31ea7bb6
timeCreated: 1728545961

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bf0f6fe0f1aa4e32a93acc3a6d4775ca
timeCreated: 1725686139

View File

@ -0,0 +1,118 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using DG.Tweening;
using UnityEngine;
namespace WordsToolkit.Scripts.GUI
{
[RequireComponent(typeof(RectTransform))]
public class AnimateTransform : MonoBehaviour
{
public Move position;
public Rotate rotation;
public Scale scale;
public Size sizeDelta;
private RectTransform rectTransform;
private void OnEnable()
{
rectTransform = GetComponent<RectTransform>();
if (position.targetValue != Vector3.zero)
{
rectTransform.anchoredPosition = position.startValue;
position.Animate(rectTransform);
}
if (rotation.targetValue != Vector3.zero)
{
rectTransform.eulerAngles = rotation.startValue;
rotation.Animate(rectTransform);
}
if (scale.targetValue != Vector3.zero)
{
rectTransform.localScale = scale.startValue;
scale.Animate(rectTransform);
}
if (sizeDelta.targetValue != Vector3.zero)
{
rectTransform.sizeDelta = sizeDelta.startValue;
sizeDelta.Animate(rectTransform);
}
}
private void OnDisable()
{
rectTransform.DOKill();
}
}
[Serializable]
public abstract class TweenAnimationParameters
{
public Vector3 startValue;
public Vector3 targetValue;
public float duration = 1f;
public float delay;
public Ease easeType = Ease.Linear;
public bool loop;
public LoopType loopType;
public void Animate(RectTransform rectTransform)
{
GetTween(rectTransform).SetEase(easeType).SetDelay(delay).SetLoops(loop ? -1 : 1, loopType);
}
protected abstract Tweener GetTween(RectTransform rectTransform);
}
[Serializable]
public class Move : TweenAnimationParameters
{
protected override Tweener GetTween(RectTransform rectTransform)
{
return rectTransform.DOLocalMove(targetValue, duration);
}
}
[Serializable]
public class Rotate : TweenAnimationParameters
{
protected override Tweener GetTween(RectTransform rectTransform)
{
return rectTransform.DOLocalRotate(targetValue, duration);
}
}
[Serializable]
public class Scale : TweenAnimationParameters
{
protected override Tweener GetTween(RectTransform rectTransform)
{
return rectTransform.DOScale(targetValue, duration);
}
}
[Serializable]
public class Size : TweenAnimationParameters
{
protected override Tweener GetTween(RectTransform rectTransform)
{
return rectTransform.DOSizeDelta(targetValue, duration);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cadee4a7f70a470daf9c57afd1455652
timeCreated: 1692895718

View File

@ -0,0 +1,84 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using UnityEngine.UI;
using VContainer;
using WordsToolkit.Scripts.Gameplay.Managers;
using WordsToolkit.Scripts.Infrastructure.Service;
using WordsToolkit.Scripts.Levels;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.GUI
{
public class BackgroundChanger : MonoBehaviour
{
[SerializeField]
private Image image;
private ILevelLoaderService levelLoaderService;
private StateManager stateManager;
[SerializeField]
private Sprite mainBackground;
[Inject]
public void Construct(ILevelLoaderService levelLoaderService, StateManager stateManager)
{
this.levelLoaderService = levelLoaderService;
this.levelLoaderService.OnLevelLoaded += OnLevelLoaded;
SceneLoader.OnGameStart += SetBack;
this.stateManager = stateManager;
}
private void OnEnable()
{
stateManager.OnStateChanged.AddListener(OnStateChanged);
}
private void OnStateChanged(EScreenStates arg0)
{
if (arg0 == EScreenStates.Game)
{
SetBack();
}else if (arg0 == EScreenStates.MainMenu)
{
image.sprite = mainBackground;
}
}
private void SetBack()
{
image.sprite = GameDataManager.GetLevel().background;
}
private void OnDestroy()
{
if (levelLoaderService != null)
{
levelLoaderService.OnLevelLoaded -= OnLevelLoaded;
SceneLoader.OnGameStart -= SetBack;
stateManager.OnStateChanged.RemoveListener(OnStateChanged);
}
}
private void OnLevelLoaded(Level level)
{
image.sprite = level.background;
}
public void SetBackground(Sprite bg)
{
image.sprite = bg;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 59912d2c0926422a8517e192d9ecc7f6
timeCreated: 1730130790

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 716a5963d39e49cfad01e43eff89511f
timeCreated: 1748674096

View File

@ -0,0 +1,69 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using DG.Tweening;
using UnityEngine;
using VContainer;
using WordsToolkit.Scripts.Data;
using WordsToolkit.Scripts.Gameplay.Managers;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.GUI.Buttons
{
public class BaseGUIButton : CustomButton, IFadeable
{
protected LevelManager levelManager;
protected GameSettings gameSettings;
protected ResourceManager resourceManager;
protected ButtonViewController buttonViewController;
public RectTransform rectTransform;
public Vector2 savePosition;
public Vector2 targetPosition;
[Inject]
public void Construct(LevelManager levelManager, GameSettings gameSettings, ResourceManager resourceManager, ButtonViewController buttonViewController)
{
this.gameSettings = gameSettings;
this.levelManager = levelManager;
this.resourceManager = resourceManager;
this.buttonViewController = buttonViewController;
this.buttonViewController.RegisterButton(this);
}
public void Hide()
{
animator.enabled = false;
rectTransform.DOAnchorPos( targetPosition, 0.5f);
}
public void InstantHide()
{
rectTransform.anchoredPosition = targetPosition;
}
public void HideForWin()
{
Hide();
}
public void Show()
{
animator.enabled = true;
rectTransform.DOAnchorPos(savePosition, 0.5f).OnComplete(ShowCallback);
}
protected virtual void ShowCallback()
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eae64b3976cb4849bb325653a674bfd0
timeCreated: 1748758607

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b4baa2b47c0445f7837eea134618de67
timeCreated: 1748527950

View File

@ -0,0 +1,139 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Linq;
using DG.Tweening;
using TMPro;
using UnityEngine;
using WordsToolkit.Scripts.Data;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
{
public abstract class BaseBoostButton : BaseGUIButton
{
public ResourceObject resourceToPay;
public ResourceObject resourseToHoldBoost;
public TextMeshProUGUI price;
public TextMeshProUGUI countText;
public GameObject priceObject;
public GameObject countTextObject;
protected int count;
[SerializeField]
private ParticleSystem waves;
private CanvasGroup canvasGroup;
private bool isActive;
protected override void OnEnable()
{
base.OnEnable();
if (!Application.isPlaying)
{
return;
}
InitializePrice();
UpdatePriceDisplay();
onClick.AddListener(OnClick);
var main = waves.main;
main.prewarm = true; // Start particles in grown state
main.loop = true;
waves.Stop(); // Ensure it's not auto-playing
}
protected override void OnDisable()
{
base.OnDisable();
onClick.RemoveListener(OnClick);
}
protected abstract void InitializePrice();
public virtual void UpdatePriceDisplay()
{
// If we have resources in the hold boost, show that count
if (resourseToHoldBoost != null && resourseToHoldBoost.GetValue() > 0)
{
countTextObject.gameObject.SetActive(true);
priceObject.gameObject.SetActive(false);
countText.text = resourseToHoldBoost.GetValue().ToString();
}
else
{
countTextObject.gameObject.SetActive(false);
priceObject.gameObject.SetActive(true);
price.text = count.ToString();
}
}
protected void OnClick()
{
if (isActive)
{
Refund();
DeactivateBoost();
return;
}
if (resourceManager.Consume(resourseToHoldBoost, 1))
{
ActivateBoost();
}
// If not, consume from the regular resource
else if (resourceManager.ConsumeWithEffects(resourceToPay, count))
{
resourseToHoldBoost.Add(gameSettings.countOfBoostsToBuy);
UpdatePriceDisplay();
}
}
private void Refund()
{
resourseToHoldBoost.Add(1);
UpdatePriceDisplay();
}
protected virtual void ActivateBoost(bool hideButtons = true)
{
UpdatePriceDisplay();
if(hideButtons)
buttonViewController.HideOtherButtons(this);
PulseAnimation();
waves.Play();
isActive = true;
priceObject.SetActive(false);
countTextObject.SetActive(false);
}
protected virtual void DeactivateBoost()
{
isActive = false;
buttonViewController.ShowButtons();
waves.Clear();
waves.Stop();
DOTween.Complete(transform);
DOTween.Kill(transform);
transform.localScale = Vector3.one;
UpdatePriceDisplay();
}
private void PulseAnimation()
{
animator.enabled = false;
transform.DOScale(Vector3.one * 0.9f, 0.5f)
.SetLoops(-1, LoopType.Yoyo)
.SetEase(Ease.InOutSine);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 48df3644dc80e4cb9bcf75be337f8fc4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,49 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.Gameplay;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
{
public class HammerBoostButton : BaseBoostButton
{
protected override void InitializePrice()
{
count = gameSettings.hammerBoostPrice;
UpdatePriceDisplay();
}
protected override void ActivateBoost(bool hideButtons = true)
{
base.ActivateBoost(hideButtons);
if (levelManager != null && !levelManager.hammerMode)
{
levelManager.hammerMode = true;
EventManager.GetEvent<Tile>(EGameEvent.TileSelected).Subscribe(OnTileSelected);
}
}
private void OnTileSelected(Tile obj)
{
DeactivateBoost();
}
protected override void DeactivateBoost()
{
levelManager.hammerMode = false;
EventManager.GetEvent<Tile>(EGameEvent.TileSelected).Unsubscribe(OnTileSelected);
base.DeactivateBoost();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cafdd253e27364743a17c8c205d36c4a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using WordsToolkit.Scripts.Gameplay.Managers;
namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
{
public class TipBoostButton : BaseBoostButton
{
protected override void InitializePrice()
{
count = gameSettings.hintBoostPrice;
UpdatePriceDisplay();
}
protected override void ActivateBoost(bool hideButtons = true)
{
base.ActivateBoost(false);
FindObjectOfType<FieldManager>().OpenRandomTile();
DeactivateBoost();
}
protected override void DeactivateBoost()
{
base.DeactivateBoost();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8c9628c9e141543b6a064c5d3cb68180
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,88 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Collections.Generic;
namespace WordsToolkit.Scripts.GUI.Buttons
{
public interface IShowable
{
void Show();
}
public interface IHideable
{
void Hide();
void InstantHide();
}
public interface IHideableForWin
{
void HideForWin();
}
public interface IFadeable : IShowable, IHideable{}
public class ButtonViewController
{
private HashSet<IShowable> buttons;
public void RegisterButton(IShowable button)
{
if (buttons == null)
{
buttons = new HashSet<IShowable>();
}
buttons.Add(button);
if (button is IHideable hideable)
{
hideable.Hide();
}
}
public void HideOtherButtons(IShowable except)
{
foreach (var button in buttons)
{
if (!ReferenceEquals(button, except) && button is IHideable hideable)
{
hideable.Hide();
}
}
}
public void ShowButtons()
{
foreach (var button in buttons)
{
button.Show();
}
}
public void HideAllForWin()
{
if (buttons == null) return;
foreach (var button in buttons)
{
if (button is IHideableForWin buttonForWin)
{
buttonForWin.HideForWin();
}
else if(button is IHideable hideable)
{
hideable.Hide();
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 717db02c9e994b8ea966b55ece00dc54
timeCreated: 1748601128

View File

@ -0,0 +1,116 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using VContainer;
using WordsToolkit.Scripts.Audio;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.System;
using WordsToolkit.Scripts.System.Haptic;
namespace WordsToolkit.Scripts.GUI.Buttons
{
[RequireComponent(typeof(Animator))]
public class CustomButton : Button
{
public AudioClip overrideClickSound;
public RuntimeAnimatorController overrideAnimatorController;
private bool isClicked;
private readonly float cooldownTime = .5f; // Cooldown time in seconds
public new ButtonClickedEvent onClick;
private new Animator animator;
public bool noSound;
private static bool blockInput;
public static CustomButton latestClickedButton;
private IAudioService audioService;
[Inject]
public void Construct(IAudioService audioService)
{
this.audioService = audioService;
}
protected override void OnEnable()
{
isClicked = false;
// run only in runtime
if (Application.isEditor)
{
return;
}
base.OnEnable();
animator = GetComponent<Animator>();
if (overrideAnimatorController != null)
{
animator.runtimeAnimatorController = overrideAnimatorController;
}
}
public override void OnPointerClick(PointerEventData eventData)
{
if (blockInput || isClicked || !interactable)
{
return;
}
if (transition != Transition.Animation)
{
Pressed();
}
isClicked = true;
if(!noSound)
audioService.PlayClick(overrideClickSound);
HapticFeedback.TriggerHapticFeedback(HapticFeedback.HapticForce.Light);
// Start cooldown
if (gameObject.activeInHierarchy)
{
StartCoroutine(Cooldown());
}
base.OnPointerClick(eventData);
}
public void Pressed()
{
if (blockInput || !interactable)
{
return;
}
latestClickedButton = this;
onClick?.Invoke();
EventManager.GetEvent<CustomButton>(EGameEvent.ButtonClicked).Invoke(this);
}
private IEnumerator Cooldown()
{
yield return new WaitForSeconds(cooldownTime);
isClicked = false;
}
private bool IsAnimationPlaying()
{
var stateInfo = animator.GetCurrentAnimatorStateInfo(0);
return stateInfo.loop || stateInfo.normalizedTime < 1;
}
public static void BlockInput(bool block)
{
blockInput = block;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c9659348afa04bc6bb30eb6900f94b65
timeCreated: 1725694504

View File

@ -0,0 +1,47 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using System.Collections;
namespace WordsToolkit.Scripts.GUI.Buttons
{
public class ExtraWordsButton : BaseGUIButton
{
private Coroutine occasionalPulseCoroutine;
private bool pulseEnabled;
private bool animated;
public void PulseAnimation(bool b)
{
pulseEnabled = b;
if (b)
{
animator.Play($"PulseLoop");
}
else
{
animator.SetTrigger($"Pulse");
}
}
protected override void ShowCallback()
{
base.ShowCallback();
if (pulseEnabled)
{
PulseAnimation(true);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2c3f8f7c7b8644ec9c726828e284a7dd
timeCreated: 1748687127

View File

@ -0,0 +1,208 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using DG.Tweening;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using VContainer;
using WordsToolkit.Scripts.Data;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.Settings;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.GUI.Buttons
{
public class GiftButton : BaseGUIButton
{
private const string SAVE_KEY = "GiftButton_CollectedItems";
[Header("Counter Settings")]
[SerializeField] private TextMeshProUGUI counterText;
[SerializeField] private GameObject counterContainer;
[SerializeField] private int collectedItems = 0;
[Header("Visual Feedback")]
[SerializeField] private float pulseScale = 1.2f;
[SerializeField] private float pulseDuration = 0.3f;
[Header("Resources")]
[SerializeField] private ResourceObject resource;
[Tooltip("Optional override for gems awarded per gift (if not set, uses value from GameSettings)")]
[SerializeField] private int gemsPerGift = 0;
[SerializeField] private TextMeshProUGUI gemsValueText;
[SerializeField] private GameObject gemsLabelObject;
[Header("Visual Appearance")]
[SerializeField] private Image mainBoxSprite;
[SerializeField] private Sprite lightModeSprite;
[SerializeField] private Sprite darkModeSprite;
[Inject]
private MenuManager menuManager;
[SerializeField]
private Popup giftPopup;
[Inject]
private GameManager gameManager;
private bool isActive;
protected override void OnEnable()
{
base.OnEnable();
EventManager.GetEvent(EGameEvent.SpecialItemCollected).Subscribe(OnSpecialItemCollected);
onClick.AddListener(ConsumeResource);
}
protected override void OnDisable()
{
base.OnDisable();
EventManager.GetEvent(EGameEvent.SpecialItemCollected).Unsubscribe(OnSpecialItemCollected);
onClick.RemoveListener(ConsumeResource);
}
protected override void Start()
{
base.Start();
if(!Application.isPlaying)
{
return;
}
// Load saved collected items
collectedItems = PlayerPrefs.GetInt(SAVE_KEY, 0);
UpdateCounterDisplay();
UpdateGemsValueDisplay();
UpdateState();
}
/// <summary>
/// Updates the displayed gems value
/// </summary>
private void UpdateGemsValueDisplay()
{
if (gemsValueText != null)
{
int gemsAmount = gemsPerGift > 0 ?
gemsPerGift :
gameSettings.gemsForGift;
gemsValueText.text = gemsAmount.ToString();
}
// Update visibility of gems label
if (gemsLabelObject != null)
{
gemsLabelObject.SetActive(collectedItems > 0);
}
else if (gemsValueText != null)
{
// If no specific label object is assigned, control the text object directly
gemsValueText.gameObject.SetActive(collectedItems > 0);
}
}
/// <summary>
/// Updates the visual state of the button based on collection status
/// </summary>
private void UpdateState()
{
isActive = collectedItems > 0;
interactable = isActive;
}
/// <summary>
/// Increments the counter when a special item is collected
/// </summary>
public void CollectItem()
{
collectedItems++;
// Save the updated count
PlayerPrefs.SetInt(SAVE_KEY, collectedItems);
PlayerPrefs.Save();
UpdateCounterDisplay();
UpdateGemsValueDisplay();
UpdateState();
PlayCollectionFeedback();
}
/// <summary>
/// Updates the counter UI text
/// </summary>
private void UpdateCounterDisplay()
{
if (counterText != null)
{
counterText.text = collectedItems.ToString();
}
// Show counter only if we've collected items
if (counterContainer != null)
{
counterContainer.SetActive(collectedItems > 0);
}
}
private void ConsumeResource()
{
// Get the gems amount from GameSettings or use the override if set
int gemsAmount = gemsPerGift > 0 ?
gemsPerGift :
gameSettings.gemsForGift;
// Attempt to consume the resource and add gems
if (resource != null && resourceManager.ConsumeWithEffects(resource,gemsAmount))
{
// Decrease the counter
collectedItems--;
// Save the updated count
PlayerPrefs.SetInt(SAVE_KEY, collectedItems);
PlayerPrefs.Save();
// Update the display
UpdateCounterDisplay();
UpdateGemsValueDisplay();
UpdateState();
menuManager.ShowPopup(giftPopup);
}
}
/// <summary>
/// Play visual feedback when item is collected
/// </summary>
private void PlayCollectionFeedback()
{
// Simple pulse animation
mainBoxSprite.transform.DOScale(pulseScale, pulseDuration / 2)
.SetEase(Ease.OutQuad)
.OnComplete(() => {
mainBoxSprite.transform.DOScale(1f, pulseDuration / 2).SetEase(Ease.InQuad);
});
}
// Event handler for when a special item is collected
private void OnSpecialItemCollected()
{
CollectItem();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4d3677e4b5b644088ad9a552da7f8f1b
timeCreated: 1742478154

Some files were not shown because too many files have changed in this diff Show More