Unity general questions

Comments

  • Sorry for spamming but I figured it out :P When you call Destroy(gameObject) in Unity, it doesn't clean up the reference on the event. You have to manually remove the reference and then bam, no stupid null errors :)
  • I was hoping someone could help me track down what is causing this:

    Internal compiler error. See the console log for more information. output was:
    Unhandled Exception: System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.
      at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (bool)
      at System.Reflection.Assembly.GetTypes () [0x00000] in <filename unknown>:0 
      at Mono.CSharp.RootNamespace.ComputeNamespaces (System.Reflection.Assembly assembly, System.Type extensionType) [0x00000] in <filename unknown>:0 
      at Mono.CSharp.RootNamespace.ComputeNamespace (Mono.CSharp.CompilerContext ctx, System.Type extensionType) [0x00000] in <filename unknown>:0 
      at Mono.CSharp.GlobalRootNamespace.ComputeNamespaces (Mono.CSharp.CompilerContext ctx) [0x00000] in <filename unknown>:0 
      at Mono.CSharp.Driver.LoadReferences () [0x00000] in <filename unknown>:0 
      at Mono.CSharp.Driver.Compile () [0x00000] in <filename unknown>:0 
      at Mono.CSharp.Driver.Main (System.String[] args) [0x00000] in <filename unknown>:0


    I'm completely stumped on how to track this down. The threads I've been looking at that address internal compile errors are vague at best.

    Any help?
  • I have to ask... Have you tried closing and re-opening your environments? Once in a while weird errors like this occurs internally, and re-setting seems to fix it...sometimes...
  • This happened to me yesterday. I reinstalled unity and monodevelop and it fixed it. So try that.
  • edited
    CiNiMoD said:
    Is there a way to set up your scene so that you can so that you can use normal pixels as opposed to the standard way it does it (in meters I presume?)
    Yes and not at all. Yes you could set up a primary object that scaled so the objects under it words at exactly the same resolution as the screen. You would need to calculate that yourself if you using an orthographic camera then the size will fit perfectly to the smallest screen dimension and you could revers that a 1/x as a scale all child objects would then work according to screen. Or you could set up an orthographic camera and set its scale to the lowest screen dimension (this will ruin physics almost completely though). In effect this is what nGUI does to allow widgets to move in pixels. However you should NEVER do this. Or at least its seriously not a good idea. Use units as meters and get used to the idea of thinking that way making sure your screen space shows a number of meters in it. Of course at some point you will need to decide how much detail you want per meter in pixels so textures will still look good.
  • I was hoping someone could help me track down what is causing this:

    Internal compiler error. See the console log for more information. output was:
    Unhandled Exception: System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.
      at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (bool)
      at System.Reflection.Assembly.GetTypes () [0x00000] in <filename unknown>:0 
      at Mono.CSharp.RootNamespace.ComputeNamespaces (System.Reflection.Assembly assembly, System.Type extensionType) [0x00000] in <filename unknown>:0 
      at Mono.CSharp.RootNamespace.ComputeNamespace (Mono.CSharp.CompilerContext ctx, System.Type extensionType) [0x00000] in <filename unknown>:0 
      at Mono.CSharp.GlobalRootNamespace.ComputeNamespaces (Mono.CSharp.CompilerContext ctx) [0x00000] in <filename unknown>:0 
      at Mono.CSharp.Driver.LoadReferences () [0x00000] in <filename unknown>:0 
      at Mono.CSharp.Driver.Compile () [0x00000] in <filename unknown>:0 
      at Mono.CSharp.Driver.Main (System.String[] args) [0x00000] in <filename unknown>:0


    I'm completely stumped on how to track this down. The threads I've been looking at that address internal compile errors are vague at best.

    Any help?
    What version of Unity and Mono are you using on what OS?
  • edited
    So I have something that has me stumped. I have a script that handles the movement of my character. Its pretty basic and looks like this:

    void Update () {
    		bool onGround = IsOnGround();
    
    		if (onGround)
    		{
    			jumping = false;
    		}
    
    		if (Input.GetKey(KeyCode.RightArrow))
    			gameObject.transform.position += new Vector3(MoveSpeed * Time.deltaTime,0,0);
    		if (Input.GetKey(KeyCode.LeftArrow))
    			gameObject.transform.position -= new Vector3(MoveSpeed * Time.deltaTime,0,0);
    		if (Input.GetKey(KeyCode.UpArrow) && onGround && !jumping)
    		{
    			gameObject.rigidbody2D.AddForce(new Vector2(0, -jumpForce));
    			jumping = true;
    		}
    	}
    
    	bool IsOnGround()
    	{
    		Vector3 pos = gameObject.transform.position;
    		RaycastHit2D hitObj = Physics2D.Raycast(new Vector2(0.0f, pos.y - 0.50f), - Vector2.up, 0.1f);
    		if (hitObj && hitObj.collider.gameObject.tag == "Ground")
    		{
    			return true;
    		}
    
    		return false;
    	}


    The problem I am having is that onGround will return true in 2 frames sometimes, meaning that the player will jump twice, effectively applying the jumpForce twice :( Any ideas of what I can do in my IsOnGround check?

    Edit: A way I can get around this is by checking the number of frames that have passed since I jumped, and only set jumping to false if onGround and numFramesPast is > 1. Just seems a bit messy :/
  • Try to make your raycast distance shorter. The jump translation may be less than 0.1 in a frame.
  • Several options available.

    Don't allow jumps to close to each other so remember the Time.time and only when its Time.time+1 will you jump again.

    Measure the current direction of your GameObject is the delta y is not downwards or even then dont jump. (This would probably have similar issues to your current solution)

    Alternatively you could measure the current velocity
    rigidbody.velocity
    if its y indicates upwards over a threshold then dont jump.

    Hope thats helpful.
  • I'd use GetKeyDown instead of GetKey. Then it only fires on the frame that the key was pressed, rather than continuously.
  • I'd use GetKeyDown instead of GetKey. Then it only fires on the frame that the key was pressed, rather than continuously.
    what if you want the character to jump again as soon as it touches the ground without having to press the jump key again? then you would use GetKey, just with a few different conditions added

    @CiNiMoD you could also use OnCollisionStay() to check if the character is on the ground if you want to. And I agree with @tbulford about measuring velocities, especialy if you want to do something like double jumps

  • what if you want the character to jump again as soon as it touches the ground without having to press the jump key again?
    I wouldn't. It breaks the one-to-one relationship between my physical input and my avatar's reaction, and discourages having variable jump height, both of which I feel are pretty important for making a jump feel good in the majority of platformers. But then I like platformers where I feel in control, and I like keeping my scripts simple, so whatever man. :P
  • I'd use GetKeyDown instead of GetKey. Then it only fires on the frame that the key was pressed, rather than continuously.
    lol...I can't believe I didn't think of this :P I was overcomplicating the matter waaaaay too much. Thanks :)

  • Anyone here got experience with this plug in for Unity

    http://unityvs.com

    I am really trying to work in VS instead of MD.
  • tbulford said:
    Anyone here got experience with this plug in for Unity

    http://unityvs.com

    I am really trying to work in VS instead of MD.
    Check @hermantulleken's comments at the end of thos thread:
    http://makegamessa.com/discussion/1252/tools-monodevelop-vs-visual-studios-for-unity#Item_48
    Thanked by 1tbulford
  • edited
    CiNiMoD said:
    So Im having the most annoying thing happen. I have 2 objects with a Box Collider 2D. One of them is my player, and the other is the ground. I have a check to see if my player is on the ground, this is the code:

    bool IsOnGround()
    	{
    		Vector3 pos = gameObject.transform.position;
    		RaycastHit2D hitObj = Physics2D.Raycast(new Vector2(0.0f, pos.y - 0.50f), - Vector2.up), 0.1f);
    		if (hitObj && hitObj.collider.gameObject.tag == "Ground")
    		{
    			return true;
    		}
    
    		return false;
    	}


    This works great for when my player hits the ground, and it returns true. The ground element is made up by taking a 25x25px sprite and scaling it to go across the bottom of the screen. The issue comes in when I duplicate the ground element and use a smaller scale. I can land on top of it, the hitObj is null :( While Im sitting on the platform if I change the scale on the x axis and make it longer IsOnGround starts to return true when my scale reaches around 13.5 ....

    I am super stumped :/

    So the platform I am on doesnt return true until I make it wider?!?!
    So Im still stuck on this. The issue isnt with my collider from what I can see. Here is a pic of what my collider looks like (I made it slightly bigger than the sprite for visual reference):

    image

    Unless I give it an x scale of like 20 it doesnt work :/


  • Hi Guys. I've been working on a little prototype which is a kind-of-cross of "sid myers pirates" and a dual stick shooter. Here is the link:

    https://dl.dropboxusercontent.com/u/187819585/PirateTester2/PirateTester2.html

    You are the little red ship (move with WASD and shoot with directional arrows - bullets do nothing yet thought). My problem is with my enemy AI (the bigger blue cube). My issue is 2 fold.

    1) I have my AI set up to travel in a direction for a set amount of time. Then when this time has passed, he waits for a couple of seconds. Then select a new direction and then travel again in that new direction for a set amount of time. My script works and does this, but my cube is "jigging and spinning" around everytime it reaches the destination (while pausing). Any idea why this is happening.

    2) Problem 2 is that when the you are close enough to the enemy he rotates to face you, then pauses slightly, then shoots at you. Again my script works, but instead of instantiating a single bullet, the AI shoots out a stream of bullets. How can I change this so that he shoots out less bullets?

    Here is my enemy behaviour script:

    using UnityEngine;
    using System.Collections;
    
    public class EnemyCIdleBehaviour : MonoBehaviour {
    
    	static public float walkSpeed = 3.0f;
    	public float rotateSpeed = 30.0f;
    
    	public float directionTravelTime = 2.0f;
    	public float idleTime = 1.5f;
    	public float attackDistance =15.0f;
    
    	static private bool isAttacking = false;
    	private float timeToNewDirection = 0.0f;
    	private Vector3 distanceToPlayer;
    
    	private Transform target;
    	
    	CharacterController controller;
    	
    	public float ShootDelay = 2.0f;
    	public GameObject Bullet;
    	public float bulletSpeed = 1.0f;
    	public bool isShooting = false;
    
    
    void Start () 
    {	
    	if(!target)
    	{
    		target = GameObject.FindWithTag("Player").transform;
    	}
    }
    	
    	void Update()
    	{
    		controller = GetComponent<CharacterController>();
    		if(isAttacking == false)
    		{
    			StartCoroutine(Idle ());
    		}
    		else
    		{
    			StartCoroutine(Attack());
    		}
    	}
    	
    	IEnumerator Idle()
    	{
    		if(Time.time > timeToNewDirection)
    		{
    			yield return new WaitForSeconds(idleTime);
    			
    			var RandomDirection = Random.value;
    			if(Random.value > 0.5)
    			{
    				transform.Rotate(new Vector3(0,1,0),rotateSpeed);
    			}
    			else
    			{
    				transform.Rotate(new Vector3(0,-1,0),rotateSpeed);
    				timeToNewDirection = Time.time + directionTravelTime;
    			}
    		}
    		var walkForward = transform.TransformDirection(Vector3.forward);
    		controller.SimpleMove(walkForward * walkSpeed);
    		distanceToPlayer = transform.position - target.position;
    		if(distanceToPlayer.magnitude < attackDistance)
    		{
    			isAttacking = true;
    		}
    		
    	}
    	
    	IEnumerator Attack()
    	{
    		//Debug.Log("I'm attacking");
    		GameObject player = GameObject.FindGameObjectWithTag("Player");
    		if(player)
    		{
    			Vector3 playerPosition = player.transform.position;
    			Vector3 aimDirection = playerPosition - transform.position;
    			transform.rotation = Quaternion.RotateTowards(Quaternion.LookRotation(transform.forward,transform.up),Quaternion.LookRotation(aimDirection,transform.up),Mathf.Rad2Deg * rotateSpeed * Time.deltaTime);
    		}
    		yield return new WaitForSeconds(2);
    
    		//Invoke("Shoot",ShootDelay);
    		Shoot();
    		isAttacking = false;
    		//Debug.Log("I'm Idle");
    		
    	}
    	
    	void Shoot()
    	{
    		//GameObject bulletInstance = Instantiate(Bullet,transform.position,Quaternion.LookRotation(transform.forward)) as GameObject;
    		//bulletInstance.rigidbody.AddForce(transform.forward * bulletSpeed,ForceMode.VelocityChange);
    		//Invoke("Shoot",ShootDelay);
    		GameObject bulletInstance = Instantiate(Bullet,transform.position,Bullet.transform.rotation) as GameObject;
    		bulletInstance.rigidbody.AddForce(transform.forward * bulletSpeed,ForceMode.VelocityChange);
    	}
    	
    	
    }


    Really hope someone can help me out
  • You are actually calling attack every frame due to the way you are calling it. Coroutines are only useful for long running event driven code, not for calling from within update (unless you have some if/switch logic associated, or are running a coroutined while loop from start instead of update.). If you prefer this logic from within update - rather have a timer/interval on when it should attack again, and check delta time against it before shooting (and remove the unnecessary coroutine).
  • @FanieG personally I am not a fan of using StartCoroutine as you are doing here (I am aware there are many examples that do this and it has little to no performance overhead, but it seams to overcomplicated something really simple.). There is no reason you could not use a finite state engine instead to manage your states. That way you will have fewer unexpected interactions between old routines and the new ones attempting to execute.

    That having been said the weird spinning when he is stationary might be because you only set the time timeToNewDirection when he turns in one of the directions. This means if the random is the other he will spin a 2nd time and a 3rd until it is >.5.

    I think your 2nd issue is that multiple executions of the Attack are been called over time each one waits 2seconds and fires. However the stats at attack until 2 seconds have past in that time you may have started 2*yourframe rate Coroutines.

    Just keep in mind that once you call StartCoroutine the update function will release and continue to function so a new StartCoroutine will be called again next frame.

    It you dead set on using Coroutine take a look at this FSM in Unity that uses it I still think its overly complicated buy hey. http://unitygems.com/fsm1/ You will notice that at the start of the function called with Start is the follow little line of code

    _busy = true;

    That at the start of his Update he returns if Busy is true. this is really awful still.

    Alternatively take a look at the following game tut on FSM's and try implementing one without Coroutine

    http://www.voidinspace.com/2013/05/a-simple-finite-state-machine-with-c-delegates-in-unity/

  • @tbulford & @farsicon - Thanks so much for the advice. I think Travis is right in saying that I was overcomplicating things unnecessary. I will try to implement the way you suggested and post my findings. Is it possible to call a waitforseconds without a coroutine? This was the main reason I was using them. Sorry if this is a silly question (I am still learning).
  • @FanieG - something like this maybe?

    if (Time.time > createdTime + waitTime) {}
  • @Pixel_Reaper - thanks. That seems strangely elegant in it's simplicity. I'll give that a go.
  • Another silly question - I have 2 PCs with Unity installed on both. I have a project on the 1 that I would now like to include/merge with a project on my other PC (into another project). I checked online and the info I got was to export the 1st project - save it to a device - then import in the other project as a custom package. Which sounds simple enough, however, are there any pitfalls that anyone knows off that I should watch out for. Don't want to break a million things (and cause myself a heap of extra work) in the process. Any advice before I try?
  • I have done that before without any major issues - but the complexity/modularity of your project could have an impact. Best thing would be to back up your project and jfdi - if it fails just roll back :)
  • @FanieG the only pitfall will be overlapping resources which I believe Unity will rename in a numerical sequence. Of course your code access and dependencies might not update to the new instance name.
  • Just an update on my problem(s) from earlier in the week. All is good now. Thanks again to @tbulford, @farsicon and @Pixel_Reaper for all the advice. I got rid of the unnecessary Coroutine and implemented the wait behaviour as Pixel_Reaper suggested. @tbulford was also right about the reason for the jittery behaviour before choosing a new direction. Anyway here is the result if anyone wants to check it out:

    https://dl.dropboxusercontent.com/u/187819585/PirateTester3/PirateTester3.html

    My idea is to have a sort of "Sid Myer's Pirates-like" with first person stages (islands) that you can dock at. Very early days still, but enjoying the new challenges a lot.

    Thanks again for the advice guys.
    Thanked by 1tbulford
  • Erm, another seemingly easy question...

    I'm working in 2D Unity, I want to set a grid of blocks, so I want to use a unit of 1 to be the width of the sprite and colliders and measurement so I can easily go from 1 to 2, 3, etc.

    So when I add a collider to a sprite the unit is 1.28 - which I've noticed is 128 pixels, the size of my sprite. Is there a way to change it so each "unit" is 128 pixels instead of having a 1.28 multiplier to each unit?

    That's so I can, for example, make sure a block is at a full "unit" of block by rounding it off to a full number.

    I've looked for units but haven't been able to find it in project settings...

    Thanks! :)
  • I think the units are set on the sprite itself. Perhaps you set it there to be something like 1/128 or something, depending on your scale. I haven't worked with it much. :)
  • Unless you work with vector graphics the preferred 2D unit is normally a pixel. This is to prevent funny scaling issues, etc. I have not touched the new unity2D yet, though, they may have added some kind of unit translation...
  • As a side note, NGUI used scale to simulate non pixel units - maybe you can look into that?
  • Update, I found where the setting is - if you look at the sprite texture asset in the inspector, there's a setting "Pixels to Units" - my sprites are 128 x 128, so if I set that to 128, then they'll tile at exactly 1 unit. AWESOME :)
  • I have a question of the utmost importance that Google cannot answer:

    How do I make it that when Unity generates scripts it does so in Cat Stance and not Egypt Stance?
  • Hey guys! Back to Unity difficulties, and this one sounds... Really silly. Omg syntax.

    So I'm making a block, and having it drop. Then I'm trying to change its sprite. The object instantiates well enough but the sprite line causes errors... What's the problem?? @_@

    GameObject newBlock = Instantiate(originalBlock,
    			                                  new Vector2 (-8 + blockColToMake, 11),
    			                                  transform.rotation)
    												as GameObject;
    			newBlock.spriteRenderer.sprite = startingSprite;


    The error:

    Assets/GameController.cs(37,34): error CS1061: Type `UnityEngine.GameObject' does not contain a definition for `spriteRenderer' and no extension method `spriteRenderer' of type `UnityEngine.GameObject' could be found (are you missing a using directive or an assembly reference?)


  • Try to use getcomponent to access the spriterenderer.
  • Why the heck can't I just access the spriterenderer by name?!?!!???!?!?!

    The GetComponent call - it's like this right? (Unity documentation is useless with example - that is, there is none)

    GetComponent<SpriteRenderer>().sprite = startingSprite;


    will try when I'm home.
  • edited
    @tuism consider the following:

    let's say someone decides to weld a towbar to his brand new lambo - which makes perfect sense for him, and there's nothing wrong with it in his case. In fact, let's say it becomes fashionable in his home town, and a whole bunch of them starts doing it... At what point does Lamborgini decide to make towbars standard on all their models..?

    This is a crude example, but should give you an idea why components are used. GameObject is the base of all objects in unity, and the behaviour exposed on it is available to all use cases. Now remember, gameobject is also used for 3d - does it make sense to have a sprite renderer for 3d objects? Components allow you to customise the standard gameobject in ways that fit your scenario.

    There are however a few components that are exposed by gameobject for ease of use, but it will probably take a lot of user requests before spriterenderer is added to this list. Also consider that 2D is new in unity - they may very well simply add this reference in future updates, but at what overhead cost for the 3d engine - which is primarily what unity is designed for.

    Edit: also remember that unity becomes intermediate to advanced once you start scripting, and concepts that may seem strange to you are quite commonplace in the c# world, and there's very good reasons for them. If you really want to benefit from the scripting, I'd strongly advise that you try to learn a bit more about c# and the basics of object oriented programming. It will help you immensely and will allay some of your frustrations.
  • Ah, so what you're saying is that for the code to be able to reach SpriteRenderer without GetComponent, it would have to be factored into the standard gameobject object, which means it will slow all other uses of GameObject down?

    Thus, anything that's a component on a GameObject should have to be reached via GetCompoent in any case? Does the same apply for colliders, renderers, etc which are also components on the object in the editor? Or are those components "standard" and on the gameobject whether or not you've put them a GameObject on in the editor? How then do you strictly tell the difference between the standard stuff and the stuff you need to GetComponent for?

    For me it's more a case of syntax, it's just been quite confusing for me moving from other scripting (GML & Flash) to this mass of new conventions.

    Though I must say I think I tried the GetComponent thing and either I did it wrong or it didn't work as expected. Will try again when I'm home.
  • For you to be able to just go foo.componentName, The GameObject class would need to have a field for every possible value of componentName. Obviously that's not a practical thing to do :)

    If this was C++, you could probably override the "." operator to first try to get an object based on the type you specified, but a) We're not using C++ and b) ZOMG the performance implications!! O_O
  • @tuism Correct. Renderer, collider, rigidbody, etc exposes components that are "expected" to be used often. But.. They can also be accessed when the component has not been added - resulting in a null reference. This is the drawback of doing shortcuts like this, and also why it is considered poor practice - it also makes code very difficult to maintain, that's one of the many reasons you'll find a lot of deprecated code on the unity stack, as it's difficult to find the sweet spot between useful shortcuts and redundancy when you have such a large user base with such broad set of use cases. Typically you'll find that the more a tool can do, the less user friendly it becomes, and scripting becomes essential.
  • @Tuism is this was said before I apologize but get the reference in your Start method not each time you want to call it.
  • @tbulford no apologies needed as I clearly need the reminder, so thank you :D

    BUT I'm instantiating GameObjects at runtime, can I still make that reference in the Start method while I'm instantiating a new one each time?

    What would it look like (in C#)?

    InstantiatedObjectSpriteRenderer = GetComponent<SpriteRenderer>();


    Then I can use

    InstantiatedObjectSpriteRenderer.sprite = startingSprite;


    to change the sprite?
  • Start will be called for each game object as it starts so the fact you creating them at run time is fine. In fact I encourage that line of thinking. I suspect you will hear something along those lines from other devs here built your contend from a script if possible not from the designer.

    We use a SpriteFactory static class to instantiate all other game objects. So we have a single place for all creating of GameObjects. I seriously recommend a model like that too. This means that if we change a requirements for a specific object or want to cache objects etc we have one place to make all those changes. Not perfect but it was a real help with some of the issues we ran into doing performance optimization on Toxic Bunny.

    Nothing wrong with your code but PLEASE learn to use upper lower and camel case in accordance with the generally accepted c# style guide. That is to say that InstantiatedObjectSpriteRenderer should have been instantiatedObjectSpriteRenderer. See http://msdn.microsoft.com/en-us/library/ff926074.aspx it may seam trivial but it really does help us communicate in code. For example your code to me read as

    InstantiatedObjectSpriteRenderer is a class with a static member sprite.
    Thanked by 3mattbenic Fengol Tuism
  • edited
    +1 for spawning objects from code as a default, the sooner you start doing that, the less painful it'll be (and for all but the most basic of prototypes you will end up having to eventually). Using generics you can fairly quickly slap together a general purpose type-safe factory to spawn all your objects based on prefabs and return the component you're actually looking for.

    @tbulford I'm glad I'm not the only one using that reference as a style bible. It's also why all public fields should be PascalCase, despite what seems to be common practice among Unity devs.
  • @mattbenic, yeah well come from a c++ to Java now C# so life is full of various code standards. Cant say I am a fan of the PascalCase for public members variables but I would guess if you don't use too many Enum's or Inner classes it would not cause too much confusion. Sure beats the old _ prefixes or worse yes m_ prefixes from old c++ guides. At least today out syntax highlighting IDE's allow a lot more information in the form of color highlights. Thing is in Java I would have few to no publicly accessible members anyway since without the get,set overrides in c# you really didn't want to break oo requirements latter by making things public to start with.

    I would add though never mind what you like or don't like work the same way as a team, even if you strongly disagree.
  • Yes, I actually know the difference between the cases, I just need to apply it and be more conscientious of it. Sometimes it's actually hard for me to figure out though XD

    And that SpriteFacory thing sounds interesting, I don't really understand what you mean though - you mean instead of instantiate you write a custom class that you call and pass parameters into to instantiate everything else? I think I need more practical examples to grasp these concepts @_@
  • @tbulford MS's logic behind using Pascal case for public fields is that they can at any point be replaced with a property and not affect dependent code. That logic wouldn't work in a language where your get/set methods are more explicit, like in Java. Also, I totally agree that you should be using public fields as little as possible, but Unity kind of works against that by using public fields to control what displays in the inspector (SerializeField aside). @Chippit and I were actually talking about the up- and downsides of basically just using Components as wrappers for non-unity objects, so your engine is as decoupled from Unity as possible.. maybe a discussion for that ever-elusive lunch meeting :)

    @tuism Conceptually, it's just a Prototype Factory, with (hidden) elements of a builder

    In concrete unity terms, it's a component on a GameObject that you would set to persist throughout your game (DontDestroyOnLoad(gameObject)), that you ask for all your objects in your game. I'm not going to provide a full implementation here (there are actually some decent ones on the web, and TBH this would be a good exercise to grow your C#/Unity coding knowledge :)), but you'd end up using it something like this:
    // Prefab reference somewhere on a component or something
       public MyComponentType Prefab;
    
       ...
    
       // Somewhere that you need to create an instance
       MyComponentType myComponent = ObjectFactory.Instance.Instantiate(Prefab);
    
       ...
    
       // Somewhere else that you can release the object so it can be reused
       ObjectFactory.Instance.Return(myComponent);


  • @Tuism,

    Ok Consider for a second that most objects you create will in all probability require some kind of configuration after they are created at the very least a location perhaps an orientation. So all over your code you will have an instantiate followed by setting some parameters in the transform and perhaps a few public variables on the object (or preferably calling an Init method on the script). So you create a projectile for example. In your code you create the same object from 20 places. Later you realize the projectile would be super cool if you could also give it a color and the amount of damage for some reason earlier on your only had one kind. Now all through your code in 20 places you would need to call the projectile code to set color and damage. However if you have a single method called CreateProjectile you could add the two required parameters and your compiler would pick out all 20 places for you.

    That is just one example of how its useful. We used the same thing for all particle effects in our game. On the game stick and the smaller platforms we have had to pull Unities particles out in favor of our own sprite particles. We simply changed the factories and all the places that called them now create sprites not unity particles. If this work was not centralized in some way we would have been digging for ages to change all of them. This is more a structured programming approach then an OO one, but the terminology and identity of the idea is less important then the result.

    Just use this one little question if you hit cut and paste STOP and ask yourself if it would not be simpler to create a static method or a poly-morphed base class you could inherit the pasted behavior from. Each paste of code is an identical copy that if you changed how you want to do that work, would have to be found and changed independently.
  • @mattbenic I have considered that too. Although for now I am still largely in Unity and Mono so the separation is not all that important. If I did separate I would want to be able to separate even further. Path finding and environmental physics etc. all would have to be covered. Ultimately this level of separation is geared towards a full client server game environment where the unity engine does only rendering. I am far from any projects like that but always considering how to be closer to one. Got it on the Pascal case.

    The public variables are untidy to someone with too many years strict OO principles behind me, but they also great for speed and as c# does have that get set override possibility I am less panicky about it.

    If you separated would you be considering forgoing MonoBehaviour all together? I have seen many recent instances where the MonoBehaviour model consumed far too many resources for what I was trying to do in it. I am not sure if that's just the nature of the platforms I am looking at or if its something to do with how it called the methods themselves.

    As for the ever elusive lunch we need to pick that up again some technical bantering is always a pleasure.
  • Just take note that unity components favour the composition model instead of inheritance. Try to stay close to that model or unity will start working against you. Composition has several benefits over inheritance, however, it does take some getting used to.
  • @farsicon do you have any online guides on that? I am very keen on OO so would like to try understand what to avoid and what to use. We have been using plenty of polymorphism to date with no side effects I am aware of.
Sign In or Register to comment.