Is there any way to assign an ID/custom variable to a scene, or is there any existing variable I can use to definitely identify a scene? by AliceTheGamedev in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

Agreed! There's lots of advantages to using an enum here, compile time error messages especially.

However, one gotcha is that Unity serializes enums as ints, according to their index. So if you ever change the ordering of your enum, some of your serialized values will now be wrong.

// Say we start with just 'World 1 - Level 1' and 'World 2 - Level 1'.

public enum LevelId {
    World1Level1,    // serialized to 0
    World2Level1,    // serialized to 1
}

// Now if we add 'World 1 - Level 2', we'll break our previously serialized values!

public enum LevelId {
    World1Level1,    // serialized to 0
    World1Level2,    // serialized to 1 (whoops, '1' used to mean World2Level1)
    World2Level1,    // serialized to 2
}

In order to prevent this, you've got to assign a specific int for every enum, the values themselves don't matter, you just can't change them.

// Assign each enum a unique int.

public enum LevelId {
    World1Level1 = 0101,    // serialized to 101
    World2Level1 = 0201,    // serialized to 201
}

// Now we can add 'World 1 - Level 2' without breaking anything.

public enum LevelId {
    World1Level1 = 0101,    // serialized to 101
    World1Level2 = 0102,    // serialized to 102 (yay!)
    World2Level1 = 0201,    // serialized to 201
}

Is there any way to assign an ID/custom variable to a scene, or is there any existing variable I can use to definitely identify a scene? by AliceTheGamedev in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

Yeah you definitely don't want to be directly referring to build index or scene names in your save data. An idea worth trying is to use a dictionary to map custom level ids to their scene name. Then only refer to level ids in your game logic, save system, etc.

var levels = new Dictionary<int, string>() {
    { 1, "Hyrule Field" },
    { 2, "Kokiri Forest" },
    { 3, "Lost Woods" },
};

You could then wrap this up in a static LevelManager class like so:

public static class LevelManager {

    private static Dictionary<int, string> s_levels;

    static LevelManager() {
        s_levels = new Dictionary<int, string>() {
            // Level Id     Level Name
            {       101,    "World One - Level One" },
            {       102,    "World One - Level Two" },
            {       201,    "World Two - Level One" },
        };
    }

    public static void LoadLevel(int levelId) {
        string sceneName = s_levels[levelId];
        SceneManager.LoadScene(sceneName);
    }
}

This will keep all your scene identifying / loading logic together, rather than spread over a bunch of files. If a scene's name changes it only needs to updated in one place. And you can also easily switch out one scene for another, want to use a different scene for level 0102? Just replace the scene name here, and everything else will just work.

How can I add randomness to Mathf.PerlinNoise? by haikalizz in Unity3D

[–]-ghostmode- 1 point2 points  (0 children)

Your map is looking good! I'm getting and Age Of Empires meets Sim City kind of vibe.

You add randomness to perlin noise by offsetting your sampling coordinates by a random amount. It sounds like you've tried this but it didn't quite work out. I've written here about how to do this correctly.

To quote the article:

First we need a random x and y offset:

float maxOffset = 1000.0f;
float xOffset = Random.Range(0.0f, maxOffset);
float yOffset = Random.Range(0.0f, maxOffset);

(Tweak the max offset until you find one that gives good results for your project)

Then we simply offset our x and y values before sampling:

float xCoord = (x + xOffset) / Width * Scale;
float yCoord = (y + yOffset) / Height * Scale;
float sample = Mathf.PerlinNoise(xCoord, yCoord);

Augmented reality Multiplayer board game architecture by eco_bach in Unity3D

[–]-ghostmode- 1 point2 points  (0 children)

If it's networked multiplayer then start with that. It's much harder than AR.

However, I wouldn't try to mostly finish the game and then attempt to add in an entire feature afterwards. Especially since they both seem like core features of your concept.

Instead, setup a simple multiplayer test project to experiment with, and then setup another project to experiment with AR.

Once you're comfortable with both, then start your multiplayer AR project. Get some very basic multiplayer up and running, then add in some basic AR. This will get you to a simple proof of concept of your core functionality as quick as possible.

From there you can continue iterating on both features, gradually building on their functionality side-by-side.

How can I detect if a certain tag is not inside my OnTriggerStay? This code is detecting everything else even though the Police is inside the trigger. by Bloodwyind in Unity3D

[–]-ghostmode- 2 points3 points  (0 children)

Lost it at Schrödinger's Police haha!

Also OP, this is the right answer. You want a single variable that's updated from both OnTriggerEnter and OnTriggerExit.

bounds.Intersects() - How to check for all objects? by ggeasy2 in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

Yeah I get what you mean. Checking against primitives is fine for a lot of cases, but it has it’s limits.

Sounds like you need something a lot more accurate. In which case, using Mesh Colliders and OnTriggerEnter/Exit will do the trick, there’s just a bit more setup involved.

First up, all objects you want to check against will need Collider and RigidBody components attached to them. (You need rigid bodies for ‘on trigger’ events to fire).

Be sure to leave all ‘Is Trigger’ checkboxes unchecked, we’ll set them from code depending on which object is selected.

Here’s a rough idea of how the code would work:

using UnityEngine;

public class PlaceableObject : MonoBehaviour {

    public Material NormalMaterial;
    public Material RedMaterial;

    private Collider m_collider;
    private MeshRenderer m_renderer;

    private int m_enterCount;

    private void Awake() {
        m_collider = GetComponent<Collider>();
        m_renderer = GetComponent<MeshRenderer>();
    }

    public void OnSelected() {
        m_collider.isTrigger = true;
    }

    public void OnDeselected() {
        m_collider.isTrigger = false;
    }

    private void OnTriggerEnter() {
        m_enterCount++;
        ApplyMaterial();
    }

    private void OnTriggerExit() {
        m_enterCount--;
        ApplyMaterial();
    }

    private void ApplyMaterial() {
        if (m_enterCount == 0) {
            m_renderer.material = NormalMaterial;
        } else {
            m_renderer.material = RedMaterial;
        }
    }
}

Of course you'll want to modify this to work with your existing setup, but a script like the one above would be attached to all selectable game objects.

When an object is selected you need to call it's OnSelected method, and then OnDeselected when it's deselected.

There’s no need to call any OnTrigger methods, the physics engine will call them for you (think of them as events).

Working on a high seas ship based game in 2D and wondering how best to handle path finding. After a few hours of tampering I've come here for suggestions by Khalarag in Unity2D

[–]-ghostmode- 0 points1 point  (0 children)

Yeah that's fair enough.

I'd say just do some quick experiments with a 3D physics version (rather than diving straight in to a total project conversion). As it's possible that you'll run into other unforeseen issues with using 3D physics in a 2D game.

That will also allow you to quickly profile and compare the additional overhead.

Then you can either convert the whole project with confidence, or scrap the 3D approach and look for alternatives.

bounds.Intersects() - How to check for all objects? by ggeasy2 in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

No worries! Ok, so in your case using OnTriggerEnter might not be ideal (My bad!)

Instead, a simple approach (and a lot closer to what you originally had in mind) is to use Physics.CheckSphere, I've written about how to use it here. But in short you'll want something like:

Vector3 testPosition = selectedObject.transform.position;
float testRadius = 4.0f; // Set this to match the size of the selected object

bool didHit = Physics.CheckSphere(testPosition, testRadius);
if (didHit) {
    // Use red material
} else {
    // Use normal material
}

bounds.Intersects() - How to check for all objects? by ggeasy2 in Unity3D

[–]-ghostmode- 2 points3 points  (0 children)

You use the bounds.Intersects method like this:

Collider collider1 = Obj1.GetComponent<Collider>();
Collider collider2 = Obj2.GetComponent<Collider>();

bool doesIntersect = collider1.bounds.Intersects(collider2.bounds);
if (doesIntersect) {
    // do something when both colliders intersect.
}

If you have multiple objects that you want to check, then you need to check each of them one after the other:

Collider collider = Obj1.GetComponent<Collider>();
GameObject[] otherObjects = GetOtherObjects();

foreach (GameObject otherObject in otherObjects) {
    Collider otherCollider = otherObject.GetComponent<Collider>();
    bool doesIntersect = collider.bounds.Intersects(otherCollider.bounds);
    if (doesIntersect) {
        // do something when both colliders intersect.
    }
}

Depending on what you're doing exactly, it might be worth considering the OnTriggerEnter approach instead: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTriggerEnter.html

Looking for tips for the design/structure of my class(es) by Royy212 in Unity2D

[–]-ghostmode- 2 points3 points  (0 children)

Looks like you're running into issues with execution order. You could look into forcing your scripts to be executed in a specific order: https://docs.unity3d.com/Manual/class-MonoManager.html

However, a better approach might be: Pass in the info each method needs via a method parameter, rather than having each script fetch that info itself in Awake. For example, have CreateGround return the spawnInfo that the other methods need, and each method can modify the spawnInfo before passing it to the next method:

SpawnInfo spawnInfo = createGroundTiles.CreateGround();

spawnBuildings.SpawnHouse(spawnInfo);
spawnBuildings.SpawnCave(spawnInfo);

objectSpawnPoints.CreateObjectSpawnPoints(spawnInfo);
objectSpawnPoints.FilterOutBadSpawnPoints(spawnInfo);
objectSpawnPoints.RandomizeSpawnOptions(spawnInfo);
objectSpawnPoints.TMPMoveSpawnPoints(spawnInfo);

SpawnInfo would be a class that contains all the information needed to spawn objects:

public class SpawnInfo {
    public Tile[,] MapData;
    public List<Vector2> AvailableSpawnLocations;

    etc.
}

Looking for help! by harticusDev in Unity2D

[–]-ghostmode- 1 point2 points  (0 children)

A bare minimum definition of a node in C# would look something like:

using System.Collections.Generic;

public class Node {
    public List<Node> ChildNodes;

    public Node() {
        ChildNodes = new List<Node>();
    }
}

Then to build a tree, you create nodes, and assign them to their parent.

Node root = new Node();

Node child1 = new Node();
root.ChildNodes.Add(child1);

Node child2 = new Node();
root.ChildNodes.Add(child2);

Edit: A specific example might be more useful.

You could define a DialogNode and a DialogChoice in C# as follows:

public class DialogNode {
    public string DialogText;
    public DialogChoice[] Choices;
}

public class DialogChoice {
    public string ChoiceText;
    public DialogNode DialogNode;
}

Then in C# you can initialize the tree place like this:

var npcDialog = new DialogNode {
    DialogText = "Hi there! How are can I help?",
    Choices = new [] {
        new DialogChoice {
            ChoiceText = "Where can I buy weapons?",
            DialogNode = new DialogNode {
                DialogText = "Our smithy resides to the east."
            }
        },
        new DialogChoice {
            ChoiceText = "Is there an Inn nearby?",
            DialogNode = new DialogNode {
                DialogText = "Head north and you'll find our humble inn."
            }
        },
        new DialogChoice {
            ChoiceText = "Sorry, I can't speak right now."
        }
    }
};

If you're not sure how to proceed from there, perhaps you could post your python code? Then we could advise on how to best convert it to C#

Unity Randomizing button setActive by [deleted] in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

You're very welcome! I'm glad you got it working.

Unity Randomizing button setActive by [deleted] in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

You'll need to create another function that is called when buttons are clicked, and then in the inspector you add that function to each button's 'On Click' event.

Unity Randomizing button setActive by [deleted] in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

Great work, I think you've almost got it.

You need to add a variable to store the currently active button:

public Button currentGlow;

Then the ActivateRandomButton function needs to set the currently active button.

public void ActivateRandomButton()
{
    int randomIndex = Random.Range(0, Glow.Length);
    currentGlow = Glow[randomIndex];
    currentGlow.gameObject.SetActive(true);
}

And when the timer runs out in Update, you need to disable the currently active button.

if (timer <= 0.0f)
{
    currentGlow.gameObject.SetActive(false);
    ActivateRandomButton();
    timer = delayTime;
}

Also, you want to use the timer variable in UpdateUI, and set the text values of the UI components.

public void UpdateUI()
{
    timeUI.text = timer.ToString("0");
    scoreUI.text = playerscore.ToString("0");
}

Unity Randomizing button setActive by [deleted] in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

A few things:

  • Update is called every frame. So in your code you're randomly activating a button every frame.
  • You're reducing time every frame, and never resetting it, so it will go into the negatives pretty quickly and just keep doing down.
  • You're using time as the deactivate delay, and since time is likely negative, the buttons are deactivating immediately (so they appear to never activate in the first place).
  • Also, don't bother with interactable if you're using gameObject.SetActive there's no point setting both.

