Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Miley Virus
Apr 9, 2010

This isn't directly a Game dev question but more of a "What the gently caress is going on with Unity" one:

I have a script attached to the player prefab which essentially handles the player's abilities. It assigns abilites to the buttons Q, E, and R, and when you press one it'll use that ability and put it on a cooldown. I have an AbilitySlot class which is instantiated for each button, which handles assignment of abilities and cooldowns, etc. So in the script's Update() I check for Q, E or R being pressed down, then call AbilitySlot.Use() which uses the current slot's ability.

For some reason, when I try and call AbilitySlot.Use() nothing happens. I have a Debug.Log() set up to output whenever AbilitySlot.Use() gets entered, but that never triggers. I have no clue what's causing this, and Unity's not giving me any error messages whatsoever. Here's the relevant code:

JavaScript code:
public class AbilitySlot {
    function Use() : IEnumerator {
        Debug.Log("in Use()");
        yield WaitForSeconds(cooldown);
    }
 
}
 
var abilityR : AbilitySlot = new AbilitySlot();
 
function Update () {
 
    if(Input.GetKeyDown("r")) {
        Debug.Log("R is down");
        abilityR.Use();
        Debug.Log("out of Use()");
    }
 
}
And here's an Answers thread I opened about it with a better explanation: http://answers.unity3d.com/questions/792461/call-to-a-class-function-not-occuring.html

I'm completely stumped as to what's causing this!

Adbot
ADBOT LOVES YOU

superh
Oct 10, 2007

Touching every treasure
So, the other logs trigger, but the Use log doesn't?

e: Alternatively use KeyCode.R instead of "r"?

http://docs.unity3d.com/ScriptReference/KeyCode.html

vvv yep this!

superh fucked around with this message at 15:44 on Sep 17, 2014

Obsurveyor
Jan 10, 2003

^^^ :ninja: :hf: :cheeky:

"r" is not a defined key identifier in your Input Settings. Use KeyCode.R or define it.

Miley Virus
Apr 9, 2010

Ah, that's a better way to do that yeah. It recognises that R has been pressed down, outputs both "R is down" and "out of Use()", but not "in Use()". Other functions other than abilityR.Use() also don't seem to get triggered.

JavaScript code:
function TestUse() {
    Debug.Log("test");
    abilityR.Use();
}
Which then gets called from where abilityR.Use() used to be doesn't output anything either, nor does it output even if it's only a Debug.Log() statement.

e: Here's the full code (excluding the actual abilities) in case there's something really stupid I've missed. I can't see anything that would break it this horribly though.

Miley Virus fucked around with this message at 16:03 on Sep 17, 2014

Obsurveyor
Jan 10, 2003

Your coroutine isn't acting as a timer in the way you want. If you continuously held it down, it would work fine, I bet. Record a lastUsed time and check that against current time to see if it's available again.

Obsurveyor fucked around with this message at 16:19 on Sep 17, 2014

Py-O-My
Jan 12, 2001
This looks like a similar issue: http://answers.unity3d.com/questions/442037/unityscript-coroutine-not-running-when-called.html
Is it because you're trying to yield from a class that isn't a MonoBehavior?

Py-O-My fucked around with this message at 17:28 on Sep 17, 2014

poemdexter
Feb 18, 2005

Hooray Indie Games!

College Slice
You can't start coroutines inside of update loop and assume they'll wait. Also I don't think you're actually starting the coroutine by just calling the method. I think you need StartCoroutine() wrapped around the Use() call. I'm not too strong with javascript in Unity so I might be wrong.

Miley Virus
Apr 9, 2010

Yeah looks like that was it, can't use yield from a non-MonoBehaviour class. Plus you can't yield from a static function (makes some amount of sense) which kind of screws over my entire method of handling temporary ability effects. Might have to reorganise the structure of this script somewhat, even though I'm not sure how else I'd do it without using that class structure.

JGTheSpy
Jul 31, 2002
Excuse me, but if I could have a moment of your time, I'd like to explain why you're not actually enjoying that game that you're enjoying. You see, I am in fact an expert. At games. I know, it's impressive.

Miley Virus posted:

