# Question
Title: How to get Keyboard working with GameInput on PC in C++
I need some help here. I try this for a while now but it won't work and I can't find anything online. I want to write my own input handling. At first I used XInput for gamepads and Win32 callbacks for Keyboard input. That worked so far. Then I stumbled across GameInput and it seemed to me like this is a more modern approach so I tried it. For Gamepads (at least the ones I got here to test) it works like a charm. Then I tried to get it to work for keayboard as well, but it just won't recognize any keystrokes.

I put together this minimum example after https://learn.microsoft.com/en-us/gaming/gdk/\_content/gc/input/overviews/input-readings#a-simple-gamepad-input-loop

```
#include <GameInput.h>
#include <iostream>
#include <thread>

IGameInput* g_gameInput = nullptr;
IGameInputDevice* g_device = nullptr;

HRESULT InitializeInput()
{
    return GameInputCreate(&g_gameInput);
}

void ShutdownInput()
{
    if (g_device) g_device->Release();
    if (g_gameInput) g_gameInput->Release();
}

bool PollGamepadInput()
{
    IGameInputReading* reading;
    if (SUCCEEDED(g_gameInput->GetCurrentReading(GameInputKindKeyboard, g_device, &reading)))
    {
        if (!g_device)
        {
            reading->GetDevice(&g_device);

            auto info = g_device->GetDeviceInfo();
            std::cout << "Family: " << info->deviceFamily << std::endl;
            std::cout << "Capabilities: " << info->capabilities << std::endl;
            std::cout << "Vendor: " << info->vendorId << std::endl;
            std::cout << "Product: " << info->productId << std::endl;

            if(info->displayName)
                std::cout << "DisplayName: " << info->displayName->data << std::endl;
        }

        auto count = reading->GetKeyCount();

        if (count > 0)
            std::cout << "Keys: " << count << std::endl;

        reading->Release();
        return true;
    }

    if (g_device)
    {
        g_device->Release();
        g_device = nullptr;
    }

    return true;
}

int main()
{
    if (InitializeInput() != S_OK)
        return -1;

    while (PollGamepadInput())
        std::this_thread::sleep_for(std::chrono::milliseconds(1));

    ShutdownInput();
    return 0;
}

```

but I get no key strokes. When I use `GameInputKindGamepad` as a filter type a can just use `getGamepadState` and it just works. Unfortunately there is no such thing as a `getKeyboardState`.

GameInput seems like a rather new thing, but the documentation states nothing about "Keyboards does not work yet". Does anyone have an idea on what I'm missing here?

# Answer
> 1 votes
Keystrokes are handled differently. It's discussed in the documentation under one of the advanced topics:

> The `GetKeyState` method retrieves scan code and virtual key data for each pressed key on a keyboard. This input data is then returned as a variable-length array of `GameInputKeyState` structs. A pressed key is one that's held down at the time that the keyboard reported an input. Keyboards vary in how frequently they report input, typically ranging from 125 Hz to 1,000 Hz. Keyboard state is reported separately for each individual keyboard that's connected to the system.

A word of caution: the docs go on to say:

> Keyboard state is reported separately for each individual keyboard that's connected to the system. The `CreateAggregateDevice` method on the `IGameInput` interface is used to get the combined system keyboard state.

However up at the top of the same reference, at the time of posting this, there's a note stating that `CreateAggregateDevice` isn't supported at this time.

---
Tags: c++, windows, visual-studio
---


# Question
Title: Character controller that can handle sloped terrain and boxy ledge traversal
I am working on a character controller for a 3D platformer in Unity. I cannot find an approach that satisfies me.

I have experimented with these approaches in order to learn about their virtues and pitfalls:

1. Rigidbody + CapsuleCollider + native physics system (gives you something like Fall Guys)
2. Rigidbody + CapsuleCollider + custom velocity handling, only using physics system to resolve collisions (this method is illustrated in Catlike Coding tutorial here)
3. Built-in CharacterController
4. Custom character controller that uses Unity methods to detect geometric collisions, but does its own collision resolution via depenetration (this method is illustrated in Roystan Ross tutorial here)

See also this video by iHeartGameDev summarizing different approaches.

---

For my particular use case, each one of these has been better than the last.

After following Roystan's tutorial, I am a big fan of the pushback method of handling collision. Rather than use casts to catch collision before you move your object, you move your object, then find collisions, then resolve them using depenetration.

Roystan's method represents the character as a stack of three spheres for the same reason people favor capsule colliders in 3D: it makes handling slopes much easier (and also because depenetration is easier when you think in terms of spheres).

But the thing I am struggling with is that **I don't want the player to be able to slide up or down ledges when traversing them**.

Basically, **when jumping up or walking off a ledge, I want my character to be treated as a box**.

So I am struggling to find a way to accommodate both of the following:

* I want to support sloped MeshCollider ground (not too noisy, but will definitely be possible to have 4 collision points at a time)
* I want ledge traversal (up and down) to treat my player as a box

Here are diagrams illustrating what you normally get with a capsule, versus what I want.

Down ledge:

Up ledge:

My thinking is that I have two options:

1. **Represent the character as a box and use box depenetration techniques to move him along sloped ground** (for example, using Unity's `ComputePenetration()`)
2. **Represent the character as a capsule** (or stack of three spheres like in Roystan's tutorial) **and add special case logic to get the boxy ledge traversal I want**

One problem I can foresee with approach 1 is properly doing the depenentration on noisy sloped ground, and one problem I can foresee with approach 2 is properly writing the special cases. (My game is relatively low-poly and retro-styled, so I wouldn't mind the player not appearing perfectly flush with slopes that comes with the box representation of approach 1.)

In any event, I am just looking for advice on how to proceed with this problem. How can I get the boxy handling of ledges while also getting traversal on sloped MeshCollider terrain.

**Is either of these approaches better than the other for what I am after, and is there an alternative approach I haven't considered?**

# Answer
> 0 votes
I recently came across this video about stair traversal in videogames, and I liked the way the solution looked. I think the main way it differs from your most recent attempt is that it **only snaps straight up or down**, giving that box-like feeling you're after.

On the way up stairs and ramps, you use a collision check to implement the snapping. To go down, you use a raycast. You'll have to skip a raycast each jump (so you can actually jump without getting immediately snapped down), and disable them until landing when you detect a frame in which the character isn't on the ground or being snapped to it (so you don't get snapped down just before landing from a long fall or just after jumping).

I don't forsee the noisy sloped ground case being terribly problematic unless it's so noisy that the player gets vibrated up and down, but perhaps the collision mesh would be the more appropriate thing to adjust there.

You should probably save the bounty for the industry veteran that you specifically requested, but I figured it couldn't hurt to give you another thing to try along with a demo.

---
Tags: unity, c#, collision-detection, collision-resolution, character-controller
---


title: Should I make my "big idea" first?

text:
# Question
Title: Should I make my "big idea" first?
I have one game idea that has stuck with me for a long time that I'm using as my inspiration for getting into game design, and I want to make sure I make it to the best of my ability. Aside from the tutorial projects and "Hello World"s of the engine I plan to use, I want this idea to be my first big project, but I'm worried I won't be able to do it justice without the experience of a few other games under my belt.

For context, I've been programming full-time for a while, so I'm not worried about making spaghetti code like Yandere Dev, my primary concern is falling deep into design shortfalls or making a subpar finished product.

Is it foolhardy to make my "big idea" my first major project, or should I do a few other projects first to work out any growing pains?

# Answer
There's a saying among game developers, "your first ten games will be bad, so get them out of the way as fast as possible".

By this reasoning, you should not make your big idea first. In fact, you should make something very small first.

You will make many, many mistakes on your early projects, but that's not as bad as it sounds. These will be *instructive* mistakes, that give you first-hand experience in what can go wrong, how to spot it early, and how to fix it.

When these mistakes happen in a massive project you've sunk months or years into and you dearly want to succeed, it's heartbreaking, and bringing it back on track can add months more to the project, which can be completely demoralizing.

But when they crop up in small 1-4 week experiments that were just stepping stones to you anyway, it's not so bad. You can scrap the whole thing and start fresh with your new and improved understanding of the problem.

Games and game developers both get better through iteration, so give yourself a good few runs before you tackle something ambitious. Your first game will not be your dream game, but you can work up to it. And by the time you get there, your dream itself will have evolved, you'll have a better idea of what it needs to succeed, so you have a more accurate target to aim for from the start.
> 24 votes

# Answer
Are you doing this as a hobby or a business?

If it is a hobby, go ahead and do whatever you are enthused and motivated to do. If that's your big idea then do that. Realistically, you're unlikely to meet the vision you have in your head, but so long as you enjoy making it then you've reached every requirement of being a hobby.

If it is a business, then you need to consider whether the time invested in your big idea is going to be financially viable. The answer, most likely, is no. It's also no for most projects you can attempt but you can at least start creating a revenue stream and building a reputation before embarking on a grander project.
> 10 votes

# Answer
Does the grand vision require a huge game (eg a MMO) and wouldn't work otherwise?

If yes, you are doomed in any case. It does not matter whether you start with the big game or the many small ones, you will not complete your grand vision. This needs a team, not just few friends that have their own ideas they would like to develop. So, the path you should probably take is the one of most near-term enjoyment. Will you be happier working on a grand game, thinking about it and making bits and pieces even knowing it will never go anywhere? Pick that. Or will you be happier that you completed several little games even if they don't resemble your grand idea? Pick that instead.

But maybe you can scale down your idea to minimum viable product (MVP) that would take you only a month to make in theory (and 6 in practice) even if the full grand game would take years? Then, both approaches will get you to your MVP eventually. Motivation to do/learn something is generally more important than better help available when going the simpler well-beaten path. So you are likely to actually learn more doing game you love (unless you are really motivated). But it also has traps a smaller well-contained existing game does not:

First, if you manage to find reasonable MVP route for your idea, make sure to keep to your MVP plan until it is completed, or those months will quickly become "never". Those other great ideas can wait on various notes until the core of it mostly works. On the other hand, starting with well-known stuff means that you probably don't want to implement some great ideas for say Tetris - no scope creep.

Second, make a plan and time it. If something you estimated for 10 hours took 40, no problem actually, simply multiply all your estimates by 4. Did not account for a module taking 1/3 of your total time so far? Add 50% to the whole project; it won't be the only thing you missed. Testing (= playing with it) took another 1/3 of total time? Another 50%. Worked 10 hours a week on average instead of 20 you planned to? No problem, twice the calendar time to complete. Etc. The point is to know how long it will really take and if you still want that. You might perhaps opt to ditch some bits for now - yeah you will remove the "Viable" from MVP (or you made mistake and didn't have "Minimal"), but at least something will be done. Well-beaten path? You should still make your own estimates from the start, but you will have good idea how much you will overshoot them right when you start.
> 4 votes

---
Tags: game-design
---


# Question
Title: How do I remove the gap in a Godot HBoxContainer between items?
I created a HBoxContainer and put two ViewportContainers into it.

They line up side by side, but there is a gap of a couple of pixels between them.

How do I tell Godot that I don't want any spacing/margin between the items in a HBoxContainer?

# Answer
> 2 votes
Ah I found it you have to go to `Theme Overrides > Constants > Separation` and enable it.

---
Tags: godot-4
---


title: Units in Unity?

text:
# Question
Title: Units in Unity?
I have read that in Unity 1 cube of size 1x1x1 and scale 1x1x1 is representing a cube in real life of 1mx1mx1m.

Now, the only setting I find, where I can input anything related to Units is gravity, which is usually 0, -9.81, 0. The Unit of the gravity is supposed to be unit/s^2, so an acceleration.

Therefore, I am wondering how to adapt/redefine Units in my project?

I want it to run in real-time, so the time would stay the same, but for the size, I want it to be in a mm space.

So, would it be possible to basically redefine the units inside the physics settings by changing the gravity (in this example by a factor of 100)?

I will not use gravity inside the project, but I want to define a force and I am wondering, if it possible to use this approach to define units in a way I want. (I want to apply a force of 1N on my objects for example and I am not sure how to do this while keeping the idea of the project the same without changing the distance?)

Or I could change the force to adapt to the units correctly, but anyways, I am not really sure how to define a force in this environment without setting the units.

What are the good approaches to set forces in Unity so that they accurately represent a physical system?

# Answer
If you make your units \\$mm\\$ instead of \\$m\\$, then you need to inject a factor of \\$\frac {1000 mm} {1 m}\\$ into any quantity that normally has an \\$m\\$ in its SI units.

e.g. I want to apply a force of 5 Newtons:

$$5 N = 5 \frac {kg \cdot m} {s^2} \cdot \frac {1000 mm} {1 m} = 5000 \frac {kg \cdot mm} {s^2}$$

So I'd use a value of 5000 instead (effectively, I'm now applying forces measured in millinewtons)
> 1 votes

---
Tags: unity, physics, physics-engine
---


# Question
Title: Unity & Google Play Game Services - error: Leaderboard not found
My game uses Google Play Game Services for leaderboard management.

In my production build, submitting high scores to and requesting the leaderboard for display from Google Play Games services works flawlessly. However, in my latest development build (open to **internal testers**), I am having trouble submitting highscores to the leaderboard.

## Here's the code that submits a highscore.

```
public void SetHighscore(uint newHighscore)
{
    highScoreInfo = new HighScoreStruct(newHighscore);
    mainPlayer.highScoreTextBox.text = string.Format("High Score: {0}", highScore);
    googlePlayGamesManager?.ReportScore((int)highScore);
    Save(highScoreInfo);
}

```

## googlePlayGamesManager's ReportScore method looks as follows:

```
public void ReportScore(int score)
    {
        if (!Social.localUser.authenticated)
        {
            AuthenticateUserOnUnitySocial();
        }
        if (!bLocalUserUnityAuthenticated)
        {
            Debug.LogWarning("Local User not authenticated. Can't submit highscore.");
        }
        else
        {
            Debug.Log("Local user authenticated. Trinyg to submit highscore.");
        }
        // post score 12345 to leaderboard ID "Cfji293fjsie_QA" and tag "FirstDaily")
        Social.ReportScore(score, GPGSIds.leaderboards_my_leaderboard, (bool success) => {
            // handle success or failure
            if (success)
                Debug.Log("Submitted highscore successfully");
            else
                Debug.LogWarning("Failed to submit highscore");
        });
    }

```

I have verified `that GPGSIds.leaderboards_my_leaderboard` contains the correct leaderboard ID, yet I get errors when trying to submit scores to the leaderboard.

Here are the logs I get every time I try to submit a score to the leaderboard:

```
05-08 22:08:44.719 14588 14646 I Unity   : Local user authenticated. Trinyg to submit highscore.
05-08 22:08:44.719 14588 14646 I Unity   : GooglePlayGamesManager:ReportScore(Int32)
05-08 22:08:44.719 14588 14646 I Unity   : HighScoreManager:SetHighscore(UInt32)
05-08 22:08:44.719 14588 14646 I Unity   : ExtraBallPowerup:OnTriggerEnter2D(Collider2D)
05-08 22:08:44.719 14588 14646 I Unity   :
05-08 22:08:44.720 14588 14646 E Unity   : Leaderboard not found
05-08 22:08:44.720 14588 14646 E Unity   : UnityEngine.SocialPlatforms.Local:ReportScore(Int64, String, Action`1)
05-08 22:08:44.720 14588 14646 E Unity   : HighScoreManager:SetHighscore(UInt32)
05-08 22:08:44.720 14588 14646 E Unity   : ExtraBallPowerup:OnTriggerEnter2D(Collider2D)
05-08 22:08:44.720 14588 14646 E Unity   :
05-08 22:08:44.721 14588 14646 W Unity   : Failed to submit highscore
05-08 22:08:44.721 14588 14646 W Unity   : UnityEngine.SocialPlatforms.Local:ReportScore(Int64, String, Action`1)
05-08 22:08:44.721 14588 14646 W Unity   : HighScoreManager:SetHighscore(UInt32)
05-08 22:08:44.721 14588 14646 W Unity   : ExtraBallPowerup:OnTriggerEnter2D(Collider2D)

```

I am unsure as to why I get the message saying "Leaderboard not found". Moreover, as stated, everything works fine in the production build, and, as far as I can tell, there are no changes to any of the files involved in highscore management.

Would anyone have a clue as to why I am getting this error message?

# Answer
> 0 votes
Usually, even if the error not telling us, this might actually be related to the API Oauth for the Google Play Console. Your authentication may not be set correctly or corrupted. Try to re-authorize the Google Play Console.

# Answer
> 0 votes
Choose Proguard for Minify \> Release and Copy the content into Assets/Plugins/Android/proguard-user.txt

```
-keep class com.google.unity.** {
   *;
}
-keep public class com.google.android.gms.ads.**{
   public *;
}
-keep public class com.google.ads.**{
   public *;
}
-keepattributes *Annotation*
-dontobfuscate
-keep class com.google.android.gms.games.PlayGames { *; }
-keep class com.google.android.gms.games.leaderboard.** { *; }
-keep class com.google.android.gms.games.snapshot.** { *; }
-keep class com.google.android.gms.games.achievement.** { *; }
-keep class com.google.android.gms.games.event.** { *; }
-keep class com.google.android.gms.games.stats.** { *; }
-keep class com.google.android.gms.games.video.** { *; }
-keep class com.google.android.gms.games.* { *; }
-keep class com.google.android.gms.common.api.ResultCallback { *; }
-keep class com.google.android.gms.signin.** { *; }
-keep class com.google.android.gms.dynamic.** { *; }
-keep class com.google.android.gms.dynamite.** { *; }
-keep class com.google.android.gms.tasks.** { *; }
-keep class com.google.android.gms.security.** { *; }
-keep class com.google.android.gms.base.** { *; }
-keep class com.google.android.gms.actions.** { *; }
-keep class com.google.games.bridge.** { *; }
-keep class com.google.android.gms.common.ConnectionResult { *; }
-keep class com.google.android.gms.common.GooglePlayServicesUtil { *; }
-keep class com.google.android.gms.common.api.** { *; }
-keep class com.google.android.gms.common.data.DataBufferUtils { *; }
-keep class com.google.android.gms.games.quest.** { *; }
-keep class com.google.android.gms.nearby.** { *; }

```

It's work for me.

---
Tags: unity, c#, google-play-services, leaderboards
---


# Question
Title: How can I solve this error and this warning when destroying instantiated prefabs?
I'm working on a level in a 2D game that includes two big triggers.

Each time the player enters them, I `Instantiate` an enemy prefab. Then, the player can shoot bullets to destroy that prefab. And finally, the enemy should die by playing an animation, disabling his collider, and destroying itself.

However, the problem is that every time a bullet hits an enemy, I get the warning "Animator is not playing an AnimatorController" and the error "Destroying assets is not permitted to avoid data loss." in the console. And these two prevent the enemy clones from getting destroyed. The warning is caused by the line `enemySpawnPoint1.destroyPurpleGoon.GetComponent<Animator>().SetTrigger("dead");` and the error is caused by the line `Destroy(enemySpawnPoint1.destroyPurpleGoon, 4f);`.

This is the script for the first trigger:

```
using UnityEngine;

public class EnemySpawnPoint1 : MonoBehaviour
{
    [HideInInspector] public int enemyCount = 0;

    // I assigned the enemy prefab to the Inspector.
    public GameObject purpleGoon;
    public GameObject destroyPurpleGoon;

    private void Awake()
    {
       // I wrote this because for some reason, instantiated enemies fall when the game begins.
       purpleGoon.GetComponent<CapsuleCollider2D>().enabled = true;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject == Player.Instance.gameObject && enemyCount < 20)
        {
            InstantiateEnemy1();
        }
    }

    void InstantiateEnemy1()
    {
        destroyPurpleGoon = Instantiate(purpleGoon, new Vector3(65.46f, -1.11f, 0), Quaternion.identity);
        enemyCount++;
    }
}

```

And this is the script for the second trigger:

```
using UnityEngine;

public class EnemySpawnPoint2 : MonoBehaviour {

    public EnemySpawnPoint1 enemySpawnPoint1;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject == Player.Instance.gameObject && enemySpawnPoint1.enemyCount < 20)
        {
            InstantiateEnemy2();
        }
    }

    void InstantiateEnemy2()
    {
        enemySpawnPoint1.destroyPurpleGoon = Instantiate(enemySpawnPoint1.purpleGoon, new Vector3(-1.309999f,
-1.11f, 0), Quaternion.identity);
        enemySpawnPoint1.enemyCount++;
    }
}

```

I write and call `DestroyInstantiatedEnemy()` function in `ShotgunBullet` script:

```
public EnemySpawnPoint1 enemySpawnPoint1;

public void DestroyInstantiatedEnemy()
{
    enemySpawnPoint1.destroyPurpleGoon.GetComponent<Animator>().SetTrigger("dead");
    enemySpawnPoint1.destroyPurpleGoon.GetComponent<CapsuleCollider2D>().enabled = false;

    Destroy(enemySpawnPoint1.destroyPurpleGoon, 4f);
}

void OnTriggerEnter2D(Collider2D collision)
{
    if (collision.gameObject.tag == "Enemy")
    {
        DestroyInstantiatedEnemy();
        Destroy(gameObject);
    }
}

```

The warning is strange to me because the animator components on the original prefab and all the prefab clones have the `AnimatorController` assigned to them in their Animator components. Even the idle animation plays perfectly fine in the runtime, which shows the Animator component works.

About the error, ideally I should use an empty game object and destroy that instead. But since I destroy the enemy prefabs in another script, I had to make it public. So now, Unity thinks I want to destroy the actual prefab and not the clones. And I can't figure out how to fix it.

I also noticed that sometimes the collider gets disabled on the original prefab (the one in Project window) and dies in Awake. So, I wrote a line of code to keep it enabled from the beginning. This and the fact that I get that error prove that I'm directly making changes to the root prefab instead of the clones. But I don't know why.

It is worth noting that in the other levels, the player uses a knife to kill the enemy prefabs (I directly put those prefabs in the scene without instantiating them) and their death function (which is the same as `DestroyInstantiatedEnemy()` but without the references to `destroyPurpleGoon`) works perfectly fine. This means that this warning only occurs in this specific scene where they are instantiated in runtime and can only die by bullets.

I researched a lot about this problem and found some similar questions with solutions on Unity forums; but none of them have worked for me. Additionally, as mentioned in the comments below, I'm aware that the way I use `destroyPurpleGoon` is problematic but I don't know a better way to use that variable.

I would appreciate it if you tell me the reason behind the warning and the error and how I should fix them.

# Answer
> 0 votes
I solved this problem more than a month ago but forgot to post an answer. So, here's the answer:

Basically, instead of constantly instantiating enemies, I put a number of them above both triggers and deactivated all of them. Then, wrote and added this script to Enemy Trigger 1:

```
using UnityEngine;

public class EnemyTrigger1 : MonoBehaviour
{
    public GameObject purpleGoon, purpleGoon_2, purpleGoon_3, purpleGoon_4, purpleGoon_5;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject == Player.Instance.gameObject && purpleGoon != null)
        {
            purpleGoon.SetActive(true);
        }

        if (collision.gameObject == Player.Instance.gameObject && purpleGoon == null && purpleGoon_2 != null && purpleGoon_3 != null && purpleGoon_4 != null && purpleGoon_5 != null)
        {
            purpleGoon_2.SetActive(true);
            purpleGoon_3.SetActive(true);

            purpleGoon_4.SetActive(true);
            purpleGoon_5.SetActive(true);
        }
    }
}

```

And added this to Enemy Trigger 2:

```
using UnityEngine;

public class EnemyTrigger2 : MonoBehaviour
{
    public GameObject purpleGoon_1, purpleGoon_6, purpleGoon_7, purpleGoon_8, purpleGoon_9, purpleGoon_10, purpleGoon_11;
    public EnemyTrigger1 enemyTrigger1;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject == Player.Instance.gameObject && purpleGoon_1 != null)
        {
            purpleGoon_1.SetActive(true);
        }

        if (collision.gameObject == Player.Instance.gameObject)
        {
            if (purpleGoon_1 == null && purpleGoon_6 != null && purpleGoon_7 != null && purpleGoon_8 != null && purpleGoon_9 != null && purpleGoon_10 != null && purpleGoon_11 != null)
            {
                if (enemyTrigger1.purpleGoon_2 == null && enemyTrigger1.purpleGoon_3 == null && enemyTrigger1.purpleGoon_4 == null && enemyTrigger1.purpleGoon_5 == null)
                {
                    purpleGoon_6.SetActive(true);
                    purpleGoon_7.SetActive(true);
                    purpleGoon_8.SetActive(true);

                    purpleGoon_9.SetActive(true);
                    purpleGoon_10.SetActive(true);
                    purpleGoon_11.SetActive(true);
                }
            }
        }
    }
}

```

After dragging and dropping the game objects into the Inspector, everything worked as expected. I didn't get that warning and that error, the enemies played their death animations, disabled their colliders, and destroyed themselves after some time.

These scripts are probably not the best in terms of performance or efficiency, but they fit my needs.

If you're using the scripts for your own project and know how to make them more efficient, feel free to do so.

I hope this answer helps!

# Answer
> 0 votes
I haven't tried this, but you probably could, instead of letting the bullet decide what happens to the enemy, add a new component, for example `Killable`. This component should then be added to every enemy (i.e. the prefab). Inside this new `Killable` component, you would have a public method `Kill`:

```
public void Kill() {
    GetComponent<Animator>().SetTrigger("dead");
    GetComponent<CapsuleCollider2D>().enabled = false;
    Destroy(gameObject, 4f);
}

```

You can then, from your bullet, see if the colliding object has this component:

```
void OnTriggerEnter2D(Collider2D collision)
{
    Killable killable = collision.gameObject.GetComponent<Killable>();
    if (killable != null) {
        killable.Kill();
        Destroy(gameObject);
    }
}

```

This way you have also decoupled the bullet from the enemy, which means that enemies can now take damage from multiple sources if you want. And if we want to add a tougher enemy, like a boss, we can supply a damage value to the `Kill` method, and decrement a health value instead of just destroying the gameObject immediately.

---
Tags: unity, c#, 2d, animation, prefabs
---


# Question
Title: What is the general technique of optimizing a game's lag by updating thousands of mesh vertices using DOTS parallelism?
\*Edit: I finally figured out after some profiling that the problematic code was not actually the ones part of ECS, but this line over here:

```
objectManagerController.GenerateMetaballEdgePointVerteciesList(metaballEdgePointVertexCoordinates); //writes magnets, this is the culprit for the lagg!!!

```

in OnRenderImage() of MainCameraController:

```
    public void OnRenderImage(RenderTexture src, RenderTexture dest) {
        //Debug.Log("Metaball Shader, OnRenderImage for main camera");
        //called after operationCamera's OnRenderImage is called game object count times?
            //How the fuck was I able to make sure that src contains the full texture upon function call?
            //Since all rendered colored slimes are moved back to default layer after each of them are separately
            //rendered. Thus by the time MainCameraController.OnRenderImage is called all slimes are back in default layer

        //Not the case where main camera is not seeing anything

        //Resolution
        Vector2Int resolution = new Vector2Int( preprocessCameraRender.width, preprocessCameraRender.height );

        //Thread control (hoping this is accurate enough)
        threadGroupX = Mathf.CeilToInt(preprocessCameraRender.width / (float)threadsPerGroup);
        threadGroupY = Mathf.CeilToInt(preprocessCameraRender.height / (float)threadsPerGroup);

        //Make a writable copy of src and dest
        //RenderTexture srcWritable = new RenderTexture(src.width, src.height, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default){ useMipMap = false };
        RenderTexture srcWritable = new RenderTexture(preprocessCameraRender.width, preprocessCameraRender.height, 32, colorFormat, 1)
        {
            useMipMap = false,
            autoGenerateMips = false,
            enableRandomWrite = true // Set the UAV usage flag
        };
        srcWritable.Create();

        //At this point both srcWritable and destWritable empty
        RenderTexture destWritable = new RenderTexture(srcWritable);
        destWritable.Create();

        RenderTexture metaballEdgeTexture = new RenderTexture(srcWritable);
        metaballEdgeTexture.Create();

        //Copying src to srcWritable
        RenderTexture.active = src;
        Graphics.Blit(src, srcWritable);

        //metaball edge texture
        // RenderTexture metaballEdgeTexture = CreateTexture("MetaballEdgeTexture", resolution, colorFormat);

        //Fill compute shader variables
        metaballComputeShader.SetTexture(kernelHandleFirst, "Src", srcWritable);
        metaballComputeShader.SetTexture(kernelHandleFirst, "Dest", destWritable);
        //Inner Edge Texture(empty at this point)
        metaballComputeShader.SetTexture(kernelHandleFirst, "MetaballEdgeTex", metaballEdgeTexture);
        metaballComputeShader.SetFloat("MaxWidth", preprocessCameraRender.width);
        metaballComputeShader.SetFloat("MaxHeight", preprocessCameraRender.height);
        metaballComputeShader.SetFloat("GameObjectListCount", colorSlimes.Count);
        metaballComputeShader.SetVector( "_Resolution", (Vector2) resolution );

    //Texture Arrays
        //First dispatch prep
        //Read (Raw) Color Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "ColorTextureArray", colorTextureArray);
        //Read (Larger) Color Texture's Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "ColorTextureArrayBeta", colorTextureArrayBeta);
        //SDF Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "SDFTextureArray", sdfTextureArray);
        //Delta X Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "DeltaXTextureArray", deltaXTextureArray);
        //Delta Y Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "DeltaYTextureArray", deltaYTextureArray);
        //Weight Texture Array(fill weight values in it)
        metaballComputeShader.SetTexture(kernelHandleFirst, "WeightTextureArray", weightTextureArray);
        //Blur Texture Array
        // metaballComputeShader.SetTexture(kernelHandleFirst, "BlurTextureArray", blurTextureArray);

        //First metaball compute shader dispatch
        metaballComputeShader.Dispatch(kernelHandleFirst, threadGroupX, threadGroupY, 1);
        //Debug.Log("First metaball effect complete!");
        // Debug.Log("destWritable size: " + destWritable.width + " " + destWritable.height);
        // Debug.Log("metaballEdgeTexture size: " + metaballEdgeTexture.width + " " + metaballEdgeTexture.height);

        //Copying destWritable(which accounts for overlap blending) to srcWritable
        // RenderTexture.active = dest;
        // Graphics.Blit(dest, src);
        // RenderTexture.active = null;

        //Apply sobel filter to metaballEdgeTexture
        RenderTexture sobelledMetaballEdgeTexture = Sobel(sobelComputeShader, metaballEdgeTexture, resolution, threadGroupX, threadGroupY);
        //Debug.Log("sobelledMetaballEdgeTexture size: " + sobelledMetaballEdgeTexture.width + " " + sobelledMetaballEdgeTexture.height);
        RenderTexture sobelledMetaballEdgeTextureFinal = new RenderTexture(metaballEdgeTexture);
        sobelledMetaballEdgeTextureFinal.Create();

    //Final dispatch prep
        //Receive previous srcWritable(which is now simply a copy of destWritable) as Src
        metaballComputeShader.SetTexture(kernelHandleFinal, "Src", srcWritable);
        //First write same value as Src to Dest and then rewrite during dispatch
        metaballComputeShader.SetTexture(kernelHandleFinal, "Dest", destWritable);
        //InnerEdgeTex
        metaballComputeShader.SetTexture(kernelHandleFinal, "MetaballEdgeTex", sobelledMetaballEdgeTexture);
        //Final processed sobelled metaball edge tex
        metaballComputeShader.SetTexture(kernelHandleFinal, "MetaballEdgeTexFinal", sobelledMetaballEdgeTextureFinal);
        //Buffer.SetCounterValue(0); only used for Append/Consume buffers

        //Color Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "ColorTextureArray", colorTextureArray);
        //SDF Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "SDFTextureArray", sdfTextureArray);
        //Delta X Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "DeltaXTextureArray", deltaXTextureArray);
        //Delta Y Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "DeltaYTextureArray", deltaYTextureArray);
        //Weight Texture Array(now read from it)
        metaballComputeShader.SetTexture(kernelHandleFinal, "WeightTextureArray", weightTextureArray);

        ComputeBuffer magnetVertexCoordinateBuffer = new ComputeBuffer(src.width * src.height, sizeof(uint) * 2, ComputeBufferType.Append);

        // Create a buffer to hold the counter.
        ComputeBuffer countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
        int[] countArray = new int[1]; //to read back counter data later

        //Set buffer to hold values and buffer to hold counter
        metaballComputeShader.SetBuffer(kernelHandleFinal, "MagnetVertexCoordinates", magnetVertexCoordinateBuffer);
        magnetVertexCoordinateBuffer.SetCounterValue(0);

        //Final metaball compute shader dispatch
        metaballComputeShader.Dispatch(kernelHandleFinal, threadGroupX, threadGroupY, 1);
        //Debug.Log("sobelledEdgeTextureFinal size: " + sobelledMetaballEdgeTextureFinal.width + " " + sobelledMetaballEdgeTextureFinal.height);

        // Copy the append buffer count to the count buffer.
        ComputeBuffer.CopyCount(magnetVertexCoordinateBuffer, countBuffer, 0);

        // Read the count to a c# int[]
        countBuffer.GetData(countArray);
        int numEdgePoints = countArray[0];

        // Now you can read back just that many edge points.
        uint2[] edgePoints = new uint2[numEdgePoints];
        magnetVertexCoordinateBuffer.GetData(edgePoints, 0, 0, numEdgePoints);

        Debug.Log("edgePoints (post EdgePointsFilled) Count: " + edgePoints.Length);
        List<Vector3> metaballEdgePointVertexCoordinates = edgePoints.Select(ep => new Vector3(ep.x, ep.y, 0)).ToList();

        //Call object manager controller's GenerateMetaballEdgePointVerteciesList(magnetic)
        objectManagerController.GenerateMetaballEdgePointVerteciesList(metaballEdgePointVertexCoordinates); //writes magnets, this is the culprit for the lagg!!!

        //Write metaball effect to final dest (non-metaballed, but hoping the magnets will work)
        Graphics.SetRenderTarget(dest);
        Graphics.Blit(destWritable, dest);
        RenderTexture.active = null;

        srcWritable.Release();
        destWritable.Release();
        metaballEdgeTexture.Release();
        sobelledMetaballEdgeTexture.Release();
        sobelledMetaballEdgeTextureFinal.Release();
        countBuffer.Release();
        magnetVertexCoordinateBuffer.Release();
        //Debug.Log("Metaball effect complete!");
    }

```

This is the code for GenerateMetaballEdgePointVerticesList in objectManagerController:

```
    public void GenerateMetaballEdgePointVerteciesList(List<Vector3> metaballEdgePixels) // Generates and initialises metaball edge vertices passed from MainCameraController
    {
        //if passed list is empty, reset all vertices (it means game objects are not close enough to metaball)
        if (metaballEdgePixels.Count == 0) {
            //Reset vertices for each game object
            foreach (GameObject colorSlimesDisplay in colorSlimesDisplayGlobal) {
                colorSlimesDisplay.GetComponent<SpriteMeshModifier>().Reset();
            }

            //Reset metaballEdgePointVertices
            foreach (var item in GetComponentsInChildren<MetaballEdgePointVertex>())
            {
                DestroyImmediate(item.gameObject);
            }
            metaballEdgePointVertices.Clear();
            //Reset metaballEdgePointVertex GOs
            metaballEdgePointVertexGOs.Clear();
        }
        else {
            //Create magnetic metaball edge points
            foreach (var item in GetComponentsInChildren<MetaballEdgePointVertex>())
            {
                DestroyImmediate(item.gameObject);
            }
            metaballEdgePointVertices.Clear();
            //Reset metaballEdgePointVertex GOs
            metaballEdgePointVertexGOs.Clear();

            int cntr = 0;
            // float circleColliderRadius = 10.0f;
            Debug.Log("Logging metaball vertex locations");

            //typeof(metaballEdgePointVertex) == typeof(Vector3)
            foreach (Vector3 metaballEdgePointVertex in metaballEdgePixels)
            {
                //Convert passed compute shader RenderTexture.id.xy to world coord
                Vector2 normalizedCoords = new Vector2(
                    metaballEdgePointVertex.x / preprocessCameraRenderTexture.width,
                    metaballEdgePointVertex.y / preprocessCameraRenderTexture.height
                );

                Vector2 screenCoords = new Vector2(
                    normalizedCoords.x * Screen.width,
                    normalizedCoords.y * Screen.height
                );

                Vector3 metaballEdgePointVertexWorldCoords = _displayCameraGlobal.ScreenToWorldPoint(new Vector3(screenCoords.x, screenCoords.y, 0));
                metaballEdgePointVertexWorldCoords.z = 0;
                Debug.Log(metaballEdgePointVertexWorldCoords);

                var go = Instantiate(MetaballEdgePointVertex, transform); //transform of the game object that will become parent of GOs == ObjectManager.transform
                go.name = go.name + " " + cntr;

                // Add CircleCollider2D
                // CircleCollider2D circleCollider = go.AddComponent<CircleCollider2D>();
                // // Configure CircleCollider2D properties
                // circleCollider.radius = circleColliderRadius;
                // circleCollider.isTrigger = true;

                metaballEdgePointVertexGOs.Add(go);

                var ver = go.GetComponent<MetaballEdgePointVertex>();
                ver.SetInitialPos(metaballEdgePointVertexWorldCoords, cntr, go); //this is reference to SpriteMeshModifier object that owns vertices
                metaballEdgePointVertices.Add(ver);
                cntr++;
            }
        }
    }

```

Here is a visual of that shows the magnets that each vertex is trying to go to:

Here are 2 techniques I can think of:

1. Create a public RenderTexture in the Unity editor using create -\> RenderTexture simply Blit in MainCameraController's OnRenderImage when the magnet texture is created. The logic for extracting opaque pixels from the public RenderTexture to a List and then generation of metaballEdgePointVerticesList in objectManagerController.cs(since this is the de-facto MonoBehavior global game object manager script)
2. In MainCameraController's OnRenderImage, update a newly created public List metaballEdgePointPositionsList(objectManagerController.cs) instead of instantiating a new List metaballEdgePointPositionsList in OnRenderImage every time.

```
metaballEdgePointPositionsList = edgePoints.Select(ep => new Vector3(ep.x, ep.y, 0)).ToList();

```

Then the ECS SystemBase class will fetch from its reference of objectManagerController its metaballEdgePointPositionsList and generate the actual global List metaballEdgePointVertexList in the first compute job using the elements of metaballEdgePointPositionsList.

My question is, which one is the better method of optimization? Also, in order to optimize the generation of vertices, what is the general method of updating MonoBehavior global list in a SystemBase object job? I am having trouble figuring out how exactly I should translate GenerateMetaballEdgePointVerteciesList to a ComputeJob, since the job GenerateMetaballEdgePointVerteciesList is to Add Vertex objects to a MonoBehavior global objectManager, and ComputeJobs require to operate on elements of a NativeArray and cannot modify MonoBehavior objects directly.

May I have some more sophisticated advice in this area in general?

\*Here is a demonstration of the lag that arises from updating the mesh vertice: https://drive.google.com/file/d/1wUGs4MV1KoIgkgBqv9zD2g87zs9AlRzN/view?usp=sharing

# Answer
> 0 votes
I was an idiot for trying to create game objects for metaball edge magnet points. After all, it was only their Vector3 position information I needed to move the vertices of the slimes accordingly. Here is how I speeded up the merging process a little

MainCameraController

```
    public Vector3 WorldCoordsTranslate(uint2 edgePoint) {
        Vector3 metaballEdgePointVertexWorldCoords = new Vector3(edgePoint.x, edgePoint.y, 0);

        //Convert passed compute shader RenderTexture.id.xy to world coord
        Vector2 normalizedCoords = new Vector2(
            metaballEdgePointVertexWorldCoords.x / preprocessCameraRender.width,
            metaballEdgePointVertexWorldCoords.y / preprocessCameraRender.height
        );

        Vector2 screenCoords = new Vector2(
            normalizedCoords.x * _displayCamera.scaledPixelWidth,
            normalizedCoords.y * _displayCamera.scaledPixelHeight
        );

        metaballEdgePointVertexWorldCoords = _displayCamera.ScreenToWorldPoint(new Vector3(screenCoords.x, screenCoords.y, 0));
        metaballEdgePointVertexWorldCoords.z = 0;

        return metaballEdgePointVertexWorldCoords;
    }

    public void OnRenderImage(RenderTexture src, RenderTexture dest) {
        //Debug.Log("Metaball Shader, OnRenderImage for main camera");
        //called after operationCamera's OnRenderImage is called game object count times?
            //How the fuck was I able to make sure that src contains the full texture upon function call?
            //Since all rendered colored slimes are moved back to default layer after each of them are separately
            //rendered. Thus by the time MainCameraController.OnRenderImage is called all slimes are back in default layer

        //Not the case where main camera is not seeing anything

        //Resolution
        Vector2Int resolution = new Vector2Int( preprocessCameraRender.width, preprocessCameraRender.height );

        //Thread control (hoping this is accurate enough)
        threadGroupX = Mathf.CeilToInt(preprocessCameraRender.width / (float)threadsPerGroup);
        threadGroupY = Mathf.CeilToInt(preprocessCameraRender.height / (float)threadsPerGroup);

        //Make a writable copy of src and dest
        //RenderTexture srcWritable = new RenderTexture(src.width, src.height, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default){ useMipMap = false };
        RenderTexture srcWritable = new RenderTexture(preprocessCameraRender.width, preprocessCameraRender.height, 32, colorFormat, 1)
        {
            useMipMap = false,
            autoGenerateMips = false,
            enableRandomWrite = true // Set the UAV usage flag
        };
        srcWritable.Create();

        //At this point both srcWritable and destWritable empty
        RenderTexture destWritable = new RenderTexture(srcWritable);
        destWritable.Create();

        RenderTexture metaballEdgeTexture = new RenderTexture(srcWritable);
        metaballEdgeTexture.Create();

        //Copying src to srcWritable
        RenderTexture.active = src;
        Graphics.Blit(src, srcWritable);

        //metaball edge texture
        // RenderTexture metaballEdgeTexture = CreateTexture("MetaballEdgeTexture", resolution, colorFormat);

        //Fill compute shader variables
        metaballComputeShader.SetTexture(kernelHandleFirst, "Src", srcWritable);
        metaballComputeShader.SetTexture(kernelHandleFirst, "Dest", destWritable);
        //Inner Edge Texture(empty at this point)
        metaballComputeShader.SetTexture(kernelHandleFirst, "MetaballEdgeTex", metaballEdgeTexture);
        metaballComputeShader.SetFloat("MaxWidth", preprocessCameraRender.width);
        metaballComputeShader.SetFloat("MaxHeight", preprocessCameraRender.height);
        metaballComputeShader.SetFloat("GameObjectListCount", colorSlimes.Count);
        metaballComputeShader.SetVector( "_Resolution", (Vector2) resolution );

    //Texture Arrays
        //First dispatch prep
        //Read (Raw) Color Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "ColorTextureArray", colorTextureArray);
        //Read (Larger) Color Texture's Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "ColorTextureArrayBeta", colorTextureArrayBeta);
        //SDF Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "SDFTextureArray", sdfTextureArray);
        //Delta X Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "DeltaXTextureArray", deltaXTextureArray);
        //Delta Y Texture Array
        metaballComputeShader.SetTexture(kernelHandleFirst, "DeltaYTextureArray", deltaYTextureArray);
        //Weight Texture Array(fill weight values in it)
        metaballComputeShader.SetTexture(kernelHandleFirst, "WeightTextureArray", weightTextureArray);
        //Blur Texture Array
        // metaballComputeShader.SetTexture(kernelHandleFirst, "BlurTextureArray", blurTextureArray);

        //First metaball compute shader dispatch
        metaballComputeShader.Dispatch(kernelHandleFirst, threadGroupX, threadGroupY, 1);
        //Debug.Log("First metaball effect complete!");
        // Debug.Log("destWritable size: " + destWritable.width + " " + destWritable.height);
        // Debug.Log("metaballEdgeTexture size: " + metaballEdgeTexture.width + " " + metaballEdgeTexture.height);

        //Copying destWritable(which accounts for overlap blending) to srcWritable
        // RenderTexture.active = dest;
        // Graphics.Blit(dest, src);
        // RenderTexture.active = null;

        //Apply sobel filter to metaballEdgeTexture
        RenderTexture sobelledMetaballEdgeTexture = Sobel(sobelComputeShader, metaballEdgeTexture, resolution, threadGroupX, threadGroupY);
        //Debug.Log("sobelledMetaballEdgeTexture size: " + sobelledMetaballEdgeTexture.width + " " + sobelledMetaballEdgeTexture.height);
        RenderTexture sobelledMetaballEdgeTextureFinal = new RenderTexture(metaballEdgeTexture);
        sobelledMetaballEdgeTextureFinal.Create();

    //Final dispatch prep
        //Receive previous srcWritable(which is now simply a copy of destWritable) as Src
        metaballComputeShader.SetTexture(kernelHandleFinal, "Src", srcWritable);
        //First write same value as Src to Dest and then rewrite during dispatch
        metaballComputeShader.SetTexture(kernelHandleFinal, "Dest", destWritable);
        //InnerEdgeTex
        metaballComputeShader.SetTexture(kernelHandleFinal, "MetaballEdgeTex", sobelledMetaballEdgeTexture);
        //Final processed sobelled metaball edge tex
        metaballComputeShader.SetTexture(kernelHandleFinal, "MetaballEdgeTexFinal", sobelledMetaballEdgeTextureFinal);
        //Buffer.SetCounterValue(0); only used for Append/Consume buffers

        //Color Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "ColorTextureArray", colorTextureArray);
        //SDF Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "SDFTextureArray", sdfTextureArray);
        //Delta X Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "DeltaXTextureArray", deltaXTextureArray);
        //Delta Y Texture Array
        metaballComputeShader.SetTexture(kernelHandleFinal, "DeltaYTextureArray", deltaYTextureArray);
        //Weight Texture Array(now read from it)
        metaballComputeShader.SetTexture(kernelHandleFinal, "WeightTextureArray", weightTextureArray);

        ComputeBuffer magnetVertexCoordinateBuffer = new ComputeBuffer(src.width * src.height, sizeof(uint) * 2, ComputeBufferType.Append);

        // Create a buffer to hold the counter.
        ComputeBuffer countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
        int[] countArray = new int[1]; //to read back counter data later

        //Set buffer to hold values and buffer to hold counter
        metaballComputeShader.SetBuffer(kernelHandleFinal, "MagnetVertexCoordinates", magnetVertexCoordinateBuffer);
        magnetVertexCoordinateBuffer.SetCounterValue(0);

        //Final metaball compute shader dispatch
        metaballComputeShader.Dispatch(kernelHandleFinal, threadGroupX, threadGroupY, 1);
        //Debug.Log("sobelledEdgeTextureFinal size: " + sobelledMetaballEdgeTextureFinal.width + " " + sobelledMetaballEdgeTextureFinal.height);

        // Copy the append buffer count to the count buffer.
        ComputeBuffer.CopyCount(magnetVertexCoordinateBuffer, countBuffer, 0);

        // Read the count to a c# int[]
        countBuffer.GetData(countArray);
        int numEdgePoints = countArray[0];

        // Now you can read back just that many edge points.
        uint2[] edgePoints = new uint2[numEdgePoints];
        magnetVertexCoordinateBuffer.GetData(edgePoints, 0, 0, numEdgePoints);

        //Debug.Log("edgePoints (post EdgePointsFilled) Count: " + edgePoints.Length);
        objectManagerController.metaballEdgePointVertices = edgePoints.Select(ep => WorldCoordsTranslate(ep)).ToList();
        //Debug.Log("edgePoints (post EdgePointsFilled) Count: " + objectManagerController.metaballEdgePointVertices.Count);

        //Write metaball effect to final dest (non-metaballed, but hoping the magnets will work)
        Graphics.SetRenderTarget(dest);
        Graphics.Blit(destWritable, dest);
        RenderTexture.active = null;

        srcWritable.Release();
        destWritable.Release();
        metaballEdgeTexture.Release();
        sobelledMetaballEdgeTexture.Release();
        sobelledMetaballEdgeTextureFinal.Release();
        countBuffer.Release();
        magnetVertexCoordinateBuffer.Release();
        //Debug.Log("Metaball effect complete!");
    }

```

VertexUpdater

```
    private void UpdatePositions(in NativeArray<VertexCopy> copiesArray, SpriteMeshModifier spriteMeshModifier) {
        for (int i = 0; i < spriteMeshModifier.vertices.Count; ++i) {
            if(copiesArray[i]._currentPos == copiesArray[i]._closestMagnetPoint) {
                Vector3 updatePosition = Vector3.Lerp(copiesArray[i]._closestMagnetPoint, spriteMeshModifier.vertices[i].initialPos, copiesArray[i]._minDistanceToInitialpos / 0.8f);
                spriteMeshModifier.vertices[i]._closestMagnetPoint = copiesArray[i]._closestMagnetPoint;
                spriteMeshModifier.UpdateVertecies(updatePosition, copiesArray[i]._index);
            }
            else {
                spriteMeshModifier.ResetPositionOfSelectedVertex(copiesArray[i]._index);
            }
            spriteMeshModifier.UpdateMesh();
        }
    }

    private void CallJobs() {
        foreach (SpriteMeshModifier spriteMeshModifier in spriteMeshModifiers) {
            if(spriteMeshModifier.vertices.Count > 0 && spriteMeshModifier._isRegenerated && spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count > 0) {
                NativeArray<VertexCopy> vertexCopies = new NativeArray<VertexCopy>(spriteMeshModifier.vertices.Count, Allocator.TempJob);
                NativeArray<Vector3> metaballVertexPositions = new NativeArray<Vector3>(spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count, Allocator.TempJob);
                CopyThingsTo(ref vertexCopies, ref metaballVertexPositions, spriteMeshModifier);
                // Do heavy computation in a job
                ComputeJob job = new ComputeJob() {
                    vertexCopyArray = vertexCopies,
                    metaballVertexPositionArray = metaballVertexPositions
                };
                job.ScheduleParallel(vertexCopies.Length, 64, default).Complete();
                UpdatePositions(vertexCopies, spriteMeshModifier);
                // Don't forget to dispose
                vertexCopies.Dispose();
                metaballVertexPositions.Dispose();
            }
            else if(spriteMeshModifier.vertices.Count > 0 && spriteMeshModifier._isRegenerated && spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count <= 0) {
                // Debug.Log("metaballEdgePointVertices.Count: " + spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count);
                //Reset vertices for each game object
                spriteMeshModifier.Reset();
            }
        }
    }

```

The final problem is that UpdatePositions is still a bit laggy due to the very fact that it's logic contains updating a mesh's vertices. As far as I know, ECS only allows copies of MonoBehavior Lists and does operations on them. Is there a way to speed this up even more? I want to harness the power of multithreading for UpdatePositions as well, but the entire mesh generation logic heavily relies heavily on MonoBehavior components. How to I translate all of the mesh vertex updating logic to DOTS such that even the mesh updating is optimized fully?

Here are additional method definitions for FYI SpriteMeshModifier

```
        public void UpdateVertecies(Vector3 moveTo, int index)    //  Update vertices
        {
            // moveTo = Quaternion.Inverse(transform.rotation) * moveTo;
            // Vector3 newMousePosition = new Vector3(moveTo.x / transform.localScale.x, moveTo.y / transform.localScale.y, moveTo.z / transform.localScale.z)
            //       - Quaternion.Inverse(transform.rotation) * new Vector3(transform.position.x / transform.localScale.x, transform.position.y / transform.localScale.y, transform.position.z / transform.localScale.z);

            //UpdatePositionOfVertices(moveTo, newMousePosition - vertices[index].currentPos);
            //UpdatePositionOfSelectedVertex(index, newMousePosition);
            UpdatePositionOfSelectedVertex(index, moveTo);
            //UpdateMesh();
        }

        private void UpdatePositionOfSelectedVertex(int index, Vector3 pos) // Update position of selected vertex
        {
            vertices[index].currentPos = pos;
        }

        public void UpdateMesh()                        // Updates Mesh
        {
            Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
            mesh.vertices = vertices.Select(x => x.currentPos).ToArray();
            GetComponent<MeshFilter>().sharedMesh = mesh;
        }

```

As you can see, the sharedMesh of the MeshFilter component of SpriteMeshModifer(which is attached to each game object) is generated using MonoBehavior logic, and what I want is to be able to run UpdateMesh for all the updated vertices in the fastest way possible.

---
Tags: unity, c#, entity-component-system, lag
---


# Question
Title: Why are the transform game objects moving away from the snail when they are swapping their direction?
I am making a game in which I created a character (main player) and another character(snail). Now the snail will move on the ground, when there is no ground detected it will change its direction. I attached transform empty game objects on either side (left and right) to detect collisions with the main player. When it changes the direction the transform empty game objects are also changing their direction. To get rid from that I swapped them in my code, when I swapped them, they are moving far away from the snail why it happened? (But they are changing their direction).

The code of snail is :

.

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnailScript : MonoBehaviour
{
    private Rigidbody2D myBody;
    private Animator anim;
    public float speed = 0.2f;
    public Transform groundCheck,up_position,left_position,right_position;
    private bool moveLeft, canMove, stun;
    public LayerMask playerLayer;
    private Vector3 leftCollisionPosition, rightCollisionPostion;

    void Start()
    {
        moveLeft = true;
        canMove = true;
    }

    void Awake()
    {
        myBody = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
        leftCollisionPosition = left_position.position;
        rightCollisionPostion = right_position.position;
    }

    void Update()
    {
        playerMove();
        collision();
    }

    void playerMove()
    {
        if (canMove)
        {
            changeDirection();
            if (moveLeft)
            {
                myBody.velocity = new Vector2(-speed, myBody.velocity.y);

            }
            else
            {
                myBody.velocity = new Vector2(speed, myBody.velocity.y);

            }
        }
    }

    void changeDirection()
    {
        if (!Physics2D.Raycast(groundCheck.position, Vector2.down, 0.1f))
        {
            moveLeft = !moveLeft;
            Vector3 tempScale = transform.localScale;
            if (moveLeft)
            {
                left_position.position = leftCollisionPosition;
                right_position.position = rightCollisionPostion;
                tempScale.x = Mathf.Abs(tempScale.x);

            }
            else
            {
                left_position.position = rightCollisionPostion;
                right_position.position = leftCollisionPosition;
                tempScale.x = -Mathf.Abs(tempScale.x);

            }
            transform.localScale = tempScale;
        }

    }

    void LeftRightCollisions()
    {
        RaycastHit2D leftHit = Physics2D.Raycast(left_position.position, Vector2.left, 0.1f, playerLayer);
        RaycastHit2D righHit = Physics2D.Raycast(right_position.position, Vector2.right, 0.1f, playerLayer);
    }

    void collision()
    {
        Collider2D upHit = Physics2D.OverlapCircle(up_position.position, 0.2f, playerLayer);
        if (upHit != null)
        {
            if(upHit.gameObject.tag == "player")
            {
                if (!stun)
                {
                    upHit.gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(upHit.gameObject.GetComponent<Rigidbody2D>().velocity.x, 7f);
                    canMove = false;
                    myBody.velocity = new Vector2(0, 0);
                    anim.Play("stunAnimation");
                    stun = true;

                }
            }
        }

        RaycastHit2D leftHit = Physics2D.Raycast(left_position.position, Vector2.left, 0.1f, playerLayer);
        RaycastHit2D righHit = Physics2D.Raycast(right_position.position, Vector2.right, 0.1f, playerLayer);

        if (stun)
        {
            if (leftHit)
            {
                myBody.velocity = new Vector2(20f, myBody.velocity.y);
            }
            if (righHit)
            {
                myBody.velocity = new Vector2(-20f, myBody.velocity.y);
            }
        }
    }
}//class

```

# Answer
It looks like you meant to use `localPosition` (the offset of the child object relative to its parent) rather than `position` (the object's absolute location in the world). Try rewriting your script like so...

```
void Awake()
{
    myBody = GetComponent<Rigidbody2D>();
    anim = GetComponent<Animator>();
    leftCollisionPosition = left_position.localPosition;
    rightCollisionPostion = right_position.localPosition;
}

```

...

```
// Use an initial uppercase letter for method names.
void ChangeDirection()
{
    if (!Physics2D.Raycast(groundCheck.position, Vector2.down, 0.1f))
    {
        moveLeft = !moveLeft;
        Vector3 tempScale = transform.localScale;
        if (moveLeft)
        {
            left_position.localPosition = leftCollisionPosition;
            right_position.localPosition = rightCollisionPostion;
            tempScale.x = Mathf.Abs(tempScale.x);
        }
        else
        {
            left_position.localPosition = rightCollisionPostion;
            right_position.localPosition = leftCollisionPosition;
            tempScale.x = -Mathf.Abs(tempScale.x);
        }
        transform.localScale = tempScale;
    }
}

```
> 0 votes

---
Tags: unity, c#, collision-detection, movement, ai
---


# Question
Title: URP Decal Projector - Decal Disappears Depending On Viewing Angle
**Issue:**

* The Decal that my URP Decal Projector is projecting disappears depending on the viewing angle. (Recording Link at bottom)

---

**Setup:**

* I've added a **URP Decal Projector** by right-clicking in the hierarchy: \> Rendering \> URP Decal Projector.
* I've created a material to use for it, added the texture I want to use as a Base Map, and set the shader to Shader Graphs/Decal.
* Here's what my Decal Projector GameObject looks like in the Inspector:

---

* Here is a recording of me replicating the issue:

https://www.youtube.com/watch?v=xNEWnccrDO8

Is anyone familiar with how I can resolve this? Thanks so much!

# Answer
For anyone else that may experience this issue, I switched to a different editor version and this issue has not occurred yet.

More specifically, I was working in version 2022.2.0b2 and switched to 2022.2.0b13. Not sure exactly how that fixed the issue, but maybe changing editor versions will resolve this for someone else.
> 0 votes

# Answer
by default decal method was set to automatic, which sometime it will be set to screen space, your problem could be the same as me, which could be fix by changing the decal method to dbuffer instead of automatic
> 0 votes

---
Tags: unity, unity-urp
---


# Question
Title: What does VSync mean on a variable refresh rate monitor?
A game which enables **VSync** means that the game frames get synchronized to the monitor's refresh rate (to avoid tearing).

A **variable refresh rate** monitor means that the monitor refresh rate gets synchronized to the game's ability to display frames.

The way I see it, VSync is only meaningful when there's a fixed frame rate monitor, yet many games allow me to enable VSync when I'm on a variable refresh rate monitor. I don't really see a difference between VSync off and on in such a case.

What does it even mean to have VSync on, on a variable refresh monitor? And by extension, what's the user's expectation when they enable VSync on a variable refresh monitor?

If anything, I'm on D3D12.

# Answer
> 2 votes
With regards to the DX API, your intuition is correct. Variable refresh rate (vrr) displays require tearing to be enabled, meaning Vsync is off. Conversely if Vsync is on, you no longer have a variable refresh rate. So the expectation should be that enabling VSync on a variable refresh monitor caps the refresh rate. This assumes that doing so is supported - ideally if it wasn't supported then it probably shouldn't be an option presented to the user.

Microsoft has some documentation & examples for supporting variable refresh rate displays, including a few points not explicitly called out in their sample code that may require specific attention. In particular, they point out that

> Disabling vsync does not necessarily uncap your frame rate: developers also need to make sure `Present` calls are not throttled by other timing events...

Regarding Nvidia's control panel settings, things are different. When used with G-Sync (Nvidia's implementation for vrr), the "Vertical sync" option in the control panel no longer acts as V-Sync on/off. When used together the to G-Sync module will compensate for frame time variances output by the system and will fall back on fixed refresh rate if the output exceeds the monitor's upper range. More info on that specifically can be found under this FAQ (in the section *"Wait, why should I enable V-SYNC with G-SYNC again? And why am I still seeing tearing with G-SYNC enabled and V-SYNC disabled? Isn’t G-SYNC suppose to fix that?"*). Again, this is with regards to how the end user configures Nvidia's control panel whereas the earlier info is with respect to how DX configured by the programmer.

---
Tags: directx12, vsync, dxgi
---


title: How to Prevent Enemy Overlap

text:
# Question
Title: How to Prevent Enemy Overlap
I am working on a 2D side-scrolling action platformer.

I am currently working on the state logic for my enemies. These are humanoid enemies that walk on the ground

They currently have idle, patrol, chase, engage, and attack states.

The default state is patrol, where they walk back and forth on a platform. If they encounter a wall or cliff, they idle for a few seconds then turn around and patrol in the other direction.

If the player comes within a `chase_radius`, they start chasing the player. If the player comes within an `attack_radius`, they enter an engaged state where they attack every few seconds.

Currently, I don't have enemies colliding with one another. I allow them to overlap each other. This is nice in the event that two enemies are patrolling in opposite directions. They simply walk passed each other.

The problem is that when two enemies are chasing a player, when one enters the engaged state, they stop and idle until they attack. The second enemy continues to walk until they too are within attack range. They then stop directly on top of the previous enemy and idle until they attack.

In this case, the enemies pretty much completely overlap and it turns an interesting situation with two enemies into a situation with essentially one enemy.

**What are some techniques or design choices I can make to prevent this ugly overlap?** Ideally, I'd like the enemies to be able to walk passed each other when they are not engaged, but to do something different during combat so that they don't end up overlapping.

I have access to all the normal stuff (for example, raycasting, collision boxes, etc.).

Similar Questions:

1. Enemies overlapping (involves pathfinding, and isn't applicable to 2D sidescroller where enemies walk on ground.)
2. How to avoid enemies overlapping each other when chasing player in Unity? (solution of gradually pulling enemies apart when they overlap won't look natural with humanoid enemies that do melee attacks).

# Answer
> 1 votes
In my game, I use a couple of techniques, and they are fairly simple and quick to implement.

Each round, as I loop through my list of enemies. I have them register with a collision manager which basically places them into buckets. These buckets are regions based upon the co-ordinates of the enemy in question. As they register, I check that their is nothing else in the bucket, if there is I know there is an overlap of some sort. I then tell the enemy unit to change course for a predetermined period of time. This is one mechanism for removing the overlap, and it works well for my game.

Hope this helps.

# Answer
> 0 votes
Have them collide with each other using collision geometry such as boxes and circles, but only when they are in chasing or even engaged state. You definitely need some collision detection mechanic to prevent overlap.

# Answer
> 0 votes
if you only want them to not overlap visually, then you can just do this:

```
private void avoidOverlap(Enemy other) {
    if(this.x == other.x) { //or in some radius of this
        this.renderx += 3; //renderx is the position where it is rendered
    }
}

```

or you can substitute `renderx` with `x` to actually change the position of the enemy. note that this could bring somee problems such as not being reachable with short - ranged weapons or, in the case of other objects that deal damage to the enemy (e.g. spells, falling objects, pets...) it may pervent them from actually hitting the enemy

# Answer
> 0 votes
If you are ok with more **work on sprites** you could simply use different sprites for the enemies.

1. You could **have enemies composted of randomized different parts**. This is probably overkill just for this issue, but would be good for user experience in general when applicable. For inspiration, blog about Papers please describes how different persons are generated there. If you have enough randomization and variability of parts no additional logic would be required for overlapping.
2. **Have multiple sprites for attack**. If generating different enemies is too much work, you could just use different sprites when enemies overlap. Just make minor changes to attack animations and decide what animation to use when attacking. Or have sprite drawn from different angle. When two enemies overlap just select different animation from other enemy. Could be still issue if more than two would overlap.

Both solutions above introduce visual variability even when not overlapping.

3. **Have some kind of indicator on top of enemy**. Many games use some kind of indicators to show type, health, etc. This indicators could be stacked instead of moving enemies itself or could indicate number of enemies.

---
Tags: 2d, game-design, ai, state
---


# Question
Title: How do games package their textures in relation to image compression?
I know that you have to keep in mind what platform you're targeting, but it feels like you might have to have multiple sets of textures. Like let's say you're targeting desktop. How do I know what users' computers are going to support the BC1-5 and BC6 and BC7 compression? How is this done? Compressing textures takes a lot of time, are you supposed to compress in BC7, and then in case the user doesn't support keep another copy of the images in BC1, and then also keep the original uncompressed versions as a fallback?

# Answer
> 0 votes
To find out which hardware compressed images to ship, you do some research about the graphics cards you want to support, then you pick the common denominator of compression formats to ship on those platforms.

A third party hardware survey helps picking a good oldest card to support.

Then in your minimum specifications you tell the user that they need a gpu of a version newer than the oldest that supports the hardware compression you shipped with (or even a few versions newer depending on other factors).

If you are going to ship uncompressed then ship a lower resolution texture, a card that old is not going to be running your game at ultra settings anyway.

---
Tags: textures, compression
---


title: Using github pages as development blog

text:
# Question
Title: Using github pages as development blog
Can I use github pages for free hosting of a development blog about my game, even if:

1. the game itself is not hosted on github, not even in a private repository,
2. the blog would contain posts not related to software development, but still related to the game design or behind the scenes ideas and discussion,
3. after the release of the game, the blog would point to a store where the game can be purchased (an ad)?

# Answer
> 1 votes
Yes, you can host a dev blog - this is covered directly in the GitHub Pages documentation:

> With GitHub Pages, you can host project blogs, documentation, resumes, portfolios, or any other static content you'd like.

However, they retain the right to remove content:

> We have the right to refuse or remove any User-Generated Content that, in our sole discretion, violates any laws or GitHub terms or policies.

And they have restrictions on advertising:

> While we understand that you may want to promote your Content by posting supporters' names or logos in your Account, the primary focus of the Content posted in or through your Account to the Service should not be advertising or promotional marketing. This includes Content posted in or through Pages, Packages, repositories, and all other parts of the Service. You may include static images, links, and promotional text in the README documents or project description sections associated with your Account, but they must be related to the project you are hosting on GitHub.

You'll need to read their terms of use carefully and consider how well they align with your plans and intent. Having backups for anything important is generally good advise & more so considering they can pull your content at their sole discretion. As mentioned in the comments, there are probably better alternatives.

---
Tags: git, blog
---


# Question
Title: Calculation of far distance plane based on yaw and pitch for a map renderer
I'm working on a vector map renderer. I want to calculate the far plane for a protective transformation, based on the yaw, pitch, roll and height of the camera above the map. Yaw (looking to the left and right), pitch (the direction you also have on Google Maps e.g.) and roll (rotation around Y axis in this case) are limited to 30°.

I recorded a video here of the movements users are able to do: https://youtu.be/NejhvULvhys

As you can see there is some clipping, which demonstrates that the calculation of the far distance field is not correct yet. Though, please note that I do have a working version if you only use pitch and roll. So this question is about: How do I calculate the far distance plane if I not only want pitch and roll?

I prepared a geogebra drawing to explain the current calculations. It is not that simple because there are not that many right-angles: https://www.geogebra.org/m/cvhtwhng

In that diagram:

* height of the blue triangle is the height of the camera.
* Roll is not really relevant as it does not influence the far distance plane.
* Yaw and pitch are equal to "pitch" in the diagram. Note that this is only a 2d cut of the real situation which is 3d. So the geogebra diagram is a simplification.

Finally, I have some code to share.

I have tried a few method to calculate the far distance plane based on the current pitch and yaw. Unfortunately, I have not gained confidence whether the correct is calculated. I am certain that the geogebra calculations are correct as they work well for the "only pitch" case. Though, the combination of both seems more involved.

Let me know if something is unclear!

# Answer
One tactic we can use here is to fire a ray through each corner of the screen and take the farthest intersection with the map plane.

Based on your camera's field of view and aspect ratio, you can compute 4 vectors in camera space that point to the corners of the screen, with a z component of 1:

```
ray.y = ± tan(fov / 2.0)
ray.x = ± aspect * ray.y
ray.z = 1 (or -1 if that's "forward" for your coordinate system)

```

These only need to change when your window size or camera FoV change, not on every rotation.

When the camera rotates, you can transform these rays into world space using the camera transform matrix. (Or construct them directly by adding together `camera.forward + tan(fov/2.0) * (±camera.up ± aspect * camera.right)` )

Now you can use a ray vs plane intersection function to get the time `t` a particle starting at the camera and moving with this ray as its velocity would hit the map plane. The greatest of these 4 `t` values is your far plane depth (and the least is your near plane, if your map is 2D with no elevation / raised overlays).

This isn't an expensive physics raycast, just a very simple subtraction, dot product, and division:

```
float GetIntersectionTime(Vector3 rayOrigin, Vector3 rayDirecton, Vector3 planeOrigin, Vector3 planeNormal) {
    float distance = Vector3.Dot(planeOrigin - rayOrigin, planeNormal);

    float approachSpeed = Vector3.Dot(rayDirection, planeNormal);

    // Returns an infinity if the ray is
    // parallel to the plane and never intersects,
    // or NaN if the ray is in the plane
    // and intersects everywhere.
    return distance / approachSpeed;

    // Otherwise returns t such that
    // rayOrigin + t * rayDirection
    // is in the plane, to within rounding error.
}

```

Note that the distance term can be pre-calculated as it only changes when the camera translates, and is constant for all rays and all rotations from a given camera position. If your plane is axis-aligned, then the dot product is just taking the e.g. z component, simplifying even further.
> 1 votes

---
Tags: mathematics, projection, trigonometry
---


# Question
Title: Validate structure for a room escape game
In a game like a simple adventure or a room escape game, I would like to know if there are established algorithms to check for simple constraints on the layout.

I would like some pointers so I could do my own research, or on the algorithms or on this kind of problems.

In a simplified case, if we guess the game is 2D, and the environment is the classic grid N x M, where a cell can be an empty place, a wall or a door, there could be these requirements:

* every room must be a rectangle
* every room must have a door at least
* every room must be reachable from any other (aside the possibile locked doors)
* all the rooms must be connected, so no disjoint groups of rooms
* all the walls must be thick only one cell

I know this sound strange because if I design my own game with few room obviously it's possible check with bare eye if everything is ok in the map. But I like the theory side of the things.

# Answer
> 2 votes
**The requirement 1 (every room must be rectangular)** can be tested using the flood fill algorithm. This algorithm allows you to start from somewhere on a tile-based map and find all tiles that can be reached from it. This is a very common and well-documented algorithm, so I don't think I need to go into detail how to implement it.

When you start this algorithm in a room and stop at any doors, then you end up with a list of all the tiles the room consists of. Are they in a rectangle? You can find that out by

1. find the the upper-leftmost tile in the array
2. find the lower-rightmost tile in the array
3. calculate the area of the rectangle formed by those two tiles
4. check that the length of the array matches the area of the rectangle

If you have less tiles, then you don't have an unbroken rectangle. If you have more tiles, then your flood-fill implementation is broken, because you are double-counting tiles.

**The requirements 2, 3 and 4 (no unreachable areas)** can also be tested using the flood fill algorithm, but instead of stopping at doors, you continue. If all tiles of the map are either reachable or walls, then you know that all the rooms are connected.

**Requirement 5 (no double-walls)** can be verified by scanning for "2x2 squares" of wall. For each tile that is wall, check that at least one of the tiles (x+1, y), (x+1, y+1) and (x, y+1) is empty.

---
Tags: algorithm
---


# Question
Title: Efficient procedural, instanced mesh rendering in Unreal using structured buffers
I need to render some procedural, instanced data in unreal. I have a mesh and a structured buffer (if that parlance is unknown in unreal land - a big GPU buffer of arbitrary data) full of instance data, pose data and so on describing position and variations in blend shapes, skin tone, overlays and so on I want to render an army of characters using an instanced draw call.

I have this running in unity and opengl and now I need to get the same system to run in Unreal.

I am very green in unreal development and it doesn't seem straightforward to do this nor is it easy to find a path that looks relevant in the documentation. Most of what I need to do is vertex shader based which, as far as I can tell, means the material graph is out of the window. Therefore I think I need a 'global shader' (I find the naming confusing, why is that 'global' and other shaders are not?) and to make use of the Render Dependency Graph. I'm also aware that I'll probably need to do some work with deferred shading but really at this stage, I just want to prove out some simple things - just get a mesh rendering using direct draw calls or injected calls to the RDG and then see if I can upload structured buffers into the shader in a way that makes sense.

Is what I'm trying to do so far out of the normal flow of things that it's either impossible or impractical, am I asking the right questions and should I go about this in another way (please bear in mind that much of what I've said are requirements that define the task I have in front of me)

Any pointers in the right direction would be appreciated.

# Answer
Since what you need is to do with vertex shader, you're gonna have to build your mesh, already, equipped with those extra resources. This is done through customizing the vertex factory and defining your required inputs for the material of the mesh. So, you're gonna need to create a custom mesh component with a custom vertex factory through which you can pass/bind your vertex shader parameters. If you need to do more custom work for material, then you can also extend your material shader class and use it through your custom scene/mesh component.
> 1 votes

---
Tags: unreal, procedural
---


title: How to block switching screen mode

text:
# Question
Title: How to block switching screen mode
When the game is full screen, pressing the window key switches the game screen to windowed mode.
How can I block this?
I tried to find related to this in official documentation
But I can't find it.

# Answer
Good question, I've never had this issue. But this would work in the same way as on other apps. You might want to catch the key code and set it to handled, depending on whether you use Winforms or SDL context, it might work differently.
> 0 votes

---
Tags: stride
---


# Question
Title: Does Stride require Visual Studio to build the release version of a project?
I've been reading through the Stride tutorials and manual, and I see on this page: https://doc.stride3d.net/latest/en/manual/files-and-folders/distribute-a-game.html

... they describe building the release version of your project as a thing you have to go through Visual Studio for, which implies it is impossible for people who can't run visual studio to produce that release version. Is this correct? Is use of visual studio necessary to produce a release build of a project developed in Stride?

Or is there another possible way? For example, would it be possible to achieve the same thing in another IDE, like SharpDevelop?

# Answer
> 0 votes
Through investigating this for the last couple of weeks, I have turned up no way to create a build of a Stride project without Visual Studio. So, apparently, the answer is yes, Visual Studio is required for creating builds of Stride Projects, meaning it is not possible to build a Stride project in circumstances where Visual Studio can't be run.

# Answer
> 0 votes
You can use `dotnet build` in the command line too.

---
Tags: stride
---


# Question
Title: Stride integrated in WPF or WinUI desktop app
I am using stride 3D engine integrated in an UWP application because stride only support this platform.

Do you know if it is possible (or one day) to integrate stride in a WPF or WinUI application because UWP has been declared obsolete ?

Thanks for your reply.

Regards.

# Answer
> 0 votes
Yes, this is possible, see here: https://github.com/Doprez/Awesome-Stride#embedded-stride

---
Tags: c#, stride
---


# Question
Title: Explode image into component pixels shader
I'm currently stuck on trying to write a shader for Godot 4.x. and get it to look right.

I'd like to take an image, pixelate a bit so that particles are a bit chunky, and then explode it into component chunky pixels. So it looks like the sprite has broken apart.

This is simple 3d animation which I mocked up in Blender to show what I want. It's basically a grid of 16 squares that shrink and fade as they move away from the centre. However they are all mapped so that together at the start they represent a whole image.

and being very new to shaders, this is what I've got so far in Godot:

```
shader_type canvas_item;

uniform sampler2D tex_diffuse; // explosion image
uniform sampler2D tex_explode; // grayscale circle
uniform float progress : hint_range(0.0, 1.0);

void fragment() {
    vec2 direction = texture(tex_diffuse, UV).xy;
    direction = direction  * progress;

    // Get UV and step them up by 4
    vec2 tex_size = 1.0 / TEXTURE_PIXEL_SIZE; // texture size
    vec2 uv = floor(UV * tex_size/4.0) / (tex_size/4.0 - 1.0); // snap to step

    // Texture with exploded UV
    vec4 tex = texture(TEXTURE, uv);

    // Dissolve with alpha
    float dissolve = texture(tex_explode, uv).x;
    dissolve = step(progress, dissolve);
    tex.a *= dissolve;

    // set tex
    COLOR = tex;
}

```

tex\_explode texture:

As you can see from the two animations, I'm not quite there. This is where I need help. I need to divide the image up into pixelated chunks - let's call them pixel particles. "Move" those pixel particles apart from one another radiating from centre. scale down and fade out the pixel particles.

Just to be clear, I'm using a scale animation on the sprite (not yet included in shader)

# Answer
This is what I have been able to come up with:

```
shader_type canvas_item;

uniform float progress : hint_range(0.0, 1.0) = 0.0;
uniform float sprite_scale_begin : hint_range(0.0, 5.0) = 1.0;
uniform float sprite_scale_end : hint_range(0.0, 5.0) = 1.0;
uniform float particle_scale_begin : hint_range(0.0, 5.0) = 1.0;
uniform float particle_scale_end : hint_range(0.0, 5.0) = 1.0;
uniform sampler2D dissolve_texture;

void vertex() {
    // GROW
    VERTEX *= mix(sprite_scale_begin, sprite_scale_end, progress);
}

void fragment() {
    // MOSAIC EFFECT
    const float pixel_step = 4.0;
    vec2 texure_size = 1.0 / TEXTURE_PIXEL_SIZE;
    vec2 steps = texure_size/pixel_step;
    vec2 uv = floor(UV * steps) / (steps - 1.0);
    COLOR = texture(TEXTURE, uv);

    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);
    vec2 direction = UV - 0.5;
    vec2 quantized_direction = sign(direction);
    float angle = PI * 1.25 - atan(quantized_direction.y, quantized_direction.x);
    float angle_sin = sin(angle);
    float angle_cos = cos(angle);
    mat2 rotation_matrix = mat2(vec2(angle_cos, angle_sin), vec2(-angle_sin, angle_cos));
    vec2 rotated_fract_uv = (rotation_matrix * (fract_uv - 0.5)) + 0.5;
    float inverse_particle_scale = 1.0 / mix(particle_scale_begin, particle_scale_end, progress);
    if (isinf(inverse_particle_scale)){
        COLOR.a = 0.0;
    }
    else
    {
        float step_position = max(rotated_fract_uv.x, rotated_fract_uv.y) * inverse_particle_scale;
        float inverse_sprite_scale = 1.0 / mix(sprite_scale_begin, sprite_scale_end, progress);
        COLOR.a *= step(step_position, inverse_sprite_scale);
    }

    // DISSOLVE EFFECT
    float dissolve = texture(dissolve_texture, uv).x;
    dissolve = step(progress, dissolve);
    COLOR.a *= dissolve;
}

```

Let us go part by part...

---

First of all, just as in your code `progress` controls the animation:

```
uniform float progress : hint_range(0.0, 1.0) = 0.0;

```

---

Now, to make the sprite grow, I have defined these `uniform`s:

```
uniform float sprite_scale_begin : hint_range(0.0, 5.0) = 1.0;
uniform float sprite_scale_end : hint_range(0.0, 5.0) = 1.0;

```

So I can compute what should be the scale of the sprite using `progress`, and the code to actually scale it is in `vertex`:

```
void vertex() {
    // GROW
    VERTEX *= mix(sprite_scale_begin, sprite_scale_end, progress);
}

```

---

The mosaic effect in `fragment` begins with the `pixel_step` constant, which I promoted from literals in your code:

```
    // MOSAIC EFFECT
    const float pixel_step = 4.0;

```

We continue with the `texture_size` as you do:

```
    // MOSAIC EFFECT
    const float pixel_step = 4.0;
    vec2 texure_size = 1.0 / TEXTURE_PIXEL_SIZE;

```

And how many steps does the texture has:

```
    // MOSAIC EFFECT
    const float pixel_step = 4.0;
    vec2 texure_size = 1.0 / TEXTURE_PIXEL_SIZE;
    vec2 steps = texure_size/pixel_step;

```

So we can get the `uv` (which is at integers steps):

```
    // MOSAIC EFFECT
    const float pixel_step = 4.0;
    vec2 texure_size = 1.0 / TEXTURE_PIXEL_SIZE;
    vec2 steps = texure_size/pixel_step;
    vec2 uv = floor(UV * steps) / (steps - 1.0);

```

*I was tempted to extract `UV * steps` as a variable, as we will use it later, but I couldn't figure out a good name for it.*

And we can set the output `COLOR`:

```
    // MOSAIC EFFECT
    const float pixel_step = 4.0;
    vec2 texure_size = 1.0 / TEXTURE_PIXEL_SIZE;
    vec2 steps = texure_size/pixel_step;
    vec2 uv = floor(UV * steps) / (steps - 1.0);
    COLOR = texture(TEXTURE, uv);

```

From here on, we will only worry about transparency. I will be setting `COLOR.a` (using `discard` is also an option, since we will not have partial transparency).

---

OK, so far it grows, and it has the mosaic effect. However, the elements of the mosaic grow, and there are no visible gaps between them.

I'm going to explain how to keep the size of the particles the same...

First we need to figure out a coordinate system inside of the particle. So we start with the fraction of the `UV` we didn't use when we rounded it:

```
    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);

```

*Here is where we use `UV * steps` again.*

This has a couple problems: It also grows, and it is in the regular orientation. We will handle the orientation first...

So, we figure out the direction from the center of the texture:

```
    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);
    vec2 direction = UV - 0.5;

