FireMe!'s WIP Scripting, from an none scriptor

Hi all, So I started this thread so I can post my scripting questions if this is the right place todo so? because of my lack of scripting knowledge. I am more artistic, but not to say programmers are not artistic, because you are. but i’m more of a guy with a paint brush, but I really want get into a programming mind. what are your suggestions? what should I learn first or should I just try to learn by creating stuff, is it best for me to start in javascript language?

here is my first little script, I was looking at creating an inventory system, because that what I felt like trying to do.

import System.Collections.Generic;

class Item {

	var Name : String;
	var Description : String;
	var itemType: ItemType; 
	var rarity : Rarity;
	var itemIcon : Texture2D;
}

enum Rarity {
	uncommon,
	common,
	rare,
	ultra_rare
}

enum ItemType {
	weapon,
	ammo,
	medical,
	other
}

if(ItemType == "weapon"){
	var Damage: int;
} else {
	return;
}

So what I was attempting to do here, was take the itemType variable and do an if statement at the bottom, so for example if itemtype equals “weapon” add the variable damage to the item, if this makes sense? but when i select weapon, damage is not showing up in the unity editor am I doing something completely wrong here? or is there a better way to do it?

Thanks
FireMe!

Hello FireMe! and welcome - this is a worthy endeavor, and I’d like to help.

If you’re not the book-learning type (I’m not) then I think learning by “creating stuff” is the best way - especially if you’re an artist, having an intuitive concept of what you’re trying to achieve will give context to the logic that will achieve the concept. I would however strongly advise you to start learning C# instead - it is more rigidly defined than JS (this is a good thing) and will definitely get you into the programming mind better than JS could (in my opinion, of course). It may have a steeper learning curve because it introduces what will seem like very abstract concepts right off the bat before you can see results, but the concepts it introduces will generally apply to most languages and I think will benefit you the most.

So, if you’re sold on C# (say “yes” : P) I would love to start showing you how you could achieve what you’ve started on in Unity with it.

You down?

Hi thanks for the reply Roland, for sure im up for C#, I was actually looking at starting with this, but there seemed to be a lot more info on the javascript side around and about. but yes I am sold for C#

Stick with JS; in Unity it’s just as strongly-typed as C# (it’s not the same language as web Javascript), and is specifically customized for working in Unity, so has less annoying hoop-jumping that crops up with C#.

If that’s really the exact code you’re using, the first thing you need to do is have a function. You can’t really have “bare code” (namely your if/else code) outside functions like that.

–Eric

I’d copy the prev statement and concerning your above problem:

You defined the variable itemType as ItemType, which is an enumeration. Your checking ItemType but not the variable itemType - and second - your checking for a string whereas it’s as enumeration. I dont do much javascrip and i hope im being corrected, but you should check:

the variable itemType for the vaue of type enumeration Item.ItemType.weapon to determine if it is set to weapon.

Excellent - let’s start with Item, I’ll just translate most of what you had into C#:

using UnityEngine;

public class Item : MonoBehaviour
{
    public string Name;
    public string Description;
    public ItemType ItemType;
    public Rarity Rarity;
    public Texture2D ItemIcon;
}

public enum ItemType
{
    Weapon,
    Ammo,
    Medical,
    Other
}

public enum Rarity
{
    Uncommon,
    Common,
    Rare,
    UltraRare
}

It seems you already have some programming knowledge/experience, so I’m going to assume most of this is self-explanatory to you. But do ask whatever questions happen to pop up, no matter how simple or inane they may seem. For now I’m just going to start honing in on your specific concern of adding a variable to an object depending on ItemType.

Technically, you can’t. There, that was simple, right? Ok, there are different ways to implement this but first let’s think a little bit about what is happening underneath the hood when we write code: Although Unity refers to the code you write as a “script”, this is a bit of a misnomer. In computer science, a script is something that is interpreted by a program during execution vs. compiled into something that can be executed (this is an oversimplification when applied to managed languages like C#, but let’s not get into that yet). When you write code you’re just writing text that isn’t really going to do anything until it’s been compiled into an executable form. And for that to happen you have to adhere to the rules of the language that the compiler itself has been programmed to follow.

I bring that up because even though it makes logical sense to say “If this item is a weapon, add a damage variable to it”, the compiler (in C# at least, JS is a funky monkey) isn’t really going to see it that way. Look at the above definition for the Item class - we’re essentially telling the compiler: “I’m defining that there’s such a thing as an Item object with these fields (given their accessibility, type, and names)” and the compiler says “Cool, I understand dat.”

But now you essentially want to add an integer field named “Damage” for items that are of a weapon type. This is a problem because an Item has already been defined, and its definition did not contain a field named “Damage”. The compiler has no way of knowing, at compile-time, that if an instance of an Item has an ItemType of Weapon it should add a new field to that Item’s definition, but not to other Item definitions - it doesn’t make sense as we’ve already defined Item for the compiler the way we did - with no field named “Damage”.

SO - we could simply add “Damage” to the Item class’ definition, which will add a “Damage” variable to all Item instances, and choose to ignore it for Items that are not of a Weapon ItemType - but that kind of practice will produce bloated and confusing code very quickly. You might still want to do that in some instances, but it shouldn’t be an actual practice. What we really want to think when we think about “adding” to an object’s definition, is an entirely new definition of an object.

Now look at this:

public class Weapon : Item
{
    public int Damage;
}

We’ve now defined a new object definition called “Weapon” and are telling the compiler: “The definition for Weapon is derived from the definition for Item” or “A Weapon is a type of Item.” By deriving from something by using the “:” symbol after a class declaration, that class will inherit the fields, properties, and methods of the thing its deriving/inheriting from. Weapon instances will have the same fields as Item (like Name, Description, ItemType [which is a problem now], etc.) and “add” to it a Damage integer field.

What’s useful about this is that we can refer to a Weapon instance as an item as well. Consider the following:

public class Inventory : MonoBehaviour
{
    private Item[] Items;

    private void Start()
    {
        Items = new Item[]
            {
                new Item(),
                new Weapon()
            };
    }
}

Note that in the Start method we create a new array of Item and put both a new Item and a new Weapon instance in it. This is totally allowable in the language and really cool, but don’t do this in Unity as Item is inheriting from MonoBehaviour and a MonoBehaviour should never be newed up in this way.

I know that’s alot to take in - you should have many questions at this point, yes?

A fair point, and one to definitely consider - of course, I’d still argue in favor of C# (especially if you’re wanting to learn programming in general, but that could also be debated). If you choose JS then no hard feelings, but I’ve very little experience with it so wouldn’t be of much help.

I wouldn’t say I have that much programming knowledge, I have done some basic work with PHP in some CMS’s in the past but thats about it, I mean i know what Int, array, etc are, but pulling everything to together to be working in a way i think it should work, its very often not the way it should be done.

So I can see the first script is nearly the same as my original but just in C#

For the second script, were you say about inhereting from item, so I assume this needs to be in a different script file called “Weapon” or am I off the mark there?

If so I guess it would be best to set the weapon type in this? instead of the first script? for example

public string ItemType;
public int Damage;

or would the limit me in anyway?

For the third script i’m not exactly sure what its meant to be doing, well I know its the inventory and adding item and weapon, when I add it to my unity I get

Assets/Inventory.cs(6,24): warning CS0414: The private field `Inventory.Items' is assigned but its value is never used

And i’m also not to sure why you say not to do this in unity? is it because “item” is already being used somewhere in MonoBehaviour?

Thanks so much for your help, really want to get into programming in general so maybe C# would be a good way to go.

You are correct but (getting into what Eric5h5 said about having to jump through hoops, which is unfortunately very true) this is a Unity-enforced requirement. As far as the language is concerned it wouldn’t normally be a requirement to have each class definition in its own file with the same name as the class, but it is considered good practice regardless. In Unity, its a specific requirement for specific types - MonoBehaviour derived classes being one of them - that they must be defined in files with the same name as the class.

If you mean replacing the ItemType enum with a string - that will totally depend on your requirements. If you have a finite number of ItemTypes, defining them within an enum would be a good way to go. It would allow you to make much quicker ItemType comparisons as an enum is basically a numeric type. You can actually specify the numeric type backing the enum as well as specify values like so:

public enum ItemType : uint
{
    Weapon = 0,
    Ammo = 1,
    Medical = 2,
    Other = 99
}

And you can use enums as indexes into a collection somewhere down the line should you ever need to. Using a string instead would make for less efficient comparisons (as internally you’d have the potential to have to compare each character in the strings). But they’d be more flexible - you could store any string value you could want during runtime, whereas storing numeric values into an enum that don’t exist within the enum definition will cause an exception to be thrown.

However, the real issue is one of design. The problem with what I’ve coded so far is that we have a definition of Item that contains an ItemType field (enum or string wouldn’t make a difference for this issue) which can change. Then we have a definition for Weapon that inherits that field from Item - which can still change. So we end up with the possibility of an instance of a Weapon that could have an ItemType value of, say, ItemType.Medical. Which is weird. Although I guess a scalpel could be that : ) But, depending on the use we’re getting from ItemType, I’d be willing to bet that would be incorrect.

Really what we need to start moving towards is a more explicit definition of the requirements of your system.

Just an example of what you can do with inheritance - namely, referencing an object as its base type (in this case, referencing a Weapon as an Item). Inheritance is one of the cornerstones of object-oriented programming, and you’ll see the usefulness of it down the line. Regarding the actual warning, you can safely ignore it. The compiler is programmed to throw these kinds of warnings at you to try and help you optimize your code. In this case it sees that we’ve instantiated a new Item array and have assigned it to a field of the class but aren’t actually using it, so as far as it can tell we’re wasting resources unnecessarily.

So that wasn’t a great example since I showed you something you could do but really shouldn’t because we’re working with Unity here. My bad. In the language itself this would normally be perfectly valid, but in the context of Unity this would circumvent their way of properly creating MonoBehaviour derived instances. You’d have to use something like the AddComponent<> method instead (which is a Unity-defined method). This is because Unity is designed to have MonoBehaviour derived objects attached to GameObjects and I imagine it also does some internal house-keeping that would be circumvented by just newing up a MonoBehaviour out of thin air like in the example.

Absolutely, as long as you’re interested in learning I’m interested in helping.

So - we’re left with something of a problem regarding ItemType, and it’d be pretty hard to determine a solution without more specific requirements. Do you have a better idea of what you are trying to do when you say “creating an inventory system”? A square grid showing item icons that you can arrange how you want and displays detailed item information depending on the item, I’m guessing?

Thanks, so yes I think this is more of a learning project than actually a fully fledged game project for me. I see it going a 3rd person game maybe, but not for certain.

So I thought why not attempt a survival zombie game? Which I have decided to start by, with creating the inventory system, which of course you need items for. So let’s put it like this the player has a backpack(inventory) which you can carry a certain amount of different items. Which you will be able to search for around the 3d world. Pickup and put in you backpack (loot) to store for when they are needed. The reason I was looking at adding item type was because I didn’t see much point in adding what shal I say “stats” that wasn’t going to be used for example and axe would be a weapon item type which would have a damage amount, I see bandage as a medical item type as it would have an heal amount, bullets would be an ammo item type and I put other just for other items for now till I come up with an item type. Hope all this makes sense.

Yes I see it at being you press I on keyboard or something and a grid GUI will show items looted, with there icons and maybe you hover over icon and it will show info if possible. With In the future being able to maybe drop item, use item etc.

Thanks FireMe

Right on, so RE-style inventory.

You’re thinking along the right lines with ItemType, and I would most definitely keep it as an enum. Regarding different types having different values like damage vs. heal amount, you could potentially abstract them under a common variable like int ItemVariable and treat it like damage when ItemType == ItemType.Weapon or treat it like healing when ItemType == ItemType.Healing; but there’s a very high probability that this won’t be their only difference. Maybe ammo will have quantity as well as damageModifier, or a healing item have numberOfUses (I think there were items in RE that had this kind of functionality, right?). So based on that, I would keep going the inheritance route as we have been so far.

Now, the problem we’ve identified is that we have our base definition for an Item that contains a field for ItemType that we’ve so far defined as being able to change (simply declaring a public ItemType ItemType member in the class definition implies this). We really don’t want this. When we have an instance of Weapon we don’t want to ever be able to say: thisWeapon.ItemType = ItemType.Ammo. There are a few ways to go about this, but I’ll just show you this one:

public class Item : MonoBehaviour
{
    public string Name;
    public string Description;
    public Rarity Rarity;
    public Texture2D ItemIcon;

    public virtual ItemType ItemType
    {
        get { return ItemType.Other; }
    }
}

public class Weapon : Item
{
    public int Damage;

    public override ItemType ItemType
    {
        get { return ItemType.Weapon; }
    }
}

public class Medical : Item
{
    public int HealAmount;

    public override ItemType ItemType
    {
        get { return ItemType.Medical; }
    }
}

public class Ammo : Item
{
    public int Quantity;

    public override ItemType ItemType
    {
        get { return ItemType.Ammo; }
    }
}

Which introduces the concept of properties.

So, a property behaves similarly to a field in that if you define it as having a get you can… well, get a value. If you define it having a set then you can, also redundantly, set a value. However, a property is technically not a field, but rather a set of methods that usually wrap around the getting and setting of a field (but don’t have to, as in our case we only have a get that returns a value). Their benefit is that they can encapsulate the logic associated with those operations while maintaining field-like access syntax. To illustrate:

public class Ammo : Item
{
    public int Quantity
    {
        get { return _quantity; }
        set
        {
            if(value < 0)
            {
                _quantity = 0;
            }
            else
            {
                _quantity = value;
            }
        }
    }

    private int _quantity;

    //These methods are functionally equivalent to the above property.
    public int GetQuantity()
    {
        return _quantity;
    }

    public int SetQuantity(int newQuantity)
    {
        if(newQuantity < 0)
        {
            _quantity = 0;
        }
        else
        {
            _quantity = newQuantity;
        }

        return _quantity;
    }
}

public class SomeGuyWithAmmo : MonoBehaviour
{
    public Ammo Ammo;

    public void Start()
    {
        Ammo.Quantity = 42;

        //This is functionally equivalent to the above.
        Ammo.SetQuantity(42);
    }
}

You can see the difference, aye? Properties are just convenient ways of defining methods (I think in other languages, like Java, you’d have to define actual methods each time instead). But the key principle here is the use of the virtual and override keywords. By declaring the ItemType property as virtual in the Item class, we are saying “This is the base implementation of this property’s getter, but it can be overridden by a deriving class.” And when we derive from the base class we can override the base implementation with our own. In our case we are saying that, if an Item derivative class doesn’t override the property, it will always return ItemType.Other; otherwise it will return whatever the deriving class says: ItemType.Weapon for instances of the Weapon class, ItemType.Medical for instances of the Medical class, etc. etc. Since we’ve declared no setter, then the property can never be set, only accessed - which I think is what we’d want.

It’s worth noting that Unity will not expose properties in the inspector - but you can implement a custom editor or property drawer to do so if you have the need.

So - let me know how far you get and what issues you start running into if you’d like to learn more stuff and things. Cool?

Hi,I haven’t had much time to have a good look through the code, but i had a quick look at updating the item class, with what you have shown, but i get the error

Assets/Item.cs(1,21): error CS0246: The type or namespace name `MonoBehaviour' could not be found. Are you missing a using directive or an assembly reference?

I assumed it was maybe because there is no using UnityEngine; which i assume bring in all the engine classes maybe?

So I added it to the top of the item class, now I get the following error’s

Assets/Item.cs(11,16): error CS0118: `Item.Rarity' is a `field' but a `type' was expected
Assets/Item.cs(17,24): error CS0118: `Item.ItemType' is a `property' but a `type' was expected
Assets/Item.cs(37,25): error CS0118: `Weapon.ItemType' is a `property' but a `type' was expected
Assets/Item.cs(57,25): error CS0118: `Medical.ItemType' is a `property' but a `type' was expected
Assets/Item.cs(77,25): error CS0118: `Ammo.ItemType' is a `property' but a `type' was expected

Am I missing something here? thanks

Exactly, you assumed correctly.

Apologies, the posted code was just an example illustrating a possible use of overridable properties - it looks like the compiler can’t find your definitions for the enums now. Make sure they haven’t been deleted somehow and reintroduce them if necessary (I’d recommend putting each of them in their own files as well, but it shouldn’t be a requirement).

Also make sure that each derived type is in its own file with the same name as the class as they are MonoBehaviours as well by virtue of deriving from Item - note that you don’t yet have to include a using UnityEngine; statement at the top since they’re not directly deriving or making use of Unity classes: they derive from Item (which will need that statement as you’ve found out), which in turn derives from MonoBehaviour making it and it’s derivatives all MonoBehaviours as well.

Makes sense?

Hi, I have I have got the script working also created some more stuff since my last post,

My Inventory GUI, works nicely, press “i” to show/hide also has a close button.

using UnityEngine;
using System.Collections;

public class InventoryGUI : MonoBehaviour {

bool inventoryMenu = false;
public int inventorySlots = 8;

public int _inventoryRows = 6;
public int _inventoryCols = 4;
public int _buttonHeight = 60;
public int _buttonWidth = 60;

	void OnGUI() {
		if (inventoryMenu == true) {

			// Make a group on the center of the screen
			GUI.BeginGroup (new Rect (Screen.width / 2 - 125, Screen.height / 2 - 227.5f, 250, 455));
			// All rectangles are now adjusted to the group. (0,0) is the topleft corner of the group.
			
			// We'll make a box so you can see where the group is on-screen.
			GUI.Box (new Rect (0,0,250,455), "Inventory");
			GUI.Label(new Rect(60, 15, 250, 20), "Items in your backpack!");
			if(GUI.Button (new Rect (5,40 + (_inventoryRows * _buttonHeight),240,50), "Close")) {
				inventoryMenu = false; // This Disables the Inventory GUI.
			}

			for(int y = 0; y < _inventoryRows; y++) {
				for(int x = 0; x < _inventoryCols; x++) {
					GUI.Button(new Rect(5 + (x * _buttonWidth), 40 + (y * _buttonHeight), _buttonWidth, _buttonHeight), (x + y * _inventoryCols).ToString());
				}
			}
			
			// End the group we started above. This is very important to remember!
			GUI.EndGroup ();
		}
	}
	
	void Update () {
		if (Input.GetKeyUp(KeyCode.I)) {
			inventoryMenu = !inventoryMenu;
		}
	}
}

also a collider trigger script for when you get close to a pickup-able item, will show the text “Press E to pick up the item” which is a gui texture2D

using UnityEngine;
using System.Collections;

public class ItemPickUp : MonoBehaviour {

	public bool hasCollided = false;
	public string labelText = "";
	public GameObject thePlayer = null;
	public Texture2D textTexture = null;

	// The Gui
	void OnGUI()

		{
			if (hasCollided == true)
		{
			GUI.Label(new Rect(Screen.width / 2 - textTexture.width / 2, Screen.height / 2 - textTexture.height / 2, textTexture.width, textTexture.height), textTexture);
		}

		}



	// Checks to see if player collides with pick up collider.
	void OnTriggerEnter(Collider other)

		{
			if(thePlayer)
		{
			hasCollided = true;
			labelText = "Hit E to pick up the key!";
		}

		}

	// disables the gui by setting the hasCollided to false.
	void OnTriggerExit(Collider other)

		{
			hasCollided = false;
		}

	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

The one problem I am having with this is the gui will show at the start of the game until i collide and un-collide with the item then it will go off. I don’t want it to be shown at the game start?

I have got to the stage also where I what to make that “E” functional to actually pick up the item, but I don’t know where to start with it? so when OnTriggerEnter and the press E comes up to actually press E “Pickup that item”, replace one of the buttons in the inventory GUI with the texture2D icon for that item, destroy it from the game world so it can’t be picked up again. then if possible when i mouse over the item icon in inventory gui have a hover effect the shows name, description, and when the icon is clicked. open a new gui with buttons like DROP (which would add the item back to the gameworld) USE (which would i guess heal etc) and EQUIP.

Thanks,
Fire

Hey Fire, sorry I couldn’t get back to you earlier; day job is getting more demanding.

The InventoryGUI script looks good from what I can tell - simple and straightforward, which is a really good paradigm to follow. Small note, just a matter of convention: Typically you would only prefix fields with “_” if they were private, public fields are usually not prefixed by an underscore and are usually capitalized. Not a big deal and what matters more is what works for you, but following a standard is a good practice to exercise from the get go. Whatever works for you, as long as its consistent.

The ItemPickUp script - to address a somewhat trivial matter first, I’d recommend you remove the definitions for the Start and Update methods if they aren’t actually doing anything. Again, not a big deal, but technically Unity should be finding and invoking them which will produce a small amount of overhead and wasted processing. It’d probably never amount to a noticeable difference, but there’s no reason for it.

So much for the nitpicking, now more to the point: Why is the pickup message being displayed when it shouldn’t be? Well, we can tell right away that the message is showing up in the OnGUI method, but only if hasCollided is equal to true. So something must be setting it to true when it shouldn’t. Looking through the script we can see that the only point where its being set to true is in the OnTriggerEnter method - and that reveals the problem.

In Unity, an object’s trigger methods get fired off indiscriminately of what triggered them (provided its a valid collision). Unity passes in the other Collider involved in the collision and leaves it up to your method implementation to know what to do, or what not to do with it. Currently, by writing:

if(thePlayer)
{
    ...
}

You are simply checking if thePlayer is not a null reference, which is functionally the same as if(thePlayer != null). This is how the language evaluates object reference as boolean statements: false if null, true otherwise. Given the context of the script, you probably meant something like:

void OnTriggerEnter(Collider other)
{
    if(other.gameObject == thePlayer)
    {
        hasCollided = true;
        labelText = "Hit E to pick up the key!";
    }
}

Given that thePlayer is actually being set to the player GameObject in the inspector.

However, you have a problem now that comes up when you start considering picking up the actual object. Before getting into any of the details of what happens when you actually pick an object up, as it stands you have to consider the possibility of there being more than one object that you can pick up. Since you’re most likely thinking of using the current ItemPickUp script on more than one object in the scene at a time, if the player collides with more than one object it’ll trigger more than one OnTriggerEnter method and you’ll end up displaying more than one “Hit E to pick up the _” message at a time. Then when you actually hit E you’ll have to find some way of deciding which object the player picks up, which may become more than irritating for the player.

What I think you need is a single script which abstracts the logic of what item you are currently in range of picking up, instead of multiple scripts that do so. Something like an “ObjetSeeker” script attached to the player that exposes a public property or field that always represents a single object you will pick up if you press E - that way when you actually press the button you only have to check if that property is not null and pick it up if it isn’t, leaving the details of how that object is determined to that single script which, if it changes, the changes will be contained to that script only.

Let me know what you come up with or if you get stumped - I think I could come up with and explain something decent for you if you get stuck. Also, any chance you could post a screenshot of what you have so far? Just curious to see what it looks like ; )