Yeah looks like that was it, can't use yield from a non-MonoBehaviour class. Plus you can't yield from a static function (makes some amount of sense) which kind of screws over my entire method of handling temporary ability effects. Might have to reorganise the structure of this script somewhat, even though I'm not sure how else I'd do it without using that class structure.


You could just make it a Monobehaviour. You'll have to do abilityR = gameobject.AddComponent<AbilitySlot>() instead of creating a regular object but it seems like it would be the same otherwise. Have Use() start a coroutine that contains the code you're already using.

I made a nice little timer component that works that way and it works great, although I have no idea what kind of performance cost it has.

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'

Miley Virus posted:

Yeah looks like that was it, can't use yield from a non-MonoBehaviour class. Plus you can't yield from a static function (makes some amount of sense) which kind of screws over my entire method of handling temporary ability effects. Might have to reorganise the structure of this script somewhat, even though I'm not sure how else I'd do it without using that class structure.

So why are you using a coroutine instead of something like saving the time at which an ability was last used, and checking that against the current time whenever Use is called?

Miley Virus
Apr 9, 2010

JGTheSpy posted:

You could just make it a Monobehaviour. You'll have to do abilityR = gameobject.AddComponent<AbilitySlot>() instead of creating a regular object but it seems like it would be the same otherwise. Have Use() start a coroutine that contains the code you're already using.

I made a nice little timer component that works that way and it works great, although I have no idea what kind of performance cost it has.

Thanks, this worked perfectly. I had looked at AddComponent, but didn't realise that's what I needed to make that class as a MonoBehaviour. Chalk that one up to me not reading/watching many tutorials and diving in head-first.


dupersaurus posted:

So why are you using a coroutine instead of something like saving the time at which an ability was last used, and checking that against the current time whenever Use is called?

