#just wanna respawn my enemy lol

1 messages · Page 1 of 1 (latest)

slow cedar
#
public void Respawn()
    {
        GameObject NewMan = Instantiate(Respawner);
        NewMan.SetActive(true);
        NewMan.transform.position = StartPos;
        NewMan.transform.parent = transform.parent.parent.parent;
        NewMan.GetComponent<Timed2>().Timer = Mathf.RoundToInt(RespawnTime);
    }```
#

NewMan is the Respawner object. it does get instantiated fine, however, when it does, the "ToRespawn" in Timed2 changes to being a missing gameobject

#

the Respawner object is inside of the prefab initially, if that means something.

slow cedar
#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Timed2 : MonoBehaviour
{
    // Start is called before the first frame update
    public int Timer;
    public GameObject toRespawn;
    public Transform TheParent;
    public IEnumerator RespawnIt()
    {
        yield return new WaitForSeconds(0.1f);
        yield return new WaitForSeconds(Timer);
        GameObject aNew = Instantiate(toRespawn);

    }
    void Start()
    {
        StartCoroutine(RespawnIt());
    }
}
lyric sierra
#

Post the entire script containing Respawn()

slow cedar
#

there's a lot in there that's not used yet. I really thought the respawning part would be the easiest thing lol

lyric sierra
#

The best approach is to Debug.Log() each step

#

helps figure out what goes wrong

#

and where

slow cedar
#

oop this line:

NewMan.GetComponent<Timed2>().TheParent = transform.parent.parent.parent;

is irrelevant as I wound up not using that bit

lyric sierra
#

Alright.

#
void HasDied()
    {
        Destroy(transform.parent.parent.gameObject, 0.5f);
    }

I believe that when you delete a parent object, it also deletes the children.

slow cedar
#

yes. but that's why I made a clone of the respawner object first

#

it gets put into the scene right as the enemy gets deleted

#

before game starts:

#

the instant the game starts this happens:

#

and then when health is 0, there is a Respawner(Clone) in the scene, which has this instead:

lyric sierra
#

You have three options:

#
  1. Upload project folder as a compressed archive (except Libraries) so I can make an attempt to fix your unique case
  2. Recreate the solution from scratch, with a more top-down or Manager approach
  3. Follow someone else's example from an online article or tutorial
slow cedar
#

damn bot what

lyric sierra
#

Damn bots blocking reaction gifs even in threads xP

slow cedar
#

it insta joined the thread too

#

crazy

#

it'd probably be best to go for 2. I didn't think it'd be necessary to do that.

lyric sierra
#

<insert Pink Floyd meme>
Leave those threads alone! xD

slow cedar
#

I know how I'd implement case 2, but then I have to restructure the entirety of how the enemies work

#

which is a pain

#

it seems illogical that just because it's in a prefab, it can't refer to the prefab. but there must be something I'm missing

lyric sierra
#

Hm. Maybe ask for a good approach to the Practical Idea of your solution. I don't have that much experience.

slow cedar
#

everything works except the respawning lol. and it feels a bit scummy to send somebody the entire project just to fix something that I'm probably just oblivious to

lyric sierra
#

Imagine this: One script to rule the entire process.
A dictator parent.

slow cedar
#

hmm that's a good point actually

lyric sierra
#

the children should only react to the parent's instructions

slow cedar
#

if I have a general manager for the respawning of enemies and all enemies are contained within, each enemy could respectively call the respawner

#

it seemed overcomplicated when I thought about it initially but in the long run it's probably a good idea

#

a dictator parent. nice

lyric sierra
#

Do you want a 30min mini-course in Object Oriented Programming?
an example I recently created - SpriteBlinker

slow cedar
#

😅 that would be cool, but I am far too broke to get any sort of course rn

lyric sierra
#

the Object Oriented Programming approach is good when there is much interactivity in code. Manager-style.
This is as opposed to using components (MonoBehaviour)
Not strictly necessary in all cases, but can give a better degree of predictability and thus control.

#

I'm not talking money, just casual conversation

slow cedar
#

o

lyric sierra
#

create or duplicate a Game Object with a SpriteRenderer, which you can easily see

slow cedar
#

should I do this in 2d?

lyric sierra
#

Unity works with both 2D and 3D.
A SpriteRenderer is 2D

#

you just need to be able to see a sprite

slow cedar
#

ok

#

@lyric sierra

lyric sierra
#

good stuff

#
using UnityEngine;

public class SpriteBlinkComponent : MonoBehaviour
{
    [Range(0f, 1f)] [SerializeField] private float alpha = 0.2f;
    [SerializeField] private float duration = 5.0f;
    [SerializeField] private float frequency = 0.2f;

    public bool isBlinking;
    
    private SpriteRenderer sprite;
    private Color colorSprite;
    private Color colorAlpha;
    private bool blink;
    private float blinkTimer;
    private float effectTimer;


    private void Awake()
    {
        sprite = GetComponent<SpriteRenderer>();
        colorSprite = sprite.color;
        colorAlpha = new Color(1f, 1f, 1f, alpha);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.B))
        {
            isBlinking = true;
        }

        if (isBlinking)
        {
            Blink();
        }
    }

    private void Blink()
    {
        effectTimer += Time.deltaTime;
        blinkTimer += Time.deltaTime;

        if (blinkTimer >= frequency)
        {
            blinkTimer -= frequency;
            blink = !blink;
        }

        if (blink)
        {
            sprite.color = colorAlpha;
        }
        else
        {
            sprite.color = colorSprite;
        }

        if (effectTimer >= duration)
        {
            effectTimer = 0f;
            blinkTimer = 0f;
            isBlinking = false;
            sprite.color = colorSprite;
        }
    }
}
#

This is a typical MonoBehaviour script

#

add it as a component to the game object

#

This is what it does:

slow cedar
#

he do be blinkin

lyric sierra
#

When isBlinking is true, it will start to play the Blink() effect
Blink() lasts for a duration
and the Sprite will blink between 0.2f and its original alpha (opacity / transparency)

#

this is achieved by setting the sprite.color to a different color
the alpha cannot be changed directly when on a sprite

#

Simple enough

slow cedar
#

mmk

lyric sierra
#

The OOP (Object Oriented Programming) approach rewrites the MonoBehaviour to a standard C# class, and instantiates it in a Manager type script

#
using UnityEngine;

public class SpriteBlinker
{
    private float alpha = 0.2f;
    private float duration = 5.0f;
    private float frequency = 0.2f;

    private SpriteRenderer sprite;
    private Color colorSprite;
    private Color colorAlpha;
    private float blinkTimer;
    private float effectTimer;
    private bool blink;
    private bool isBlinking;
    
    public float Alpha
    {
        get { return alpha; }
        set
        {
            alpha = Mathf.Clamp01(value);
            colorAlpha.a = alpha;
        }
    }

    public float Duration
    {
        get { return duration; }
        set { duration = value; }
    }

    public float Frequency
    {
        get { return frequency; }
        set { frequency = value; }
    }

    public SpriteBlinker(SpriteRenderer sprite, float alpha = 0.2f, float duration = 5.0f, float frequency = 0.2f)
    {
        this.sprite = sprite;
        this.alpha = alpha;
        this.duration = duration;
        this.frequency = frequency;

        colorSprite = sprite.color;
        colorAlpha = sprite.color;
    }

    public void Blink()
    {
        isBlinking = true;
    }

    public void Listen()
    {
        if (isBlinking)
        {
            effectTimer += Time.deltaTime;
            blinkTimer += Time.deltaTime;

            if (blinkTimer >= frequency)
            {
                blinkTimer -= frequency;
                blink = !blink;
            }

            if (blink)
            {
                sprite.color = colorAlpha;
            }
            else
            {
                sprite.color = colorSprite;
            }

            if (effectTimer >= duration)
            {
                effectTimer = 0f;
                blinkTimer = 0f;
                isBlinking = false;
                sprite.color = colorSprite;
            }
        }
    }
}
#
using UnityEngine;

public class PlayerManager : MonoBehaviour
{
    private SpriteRenderer sprite;
    private SpriteBlinker blinker;

    private void Awake()
    {
        sprite = GetComponent<SpriteRenderer>();

        blinker = new SpriteBlinker(sprite);
        blinker.Alpha = 0.2f;
        blinker.Duration = 2.5f;
        blinker.Frequency = 0.2f;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.X))
        {
            blinker.Blink();
        }

        blinker.Listen();
    }
}
#

There are two concepts which might be unfamiliar to you

#
  1. Properties (public get set)
  2. this.variable = variable
slow cedar
#

uhhh quick question

#

I applied the scripts and ran it

#

when I pressed X unity crashed

#

lol

lyric sierra
#

Properties are best practice when it comes to OOP
In this solution, I use it to validate the input of the setter in Alpha, because simply changing the value doesn't reflect all the changes I need

#

Hm

slow cedar
#

the whole screen went black for a sec

lyric sierra
#

That's unexpected. I hope you had saved your project?

#

Huh.

#

How old is your computer?

slow cedar
#

idk. it's a windows 7 pc

lyric sierra
#

if the Harddrive is 6 years old it could fail any day

#

invest in SSD if you can. Mechanical HDDs are slow.

#

speeds up the entire computer

slow cedar
#

oop not sure if this is relevant but I had named it wrong

#

not sure how that could've caused a crash but

lyric sierra
#

just name things the same things I've named them, unless you have another PlayerManager

#

the Class name needs to be the same as the Script name

slow cedar
#

hey how I do the reloading scripts thing or whatever for VS again?

lyric sierra
#

What do you mean?

slow cedar
#

you mentioned it earlier when I was talking about using the other unity version

#

I can't remember the right word for it

lyric sierra
#

Regenerate Project Files

#

Edit > Preferences

slow cedar
#

ah ok there we go

#

pretty sure I broke Unity somehow when I changed the script cos then all of a sudden it's expecting a mono where theres no mono and it shouldn't have been able to be on an object in the first place lol.
got it working now

lyric sierra
#

In order to test the OOP script - remove the SpriteBlinkerComponent from the game object, and add the PlayerManager
the SpriteBlinker class only needs to exist in a file on the project

slow cedar
#

yeah I figured that out

#

pretty sure it breaks unity if you don't do that

lyric sierra
#

looks like it :)

slow cedar
#

now you could send it to people to break their game

#

jk jk

#

but ye works like a charm now

lyric sierra
#

so, at this point, study the difference between the two different approaches - Class vs MonoBehaviour

#

Any questions about Properties?

slow cedar
#

ehh I think they make sense logically. I haven't done a whole lot with just Classes but I get the jist of it, ish.

lyric sierra
#
// Fields
    private float alpha = 0.2f;
    private float duration = 5.0f;
    private float frequency = 0.2f;

// Properties
    public float Alpha
    {
        get { return alpha; }
        set
        {
            alpha = Mathf.Clamp01(value);
            colorAlpha.a = alpha;
        }
    }

    public float Duration
    {
        get { return duration; }
        set { duration = value; }
    }

    public float Frequency
    {
        get { return frequency; }
        set { frequency = value; }
    }

#
// This is the Constructor. It is called upon initializing a new SpriteBlinker()
public SpriteBlinker(SpriteRenderer sprite, float alpha = 0.2f, float duration = 5.0f, float frequency = 0.2f)
{
    this.sprite = sprite;
    this.alpha = alpha;
    this.duration = duration;
    this.frequency = frequency;

    colorSprite = sprite.color;
    colorAlpha = sprite.color;
}
#

this. refers to the sprite variable of the class (fields)
while simply sprite will refer to the Local Variable of the method, which is the Constructor

#

it was not necessary to use this. as I could just name the Local Variables differently

#

but it's less tedious, and Visual Studio 2022 makes it very easy to autocomplete when that is used

slow cedar
#

I see

lyric sierra
#

now, the SpriteBlinker could arguably simply be a component
but if you want other scripts to interact, it would be easier this way, and more controllable

#

if you need multiple scripts to catch each other's callbacks during Update, you will have to make sure the Logical Execution Order is correct, but in Unity the order is arbitrarily linked to the order of instantiation, as far as I've observed

#

using an OOP approach negates those issues

slow cedar
#

so you're suggesting having an OOP thing for managing the respawning of any given enemy

#

in essense

lyric sierra
#

More than less. If not OOP, I would strongly advise a top-down design.

#

if you have a SpawnManager, simply tell it that an object is supposed to die, and then the SpawnManager destroys it, and also spawns another

slow cedar
#

so with a spawnmanager, how would I get the prefab instance of anything inside?
say I have a function in the spawnmanager script that gets a copy of the enemy, destroys the enemy, waits X seconds, and places in the copy.
is that doable dynamically? or would each enemy in this instance require a preset spawn manager?

#

[assuming not OOP, that is]

#

so the argument passed to the function would just be like
a respawntime, a position, and the correct prefab

lyric sierra
#

let's say you have a game object named SpawnManager, along with a MonoBehaviour script with the same name

slow cedar
#

alright

lyric sierra
#

sec

#
using UnityEngine;

public class SpawnManager : MonoBehaviour
{
    public SpawnManager Instance;

    [SerializeField] private GameObject myPrefab;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else if (Instance != this)
        {
            Destroy(gameObject);
        }

        DontDestroyOnLoad(this.gameObject);
    }

    public void Respawn(GameObject todestroy)
    {
        // Code to destroy
        Instantiate(myPrefab);
    }
}
#

sec, having issues

slow cedar
#

what is the usage of the Awake()? is that just so its persistent through scenes?

lyric sierra
#

Yes. It creates a static instance of the script, which will be accessible to all other scripts
But there can only be one, which that code ensures.

slow cedar
#

ah

#

I get it, but how can this apply to multiple different enemies? say I have idk, a goblin and a warrior. both with different starting locations.
I could do a check in the Respawn void, but then I need to have several myPrefab instances from the start, one for every single enemy

#

or is there more to this?

lyric sierra
#

It makes things simple, but right now I have no idea why the example I'm creating is not working,
so for now, here's an example from my existing code

#
private void OnCollisionExit2D(Collision2D collision)
{
    // Damage Bricks
    if (collision.gameObject.layer == layerBricks)
    {
        //LevelManager.instance.bricks.Find(x => x.name == collision.gameObject.name).TakeDamage(ballDamage);
            
        string name = collision.gameObject.name;

        LevelManager.instance.DealDamageToBrick(name, ballDamage);
            
        DebugLine(name);
    }
}
#

LevelManager.instance.DealDamageToBrick(name, ballDamage);

#

the idea is that the Manager contains the functions

#

and other game objects can trigger those functions

#

by activating them, and passing along information

#

by making the Manager accessible via a static instance,
it enables the other scripts to access your "game functions" like any other C# or Unity function

#

this isn't easy to wrap one's head around
I'm currently in the process of rethinking my current project, and I think the next one after that will be fully OOP

#

but it's very logical, especially since you get to create the language that runs your game

slow cedar
#

I dig it

lyric sierra
#

the words we use when thinking about logic have a lot to say about how we arrive at a solution
that's why we often answer ourselves when typing out questions xD

slow cedar
#

is this flawed at all? am I missing any key components here? trying to follow along.

#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RespawnAnyEnemy : MonoBehaviour
{
    public RespawnAnyEnemy Instance;
    public List<GameObject> Guys = new List<GameObject>();
    GameObject CloneHim;
    Transform GottenParent;
    private void Start()
    {
      foreach(Transform Enemy in transform)
        {
            GameObject Copy = Instantiate(Enemy.gameObject);
            Copy.SetActive(false);
            Guys.Add(Copy);
        }
    }
    public IEnumerator RespawnHim(GameObject Him, Vector3 StartPos, float Time)
    {
        foreach(GameObject WhoIsIt in Guys)
        {
            if (WhoIsIt.name == Him.name)
            {
                if (WhoIsIt.transform.position == StartPos)
                {
                    CloneHim = Instantiate(WhoIsIt) as GameObject;
                    GottenParent = WhoIsIt.transform.parent;
                    yield break;
                }
            }
        }
        if (CloneHim != null)
        {
            yield return new WaitForSeconds(Time);
            GameObject Respawned = Instantiate(CloneHim) as GameObject;
            Respawned.transform.position = StartPos;
            Respawned.SetActive(true);
            Respawned.transform.parent = GottenParent;
        }
    }
}```
#

I don't have the bit in there that makes sure theres only one instance

#

is that required for it to work?

lyric sierra
#

only if you change scene, or have any way of potentially spawning more managers

slow cedar
#

alright.

lyric sierra
#

if you change scene without DontDestroyOnLoad the Manager will forget everything that happened

slow cedar
#

gotcha.

#

my thinking here is that it'll store a copy of all enemies within it, and then the enemies can call the respawn script

lyric sierra
#

tbh I need more food to properly analyze your code

slow cedar
#

oh, I literally forgot to have it destroy the original

#

lol

lyric sierra
#

just make sure you don't destroy the asset prefab, but the game object

#

and if you EVER use DestroyImmediate() for the Editor, make absolutely sure it does Not target an asset, because it will permanently delete it

slow cedar
#

Question

#

you can destroy asset prefabs with code?!

#

that seems dangerous

#

lol

lyric sierra
#

in Play Mode, changes do not persists

#

if you're going to destroy object while in Editor Mode, you must use DestroyImmediate() instead of Destroy()
But if you target an asset, it will be poof gone

slow cedar
#

that'd be a big f

lyric sierra
#

export your complex prefabs

#

to avoid fuckups like that

slow cedar
#

if I pass a GameObject to a function, and that gameobject is something like "transform.parent", that won't target the prefab, right?

#

I mean, I didn't even know prefabs were deletable like that, so

lyric sierra
#

Destroy(gameObject) // ok
DestroyImmediate(gameObject_inTheScene) // ok
DestroyImmediate(gameObject_WhichIsAnAsset) <--- avoid

slow cedar
#

gotcha

#

so how can I reference to my RespawnAnyEnemy script as you have referenced to your LevelManager? if I try to do
RespawnAnyEnemy.RespawnHim() I just get an error currently

#

oh nvm

#

just didn't understand what vs was saying

lyric sierra
#

kk

slow cedar
#

ah there we go

#

I got a different error

#

lol

lyric sierra
#

progress

slow cedar
#

fact

lyric sierra
#

post the line of code

slow cedar
#
StartCoroutine(RespawnAnyEnemy.RespawnHim(transform.parent.parent.gameObject,StartPos,RespawnTime));
lyric sierra
#

Better: Make a function which starts the coroutine from the manager

slow cedar
#

oo true

#

will do that

#

but it is still not able to get RespawnAnyEnemy for some reason

lyric sierra
#

oh god

#

I forgot something xD

#

public static SpawnManager Instance;

slow cedar
#

ah I thought static was needed somewhere. wasn't sure how that worked lol

lyric sierra
#

it's early here lol

#

I need to go soon

slow cedar
#

12:55am here

#

same tbh. just really want this to work nicely

lyric sierra
#
SpawnManager.Instance.Respawn();
slow cedar
#

ayy

#

no error

lyric sierra
#

nice

#

some last words

#

when Managers manage multiple objects, it is normal to add them into a List<ofThoseObjects>

#

then you can use the List's Find function, along with some Lambda expressions, to interact with the desired object

slow cedar
#

I may have made an error in my codes logic

#

but I'll figure that out

#

lol

lyric sierra
#

lol

#

looks like progress to me ^^

#

Example:

#
private List<Brick> bricks;

public void DealDamageToBrick(string brickName, int ballDamageAmount)
{
    var target = bricks.Find(x => x.Name == brickName);
    target.TakeDamage(ballDamageAmount);

    if (target.Health <= 0)
    {
        target.Die();
        BrickDestroyed();
    }
}
#
// in the Brick class
public void TakeDamage(int damageAmount)
    {
        Health -= damageAmount;
    }
#

Gotta run

#

I'll check back later.

#

Have a nice day o/

slow cedar
#

you too