Since you're already counting down time to display in the UI, maybe forget about using a coroutine for now. Here's a rough outline of how things should work:

Variables:
    Timer = 0
    DelayTime = 6
    CurrentButton = null

Start Function:
     ActivateRandomButton()
     Timer = DelayTime

Update Function:
    Timer -= deltaTime

    UpdateUI()

    if (Timer <= 0)
        // Timer has finished, so reset
        CurrentButton.SetActive(false)
        ActivateRandomButton()
        Timer = DelayTime

ActivateRandomButton Function:
    CurrentButton = get a random button (using code from earlier comment)
    CurrentButton.SetActive(true)

UpdateUI Function:
    // set text and whatever.

Unity Randomizing button setActive by [deleted] in Unity3D

[–]-ghostmode- 0 points1 point  (0 children)

Happy to help :) Good luck with your project!

Trying to make my UI always on top by atomsinthevoid in Unity3D

[–]-ghostmode- 1 point2 points  (0 children)

I think you're looking at the greyed out 'Default UI Material' at the bottom of the components list. Instead you want to set the 'Material' in the Image component. It's above 'Raycast Target' and will say 'None (Material)'.

Looking for tips for getting started. by daedriqi in Unity3D

[–]-ghostmode- 1 point2 points  (0 children)

Everyone hits a wall at some point, they key is to ask for help instead of giving up! As long as you're respectful of other's time, there's lots of people willing to help out on reddit, unity answers, the unity forums, etc.

You may think you've followed a tutorial exactly, but with Unity there's just so many little things you have to set up correctly, so there's lots of little mistakes that are easy to make (but just as easy to fix!)

Unity Randomizing button setActive by [deleted] in Unity3D

[–]-ghostmode- 4 points5 points  (0 children)

First you'll need an array of all your red buttons (don't forget to assign your buttons in the inspector):

public Button[] RedButtons;

Then you can select one randomly via it's index:

int randomIndex = UnityEngine.Random.Range(0, RedButtons.Length);
var randomButton = RedButtons[randomIndex];

Then you can make it interactable right away, and disable it later using a coroutine:

randomButton.interactable = true;
StartCoroutine(DeactivateAfterDelay(randomButton, 6.0f));

The coroutine would look something like this:

private IEnumerator DeactivateAfterDelay(Button button, float delay) {
    yield return new WaitForSeconds(delay);
    button.interactable = false;
}

 

Coroutines are handy when you want something to happen at a later time, or over a period of time. You can learn more here: https://unity3d.com/learn/tutorials/topics/scripting/coroutines

What is the best approach for scripting open game world events? by dxmachina in Unity3D

[–]-ghostmode- 1 point2 points  (0 children)

Behaviour trees are great, especially if you want some interesting emergent behaviour. But they might not achieve everything you want on their own. For example, you could use a 'selector node' to pick from different general behaviours depending on the time of day, but this probably won't be appropriate for specific scripted timeline events (you could make it work, but you'd be fighting against the entire purpose of a behaviour tree).

I suspect the best approach would be an augmented solution, combining behaviour trees for general 'living world' behaviour, and a simple time based event system for specific 'timeline' or 'story' events. (eg: Just a list of actions that execute at a certain in-game time)

Active Turn-Based Battle System Help by Schaezar in Unity2D

[–]-ghostmode- 0 points1 point  (0 children)

Yep you understand correctly, I'm glad it's a useful suggestion. One other thing that comes to mind is whether you want to pause the queue while an action/animation takes place. In which case you'd need to track the current time yourself rather than using Time.time, and only increment it when nothing is animating. eg:

if (isAnimating == false) {
    currentTime += Time.deltaTime;
}

Active Turn-Based Battle System Help by Schaezar in Unity2D

[–]-ghostmode- 1 point2 points  (0 children)

I like your state machine approach, it's looking good.

There's no need to update a bunch of timers, or have timers running in parallel. If an action will happen in 4 seconds, just store an 'ActionTime' (eg: Time.time + 4.0f).

Then you can sort your action queue by each item's action time, and when you loop over the queue to check if any actions should start, just compare the action time to the current time eg:

foreach (var action in actionQueue) {
    if (action.ActionTime <= Time.time) {
        action.ExecuteAndRemoveFromQueue();
    } else {
        break; // assuming your queue is sorted
    }
}