It seemed easier that way? I imagine the way you and Obsurveyor described is more efficient, especially if Use could theoretically be called every frame (I don't know how expensive calling a coroutine is compared to a reg function). Something like that would allow me to do a countdown timer or something in the GUI easier too. I'll probably end up doing that so I don't end up loving myself over down the road.

JGTheSpy
Jul 31, 2002
Excuse me, but if I could have a moment of your time, I'd like to explain why you're not actually enjoying that game that you're enjoying. You see, I am in fact an expert. At games. I know, it's impressive.

Miley Virus posted:

Thanks, this worked perfectly. I had looked at AddComponent, but didn't realise that's what I needed to make that class as a MonoBehaviour. Chalk that one up to me not reading/watching many tutorials and diving in head-first.

I think that's just one of those things you don't learn until you need it. I dove in head-first recently as well and that seems to be my experience with Unity in general. I think it works really well in that way since pretty much every possible question has already been answered if you can figure out what the hell to search for.

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'

Miley Virus posted:

...you and Obsurveyor described is more efficient...

Teach me to skim over things...

I think the conceptual problem you have is that you're thinking of a StartCoroutine call as a normal function call, but it's not. (WARNING: the following may be talking out of my rear end) When you start a coroutine you're sticking it in a stack of stuff that Unity evaluates for changes whenever it runs (like a big update manager). So when you call StartCoroutine(Use()), Use() isn't actually called until Unity runs through the stack (to people more knowledgeable: is this at the end of the current frame, start of the next, fixed update, or voodoo?), even if Use() immediately breaks out because another Use() is still running.

It's fine to use coroutines as timers for convenience for things that you don't really need to build a whole timer system for. But that's a "do X in Y seconds" thing, where your Use() is "do X and don't do it again until Y seconds," which is trivial to implement by just storing the time it was last called on. As you mention, that's extremely more useful because now you can tell where you are in the cooldown, not just that you're still in cooldown; all you're changing is your logic check from "has the coroutine finished" to "is the current time greater than last use time plus cooldown time".

poemdexter
Feb 18, 2005

Hooray Indie Games!

College Slice
Coroutines seem awesome until you have to debug them and then you start scribbling notes down furiously in hopes to one day build a time machine so you can go back and stab yourself with a dull spoon.

Yodzilla
Apr 29, 2005

Now who looks even dumber?

Beef Witch
That's why I've (so far) not used them for anything super complicated.

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'
The worst I've ever done with them was a WaitForSeconds(0.1) because I needed to do something to a newly-created GameObject, but only after it had a chance to spawn and start up.

:catholic: Forgive me father, for I have sinned.

Stick100
Mar 18, 2003

dupersaurus posted:

The worst I've ever done with them was a WaitForSeconds(0.1) because I needed to do something to a newly-created GameObject, but only after it had a chance to spawn and start up.

:catholic: Forgive me father, for I have sinned.

Why not put that in the constructor of the Gameobject? Also it never hurts too much to do wacky stuff like that if you have a fixed platform (like Xbox 360) as you can generally expect the same CPU performance, but that could easily cause you an issue on something like Windows/Android where something could act in the background and draw CPU or on lower end devices.

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'

Stick100 posted:

Why not put that in the constructor of the Gameobject? Also it never hurts too much to do wacky stuff like that if you have a fixed platform (like Xbox 360) as you can generally expect the same CPU performance, but that could easily cause you an issue on something like Windows/Android where something could act in the background and draw CPU or on lower end devices.

I don't remember the exact situation, but that was the only way it was going to work without a massive restructuring that was never going to be able to happen.

Yodzilla
Apr 29, 2005

Now who looks even dumber?

Beef Witch

dupersaurus posted:

The worst I've ever done with them was a WaitForSeconds(0.1) because I needed to do something to a newly-created GameObject, but only after it had a chance to spawn and start up.

:catholic: Forgive me father, for I have sinned.

:barf: For shaaaaaaaaaaaaame. :barf:

xgalaxy
Jan 27, 2004
i write code
You do realize thats the diff between Awake and OnStart right?

Miley Virus
Apr 9, 2010

dupersaurus posted:

Teach me to skim over things...

I think the conceptual problem you have is that you're thinking of a StartCoroutine call as a normal function call, but it's not. (WARNING: the following may be talking out of my rear end) When you start a coroutine you're sticking it in a stack of stuff that Unity evaluates for changes whenever it runs (like a big update manager). So when you call StartCoroutine(Use()), Use() isn't actually called until Unity runs through the stack (to people more knowledgeable: is this at the end of the current frame, start of the next, fixed update, or voodoo?), even if Use() immediately breaks out because another Use() is still running.

It's fine to use coroutines as timers for convenience for things that you don't really need to build a whole timer system for. But that's a "do X in Y seconds" thing, where your Use() is "do X and don't do it again until Y seconds," which is trivial to implement by just storing the time it was last called on. As you mention, that's extremely more useful because now you can tell where you are in the cooldown, not just that you're still in cooldown; all you're changing is your logic check from "has the coroutine finished" to "is the current time greater than last use time plus cooldown time".

Yeah, that makes some amount of sense now, thanks. Odd that they disguise it if you're using JS, but I guess it's stuff that new users (who would probably be using UnityScript or whatever) shouldn't have to worry about -- until it breaks and you have no idea why of course.

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'

xgalaxy posted:

You do realize thats the diff between Awake and OnStart right?

I'm going to try to find it at work tomorrow but I assure you it was a desperation move. Of course if I find it I'll probably go "oh duh" and kill myself, but I'm pretty sure it was something Unity was being stupid about.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

dupersaurus posted:

I'm going to try to find it at work tomorrow but I assure you it was a desperation move. Of course if I find it I'll probably go "oh duh" and kill myself, but I'm pretty sure it was something Unity was being stupid about.
Possibly a thing where you needed to initialize it based on some other object's state after its onAwake is called. Since the onAwakes happen in an arbitrary order, if you want one to go after another you have to do some tomfoolery.

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'

roomforthetuna posted:

Possibly a thing where you needed to initialize it based on some other object's state after its onAwake is called. Since the onAwakes happen in an arbitrary order, if you want one to go after another you have to do some tomfoolery.

I found it and it wasn't as bad as I remembered it being. Process A uses a UI, triggers process B, then closes the UI. Process B needed the same UI so it was opening it immediately, but only for it to be closed by A. So I stuck a WaitForSeconds(0.75f) on B to let the UI close before opening it again. Hacky, but I didn't have the time to redo the system to do it properly.

Yodzilla
Apr 29, 2005

Now who looks even dumber?

Beef Witch
I've found for a lot of my objects that I just plain don't use Awake or Start if I need to make sure something initializes before something else. I've started just making my own public Init method for these objects and it works out pretty nice.

Chunderstorm
May 9, 2010


legs crossed like a buddhist
smokin' buddha
angry tuna

joe_eyemobi posted:

Are any of the asset store systems any good? I don't remember specifics but I have seen a couple in the past that allow for multidirectional gravity.

I appreciate the response, but I managed to figure it out. Got the clamp working and put a script on the camera itself, rather than accessing it through a script. Allowed for the clamp to work as normal in any direction.

Programmer Humor
Nov 27, 2008

Lipstick Apathy

Programmer Humor posted:

One nice feature in Unreal I've found is you can do all kinds of procedural adding of Static Meshes based on variables in the construction script. These show up in the editor and can have static light calculated on them, etc, very nice. You can even have little vector variables you adjust by moving them around like any other object.

I also tried doing the same with C++, but it seems like OnConstruction, the C++ "equivalent" of a construction script, is rerun when the game starts so even if the editor lets you calculate light on your procedurally generated content, it's thrown away as soon as the game starts. Too bad.

As a follow up to this, in case anyone was curious, it's at least possible to generate everything you need in C++ and pass it to a blueprint construct script via variables or functions. Kind of dirty, but it works.

Praseodymi
Aug 26, 2010

What's the best/most correct way, in C++, to store items for an RPG or such? Say I have swords that the player can pick up, do I have an instance of the sword class for every different sword, even though they will all be identical, or do I have a single sword that can be accessed everywhere it is needed? Seeing as I'll probably do a debugging method to spawn items, it seems like I would have to write an enormous switch statement to handle what to spawn, while if there was a collection of 'model' items I could make it searchable and store the field with the item.

I realise writing this there's probably a lot of parallels with how the Elder Scrolls games do their console item spawning, so just picture that if I've explained what I want badly.

Flownerous
Apr 16, 2012
The standard way would be to have something like an ItemTemplate/ItemDefinition/ItemType class and an Item class. You have one instance of the ItemTemplate class for each type of item, such as Fire Sword +1, and one instance of the Item class for each actual instance of an item (my Fire Sword +1 with a blue gem and 17/30 durability, the ogre's Fire Sword +1 with ...). The Item object would reference the ItemTemplate object that it is an instance of.

Flownerous fucked around with this message at 01:02 on Sep 19, 2014

Dauq
Mar 21, 2008
I expect you want an instance of the Sword class for every item in the game yes. You might load some default swords from file and clone those every time you need a sword of some type.
Since at the very least you want an individual sword to have it's own individual location, but also presumably spawn and delete them, maybe enhance it's attributes through enchanting or whatever, etc..

Bongo Bill
Jan 17, 2012

Favor a flatter type hierarchy. Have just an Item class, with data members indicating that it can be equipped by sword users, that it has a sword icon, that it is called a Sword, what its stats are, etc.

Praseodymi
Aug 26, 2010

So have an Item class and differentiate them with the variables?

Mata
Dec 23, 2003

Praseodymi posted:

So have an Item class and differentiate them with the variables?

Well, do the items behave differently, or do they do more or less the same thing but in varying quantities? It doesn't make much sense to have a different class for a sword +1 and a sword +2, but maybe a you can have a class called Weapon and one called Armor, both inheriting Item. It depends on how they should behave...

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'

Praseodymi posted:

What's the best/most correct way, in C++, to store items for an RPG or such? Say I have swords that the player can pick up, do I have an instance of the sword class for every different sword, even though they will all be identical, or do I have a single sword that can be accessed everywhere it is needed? Seeing as I'll probably do a debugging method to spawn items, it seems like I would have to write an enormous switch statement to handle what to spawn, while if there was a collection of 'model' items I could make it searchable and store the field with the item.

I realise writing this there's probably a lot of parallels with how the Elder Scrolls games do their console item spawning, so just picture that if I've explained what I want badly.

Go with Flownerous with this, that's pretty much the proper and most flexible way to do it. Usually all of the types of swords and their stats are in a file that you parse, which make up the templates that you read in. (See this.) The sword item will reference the template for its base stats, but each sword instance will keep track of modifiers that are unique to it and affect the template values (buffs, wear, player mods, etc).

SupSuper
Apr 8, 2009

At the Heart of the city is an Alien horror, so vile and so powerful that not even death can claim it.

Flownerous posted:

The standard way would be to have something like an ItemTemplate/ItemDefinition/ItemType class and an Item class. You have one instance of the ItemTemplate class for each type of item, such as Fire Sword +1, and one instance of the Item class for each actual instance of an item (my Fire Sword +1 with a blue gem and 17/30 durability, the ogre's Fire Sword +1 with ...). The Item object would reference the ItemTemplate object that it is an instance of.
I recommend this approach. Build a list of ItemTemplates with all the item "types" you need, and then associate them to Items on spawn which contain individual attributes like their location in the world.
You should keep your shared properties and your individual properties separate. This reduces the overhead of having twenty Fire Sword +1 all duplicating the same info, and gives you the flexibility of being able to change your ItemTemplates easily, so if you later decide to rebalance your Fire Sword +1 it will automatically apply to all instances already spawned.
You can read more about it here: http://gameprogrammingpatterns.com/flyweight.html

Bongo Bill posted:

Favor a flatter type hierarchy. Have just an Item class, with data members indicating that it can be equipped by sword users, that it has a sword icon, that it is called a Sword, what its stats are, etc.
You gotta be careful with this though. You don't want to end up with a blob Item class that can represent everything from a sword to a pair of pants. Distinct behaviors should have distinct classes (either by inheritance or composition or etc).

Bongo Bill
Jan 17, 2012

SupSuper posted:

You gotta be careful with this though. You don't want to end up with a blob Item class that can represent everything from a sword to a pair of pants. Distinct behaviors should have distinct classes (either by inheritance or composition or etc).

On the contrary, in some cases you do want to dispense with all pretense of object-oriented design and make everything from the items in your inventory to the UI out of completely generic Entities. This is not suitable for every type of game, however.

SupSuper
Apr 8, 2009

At the Heart of the city is an Alien horror, so vile and so powerful that not even death can claim it.

Bongo Bill posted:

On the contrary, in some cases you do want to dispense with all pretense of object-oriented design and make everything from the items in your inventory to the UI out of completely generic Entities. This is not suitable for every type of game, however.
Sure, but ECS is not just "Have just an Item class, with data members indicating that it can be equipped by sword users...", you're still separating different behavior in different classes (components). It's still object-oriented design.

pianoSpleen
Jun 13, 2007
printf("Java is for programmers with no %socks", "c");
I'd suggest having an Item object (the item instance) with a pointer to an abstract ItemType class. Then you have subclasses of the ItemType based on functionality (weapons, armour etc).

IMO this is the optimal solution for most cases - it's only un-flat where there actually is a divergence in functionality (ie - the game actually needs to treat armour differently to weapons).

The only place it gets awkward is if there are specific instance traits that only certain ItemTypes can have (for example, a "Condition"/"Durability" trait for only armour). There are a few workarounds but they're all a bit clunky.

pianoSpleen fucked around with this message at 16:30 on Sep 20, 2014

Inverness
Feb 4, 2009

Fully configurable personal assistant.

pianoSpleen posted:

The only place it gets awkward is if there are specific instance traits that only certain ItemTypes can have (for example, a "Condition"/"Durability" trait for only armour). There are a few workarounds but they're all a bit clunky.
I'm using C# so a simple cast is sufficient. The same can be done in C++ with dynamic_cast.

If you have a limited amount of types and want to be more strict, using an enum for all possible types is fine.

Adbot
ADBOT LOVES YOU

dupersaurus
Aug 1, 2012

Futurism was an art movement where dudes were all 'CARS ARE COOL AND THE PAST IS FOR CHUMPS. LET'S DRAW SOME CARS.'
If I'm making a tick manager in Unity, should I be using C# events, or roll my own with linked lists or something? Events are drat handy, but I don't know what sort of extra performance overhead (if any) is there with them, with dozens of listeners frequently coming in and out.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply