I'm creating a unity project where when the user presses a certain button a stat modifier will increase, how would I get this to work using C#? this is the current code but I feel like this is entirely in the wrong direction
public class logicBook
{
public void Equip(Character c)
{
c.logic.AddModifier(10);
}
public int logic;
logic = 0;
}
I'm pretty new to C# and Unity so help would be really apricated!
I believe by button you meant key so if you want to implement that you need first to have your class inherit from Monobehaviour so that you can use your script as a component of a gameobject.
then you should have an Update function (it is a function that gets called every frame) and rihgt there you can check the input
public class logicBook : MonoBehaviour{
public void Equip(Character c){
// do some cool stuff here
}
void Update(){
if(Input.GetKeyDown(/* Key that triggers this */){
Equip(/* Argument here */);
}
}
If you want to have a button in game that triggers this function create a canvas UI in your scene and create a button object as a child of your canvas and then add the function to the button onClick component.
Related
Edit: It turns out it was how I was getting the ProjectileWeapon component. I was getting the one that was on the non-instantiated prefab instead of getting the one on weapon gameobject. I changed it so that the code instantiates the game object first (or gets the existing one if we've already picked it up), and then get the component from that. So the rest of the code works fine. Now I can move on and improve it!
I have an issue with the class below called ProjectileWeapon. It is based on an abstract class called Weapon, and that class inherits MonoBehaviour.
Weapon has two abstract functions called BeginCycle and EndCycle which are implemented in the ProjectileWeapon class. Those functions set a variable called "firing".
The problem is, "firing" doesn't ever seem to be set despite the functions being called correctly. I know the functions are called because I can see the prints in the console.
Also, when I use that variable in the update function, it doesn't do anything because the variable never changes.
The OnGUI function is working and is displaying text on screen, however the "firing" variable is never updated.
Am I misunderstanding how to use inheritance?
This class is on the weapon prefab which is then instantiated during the equipping function in the game
public class ProjectileWeapon : Weapon
{
private bool firing;
private float firingTimer;
void Start()
{
print("ProjectileWeapon start");
}
void OnGUI()
{
GUI.Label(new Rect(0,100,100,100), "ProjectileWeapon firing: " + firing);
}
void Update()
{
// this function is called but "firing" is not updated
}
public override void BeginCycle()
{
print("projectile begin cycle");
firing = true;
}
public override void EndCycle()
{
print("projectile end cycle");
firing = false;
}
}
Here's the base class:
public abstract class Weapon : MonoBehaviour
{
public abstract void BeginCycle();
public abstract void EndCycle();
}
EDIT: Here is the code that calls the above
This component is added to the player game object
public class WeaponHandler : MonoBehaviour
{
public bool FireInput { get; set; } // set to true when user holds the mouse button down, and false when let go
public Weapon WeaponBehaviour; // this is the script that does the weapon functionalility. Any subclass of Weapon can be put here e.g. ProjectileWeapon, MeleeWeapon
private bool isFiring = false;
void OnGUI()
{
GUI.Label(new Rect(0,0,100,100), "fire input:" + FireInput + ", isFiring:" + isFiring);
}
void Update()
{
// fire weapon
if (WeaponBehaviour && FireInput && !isFiring)
{
ActivateWeapon();
}
else if (!FireInput && isFiring)
{
DeActivateWeapon();
}
}
private void ActivateWeapon()
{
print("activate weapon");
isFiring = true;
WeaponBehaviour.BeginCycle();
}
private void DeActivateWeapon()
{
print("deactivate weapon");
isFiring = false;
WeaponBehaviour.EndCycle();
}
}
Based on the code you've provided, there are three possible scenarios:
You're not calling the functions. However, if the print functions are called, then you must be calling them.
You're calling both functions, which sets the variable to true, and then to false.
You're overriding the variable with a local variable with the same name. Visual Studio will warn you if that's the case.
It's hard to tell without knowing where the variables are supposed to be called. If you upload the rest of the code, I'm sure the answer will be clear.
It turns out it was how I was getting the ProjectileWeapon component. I was getting the one that was on the non-instantiated prefab instead of getting the one on weapon gameobject. I changed it so that the code instantiates the game object first (or gets the existing one if we've already picked it up), and then get the component from that. So the rest of the code works fine. Now I can move on and improve it!
I'm new to coding and Unity, I'm working on a simple click style game to learn the basics of both. I've created several scenes: MainMenu, UI, 1st level and 2nd level. After pressing 'Start' in main menu i'm loading UI and 1st level additively.
In UI layer I have a shop UI and other bits that I never want to unload. On the 1st and 2nd level i have the bits that i want to have only on those scenes.
So, what I'm trying to do is when i purchase an item or upgrade for the 1st level i want a GameObject (sprite) to be set as active.
What I've tried to do is to call a function in one script that is attached to GameObject in 1st level from script that is attached to a purchase button in UI scene, but from what I was able to understand from messing with it will set that game object active if it's assigned in the UI scene - so the whole thing is basicly pointless and i can do it much easier.
Code in script attached to GameObject in 1st level scene
public class Work_Button : MonoBehaviour
{
public GameObject hubert12;
public void Huberd()
{
hubert12.SetActive(true);
}
}
Code in script attached to GameObject in UI scene
public class Shop : MonoBehaviour
{
public GameObject buyHubertOnebutton;
public GameObject test;
public void UnlockHubert1()
{
if (Global_Cash.CashCount >= 20)
{
Global_Cash.CashCount -= 20;
buyHubertOnebutton.GetComponent<UnityEngine.UI.Button>().interactable = false;
Work_Button sn = test.GetComponent<Work_Button>();
sn.Huberd();
}
}
}
If you have any remarks anout how i've spit scenes or anything else they will be more than welcome!
Thanks!
There's something you need to be aware of, and that is that you can't reference an object from one scene, in another. You CAN reference the same Prefab though, but that's a slightly different issue.
One way I find effective is to do something like this:
public class Work_Button : MonoBehaviour
{
public GameObject hubert12;
public void Awake ( )
{
Shop.Register ( this );
}
public void Huberd ( )
{
hubert12.SetActive ( true );
}
}
Then you can have a Shop manager that has instance and static components.
public class Shop : MonoBehaviour
{
// Static variables
private static Work_Button _workButton;
// Instance variables
public GameObject buyHubertOnebutton;
public static void Register ( Work_Button workButton )
{
_workButton = workButton;
}
public void UnlockHubert1 ( )
{
if ( Global_Cash.CashCount >= 20 )
{
Global_Cash.CashCount -= 20;
buyHubertOnebutton.GetComponent<UnityEngine.UI.Button> ( ).interactable = false;
if ( _workButton != null )
_workButton.Huberd ( );
}
}
}
This works by having your button register with the shop. And because we're using the static variable here, we don't need to "find" the Shop object. The instance method UnlockHubert1 will check to make sure there is a button registered.
This represents just one of many ways to accomplish this. It's also the most basic of basic implementations. But as of right now I'm fond of this method. Extending this, you could store the registered items in a Dictionary collection, and you could do some cleanup/deregister when a button is destroyed (i.e. OnDestroy ).
The assumption here is that there is only one Work_Button in the scene, otherwise you'll need a way to differentiate them (i.e. a Dictionary with am identifier as the key).
I am facing the following problem:
when I want to place an object in the Scene it moves around,
I need it to stay in its place so it must be an anchor object.
Unfortunately, we can't anchor an object in Vuforia without Using Plane Ground detection.
Moreover after "Enabling Plane Ground Detection", the augmented object appear and never gets lost and the function "onTrackingLost" never triggered.
It seems that this function is not automatically being Called and not working!
How can we solve this issue, please ?!
You could detach the object from the vuforia target - making it not a child but instead set it somewhere else in the hierachy - and only move it to the correct coordinates OnTargetFound.
Add e.g. a UnityEvent<Transform> like (this goes to the vuforia target)
[system.Serializable]
public class TransformEvent : UnityEvent<TargetFoundEventHandler>
{
}
public class TargetFoundEventHandler : DefaultTrackableEventHandler
{
public TransformEvent onTrackingFound;
protected override void OnTrackingFound()
{
onTrackingFound.Invoke(transform);
}
}
you can use that to reference callbacks (similar to the onClick of Buttons) but those methods have to expect a TargetFoundEventHandler parameter like (this goes to the object to place)
public class PlaceMeOnTarget()
{
public void PlaceOnTarget(TargetFoundEventHandler target)
{
transform.SetPositionAndRotation(target.transform.position, target.transform.rotation);
// optinally remove the callback so this object
// will not be placed elsewhere
target.onTrackingFound.RemoveListener(PlaceOnTarget);
}
}
I'm trying to make a button interactable after a certain scene (playing level) has been loaded. It's a button in a menu scene that represent the loaded scene itself (level selectable after playing it).
The problem is this: If the users passes a certain level, say level 1, level 2 gets loaded, and a static method gets called:
public static void AllowTut2()
{
Tut2Allowed = true; //public static bool initialised in this script
tutorial2.interactable = true; //tutorial2 is a button in the "menu scene"
}
To make it clear where the variables come from, this is part of the same script:
public class LevelSelectScript : MonoBehaviour {
public Button tutorial2;
public static bool Tut2Allowed = false;
//...some other variables
void Start ()
{
tutorial2 = tutorial2.GetComponent<Button>();
tutorial2.enabled = false; //more later on
///... some other code
}
}
Now the problem is this error: An object reference is required to access non-static member `LevelSelectScript.tutorial2' (refers to method AllowTut2).
It seems that I cannot change tutorial2.interactable trough the given static method (called in another script).
It basically says the button tutorial2 is non-static, therefore cannot use this in a static method.
Now if I make the button static, i.e. change
public Button tutorial2;
to
public static Button tutorial2;
then I have no way to assign the button object in the scene to this variable in the attached script.
Does someone perhaps know a solution to this problem?
Thanks in advance!
if you want to use static varaibles and also use inspector for assigning you can use singleton , here is where you can learn it
I'm creating a 2d Turret Defense game in C# and I have a question about the management of the updates of the turrets.
I want to create the menu over the turret sprite with several options for the upgrade.
My idea is to load the menu from the resources as sprite, assign it as child to the turret gameObject and then manage the comunication between the button to the turret to start the upgrade process.
There is a way to assign a method/function to a resource freshly loaded?
For example (in turret class):
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
myMenuButton.OnMouseDown(){
// do something with the current turret's class
};
Or I have to save the gameObject sprite in resource folder with inside a script that will manage the OnMouseDown method searching the parent script of the turret and use the correct method?
For example (in menu sprite class):
void OnMouseDown(){
GameObject parent = gameObject.transform.parent.gameObject;
turretScript parentScript = (turretScript) go.GetComponent(typeof(turretScript));
parentScript.doUpgrade();
}
Thanks for any help!
I don't know about Sprite itself (documentation may have information about it, did you already research there?)
But I don't see why you cant use Buttons instead of Sprite to handle this "menu behaviour" you wants to do. Button class have an onClick event handler that you can use to assign listners at runtime like
myMenuButton.onClick.AddListener(() => {
//handle click here
});
you can also set methods by lambda expression, just google about it and you'll find a lot of resources to learn how to use it ;)
first create a class which already implements the OnMouseDown and a list of function pointers and attach this class to every single item you are going to use it on beforehand.
public class MouseDownScript : MonoBehaviour
{
public List<Action> Actions = new List<Action>();
void OnMouseDown(){
foreach(Action action in Actions)
action();
}
}
Then you have the ability to:
{
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
// Cache the script
MouseDownScript mouseScript = myMenuButton.GetComponent<MouseDownScript>();
// Add anonymous actions with a lambda as such:
mouseScript.Actions.Add(() => /*Any action here*/);
// Add existing functions as such:
mouseScript.Actions.Add(MouseDownAction));
}
public void MouseDownAction() {}
I don't know Unity but you might be able to inherit from Sprite, add a property to it of type Action and assign that after you create it with Resources.Load
class Program
{
static void Main(string[] args)
{
var s = new Sprite();
s.Action = dostuff;
// outputs Hello
s.Action.Invoke();
Console.ReadLine();
}
public static void dostuff() { Console.WriteLine("Hello"); }
public class Sprite
{
public Action Action { get; set; }
}
}
You can add new class to Sprite when create Sprite
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
myMenuButton.AddComponent<ClassForSprite>();
In ClassForSprite
public class MouseDownScript : MonoBehaviour
{
void onAction1(){
//Code process for action 1
}
void onAction2(){
//Code process for action 2
}
}
I think you'll want to use delegates.
Basically you define a method signature e.g.
public delegate void ClickHandler();
then you define an instance of that signature:
public ClickHandler OnClick;
you can assign a method to OnClick on runtime and execute.
in turret:
public void ExecuteOnTurrent()
{
// do stuff in turret
}
public void LoadSprite()
{
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
myMenuButton.OnClick= ExecuteOnTurrent;
}
in sprite
public delegate void ClickHandler();
public ClickHandler OnClick;
public void Update()
{
//- detect click or other action
if(click and OnClick!= null)
{
OnClick();
}
}