# Question
Title: How do I implement Minecraft Forge Config GUI (1.8.x)
So I have recently been working on a minecraft 1.8.9 forge mod, just to play around and see what there is (eventually I am planning on making a utilities mod with versions for 1.8-1.19, which is why I'm so far back). I have had no problems... until I got to configs. I already have code to create and read from a config file, but I can not figure out how to use MinecraftForge's mod options \> config menu to allow GUI modification of the settings. I have had no luck finding any information on how to do this back in 1.8, so if anyone could help me out a bit (linking sources, giving example code, or referring me to a forge class that has the relevant code in it), I would greatly appreciate it.

TL;DR I need help implementing forge's config gui system.

My current config code (in the Main class):

```
public static Configuration config;
    private File confDir;

    public static Logger lmao;

    public static Configuration getConfig()
    {
        return config;
    }
    @EventHandler
    public void preinit(FMLPreInitializationEvent event) {
        lmao = event.getModLog();

        confDir = event.getModConfigurationDirectory();
        config = null;
        File configFile = new File(confDir,"config.cfg");
        config = new Configuration(configFile);
        syncConfig(true);
        event.getModLog().log(Level.ALL,"Preinitialization complete.");
    }
    private static void syncConfig(boolean load)
    {
        List<String> propOrder = new ArrayList<String>();

        if (!config.isChild)
        {
            if (load)
            {
                config.load();
            }
            Property enableGlobalCfg = config.get(CATEGORY_GENERAL, "enableGlobalConfig", false).setShowInGui(false);
            if (enableGlobalCfg.getBoolean(false))
            {
                Configuration.enableGlobalConfig();
            }
        }

        Property prop;

        //set prop value, then:
        //propOrder.add(prop.getName());

        prop = config.get(CATEGORY_GENERAL,"testbool",false);
        prop.comment = "for testing purposes";
        prop.setLanguageKey("mod.conf.testbool");
        propOrder.add(prop.getName());

        prop = reConf.get(CATEGORY_GENERAL,"testvar","can you see this?");
        prop.comment = "for testing purposes only";
        prop.setLanguageKey("mod.conf.teststring");
        propOrder.add(prop.getName());

        config.setCategoryPropertyOrder(CATEGORY_GENERAL, propOrder);

        if (config.hasChanged())
        {
            config.save();
        }
    }
          public static void syncConf(boolean load1) {
          //public configuration sync method
        syncConfig(load1);
    }
    @SubscribeEvent
    public void onConfigChangedEvent(OnConfigChangedEvent event)
    {
        if (event.modID.equals(MODID))
        {
            if (Configuration.CATEGORY_GENERAL.equals(event.configID))
            {
                syncConfig(false);
            }
        }
    }
          //much of this was taken from or inspired by forge's source code, and adapted to work with this mod.

```

I have written some GUI code, but managed to mess it up enough that I will just rewrite it based off ForgeGuiFactory.java later, which is why I have attached no GUI code here.

If anyone can help, please do. If this post is breaking a forum rule, DEFINITELY tell me, since I need to know.

Thanks ahead of time,

-MiSt\_Rocky

# Answer
> 0 votes
To do this you need 3 things:

* A class that extends `net.minecraftforge.fml.client.config.GuiConfig`:

```
public class ExampleConfig extends GuiConfig {
        ExampleConfig(GuiScreen parent) {
            super(
                    parent,
                    new ConfigElement(config.getCategory(Configuration.CATEGORY_CLIENT)).getChildElements(),
                    "modid",
                    false,
                    false,
                    "title"
            );
        }
    }

```

Take a look at the `GuiConfig` class for what the parameters mean. The most important one here is the 2nd one, which is the list of elements this gui will have.

`new ConfigElement(config.getCategory(Configuration.CATEGORY_CLIENT)).getChildElements()` will get all the elements inside the `"client"` category. (You do not need to do this, I just thought it'd be cool to mention)

* A class that implements `net.minecraftforge.fml.client.IModGuiFactory`:

```
public class GuiFactory implements IModGuiFactory {
    @Override
    public void initialize(Minecraft minecraft) {}

    @Override
    public Class<? extends GuiScreen> mainConfigGuiClass() {
        return ExampleConfig.class;
    }

    @Override
    public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
        return null;
    }

    @Override
    public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement runtimeOptionCategoryElement) {
        return null;
    }
}

```

The only notable thing here is the `mainConfigGuiClass` method, which returns the class made on the step before.

* Add the `GuiFactory` to your `Mod` annotation:

```
@Mod(
    // ... previous arguments
    guiFactory = "path.to.GuiFactory"
)
public class ExampleMod {
    // ...
}

```

With all of this done, once you launch the game, the `Config` options in the mod options menu should no longer be greyed out.

Hope this helps.

---
Tags: java, gui, minecraft-modding, configuration
---


title: How to hide UI elements in Unity?

text:
# Question
Title: How to hide UI elements in Unity?
I'd like to ask a case when developing a game using Unity.

There are many UI elements in the game.

These UI elements normally disappear from scenes when the purpose is achieved.

However, the `Destroy` or `SetActive` methods provided by Unity greatly affect game objects and sometimes lead to errors, especially when using coroutines, causing stability problems.

When making and using UI, is it standard and stable to use Alpha values of the UI's `Image`/panel component or `Text` component to make it disappear or appear?

Or is it standard and stable to use the `SetActive` function, passing true or false?

# Answer
> 0 votes
DMGregory's comment is very useful thanks

> If Destroy or SetActive are leading to errors, you have written your code wrong, or made an error in your scene setup. API methods don't throw errors randomly — they obey a specific contract, and if you use them out of contract leading to unwanted behaviour, that's your error, and something you can fix. If you'd like help fixing those root problems, edit your question to document the steps to create a Minimal Complete Verifiable Example of one specific problem you've encountered when trying to use one of these methods

---
Tags: unity, c#, unity-ui
---


# Question
Title: Godot 4.1 warning: Node 'NodeName' was modified from inside an instance, but it has vanished
I've recently modified my `Enemy` class and removed some `Node`s from it. This `Enemy` class is like an abstract class: it's not supposed to be instantiated but all enemies inherit from it.

Now, when I instantiate an enemy, **sometimes** I get this warning:

```
W 0:00:01:0018   enemies_manager.gd:44 @ instance_enemy(): Node './DamageLabel' was modified from inside an instance, but it has vanished.
  <C++ Source>   scene/resources/packed_scene.cpp:182 @ instantiate()
  <Stack Trace>  enemies_manager.gd:44 @ instance_enemy()
                 enemies_manager.gd:93 @ spawn_enemy_pack()
                 enemies_manager.gd:116 @ spawn_random_enemy_pack()
                 enemies_manager.gd:26 @ _ready()

```

And when I mean sometimes, I really mean it! I press `F5` to run the project and it's fine, no warnings. Close the project's window, press `F5` again and **maybe it shows the warnings, maybe not**. It's like 50 / 50. **The game works correctly, with or without warnings**.

And no, the actual enemies that `extends Enemy` do not even try to access the deleted nodes. They are just a bunch of stats variables, sprites and death effects.

Googling this question gives one result to ask.godotengine.org, but the website has been down from days now, so I don't know if it's solved there.

Anybody knows about this warning? Even if the game works, it's something that I don't like.

Edit: The project was started with Godot 4.0.3 and then upgraded to Godot 4.1, all stable versions.

# Answer
About the message, as the stack points out, it comes from `PackedScene` (here):

> ```
> scene/resources/packed_scene.cpp:182 @ instantiate()
>
> ```

For what I've been able to gather this is a warning can happen with scene inheritance. In particular that the derived scene is trying to set some properties of a `Node` that no longer exists in the base scene.

That is:

* You had a base scene.
* You created a scene derived from it.
* In the derived scene you set some properties of `Node`s from the base scene in the editor (i.e. via the inspector). *I suppose it is possible that Godot might have erroneously saved the properties as if they were modified, as there were some related issues in the past.*
* You modified the base scene so that those `Node`s are no longer there.

And now when instantiating the derived class, Godot reads from the scene file that it has to set some properties of a `Node` it cannot find.

That is, the issue is that the derived scene file still have the reference to the `Node`s that are no longer available. In fact, you should get the same warning upon opening the derived scene in the editor. However, re-saving it should fix it.

Barring that, if you have a `tscn` file, you might try opening it with a text editor and try to find out which `Node`s it references that no longer exist in the base scene, and remove them.

---

I have no idea why you would get the message only *sometimes*. The first thing it suggests to me is that the situation depends on timing or load order (i.e. it is a race condition). However, that would imply some code manipulating the scene in unexpected ways (either before or while it is being instantiated). The fact that this coincided with upgrading to Godot 4.1 makes me wonder if it has anything to do with recent changes to scene threading. But that is all speculation.
> 4 votes

---
Tags: godot-4
---


title: Avoiding nausea when spinning

text:
# Question
Title: Avoiding nausea when spinning
I'm working on a top down space sim where the ship fills most of the screen and has a fixed heading, i.e. the front of the ship is always at the top. However, there are stars in the background, so when you rotate the ship to a new heading, you get a circular spiral effect in the background, which is predictably somewhat nauseating (and probably an accessibility concern).

It might help if the ship rotated instead of everything else, but that's not the look and feel I'm going for.

I'm thinking of making the stars pretty dim, but fixed points of reference (e.g. nearby planets) would still be highly visible. Or...maybe the ship can only rotate very slowly, but that's going to impact gameplay.

Anyone have any suggestions? Or seen this addressed in other games?

# Answer
> 4 votes
The best solution can be determined on how your game "feels" while playing it, but here's a few suggestions that you can consider:

## Smooth Camera

Sure the ship needs to always point at the top, but the camera doesn't have to force that to happen. The ship could move/rotate at really big speeds, but the camera needs to be a bit easier on the eyes.

To do that, make the camera "follow" the position and orientation of the ship, so that for example when the ship moves and rotates, the camera will slowly follow the same motion in the next few seconds.

## Contrast

Objects with high contrast (like bright white stars on a dark black background) are asking for the eye's attention. When they move erratically, while asking for attention, the eye could get more tired.

A solution could be to make the stars have less contrast (assuming they are just background), or even better, make the stars dimmer as the camera moves around, but have them high contrast once it's more stationary.

## Accessibility

You mentioned an accessibility concern on your post, so I'll mention some extra info about it. To make things easier to see on the screen, there need to be multiple "hints" of something being there. A usual example is making an object have a color and a shape that's distinct.

I'm not sure how that can translate to your game, if stars all important (gameplay-wise) and there are different kind of stars, it helps to make each kind of star a different colour **and** shape. When choosing colours it's good to consider the `Contrast` section above.

---
Tags: 2d, movement
---


# Question
Title: How to check if a 2D GameObject is touching something without OnTriggerEnter
I want to avoid using OnTriggerEnter2D because I want to use it in a function like this:

```
void MyFunction()
{
    If (this.GameObject.IsTouchingSomething) {
        Debug.Log("I am touching somethin'");
    }
}

```

# Answer
> 0 votes
Be sure to read the documentation. Any of these methods can do what you need:

```
public class TouchDetector : MonoBehaviour {

    public LayerMask layersToCheck;

    public Collider2D collider;

    public void DetectTouch() {
        if (collider.IsTouchingLayers(layersToCheck)) {
             Debug.Log("I am touching something");
        }
    }
}

```

---
Tags: unity, c#, 2d, collision-detection, collider
---


# Question
Title: how can I make dropdown elements unselectable, but can visible?
this is basic dropdown Ui object

I want to make it ,if I click dropdown, show every elements but

can only select top element others not.

like this image, because I made tutorial.

how can I restrict other element to select?

# Answer
You can create your custom drop down and setup Interactable to false for options you are not able to select. Or you need to modify Dropdown script, better copy it and rename then setup Interactable opiton for your items list.
> 0 votes

# Answer
On picture DropDown - button OnClick -\> DropDownFields-\>gameObject.Active(true); Green Red Blue - fields with buttons. when onClick-\>{SelectFieldAction();DropDownFields-\>gameObject.Active(false)} To DropDownFields you need to add components ContentSizeFilter and VerticalLayoutGroup. And you have custom ScrollDown you can add as many field as you need and setup Interactable for each button true of false.
> 0 votes

---
Tags: unity, unity-ui
---


# Question
Title: Is it possible to use C++ with Unity instead of C#?
The title kind of says it all. Is it possible to replace C# with C++ on a game using Unity?

# Answer
> 28 votes
It is possible to use C++ with the Free version of Unity, although it is easier to work with if you have a Unity Pro license. All you have to do is wrap it up in a DLL and follow the instructions below on where to place it.

I wrote an article that covers this topic: **Unity and DLLs: C# (managed) and C++ (unmanaged)**

> For Unity 4 Free:
>
> * Add unmanaged code to the Unity Project Root: `UnityProject`
> * Add managed code to the Plugins folder: `UnityProject`-\>`Plugins`
> * When you build a project, copy the unmanaged code to `BuildRoot`-\>`Data`-\>`Plugins`
>
> For Unity 4 Pro and any Unity 5:
>
> * Just copy the DLLs into `UnityProject`-\>`Plugins`

Unmanaged means C++ and Managed means C#

# Answer
> 4 votes
It is possible though inconvenient. You'd have to write managed C++ to achieve it. And yes, there is such thing as managed C++. Managed doesn't specifically mean C# and unmanaged C++. To achieve it you'll need to import UnityEngine DLL file. When you're finished you put it in the (Unity Project Name)/Plugins folder. Here would be the code you'd use: In the C++ file:

```
public ref class CPPUNITY {
  public:
     void Start() {
         Debug::Log("C++ printed message");
     }

};

```

In the C# file:

```
     using UnityEngine;
     public class FileName {
         void Start() {
              CPPUNITY.Start();
         }
     }

```

That exact code wouldn't work but thats a base.

# Answer
> 3 votes
Yes, you can use https://github.com/jacksondunstan/UnityNativeScripting

This is basically a code generator which allows you to write C++ code which calls generated C# bindings. Your C++ is then compiled to a binary "Unity plugin" which can be used in your game. Of course, the README of the above repository goes into a lot more detail.

---
Tags: c++, unity
---


# Question
Title: How do I create and import a class in GDScript
I would like to create and import a class in GDScript. Here is some non-functional pseudo code to explain what I'm trying to do:

```
class_name WordPrinter

var my_word: String

func _init(word: String)
  my_word = word

func print_word()
  print(my_word)

```

```
const word_printer = import("./word_printer.gd").new("Hello World")

word_printer.print_word()

```

I've found various tutorials on classes and imports, but I have yet to find a straightforward code example that works. Here are some places I've looked:

The second link above does show working code, but the imported class does not have any type definitions, and is not very useful.

# Answer
You have specified a `class_name` for your class:

```
class_name WordPrinter

var my_word: String

func _init(word: String)
  my_word = word

func print_word()
  print(my_word)

```

Thus, you should be able to use it directly:

```
func _ready():
    var say_hello := WordPrinter.new("Hello World")
    say_hello.print_word()

```

By the way, here I'm setting the type of `say_hello` implicitly by using `:=`. We can do it explicitly too:

```
func _ready():
    var say_hello:WordPrinter = WordPrinter.new("Hello World")
    say_hello.print_word()

```

---

And yes, you could instead use `preload` with the path:

```
const word_printer := preload("res://path/to/word_printer.gd")

```

The `preload` is resolved while the script is being parsed, which is how this is a constant expression (and thus can be set to a `const`).

In this case `word_printer` holds a `GDScript` object, which you can use like this:

```
func _ready():
    var say_hello := word_printer.new("Hello World")
    say_hello.print_word()

```

And setting the type explicitly still works:

```
func _ready():
    var say_hello:word_printer = word_printer.new("Hello World")
    say_hello.print_word()

```

---

Since what you are actually using is a `GDScript` object, the same should also work if you get it by other means. For example using `load`, which would allow you to use a variable for the path (for example if you want to decide dynamically which script to load):

```
func _ready():
    var my_word_printer := load("res://path/to/word_printer.gd")
    var say_hello = my_word_printer.new("Hello World")
    say_hello.print_word()

```

However, since `load` is resolved in runtime (instead of being resolved while parsing the script like `preload`) Godot does not know the type until runtime.

Consequently, the variable instantiated from the the script cannot be statically typed (it will be a Variant), and we won't get auto-completion.

Despite not having auto-completion the code still works in runtime.

---

This is all covered in the official documentation under Classes and under Static typing.

---

*Addendum: You don't need `class_name` for `preload` or `load` to work.*
> 4 votes

# Answer
Importing a class in gdscript can be done with the `preload()` command. To make the code above usable, all that needs to change is the import line, like so:

```
const word_printer = import("res://path/to/word_printer.gd")

func _ready():
  var say_hello = word_printer.new("Hello World")
  say_hello.print_word()

```
> 0 votes

---
Tags: godot, gdscript
---


# Question
Title: Double trouble with Python's Ursina 3D engine
I'm making a weather simulator with Python's Ursina module, but the script crashes with two exceptions.

Console output:

```
C:\Users\x\Desktop\WeatherSim>weathersim.py
Loading modules ... done
Defining functions ... done
Loading 3D engine ... done
Defining clouds ...
 done
Loading clouds ...
01
Traceback (most recent call last):
  File "C:\Users\x\Desktop\WeatherSim\WeatherSim.py", line 158, in <module>
    Clouds.Load(n)
  File "C:\Users\x\Desktop\WeatherSim\WeatherSim.py", line 146, in Load
    self.Clouds[self.cat[int(id)]].append(load_texture("Assets/Clouds/"+id+".png"))
                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\site-packages\ursina\texture_importer.py", line 40, in load_texture
    t = Texture(filename.resolve())
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\site-packages\ursina\texture.py", line 23, in __init__
    self._texture = loader.loadTexture(Filename.fromOsSpecific(str(value)))
                    ^^^^^^
NameError: name 'loader' is not defined. Did you mean: 'Loader'?
Exception ignored in: <function Texture.__del__ at 0x0000019C62A44360>
Traceback (most recent call last):
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\site-packages\ursina\texture.py", line 185, in __del__
    del self._cached_image
        ^^^^^^^^^^^^^^^^^^
AttributeError: 'Texture' object has no attribute '_cached_image'

C:\Users\x\Desktop\WeatherSim>

```

The file structure is like this:

```
WeatherSim/
    WeatherSim.py
    Assets/
        Clouds/
            01.png
            02.png
            ...
            99.png
            100.png

```

Here is the code:

```
print("Loading modules ...",end="")
#from rich import print
from contextlib import contextmanager
import sys, os
print(" done")

print("Defining functions ...",end="")
@contextmanager
def no_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:
            yield
        finally:
            sys.stdout = old_stdout
print(" done")

print("Loading 3D engine ...",end="")
with no_stdout():
    from ursina import *
print(" done")

print("Defining clouds ...")

class _clouds:
    def __init__(self):
        # variables for self.cat list
        cum = "Cumulus"
        nimb = "Nimbus"
        alt = "Alto"
        els = "Else"
        big = "Big"

        self.cat = [None, # catalog of all cloud types for the 100 textures
            cum,
            cum,
            big,
            els,
            alt,
            nimb,
            cum,
            nimb,
            cum,
            cum,
            big,
            cum,
            alt,
            cum,
            big,
            cum,
            cum,
            els,
            nimb,
            big,
            cum,
            cum,
            cum,
            big,
            big,
            big,
            nimb,
            cum,
            nimb,
            big,
            cum,
            cum,
            alt,
            cum,
            alt,
            big,
            alt,
            cum,
            alt,
            cum,
            alt,
            cum,
            cum,
            cum,
            cum,
            cum,
            big,
            alt,
            alt,
            nimb,
            cum,
            cum,
            big,
            big,
            cum,
            cum,
            cum,
            cum,
            cum,
            nimb,
            alt,
            alt,
            alt,
            els,
            cum,
            alt,
            cum,
            cum,
            cum,
            alt,
            alt,
            cum,
            big,
            alt,
            big,
            cum,
            big,
            cum,
            big,
            cum,
            big,
            els,
            alt,
            big,
            cum,
            cum,
            cum,
            nimb,
            big,
            cum,
            alt,
            els,
            big,
            nimb,
            nimb,
            els,
            cum,
            cum,
            big,
            alt
        ]

        self.Clouds = { # sub-lists will be filled with Texture objects by load_texture()
            "Cumulus": [],
            "Nimbus": [],
            "Alto": [],
            "Else": [],
            "Big": []
        }

    def Load(self,id):
        self.Clouds[self.cat[int(id)]].append(load_texture("Assets/Clouds/"+id+".png"))
    def Load100th(self):
        self.Clouds[self.cat[101]].append(load_texture("Assets/Clouds/100.png"))

Clouds = _clouds()

print(" done")

print("Loading clouds ...")
for x in range(1,100):
    n = ("0"*(2-len(str(x))))+str(x)
    print(n)
    Clouds.Load(n)
Clouds.Load100th()

print(Clouds.Clouds)

```

What is the cause of this double error in Ursina's `texture.py` sub-module?

# Answer
According to this, it seems the engine needs to be initialized first; this code worked for me:

Replace the `with` statement on line 20 in the question with this:

```
with no_stdout():
    from ursina import *
    app = Ursina()

```
> 1 votes

---
Tags: python, ursina-engine
---


# Question
Title: Where is the illusion of a moving camera perspective coming from in this rotatable cube model?
Just for fun, I had been attempting to build a **model cube in vanilla JS** that can be moved and/or rotated. What I was going for was **the simplest possible representation** (so, no adjusting for perspective or anything: it just uses the literal x, y and z positions for each vertex).

The result I got is in fact 3-dimensional: rotating about the axes in the plane of the screen reveals the further-back vertices which were originally hidden. But the way it rotates isn't at all what I intended, since instead of spinning in place, it stretches, distorts, and even scales!

I asked a friend what was going on with this, and he said that what was actually happening was that the *camera perspective was changing*. (As opposed to the cube truly changing shape.) I confirmed that this is correct by superimposing my cube model on a representation of the 3 axes (x, y, z) and using the same rotation algorithm on the axes themselves - sure enough, their movement paralleled that of the cube.

This is the bizarre part, though: I did not try (and don't even know how) to program any kind of 'camera object'! What this cube simulation is supposed to do is 'physically' (or as close as you can get for a virtual object, anyway) move/spin the cube within a fixed coordinate space. Looking back over the code, I don't see any way that anything other than this could be happening, but it is.

I had also received feedback that it isn't possible to accurately represent a 3D object in 3D space, and that to work correctly, it would have to be modeled in 4 dimensions. While I know that this is true *in general*,\* that really doesn't seem like it should apply here.\** Especially, since it isn't an actual 3D cube, but instead the *projection* of a 3D cube onto a 2D plane (the screen), since only the x and y coordinates are used in actually *displaying* it (z is only there to calculate changes in x and y).

**So, what exactly is going on to create the 'moving camera' illusion, and is there a simple fix?** I want the cube to rotate in place, and the coordinate system to remain fixed. I would be very interested to learn where, specifically, my version diverges from the expected outcome, and whether or not the version I intended is actually possible to program using only 3 dimensions. I have included the complete code as a Stack Snippet, so you can see the strange results for yourself! (Translation works as intended, only rotation is problematic.)

Comments are included next to the relevant parts of the code to describe the method being used in modeling the rotations (basically, conversion back and forth from Cartesian to polar coordinates).

---

\*The general rule is that you need n + 1 dimensions to observe all possible rotations of an n-dimensional object - e.g. for a line (1D), you have to have a 2D plane to rotate it in; for a square (2D), you have to have a 3D space, etc.

\**In every case, there is always an exception to the n + 1 rule. It is possible to rotate an n-dimensional object in only n dimensions *within the dimension containing the object*. You can rotate a line segment within the line it is a part of; you can rotate a square within the theoretical infinite plane which contains it; it's only when the object *leaves* the dimension that originally contained it (as in the square being rotated perpendicularly to the original plane) that you need the extra dimension. Since we can't actually leave the 3rd dimension, it seems like *any* rotation being performed on a real 3D object should fit into this 'special case' that does *not* require an extra axis to represent.

```
// References: https://www.w3schools.com/graphics/canvas_drawing.asp and https://www.w3schools.com/jsref/api_canvas.asp

// CANVAS SETUP
var canvas = document.getElementById("_canvas");
var c = canvas.getContext("2d");
c.fillStyle = "rgb(0, 20, 0)";
c.fillRect(0, 0, 256, 256);

// GLOBAL VARIABLES
var CENTER = {x: 128, y: 128, z: 128};
var SIDE_LENGTH = 32;
var translationIncrement = 1;
var rotationIncrement = 1;
var mouseIsDown = false; // Potential Bug - You can cause infinite recursion inside the cube's translate and rotate methods by pressing down a button, then sliding the mouse off of the button before releasing the mouse.  Why would anyone do this, though? :D  (Can be stopped by clicking any of the translation buttons again)
var buttons = {
    translation: [
        {button: document.getElementById("translateX+"), action: function() { mouseIsDown = true; return theCube.translate('x', translationIncrement); }},
        {button: document.getElementById("translateY+"), action: function() { mouseIsDown = true; return theCube.translate('y', translationIncrement); }},
        {button: document.getElementById("translateX-"), action: function() { mouseIsDown = true; return theCube.translate('x', -translationIncrement); }},
        {button: document.getElementById("translateY-"), action: function() { mouseIsDown = true; return theCube.translate('y', -translationIncrement); }}
    ],
    rotation: [
        {button: document.getElementById("rotateX+"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('x', rotationIncrement); }},
        {button: document.getElementById("rotateY+"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('y', rotationIncrement); }},
        {button: document.getElementById("rotateZ+"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('z', rotationIncrement); }},
        {button: document.getElementById("rotateX-"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('x', -rotationIncrement); }},
        {button: document.getElementById("rotateY-"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('y', -rotationIncrement); }},
        {button: document.getElementById("rotateZ-"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('z', -rotationIncrement); }}
    ]
};
for (buttonSet in buttons) {
    for (var btn = 0; btn < buttons[buttonSet].length; btn++) {
        buttons[buttonSet][btn].button.addEventListener('mousedown', buttons[buttonSet][btn].action);
        buttons[buttonSet][btn].button.addEventListener('mouseup', function() { mouseIsDown = false; });
    }
}

// UTILITY FUNCTIONS
var toRadians = function(numberInDegrees) {
    return numberInDegrees * Math.PI / 180;
};
var toDegrees = function(numberInRadians) {
    return numberInRadians * 180 / Math.PI;
};
// Returns the angle (in degrees) representing a point's rotational position relative to the specified axis
// aboutAxis should be a string representing the name of the axis (capital or lowercase); center should be an object with x, y and z properties; coords should also be an object with x, y and z properties
var getAngleAboutAxisForPointRelToCenter = function(aboutAxis, center, coords) {
    // Vertical and horizontal displacements of coords relative to center
    var vrt, hrz;
    if (aboutAxis.toLowerCase() === 'x') {
        vrt = coords.y - center.y;
        hrz = coords.z - center.z;
    }
    else if (aboutAxis.toLowerCase() === 'y') {
        vrt = coords.z - center.z;
        hrz = coords.x - center.x;
    }
    else if (aboutAxis.toLowerCase() === 'z') {
        vrt = coords.y - center.y;
        hrz = coords.x - center.x;
    }

    // Avoid division by 0 inside expression to calculate the angle if the point is the same as the center of rotation
    if (!vrt && !hrz) {
        return undefined;
    }

    // The intermediate value A will be a value between 0 and 180 degrees.
    // Math.asin returns an angle which is 90 degrees offset from what you'd expect it to be, and also the negative of the expected value, so A is adjusted for this.  (The final absolute value call is to avoid the 0 degree angle being output as -0.)
    var A = Math.abs(-(toDegrees(Math.asin(hrz/(vrt**2 + hrz**2)**0.5)) - 90));

    // The vertical axis is inverted on the HTML canvas element!
    if (vrt > 0) { // QIII and QIV - angle is decreasing when it should be increasing.  Fix this by subtracting value from 360.
        return 360 - A;
    } else {
        return A; // QI and QII: No adjustments needed
    }
};
// Returns the differences in a point's vertical and horizontal coordinates after it has been rotated about the specified axis by angle degrees, centered on the specified center coordinates.
// aboutAxis should be a string representing the name of the axis (capital or lowercase); center should be an object with x, y and z properties; coords should also be an object with x, y and z properties
// initialAngle parameter is optional; it will be calculated inside this function only if it hasn't already been provided as input, to reduce unnecessary computations.
var getCoordChangesForPointRotatedAboutAxisRelToCenter = function(aboutAxis, center, coords, angle, initialAngle) {
    if (initialAngle === undefined) {
        initialAngle = getAngleAboutAxisForPointRelToCenter(aboutAxis, center, coords);
    }
    // Vertical and horizontal displacements of coords relative to center
    var vrt, hrz, vName, hName;
    if (aboutAxis.toLowerCase() === 'x') {
        vrt = coords.y - center.y;
        hrz = coords.z - center.z;
        vName = 'y', hName = 'z';
    }
    else if (aboutAxis.toLowerCase() === 'y') {
        vrt = coords.z - center.z;
        hrz = coords.x - center.x;
        vName = 'z', hName = 'x';
    }
    else if (aboutAxis.toLowerCase() === 'z') {
        vrt = coords.y - center.y;
        hrz = coords.x - center.x;
        vName = 'y', hName = 'x';
    }

    // Length of the line segment connecting the point to the center of rotation
    var distToCenter = (vrt**2 + hrz**2)**0.5;

    // The differences in horizontal and vertical positions
    diffs = {};
    // When rotating about x or z axis, the vertical coordinate will be y, which is inverted on the HTML canvas.
    var invertMultiplier = ((-1)**(aboutAxis.toLowerCase() === 'z' || aboutAxis.toLowerCase() === 'x'));
    diffs[hName] = distToCenter*(Math.cos(toRadians(angle + initialAngle)) - Math.cos(toRadians(initialAngle)));
    diffs[vName] = distToCenter*(Math.sin(toRadians(angle + initialAngle)) - Math.sin(toRadians(initialAngle)))*invertMultiplier;
    return diffs;
};

// CUBE MODEL PROTOTYPE
/* A hollow cube consists of |8 vertices| and |the set of all line segments, connecting those vertices, which are not diagonals| */
/** The argument for the 'center' parameter should be an object of the form {x: n1, y: n2, z: n3} where n1, n2 and n3 are Numbers; sideLength should be a Number */
var HollowCube = function(center, sideLength) {
    // Store references to the cube's dimensions and center position
    this.center = {x: center.x, y: center.y, z: center.z}; // Make a deep copy, not a shallow copy here
    this.sideLength = sideLength;

    // Format of each vertex is {x, y, z}
    this.vertices = [{x: center.x - 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z - 0.5*sideLength},
                     {x: center.x - 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z + 0.5*sideLength},
                     {x: center.x + 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z + 0.5*sideLength},
                     {x: center.x + 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z - 0.5*sideLength},
                     {x: center.x - 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z - 0.5*sideLength},
                     {x: center.x - 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z + 0.5*sideLength},
                     {x: center.x + 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z + 0.5*sideLength},
                     {x: center.x + 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z - 0.5*sideLength}];
    this.initialVertexAngles = [];
    // Initial angular positions of each vertex (represented as angles of rotation about the 3 axes)
    for (var i = 0; i < this.vertices.length; i++) {
        this.initialVertexAngles[i] = {
            x: getAngleAboutAxisForPointRelToCenter('x', this.center, this.vertices[i]),
            y: getAngleAboutAxisForPointRelToCenter('y', this.center, this.vertices[i]),
            z: getAngleAboutAxisForPointRelToCenter('z', this.center, this.vertices[i])
        };
    }
    // Cumulative angles of rotation about each axis, representing the cube's current position
    this.currentRotationsAboutAxes = {x: 0, y: 0, z: 0};
    // Amounts (Cartesian coordinates) by which each vertex is currently displaced from its initial position
    this.vertexDisplacementsFromInitial = [{x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0},
                                {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}];

    // Format of each edge is [vertex1, vertex2] where vertex1 and vertex2 are the indices of vertices in this.vertices - Note that each line is only specified once (i.e. all vertex pairs which would be duplicates have been omitted)
    this.edgesConnectingVertices = [[0, 1], [0, 3], [0, 4], [1, 2], [1, 5], [2, 3], [2, 6], [3, 7], [4, 5], [4, 7], [5, 6], [6, 7]];
    this.edgeColors = ["rgb(255, 0, 0)", "rgb(0, 0, 255)", "rgb(0, 255, 255)", "rgb(255, 255, 0)", "rgb(255, 0, 255)", "rgb(0, 255, 0)",
                       "rgb(0, 255, 255)", "rgb(255, 0, 255)", "rgb(0, 255, 0)", "rgb(255, 255, 0)", "rgb(0, 0, 255)", "rgb(255, 255, 0)"];

    // Used in setting a delay between recursive calls of the translation and rotation functions, when one of the buttons is pressed down
    this.onCooldown = false;
};
/** The argument for the 'alongAxis' parameter should be a string representing the letter name of an axis, either capital or lowercase.  The argument for the 'amountInPixels' parameter should be of type Number */
HollowCube.prototype.translate = function(alongAxis, amountInPixels, canvasContext = c) {
    this.center[alongAxis.toLowerCase()] += amountInPixels;
    for (var v = 0; v < this.vertices.length; v++) {
        this.vertices[v][alongAxis.toLowerCase()] += amountInPixels;
    }
    this.display(canvasContext);
    // Keep on moving the cube until the mouse is released; don't make the user have to click for every single increment
    if (mouseIsDown && !this.onCooldown) {
        this.onCooldown = true;
        // Inside setTimeout, 'this' no longer refers to the HollowCube object, so it is necessary to set up a new reference to the original object to use inside setTimeout.  It is important that the statement that resets the cooldown timer go INSIDE the inner wrapped function (not outside it!) in order for the timing to function as intended.
        var temp = function(obj) { return function() { obj.onCooldown = false; obj.translate(alongAxis, amountInPixels, canvasContext); }};
        var temp2 = this;
        setTimeout(temp(temp2), 10); // BARF - this is an ugly kludge :(
    }
};
/** The argument for the 'aboutAxis' parameter should be a string representing the letter name of an axis, either capital or lowercase.  The argument for the 'amountInDegrees' parameter should be of type Number */
HollowCube.prototype.rotateAboutOwnCenter = function(aboutAxis, amountInDegrees, canvasContext = c) {
    this.currentRotationsAboutAxes[aboutAxis.toLowerCase()] += amountInDegrees;

    // Reset this before calculating the current displacements, as they aren't cumulative (displacements are recalculated every time the cube is rotated, for the new resultant angle
    this.vertexDisplacementsFromInitial = [{x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0},
                                {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 0}];

    for (var i = 0; i < this.vertices.length; i++) {
        for (var axs in this.currentRotationsAboutAxes) {
            var rotn = getCoordChangesForPointRotatedAboutAxisRelToCenter(axs, this.center, this.vertices[i], this.currentRotationsAboutAxes[axs], this.initialVertexAngles[i][axs]);
            for (var cmpnt in rotn) {
                this.vertexDisplacementsFromInitial[i][cmpnt] += rotn[cmpnt];
            }
        }
    }

    this.display(canvasContext);
    // Keep on rotating the cube until the mouse is released; don't make the user have to click for every single increment
    if (mouseIsDown && !this.onCooldown) {
        this.onCooldown = true;
        var temp = function(obj) { return function() { obj.onCooldown = false; obj.rotateAboutOwnCenter(aboutAxis, amountInDegrees, canvasContext); }};
        var temp2 = this;
        setTimeout(temp(temp2), 10);
    }
};
/** Since the screen is 2-dimensional, the depth information (z-axis) cannot be used directly and is only perceived via its effects in calculating the new x and y coordinates when the cube is rotated. */
HollowCube.prototype.display = function(canvasContext) {
    // Redraw background to avoid the cube leaving trails across the canvas
    c.fillStyle = "rgb(0, 20, 0)";
    c.fillRect(0, 0, 256, 256);
    c.lineWidth = 2;
    for (var segment = 0; segment < this.edgesConnectingVertices.length; segment++) {
        canvasContext.beginPath();
        canvasContext.moveTo(this.vertices[this.edgesConnectingVertices[segment][0]].x + this.vertexDisplacementsFromInitial[this.edgesConnectingVertices[segment][0]].x, this.vertices[this.edgesConnectingVertices[segment][0]].y + this.vertexDisplacementsFromInitial[this.edgesConnectingVertices[segment][0]].y);
        canvasContext.lineTo(this.vertices[this.edgesConnectingVertices[segment][1]].x + this.vertexDisplacementsFromInitial[this.edgesConnectingVertices[segment][1]].x, this.vertices[this.edgesConnectingVertices[segment][1]].y + this.vertexDisplacementsFromInitial[this.edgesConnectingVertices[segment][1]].y);
        canvasContext.strokeStyle = this.edgeColors[segment];
        canvasContext.stroke();
    }
};

// INSTANTIATION
var theCube = new HollowCube(CENTER, SIDE_LENGTH);
theCube.display(c);
```

```
body {
    background-color: lightgreen;
}
div {
    background-color: green;
    width: 80%;
    margin-left: 10%;
    padding-top: 2%;
    padding-bottom: 2%;
}
button {
    background-color: lightgreen;
    color: darkgreen;
    font-weight: bold;
    height: 25pt;
}
```

```
<body>
   <div>
     <p align="center">
          <canvas id="_canvas" width="256" height="256"></canvas>
     </p>
     <p align="center">
          <button type="button" id="translateX+">Move Along Positive X</button>
          <button type="button" id="translateY+">Move Along Positive Y</button><br><br>
          <button type="button" id="translateX-">Move Along Negative X</button>
          <button type="button" id="translateY-">Move Along Negative Y</button><br><br><br>
          <button type="button" id="rotateX+">Rotate About X (+)</button>
          <button type="button" id="rotateY+">Rotate About Y (+)</button>
          <button type="button" id="rotateZ+">Rotate About Z (+)</button><br><br>
          <button type="button" id="rotateX-">Rotate About X (-)</button>
          <button type="button" id="rotateY-">Rotate About Y (-)</button>
          <button type="button" id="rotateZ-">Rotate About Z (-)</button>
     </p>
   <div>
</body>
```

P.S. This question is not a duplicate of the one here: 2D camera perspective projection from 3D coordinates -- HOW? because in that question, OP wanted to design a *perspective projection*, while I'm going for what I believe is called an 'orthographic projection' - one that does *not* use perspective. It is also not a duplicate of this one: Rotate object around fixed axis, because they're using 3D rendering software (not vanilla JS), and also quaternions (I'm specifically asking whether it's possible *without* modeling the cube in 4 dimensions).

---

**EDIT (a reply to the accepted answer):**

@Theraot, your version is everything I was going for in half the number of lines!

1. About your observation "I understand that you were trying to not move the vertex" - initially, I had tried a version that DID actually change the vertex coordinates for rotation as well as for translation. It also used the length of the internal diagonal from the cube's center to any one of the vertices in place of the `var distToCenter = (vrt**2 + hrz**2)**0.5;` equation. The problem was that somehow, a vertical asymptote was appearing at the 90 degree point: as the cube was rotated to this point, it started stretching infinitely instead of rotating past that point. Your version avoids that problem, so is actually more like the effect I originally wanted than was my 'patched' version with the `vertexDisplacementsFromInitial` .
2. Inside the (much streamlined) `rotateAboutOwnCenter` method, you're now *assigning* the vertices' positions to the rotation's components, instead of *incrementing* them. I see that you've added the extra term `+ center[(h/v)Name]` inside the function that performs the rotations, to be equivalent to the end result of adding the original vertex positions to the displacements in my version. What I'm still confused about is how yours works (and it *does* work perfectly) without having any kind of 'accumulator' to store the partial vs. total changes in each coordinate (x, y and z). In the original, I was calculating *delta(x) = xy + xz*, etc.: each coordinate's total change was the sum of two partial components from rotations about two different axes. With assignment instead of incrementation inside the for loop, shouldn't the second partial component just overwrite the first? Again, I know yours is correct, but just don't see *how*.
3. Now you have me really curious about how you would have fixed the button kludge! I'm also interested in seeing how the rotation matrix would replace my implementation which used individual, separate calculations for X, Y and Z axis rotations. I'm familiar with the concept of matrices from the one matrix algebra class I took, but it definitely isn't the way that naturally occurs to me to go about solving problems. A side-by-side comparison would be really neat, to see how the matrix version performs the calculations 'in parallel' instead of 'in series' (at least, I'd assume that it would). If I post a new question on the code review site, asking about how the cube model could be improved *in those two aspects specifically*, would you be interested in answering?

# Answer
> 1 votes
**On the camera illusion**

The camera projection (regardless of it being perspective, orthogonal, or something else) is a transformation or series of transformations.

When you move your cube, you move its vertices. This can be understood as applying a transformation to the vertices. And, you are, of course, having a 2D view of it. That is a projection.

So, there is a camera projection that is equivalent to - most※ - of what you are doing.

The illusion is further solidified by the fact that there aren't other objects moving independently. So we don't register it as an cube moving relative to something else.

*Something else that might or might not contribute to the illusion is the fact that you do not seem to define the rotation axis in the local space of the cube.*

※: With your current code it is possible to distort the cube in ways that an orthogonal camera would not.

---

There are, of course, no actual cameras in virtual video game worlds. It is all an illusion anyway. It just happens that this illusion is packaged in a re-utilizable component that we call "camera".

Such re-utilizable component would abstract the cumulative transformation you would apply to the vertices to account for the camera position, rotation, and so on. And thus, allowing you to keep the positions of the vertices fixed... Or move them only when they need to be moved relative to each other.

At the end, a frame must be rendered, and thus the transformation must be computed... And there more ways to get there than game engines. Literally.

*Of course, hardware and software architecture might make the solutions more or less converge.*

---

**On 4D**

No, you don't need to represent your cube with four coordinates per vertex.

What you describe about rotations makes no sense to me. For example, if you have a 1D line, sure you can rotate it in 2D, but you can also rotate it in 3D in ways that you cannot rotate it in 2D, and so on... There is no "observe all possible rotations". For rotation you only needs as many dimensions as the space you want to work with, and - as you point out - you are not trying to rotate beyond three dimensions.

Instead the push to work with 4D is something we do so we can have translation along with the other 3D affine transformation represented in a single transformation matrix.

That is, we can use a 3 by 3 matrix to represent scaling, rotating and skewing in 3D. But we need to augment it to add 3D translation in the same matrix (3D translation is a linear transformation in 4D, but only an affine transformation in 3D). But of course, for the vector-matrix multiplication to work, we would also have to augment the vectors with an extra component.

Working with transformation matrices is convenient because we can compose transformations by multiplying their matrices, and also because hardware is very fast at doing matrix multiplications.

By the way, the approach in which we have settled on for doing a perspective projection requires a 4 by 4 matrix. Which I know is not intuitive given that we are going to drop to two dimensions... But we need those two dimensions to be affected by the position on the third dimension in a non linear way, and we are encoding that in the fourth dimension. *More precisely we do it by working with homogeneous coordinates. We need the two dimension we are going to see. The third dimension for z-ordering. And the the fourth dimension is the non-zero scalar that makes them homogeneous, which is encoding foreshortening.*

So, if you use 4 by 4 matrices for all the transformation, you can have a whole stack of transformations (from positioning and scaling an object, to positioning a camera, to doing the perspective transformation) in a single matrix.

With all that said, I want to reiterate that four dimensions are not a requirement for 3D rotation, scaling or skewing.

---

**Addendum on Quaternions**

Quaternions are 4D numbers in the same sense that complex numbers are 2D numbers. Due to the way they are constructed, making 3D numbers the same way would not preserve all the properties of divisions.

As it turns out, *unit* quaternions (that is quaternions of length 1) are a convenient way to represent rotations and orientations. They can also be composed in a similar fashion as transformation matrices, but take less memory and less operations.

However, aside from optimizations, it is not necessary to use quaternions for 3D rotations. Although they are helpful in many cases.

---

**Fixing the rotation**

I understand that you were trying to not move the vertex. However, that made it harder for me. So I went on removing all the "current" and "initial" and "DisplacementsFromInitial", I don't care if the y axis is flipped, you can fix that... and replaced what I didn't understand with things I understand, until I got it working.

```
    // References: https://www.w3schools.com/graphics/canvas_drawing.asp and https://www.w3schools.com/jsref/api_canvas.asp

    // CANVAS SETUP
    var canvas = document.getElementById("_canvas");
    var c = canvas.getContext("2d");
    c.fillStyle = "rgb(0, 20, 0)";
    c.fillRect(0, 0, 256, 256);

    // GLOBAL VARIABLES
    var CENTER = {x: 128, y: 128, z: 128};
    var SIDE_LENGTH = 32;
    var translationIncrement = 1;
    var rotationIncrement = 1;
    var mouseIsDown = false; // Potential Bug - You can cause infinite recursion inside the cube's translate and rotate methods by pressing down a button, then sliding the mouse off of the button before releasing the mouse.  Why would anyone do this, though? :D  (Can be stopped by clicking any of the translation buttons again)
    var buttons = {
        translation: [
            {button: document.getElementById("translateX+"), action: function() { mouseIsDown = true; return theCube.translate('x', translationIncrement); }},
            {button: document.getElementById("translateY+"), action: function() { mouseIsDown = true; return theCube.translate('y', translationIncrement); }},
            {button: document.getElementById("translateX-"), action: function() { mouseIsDown = true; return theCube.translate('x', -translationIncrement); }},
            {button: document.getElementById("translateY-"), action: function() { mouseIsDown = true; return theCube.translate('y', -translationIncrement); }}
        ],
        rotation: [
            {button: document.getElementById("rotateX+"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('x', rotationIncrement); }},
            {button: document.getElementById("rotateY+"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('y', rotationIncrement); }},
            {button: document.getElementById("rotateZ+"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('z', rotationIncrement); }},
            {button: document.getElementById("rotateX-"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('x', -rotationIncrement); }},
            {button: document.getElementById("rotateY-"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('y', -rotationIncrement); }},
            {button: document.getElementById("rotateZ-"), action: function() { mouseIsDown = true; return theCube.rotateAboutOwnCenter('z', -rotationIncrement); }}
        ]
    };
    for (buttonSet in buttons) {
        for (var btn = 0; btn < buttons[buttonSet].length; btn++) {
            buttons[buttonSet][btn].button.addEventListener('mousedown', buttons[buttonSet][btn].action);
            buttons[buttonSet][btn].button.addEventListener('mouseup', function() { mouseIsDown = false; });
        }
    }

    // UTILITY FUNCTIONS
    var toRadians = function(numberInDegrees) {
        return numberInDegrees * Math.PI / 180;
    };
    var toDegrees = function(numberInRadians) {
        return numberInRadians * 180 / Math.PI;
    };
    // Returns the angle (in degrees) representing a point's rotational position relative to the specified axis
    // aboutAxis should be a string representing the name of the axis (capital or lowercase); center should be an object with x, y and z properties; coords should also be an object with x, y and z properties
    var getAngleAboutAxisForPointRelToCenter = function(aboutAxis, center, coords) {
        // Vertical and horizontal displacements of coords relative to center
        var vrt, hrz;
        if (aboutAxis.toLowerCase() === 'x') {
            vrt = coords.y - center.y;
            hrz = coords.z - center.z;
        }
        else if (aboutAxis.toLowerCase() === 'y') {
            vrt = coords.z - center.z;
            hrz = coords.x - center.x;
        }
        else if (aboutAxis.toLowerCase() === 'z') {
            vrt = coords.y - center.y;
            hrz = coords.x - center.x;
        }

        return toDegrees(Math.atan2(vrt, hrz));
    };
    // Returns the point's vertical and horizontal coordinates after it has been rotated about the specified axis by angle degrees.
    // aboutAxis should be a string representing the name of the axis (capital or lowercase); center should be an object with x, y and z properties; coords should also be an object with x, y and z properties
    // angle parameter is the desired rotation.
    var getCoordChangesForPointRotatedAboutAxisRelToCenter = function(aboutAxis, center, coords, angle) {
        var currentAngle = getAngleAboutAxisForPointRelToCenter(aboutAxis, center, coords);
        // Vertical and horizontal displacements of coords relative to center
        var vrt, hrz, vName, hName;
        if (aboutAxis.toLowerCase() === 'x') {
            vrt = coords.y - center.y;
            hrz = coords.z - center.z;
            vName = 'y', hName = 'z';
        }
        else if (aboutAxis.toLowerCase() === 'y') {
            vrt = coords.z - center.z;
            hrz = coords.x - center.x;
            vName = 'z', hName = 'x';
        }
        else if (aboutAxis.toLowerCase() === 'z') {
            vrt = coords.y - center.y;
            hrz = coords.x - center.x;
            vName = 'y', hName = 'x';
        }

        // Length of the line segment connecting the point to the center of rotation
        var distToCenter = (vrt**2 + hrz**2)**0.5;

        result = {};
        result[hName] = distToCenter*(Math.cos(toRadians(angle + currentAngle))) + center[hName];
        result[vName] = distToCenter*(Math.sin(toRadians(angle + currentAngle))) + center[vName];
        return result;
    };

    // CUBE MODEL PROTOTYPE
    /* A hollow cube consists of |8 vertices| and |the set of all line segments, connecting those vertices, which are not diagonals| */
    /** The argument for the 'center' parameter should be an object of the form {x: n1, y: n2, z: n3} where n1, n2 and n3 are Numbers; sideLength should be a Number */
    var HollowCube = function(center, sideLength) {
        // Store references to the cube's dimensions and center position
        this.center = {x: center.x, y: center.y, z: center.z}; // Make a deep copy, not a shallow copy here
        this.sideLength = sideLength;

        // Format of each vertex is {x, y, z}
        this.vertices = [{x: center.x - 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z - 0.5*sideLength},
                         {x: center.x - 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z + 0.5*sideLength},
                         {x: center.x + 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z + 0.5*sideLength},
                         {x: center.x + 0.5*sideLength, y: center.y - 0.5*sideLength, z: center.z - 0.5*sideLength},
                         {x: center.x - 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z - 0.5*sideLength},
                         {x: center.x - 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z + 0.5*sideLength},
                         {x: center.x + 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z + 0.5*sideLength},
                         {x: center.x + 0.5*sideLength, y: center.y + 0.5*sideLength, z: center.z - 0.5*sideLength}];

        // Format of each edge is [vertex1, vertex2] where vertex1 and vertex2 are the indices of vertices in this.vertices - Note that each line is only specified once (i.e. all vertex pairs which would be duplicates have been omitted)
        this.edgesConnectingVertices = [[0, 1], [0, 3], [0, 4], [1, 2], [1, 5], [2, 3], [2, 6], [3, 7], [4, 5], [4, 7], [5, 6], [6, 7]];
        this.edgeColors = ["rgb(255, 0, 0)", "rgb(0, 0, 255)", "rgb(0, 255, 255)", "rgb(255, 255, 0)", "rgb(255, 0, 255)", "rgb(0, 255, 0)",
                           "rgb(0, 255, 255)", "rgb(255, 0, 255)", "rgb(0, 255, 0)", "rgb(255, 255, 0)", "rgb(0, 0, 255)", "rgb(255, 255, 0)"];

        // Used in setting a delay between recursive calls of the translation and rotation functions, when one of the buttons is pressed down
        this.onCooldown = false;
    };
    /** The argument for the 'alongAxis' parameter should be a string representing the letter name of an axis, either capital or lowercase.  The argument for the 'amountInPixels' parameter should be of type Number */
    HollowCube.prototype.translate = function(alongAxis, amountInPixels, canvasContext = c) {
        this.center[alongAxis.toLowerCase()] += amountInPixels;
        for (var v = 0; v < this.vertices.length; v++) {
            this.vertices[v][alongAxis.toLowerCase()] += amountInPixels;
        }
        this.display(canvasContext);
        // Keep on moving the cube until the mouse is released; don't make the user have to click for every single increment
        if (mouseIsDown && !this.onCooldown) {
            this.onCooldown = true;
            // Inside setTimeout, 'this' no longer refers to the HollowCube object, so it is necessary to set up a new reference to the original object to use inside setTimeout.  It is important that the statement that resets the cooldown timer go INSIDE the inner wrapped function (not outside it!) in order for the timing to function as intended.
            var temp = function(obj) { return function() { obj.onCooldown = false; obj.translate(alongAxis, amountInPixels, canvasContext); }};
            var temp2 = this;
            setTimeout(temp(temp2), 10); // BARF - this is an ugly kludge :(
        }
    };
    /** The argument for the 'aboutAxis' parameter should be a string representing the letter name of an axis, either capital or lowercase.  The argument for the 'amountInDegrees' parameter should be of type Number */
    HollowCube.prototype.rotateAboutOwnCenter = function(aboutAxis, amountInDegrees, canvasContext = c) {
        for (var i = 0; i < this.vertices.length; i++) {
            var result = getCoordChangesForPointRotatedAboutAxisRelToCenter(aboutAxis, this.center, this.vertices[i], amountInDegrees);
            for (var component_index in result) {
                this.vertices[i][component_index] = result[component_index];
            }
        }

        this.display(canvasContext);
        // Keep on rotating the cube until the mouse is released; don't make the user have to click for every single increment
        if (mouseIsDown && !this.onCooldown) {
            this.onCooldown = true;
            var temp = function(obj) { return function() { obj.onCooldown = false; obj.rotateAboutOwnCenter(aboutAxis, amountInDegrees, canvasContext); }};
            var temp2 = this;
            setTimeout(temp(temp2), 10);
        }
    };
    /** Since the screen is 2-dimensional, the depth information (z-axis) cannot be used directly and is only perceived via its effects in calculating the new x and y coordinates when the cube is rotated. */
    HollowCube.prototype.display = function(canvasContext) {
        // Redraw background to avoid the cube leaving trails across the canvas
        c.fillStyle = "rgb(0, 20, 0)";
        c.fillRect(0, 0, 256, 256);
        c.lineWidth = 2;
        for (var segment = 0; segment < this.edgesConnectingVertices.length; segment++) {
            canvasContext.beginPath();
            canvasContext.moveTo(this.vertices[this.edgesConnectingVertices[segment][0]].x, this.vertices[this.edgesConnectingVertices[segment][0]].y);
            canvasContext.lineTo(this.vertices[this.edgesConnectingVertices[segment][1]].x, this.vertices[this.edgesConnectingVertices[segment][1]].y);
            canvasContext.strokeStyle = this.edgeColors[segment];
            canvasContext.stroke();
        }
    };

    // INSTANTIATION
    var theCube = new HollowCube(CENTER, SIDE_LENGTH);
    theCube.display(c);
```

```
body {
    background-color: lightgreen;
}
div {
    background-color: green;
    width: 80%;
    margin-left: 10%;
    padding-top: 2%;
    padding-bottom: 2%;
}
button {
    background-color: lightgreen;
    color: darkgreen;
    font-weight: bold;
    height: 25pt;
}
```

```
<body>
   <div>
     <p align="center">
          <canvas id="_canvas" width="256" height="256"></canvas>
     </p>
     <p align="center">
          <button type="button" id="translateX+">Move Along Positive X</button>
          <button type="button" id="translateY+">Move Along Positive Y</button><br><br>
          <button type="button" id="translateX-">Move Along Negative X</button>
          <button type="button" id="translateY-">Move Along Negative Y</button><br><br><br>
          <button type="button" id="rotateX+">Rotate About X (+)</button>
          <button type="button" id="rotateY+">Rotate About Y (+)</button>
          <button type="button" id="rotateZ+">Rotate About Z (+)</button><br><br>
          <button type="button" id="rotateX-">Rotate About X (-)</button>
          <button type="button" id="rotateY-">Rotate About Y (-)</button>
          <button type="button" id="rotateZ-">Rotate About Z (-)</button>
     </p>
   <div>
</body>
```

I was really tempted to start over (fix the button kludge, work in radians, etc). That might have resulted in something easier to understand. Had I followed that route I would have implemented this with rotation matrices. But perhaps having something at least similar to what you had is more helpful for you.

---

I'll expand the answer by going over the differences:

First the code for getting the angle:

```
    // Avoid division by 0 inside expression to calculate the angle if the point is the same as the center of rotation
    if (!vrt && !hrz) {
        return undefined;
    }

    // The intermediate value A will be a value between 0 and 180 degrees.
    // Math.asin returns an angle which is 90 degrees offset from what you'd expect it to be, and also the negative of the expected value, so A is adjusted for this.  (The final absolute value call is to avoid the 0 degree angle being output as -0.)
    var A = Math.abs(-(toDegrees(Math.asin(hrz/(vrt**2 + hrz**2)**0.5)) - 90));

    // The vertical axis is inverted on the HTML canvas element!
    if (vrt > 0) { // QIII and QIV - angle is decreasing when it should be increasing.  Fix this by subtracting value from 360.
        return 360 - A;
    } else {
        return A; // QI and QII: No adjustments needed
    }

```

I don't to want to think about it. This is mine:

```
    return toDegrees(Math.atan2(vrt, hrz));

```

Second, since I removed "initial" et.al. are gone, the function `getCoordChangesForPointRotatedAboutAxisRelToCenter` rotates. It returns the rotated vector. Similarly `rotateAboutOwnCenter` is much more straight forward.

Third, the constructor for `HollowCube` is simpler because there is less to initialize.

And finally in `display`, `vertexDisplacementsFromInitial` is gone.

---

**Addendum on how rotation works**

It is a conversion to polar coordinates. By using Pythagoras and `getAngleAboutAxisForPointRelToCenter`, we get the coordinates of the vertex expressed as distance to the center, and an angle around the rotation axis (passing through the center). Then we modify the angle, and convert back to Cartesians.

---

**Addendum on fixing the button kludge**

If I were re-implementing this code form nothing, I'd start by using `requestAnimationFrame` as game loop.

The code would be an state machine, with an idle state where it does nothing... And pressing each button changes the state according to the button function. Releasing the button changes the state back to idle.

Being this JavaScript, I would literally set a `function` to an `state` variable (and "idle" can be an empty function saving me a check).

Then `requestAnimationFrame` can call the `state` `function` each loop. I might also pass the elapsed time so I can work with speeds inside the `function`s for the different states.

---

**Addendum on using transformation matrices**

The rotation matrix only requires to know the `angle`, and it uses `sin` and `cos`. You would make a different one for each main axis.

However, the rotation matrix rotates around the origin. Since you want to rotate around an arbitrary center point, we first translate to make the center of rotation the origin. Then we do the rotation. And then do the inverse of the translation we did.

If we worked with an augmented 3 by 3 matrix (i.e. a rectangular 3 by 4 matrix) or with 4 by 4 matrices, then we could compose the translation, rotation, and inverse translation in a single matrix.

You can then opt to apply the changes, which means to do a vector-matrix multiplication to get the new position of the vertices and update them.

Alternatively, you can opt to accumulate the transformations. That is, you start with an identity matrix, and keep composing translation and rotation matrices according to the operations the user makes, and only do the vector-matrix multiplication for display. *And that accumulated transformation you keep, is your camera transformation (well, arguably it has both model and view matrices, see The view matrix finally explained.*

---

The vector-matrix multiplication can be understood as a series of dot products (so it boils down to multiplying and adding).

Be aware that for the vector-matrix multiplication with a 4 by 4 matrix you would need to also augment the vector. Since we want the vertex to be translated, we augment them with a `1.0` in the fourth dimension (that `1.0` gets multiplied with the translation stored in the matrix, and added to the other components). And after the transformation we don't need the fourth component anymore, so we can discard it, getting back to three dimension. *Unless it is a perspective transformation, in which case you first divide by whatever you got in the fourth component, so it is back to `1.0` before you discard it.*

---

The video series Triangles and Pixels might help you understand how transformation matrices are used (for matrices you want in particular the second video, but I still recommend the whole playlist). If you need more material, I recommend 3Blue1Brown videos on Linear Algebra.

And given that you are working with JavaScript, you might find Matrix math for the web useful for the code.

---
Tags: 3d, javascript, rotation, models
---


# Question
Title: 3rd Button on UI Seems to not Register the onClick.AddListener()
I have a `UIManager` meant to control the UI. The UI manager is attached to an empty game object.

The `Canvas` has three panels, each with a button. All the panels are initially set to inactive in the inspector.

When I run the program, the `WelcomePanel` displays. When I click the button on `WelcomePanel`, it closes the panel and sets the `GenerateTerrainPanel` to active *as intended*.

When I click the button on the `GenerateTerrainPane`l, it generates the terrain - so I know the call to the other class is working (*this method takes 4-5 minutes to execute*), and it closes the panel and then sets the `BuildTownCenterPanel` to active *as intended*.

But the button on that panel (`BuildTownCenterPanel`) will not execute the code attached to it.

I'm a noob, and way out of my league and trying to learn as I build my project. I thought I was understanding delegates/actions, and I do understand them enough to make the call across classes happen, but I cannot figure why this button doesn't seem to register the method passed in the `onClick.AddListener()` for the life of me. Any help is greatly appreciated.

Yes - `buildTownCenterBtn` is set to Interactable in the Inspector.

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

public class UIManager : MonoBehaviour
{
    // KEEP YOUR METHODS SIMPLE!

    // Create Actions
    Action onGenerateTerrain;

    [SerializeField]
    private GameObject generateTerrainPanel, welcomePanel, buildTownCenterPanel;
    [SerializeField]
    private Button welcomeGetStartedBtn, buildTownCenterBtn, generateTerrainBtn;

    // Start is called before the first frame update
    void Start()
    {
        // Add all our button listeners.
        welcomeGetStartedBtn.onClick.AddListener(onWelcomeGetStartedCallBack);
        generateTerrainBtn.onClick.AddListener(onGenerateTerrainCallBack);
        buildTownCenterBtn.onClick.AddListener(onBuildTownCenterCallBack);

        ShowWelcomePanel();

    }

    // Update is called once per frame
    void Update()
    {

    }

    // Define button callbacks.
    private void onWelcomeGetStartedCallBack()
    {
        HideWelcomePanel();
        ShowTerrainGeneratorPanel();
    }
    private void onGenerateTerrainCallBack()
    {
        // Call the GenerateNewTerrain() in TerrainGenerator.cs.
        onGenerateTerrain?.Invoke();
        // Call the method to show the next panel.
        ShowBuildTownCenterPanel();

    }

    private void onBuildTownCenterCallBack()
    {
        Debug.Log("This button works! You made it to onBuildTownCenterCallBack()!");
    }

    // This method allows GameManager.cs to assign the GenerateNewTerrain() in TerrainGenerator.cs to the onGenerateTerrain action.
    public void AddListenerOnGenerateTerrain(Action listener)
    {
        onGenerateTerrain += listener;
    }

    // Handle panels.
    private void ShowTerrainGeneratorPanel()
    {
        generateTerrainPanel.SetActive(true);

    }

    private void HideTerrainGeneratorPanel()
    {
        // I think the ? either ensures it's not null, or checks to see if it's active.
        generateTerrainPanel?.SetActive(false);
    }

    private void ShowWelcomePanel()
    {
        welcomePanel.SetActive(true);

    }

    private void HideWelcomePanel()
    {
        welcomePanel.SetActive(false);
    }

    private void ShowBuildTownCenterPanel()
    {
        generateTerrainPanel?.SetActive(false);
        buildTownCenterPanel.SetActive(true);

    }

}

```

# Answer
I found it. When I call the method GenerateNewTerrain(), is start by destroying all the game objects in the world unless they have a certain tag.

```
public void DestroyAllGameObjects()
    {
        GameObject[] GameObjects = (FindObjectsOfType<GameObject>() as GameObject[]);

        for (int i = 0; i < GameObjects.Length; i++)
        {
            if (!GameObjects[i].CompareTag("MainCamera") && !GameObjects[i].CompareTag("Light") && !GameObjects[i].CompareTag("EmptyObject") && !GameObjects[i].CompareTag("Terrain") && !GameObjects[i].CompareTag("UI"))
            {
                //Debug.Log("This ain't the camera.");
                Destroy(GameObjects[i]);
            }

        }
    }

```

When I had created my UIController as an empty game object, I never gave it a tag. Therefore, my GenerateNewTerrain() method was destroying the game object and the UIManager.cs that was attached to it, so the button had no script to control its behavior.

I discovered it this morning as I sat down to make a video to help you all understand.

This simple mistake has driven me mad for 3 or 4 days.

Thanks for taking a look, and for your willingness to help. Crisis averted for now.

Respectfully, Tim
> 1 votes

---
Tags: unity, c#, events, unity-ui
---


title: Audio source with multiple sound files

text:
# Question
Title: Audio source with multiple sound files
I am limited in the number of audio sources I can add. Is it possible to use a single audio source and then rotate between a collection of audio files. This is for an avatar for VRChat so scripting is not an option as scripts will be removed at build time. It would need to be a feature built into Unity that maybe I am just missing.

# Answer
> 0 votes
Put this script into the folder named Editor and you will get list with audioClips in your inspector. Set slider to count of elements and empty slots appear.

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

[CustomEditor(typeof(AudioSource))]
public class AudioSourceEditor : Editor
{
    public List<AudioClip> audioClips;

    [Obsolete]
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        EditorGUILayout.LabelField("Audio Clips:");
        EditorGUILayout.BeginHorizontal();
        {
            int count = EditorGUILayout.IntSlider("Count", audioClips.Count, 0, 10);
            if (count != audioClips.Count)
            {
                audioClips.Clear();
                for (int i = 0; i < count; i++)
                {
                    audioClips.Add(null);
                }
            }
        }
        EditorGUILayout.EndHorizontal();
        foreach (AudioClip audioClip in audioClips)
        {
            EditorGUILayout.ObjectField(audioClip, typeof(AudioClip));
        }
    }
}

```

# Answer
> -1 votes
Yes you can add to your script collection of AudioClips and then play them via audiosource.

```
[SerializeField] List<AudioClip> clips;
IEnumerator Start()
{
 AudioSource audio = GetComponent<AudioSource>();
 for(int i = 0;iclips.Count();i++)
    {
    audio.clip = clips[i];
    audio.Play();
    yield return new WaitForSeconds(audio.clip.length);
    i++;
    }
}

```

---
Tags: unity, audio
---


# Question
Title: Algorithms for large scale deformable terrain with multiple heights, i.e. not heightmap based
Every search I do results in heightmap based terrain, where you can't have a tunnel, or cave, etc within the terrain.

What good algorithms are there to do this kind of deformable terrain?

I'm aware of voxel based terrains, however I would like to explore not necessarily aligned, mesh based ones.

# Answer
A height map defines a height for each point of your plane tessellation mesh grid. So it is defining an offset on the vertical axis. Or, if you will, vertex displacement on the vertical axis.

Using a height map the traditional way to get overhangs is to add meshes on top of the terrain.

---

As alternative, instead of defining just a displacement on the vertical axis, you could define displacement on all axis... That is, you could define a vector. *It can still be a texture, except you use separate color channels for each axis.*

That is, you would use vector field displacement maps. *Yes, it is similar to vector displacement map in sculpting software, but I'm NOT asking to dynamically tesselate your mesh - to be fair, you could.*

First of all, this means that you can use the map to move the points along the plane of the terrain. Which means you can move points away from areas that need less detail, and towards areas that need more detail.

And once you have additional points in the areas where you need them, you can lift them off the terrain and sculpt them to make overhangs.

See HALO WARS: The Terrain of Next-Gen (GDC 2009).

---

However, what I said above is NOT enough for a tunnel or a cave system. The reason being that we are displacing the vertex, but the topology is the same. Thus, a hole through one side of the terrain to the other (such as a tunnel) is not possible.

For that, you could define holes in the terrain. That is, you use a mask to decide which vertex to discard (e.g. alpha scissors). And then stitch in the hole another mesh which might or might not have been created with the same tools.

And, of course, as you are already aware, you could instead work with voxels or implicit surfaces (and mesh them with marching cube or similar approaches).
> 2 votes

---
Tags: terrain
---


# Question
Title: Python ursina\mesh_importer.py: AttributeError: 'str' object has no attribute 'glob'
I'm making a weather simulator with Python's Ursina engine, but I cannot load models.

The error stack:

```
C:\Users\x\Desktop\WeatherSim>WeatherSim.py
...
Loading assets: Assets/Models/Plane.obj
Traceback (most recent call last):
  File "C:\Users\x\Desktop\WeatherSim\WeatherSim.py", line 207, in <module>
    Assets.LoadM("Empty","Assets/Models/Plane.obj")
  File "C:\Users\x\Desktop\WeatherSim\WeatherSim.py", line 163, in LoadM
    setattr(self,n,load_model(obj_to_ursinamesh(obj)))
                              ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\site-packages\ursina\mesh_importer.py", line 224, in obj_to_ursinamesh
    for f in path.glob(f'**/{name}.obj'):
             ^^^^^^^^^
AttributeError: 'str' object has no attribute 'glob'

C:\Users\x\Desktop\WeatherSim>

```

Some code (`import`s, the `Assets.LoadM()` function and the function call):

```
from contextlib import contextmanager

...

@contextmanager
def no_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:
            yield
        finally:
            sys.stdout = old_stdout

...

with no_stdout():
    from ursina import *
    from ursina.mesh_importer import *
    app = Ursina()

...

class _assets:
    ...
    # load a model and assigns it to the new attribute with name n to _assets
    def LoadM(self,n,obj):
        setattr(self,n,load_model(obj_to_ursinamesh(obj)))

Assets = _assets()

...

# the \r and end="" is so that it prints every "Load assets: ..." line in one line
print("\rLoading assets: Assets/Models/Plane.obj",end="")
Assets.LoadM("MeshPlane","Assets/Models/Plane.obj")

```

Also, I don't want to use Ursina's built-in `plane` mesh since mine has special UV coordinates, sizes, etc.

What is the cause of this error?

# Answer
You get this error because you don't pass the right thing to `obj_to_ursinamesh`.

I'm not sure whether you're using the engine the way it is meant to be used, so you need to be very much aware how to debug your code and find your way around when doing something exotic with a library.

In this specific case, you call `obj_to_ursinamesh` with a string. Looking at the function in the source of the engine, we find (formatted):

```
def obj_to_ursinamesh(path=application.compressed_models_folder,
        outpath=application.compressed_models_folder, name='*', return_mesh=True,
        save_to_file=False, delete_obj=False):
    if name.endswith('.obj'):
        name = name[:-4]

    for f in path.glob(f'**/{name}.obj'):
        # filepath = path / (os.path.splitext(f)[0] + '.obj')
        print('read obj at:', f)

[...]

```

Looking around, the `path` object that you pass as the first and single parameter is expected to be a `Path` from `pathlib`, not a string (it appears to be the type of `application.compressed_models_folder`).

Now looking at how the function is written, you need to pass the directory path as a separate argument from the actual model you want to load, unless you want to load all the models in that directory.

You'll likely need to call `obj_to_ursinamesh` like such:

```
obj_to_ursinamesh(path=Path('Assets/Models'), name='Plane')

```

or

```
obj_to_ursinamesh(path=Path('Assets/Models'), name='Plane.obj')

```

---

So the key takeaways here: dig, dig, dig deeper in the source engine to see how it works, how are the parameters composed, what is the chain of functions that are called.
> 0 votes

# Answer
This tells you that you've passed a value of type `str` (a string of text) where code down the line was expecting a type that has a method called `.glob`. Specifically, the variable that got this unexpected value was called "path".

Doing a quick web search with some key words from the call site, we can find that the Python library PathLib has a `Path` type that fits this description.

So somewhere you've passed a raw string where a function was expecting a `Path` object from this library.

Let's look at the Ursina docs to see what they say about how to use the `obj_to_ursinamesh` function. Note that they wrap their file path in a `Path()` constructor:

```
application.asset_folder = Path(r'''C:\Users\Petter\Downloads''')

```

So, make sure you wrap your asset path string into a `Path` object before passing it into a function from Ursina that expects paths.
> 0 votes

---
Tags: python, ursina-engine
---


# Question
Title: Do game engines draw terrain and textures every single frame?
Let's say I have multiple meshes of static terrain, consisting of rocks and dirt that do not move.

Does the game engine still need to draw static objects every single frame?

Therefore, is it necessary for the game engine to draw a terrain consisting of 35k quads with 100+ materials 60 times per second

If not, how can I inform the engine to refrain from updating the dirt, as it serves no functional purpose and remains static?

Would instructing the game engine to update the terrain less frequently conflict noticeably with a distance-based LOD system?

This may sound like a trivial question, but I'm asking because I reduced the refresh rate of some AI regardless of player FPS. I noticed that when the AI's FPS is 50% to 60% slower than the player's, the AI NPCs and enemies leave trails of double images behind.

If I set the terrain to refresh, for example, only once per second or even less frequently, would players see the terrain leaving double images behind? This shouldn't happen, right? Since the terrain doesn't store any movement or position data; it only consists of colors and geometry... or does it?

# Answer
A typical 3D game draws *everything* every frame.

That's because in a 3D game, even when content isn't moving/animating, your camera is very frequently moving continuously. So the system has to be able to draw the whole scene from a new perspective every 60th of a second (or whatever the framerate).

That case of a moving camera becomes your bottleneck, and you design around that. Even if the camera isn't *always* moving, you need to curate and engineer your content to fit in that time budget, so that when the camera *does* move, your framerate doesn't stutter.

Once your game is consistently able to draw the scene from scratch every frame, there's not a lot of added benefit to stopping it from doing so — the code to detect what can be re-used and render selectively adds complexity and could bog down a game that's already hitting a solid 60 fps. Even something that hasn't moved or changed since last frame might be *behind* something that *did* move, so it still needs to be re-drawn to fill the hole where that thing was previously (otherwise you get those trails of ghost images you describe).

It may be helpful for mobile games in terms of reducing heat and battery drain, but only if there are large swaths of time in your game when most of the screen stays frozen, pixel-for-pixel identical to the frame before. That does not describe many mobile games, which are usually animating constantly, and you want to make sure those frames where lots of stuff is happening stay fast too. So it makes more sense to focus on making the re-draw efficient than trying to skip re-draw entirely in the very rare cases when we could.

Some things we do to avoid *completely* redrawing complex terrain every frame include:

* Culling: detect which parts of the terrain are not going to be visible in this frame and skip rendering them entirely.
* LoD: draw simpler versions of the terrain mesh for distant parts, with simpler materials, or maybe even falling back on imposters over full meshes.

Updating the correct level of detail to use for each chunk can be a significant amount of work, but it can often be done at a low frequency, spreading the work across multiple frames, at the cost of having some objects drawn a little under-/over-detailed for a frame till the correct LoD is swapped. Avoiding visible pops during the transitions is a whole art of its own too.
* Dynamic resolution with temporal anti-aliasing and upscaling: here we render at a lower resolution from slightly jittered camera positions each frame, and keep a buffer of one or more previous frames. When picking the final colour for a pixel, we reproject its position to find where it was in the previous frames, and blend the colours from multiple frames together. This spreads the work of rendering a smooth, high-res image across multiple frames: we render less detail in any one frame, knowing we can reconstruct a lot of it with the context of previous frames.

Of course, when the camera is moving dramatically or lots of stuff is changing on screen, this is less effective, but it's mainly when things settle down that players are able to scrutinize the pixels, and that's when temporal techniques shine.
* Virtual texturing: a complex terrain material with tons of layered textures and procedural calculations can be expensive to evaluate for every on-screen pixel as we render each frame. Instead, we can detect which sections of terrain are visible and bake the swatch of material they need to a texture in memory, then render them by just sampling the texture instead of evaluating an expensive shader.

The virtual texture needs to be updated when new parts of the terrain enter view, or get close enough to need a higher resolution, but this can be done at a lower frequency than every frame, exploiting the persistence of detail we already calculated on previous frames.

These are fairly large tech investments, and not applicable or beneficial to every project, so profile carefully to determine where your major bottlenecks are and what areas will give you the most return on your investment for the least excess complexity.
> 3 votes

# Answer
Usually engines clean the color and depth buffers every frame. And, of course, also render everything every frame.

Some engines allow you to tell them to not clean the buffers, but they would still render everything every frame. *Which can yield some trippy results, including trails of images in the void (where there was nothing to render on top to replace them).*

Having some things render less frequently than others is usually not a feature.

*If we are not talking about disabling clearing the buffers, then the behavior I would expect is not double images, but having the object appear one frame, disappear because the engine cleared the buffers and rendered everything else, and then some frames later appear again for a single frame and so on.*

---

You might hack it by rendering to a texture/viewport and overlaying the result※, except, of course, render that less frequently. But it would stay in place in the screen as the camera moves.

I don't know the details of your terrain system, but even if it does not move, the camera does. And assuming the camera has moved but the image of the terrain has not been updated, it would look wrong.

*You could try further hackery to move the overlay on the screen according to camera motion. But it won't be perfect, as you are working with a 2D image at this point, so the perspective won't change. And also moving the overlay can't reveal parts of the terrain that were outside of what you rendered.*

※This is similar to what some games do for first person weapons so they don't clip into the scenario geometry. It is also similar to some old school crowd solutions that render a cluster of objects once and repeat it on the screen.

---

About level of detail, most of the time the model used the last frame is the same you want to use this frame, since you only swap models when the object passes some distance threshold. If you swap the model a few frames late it is unlikely to be a problem, and if it is, we are talking about popping.

Be aware that often this swap is done in CPU, not GPU. So this process does not need to be tied to the render frequency... While doing it faster than the render frequency is wasting effort, you can do it less frequently with moderate impact... Unless the player is moving way too fast for the frequency you pick.

*Updating the level of detail more or less frequently based on the speed at which the camera moves might be a good optimization.*

---

I remind you that rendering is not the same as updating. You might have object skip update/process/tick/whatever-your-engine-calls-them calls or update in a separate thread with a different frequency, and still have them render normally.
> 2 votes

---
Tags: performance
---


title: Player twitching in cinemachine 2d

text:
# Question
Title: Player twitching in cinemachine 2d
Good afternoon, currently my player shakes when you move it to the left or right. I am using cinemachine 2d virtual cammera.

Here's my movement script:

```
using Microsoft.Cci;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private float horizontal;
    private float speed = 8f;
    private float jumpingPower = 5f;
    private bool isFacingRight = true;
    public bool  OnGround = true;
    public int JumpNum = 1;

    [SerializeField] private Rigidbody2D rb;
    [SerializeField] private Transform groundCheck;
    [SerializeField] private LayerMask groundLayer;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }
    private void OnCollisionEnter2D(Collision2D collision)
    {
        OnGround = false;
        Debug.Log("InAir false");
    }
    private void OnCollisionExit2D(Collision2D collision)
    {

        OnGround = true;
        Debug.Log("InAir True");
    }
    void Update()
    {
        horizontal = Input.GetAxisRaw("Horizontal");

        if(Input.GetKeyDown(KeyCode.W) && JumpNum < 2)
        {
          rb.velocity = new Vector2(rb.velocity.x, jumpingPower);
           JumpNum++;
            //double jump
        }

        if (Input.GetKeyDown(KeyCode.W) && !OnGround && JumpNum >= 2)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpingPower);
            JumpNum = 1;
            //if jumpnum == 2, then reset jumpNum
        }

      //  if (Input.GetKeyDown(KeyCode.W) && rb.velocity.y > 0f)
       // {
            //rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f);
           // OnGround= false;
        //}
        //redundant

        Flip();
    }

    private void FixedUpdate()
    {
        rb.velocity = new Vector2(horizontal * speed, rb.velocity.y);
    }

    //private bool IsGrounded()
   // {
       // return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer);
   // }
   //doesn't work
    private void Flip()
    {
        if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f)
        {
            isFacingRight = !isFacingRight;
            Vector3 localScale = transform.localScale;
            localScale.x *= -1f;
            transform.localScale = localScale;
        }
    }
}

```

I looked at similar questions such as: https://www.reddit.com/r/Unity2D/comments/o84k7x/weird\_shaking\_with\_player\_controllercinemachine/

https://stackoverflow.com/questions/72441202/picked-up-object-is-shaking-when-moving#:~:text=The%20ways%20around%20this%20all%20revolve%20around%20either,the%20same%20time%20%28moving%20your%20interaction%20to%20Update%29.

https://stackoverflow.com/questions/35158051/twitching-objects-in-unity-during-camera-movement-in-2d

But the answers to those questions did not help me.

Is there any way to fix the player's shaking when moving it left or right?

# Answer
> 0 votes
```
using Microsoft.Cci;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private float horizontal;
    public float speed = 1f;
    private float jumpingPower = 5f;
    private bool isFacingRight = true;
    public bool  OnGround = true;
    public int JumpNum = 1;

    [SerializeField] private Rigidbody2D rb;
    [SerializeField] private Transform groundCheck;
    [SerializeField] private LayerMask groundLayer;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }
    private void OnCollisionEnter2D(Collision2D collision)
    {
        OnGround = false;
        Debug.Log("InAir false");
    }
    private void OnCollisionExit2D(Collision2D collision)
    {

        OnGround = true;
        Debug.Log("InAir True");
    }
    void Update()
    {
        horizontal = Input.GetAxisRaw("Horizontal");

        if(Input.GetKeyDown(KeyCode.W) && JumpNum < 2)
        {
            rb.AddForce(Vector2.up * jumpingPower, ForceMode2D.Impulse);
          //rb.velocity = new Vector2(rb.velocity.x, jumpingPower);
           JumpNum++;
            //double jump
        }

        if (Input.GetKeyDown(KeyCode.W) && !OnGround && JumpNum >= 2)
        {
            rb.AddForce(Vector2.up * jumpingPower, ForceMode2D.Impulse);
            JumpNum = 1;
            //if jumpnum == 2, then reset jumpNum
        }

      //  if (Input.GetKeyDown(KeyCode.W) && rb.velocity.y > 0f)
       // {
            //rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f);
           // OnGround= false;
        //}
        //redundant

    }

    private void FixedUpdate()
    {
        //rb.AddForce(Vector2.right * speed);
        rb.AddForce(new Vector2(horizontal * speed, 0f), ForceMode2D.Impulse);

        Flip();
    }

    //private bool IsGrounded()
   // {
       // return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer);
   // }
   //doesn't work
    private void Flip()
    {
        if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f)
        {
            isFacingRight = !isFacingRight;
            Vector3 localScale = transform.localScale;
            localScale.x *= -1f;
            transform.localScale = localScale;
        }
    }
}

```

I figured it out. Thank you so much for the help!

---
Tags: unity, 2d, cinemachine
---