```

By substracting `UV - 0.5` we have the `UV` coordinates shifted, so the origin is at the center (since `UV` goes from `(0, 0)` to `(1, 1)`, `UV - 0.5` goes from `(-0.5, -0.5)` to `(0.5, 0.5)`).

We do not need to normalize it... Instead we will quantize it. That is, we will "round" the direction to a few possible ones, in this case I want the directions we get by simply getting the `sign` of the components:

```
    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);
    vec2 direction = UV - 0.5;

```

From this I expect four directions:

* Top Left: `(-1.0, -1.0)`
* Top Right: `(1.0, -1.0)`
* Bottom Left: `(-1.0, 1.0)`
* Bottom Right: `(-1.0, 1.0)`

That is: I expect the diagonals. I do not expect straight up, down, left and right, unless you have set a `pixel_step` and `texure_size` that result in an odd number of particles so that there are particles aligned with the center of the texture.

Now, I figure out an angle...

```
    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);
    vec2 direction = UV - 0.5;
    vec2 quantized_direction = sign(direction);
    float angle = PI * 1.25 - atan(quantized_direction.y, quantized_direction.x);

```

Here `atan(quantized_direction.y, quantized_direction.x)` is the angle of the `quantized_direction` measured from the positive horizontal axis (this is the standard)… Except I want the angle for the Top Left corner to be zero (that part is already oriented how I wanted it), and, well, It might make more sense with the next steps: I rotate the `fract_uv`:

```
    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);
    vec2 direction = UV - 0.5;
    vec2 quantized_direction = sign(direction);
    float angle = PI * 1.25 - atan(quantized_direction.y, quantized_direction.x);
    float angle_sin = sin(angle);
    float angle_cos = cos(angle);
    mat2 rotation_matrix = mat2(vec2(angle_cos, angle_sin), vec2(-angle_sin, angle_cos));
    vec2 rotated_fract_uv = (rotation_matrix * (fract_uv - 0.5)) + 0.5;

```

As you can figure out, I made a rotation matrix from the computed angle. The idea here is to get a rotated version of `fract_uv`, such that the zero is on the outer corner of the particle.

Now, I need to take the difference with `PI * 1.25` (225º) so the top left has a rotation of zero. And - via trial an error - I figured out that I need to do `PI * 1.25` minus the angle, and not the other way around.

I do substract `0.5` before rotating, and add it again after the rotation, so the rotation happens around the center of the particle.

Next I need to do this to keep the particles of the same size:

```
    float step_position = max(rotated_fract_uv.x, rotated_fract_uv.y);
    float inverse_sprite_scale = 1.0 / mix(sprite_scale_begin, sprite_scale_end, progress);
    COLOR.a *= step(step_position, inverse_sprite_scale);

```

Here `step_position` is a measure of where on the particle the current fragment is... measured from the outer corner (which was the point of all the rotation stuff). And - again via trial and error - I figured that comparing it with `inverse_sprite_scale` allows me to cut the particle so it retains its original size (the size it had when the sprite scale was `1.0`).

---

Ah, but in your mock up animation I notice the particles shrink! So to add that we have two more `uniform`s:

```
uniform float particle_scale_begin : hint_range(0.0, 5.0) = 1.0;
uniform float particle_scale_end : hint_range(0.0, 5.0) = 1.0;

```

And we do this instead:

```
    // PARTICLE SIZE
    vec2 fract_uv = fract(UV * steps);
    vec2 direction = UV - 0.5;
    vec2 quantized_direction = sign(direction);
    float angle = PI * 1.25 - atan(quantized_direction.y, quantized_direction.x);
    float angle_sin = sin(angle);
    float angle_cos = cos(angle);
    mat2 rotation_matrix = mat2(vec2(angle_cos, angle_sin), vec2(-angle_sin, angle_cos));
    vec2 rotated_fract_uv = (rotation_matrix * (fract_uv - 0.5)) + 0.5;
    float inverse_particle_scale = 1.0 / mix(particle_scale_begin, particle_scale_end, progress);
    if (isinf(inverse_particle_scale)){
        COLOR.a = 0.0;
    }
    else
    {
        float step_position = max(rotated_fract_uv.x, rotated_fract_uv.y) * inverse_particle_scale;
        float inverse_sprite_scale = 1.0 / mix(sprite_scale_begin, sprite_scale_end, progress);
        COLOR.a *= step(step_position, inverse_sprite_scale);
    }

```

The reason I'm checking for an infinite `inverse_particle_scale` is because you might have set the particle scale to zero (so they shrink to nothing), which result in a division by zero.

Otherwise, what I do to scale the particles is scale `step_position` by `inverse_particle_scale`.

---

Finally, you had a dissolve effect which uses a texture, so we have a texture `uniform`:

```
uniform sampler2D dissolve_texture;

```

And the code is basically what you had:

```
    // DISSOLVE EFFECT
    float dissolve = texture(dissolve_texture, uv).x;
    dissolve = step(progress, dissolve);
    COLOR.a *= dissolve;

```

---

Hopefully this is the effect you want. Barring that, I hope I gave you the tools to figure it out.
> 3 votes

---
Tags: shaders, godot
---