I'm new to C Sharp, and writing a game w/ the XNA Framework.
I'm trying to establish variables for the buttons on the XBox 360 controller, so I can reconfigure the buttons' game functions in one place and not have to change direct references to the buttons everywhere.
So if I want to assign a button to "attack", instead of this:
if (gamePadState.IsButtonDown(Buttons.B)
{
// do game logic
}
I want to do this:
if (gamePadState.IsButtonDown(MyAttackButton)
{
// do game logic
}
Any ideas? I'm sure it's a very simple solution, but I've tried several approaches and none have worked yet. Thanks!
Buttons is just an enum, so you just need to create a variable with that name like
Buttons MyAttackButton = Buttons.B;
An alternative would be to define an enum somewhere:
public enum MyButtons
{
AttackButton = Buttons.B,
DefendButton = Buttons.A
}
Then to test it:
if (gamePadState.IsButtonDown((Buttons)MyButtons.DefendButton))
You could also create a dictionary:
enum MyButtons { ShootButton, JumpButton }
Dictionary<MyButtons, Buttons> inputMap = new Dictionary<MyButtons, Buttons>()
{
{ MyButtons.ShootButton, Buttons.Y },
{ MyButtons.JumpButton, Buttons.B },
}
...
if (gamePadState.IsButtonDown(inputMap[MyButtons.ShootButton]))
{
// Shoot...
}
The advantage of this method is that the button map can be modified at runtime, so you can use it to implement customizable control settings.
Related
my situation..
private void Win()
{
OpenNextStage();
CheckGameCount();
Managers.Ui.SetSmallPopup(UiManager.SmallPopupUi.ClearPopup);
_uiGamePopup.SetLineOnOff(false);
}
private void CheckGameCount()
{
_gameCounter++;
if (_gameCounter >= 1)
{
Managers.Ads.ShowInterstitial();
_gameCounter = 0;
}
}
this is my code.
my code make popup object after show Ads.
i want control this Ads's canvas, and change sort order.
but Ads object name is 768x1024(Clone). it's uneasy to be convinced of that always have that name.
how to find that object?? or is there any good way?
i use GameObject.Find() but this is not good way i think.
Go to GoogleMobileAds Folder and set sort order of different ad canvases as in:
I am trying to make a dropdown that allows you to select different ways to display time. I got it all working except I need to find a way to save and load the option the player selected.
private void Start() {
timeDropdown.options.Clear();
List < string > items = new() {
"",
DateTime.Now.ToString(),
DateTime.Now.ToLongDateString(),
DateTime.Now.ToLongTimeString()
};
foreach(var item in items) {
timeDropdown.options.Add(new TMP_Dropdown.OptionData() {
text = item
});
}
DropdownItemSelected(timeDropdown);
timeDropdown.onValueChanged.AddListener(delegate {
DropdownItemSelected(timeDropdown);
});
}
void DropdownItemSelected(TMP_Dropdown timeDropdown) {
int index = timeDropdown.value;
timeText.text = timeDropdown.options[index].text;
}
I think you would use an int to save it but I don't know how to do that. Thank you.
You could use unity's player prefs system below is a link to documentation on how it works.
Unity player prefs documentaion
Alternatively you could create your serialisation system here's a Brackey's video which shows how to make a basic class serialisations system
YouTube tutorial
For what your trying to do the fastest and quickest approach would be to just use player prefs for saving and loading the int value.
So I created a method to populate the inventory system I have created in Unity, however I can't seem to figure out a way to order them in alphabetical order. Each button is created as a child of the button holder panel which is a game object variable. This method is called whenever the player picks something up.
private void Populate_Inventory ( )
{
Button btn_CurrentItem;
int int_Count;
for ( int_Count = int_PreviousCount; int_Count < strList_Inventory.Count; int_Count++ )
{
btn_CurrentItem = Instantiate ( btn_Item, pnl_ButtonHolder.transform );
btn_CurrentItem.name = strList_Inventory [ int_Count ];
btn_CurrentItem.GetComponentInChildren<Text> ( ).text = strList_Inventory [ int_Count ];
btn_CurrentItem.gameObject.AddComponent<Inventory_Item> ( );
btn_CurrentItem.GetComponent<Inventory_Item> ( ).str_Name = cls_Pickup.str_PickupName;
btn_CurrentItem.GetComponent<Inventory_Item> ( ).str_Information = cls_Pickup.str_PickupInformation;
int_PreviousCount = int_Count;
}
int_PreviousCount++;
}
If anyone can help it would be very appreciated.
Jonathan Palmer
The primary issue with this approach is that you're adding single buttons at a time whenever you pick up an item, and those buttons are created as children of the pnl_ButtonHolder object, but your method has no knowledge of previous buttons that have been created.
Option 1 (Bad)
You can use the GetComponentsInChildren<Button>() method on the pnl_ButtonHolder object to get all of the button components that have been previously created once you've added a new button, and then sort your buttons according to their name.
This isn't ideal as GetComponentsInChildren<>() is an expensive method, and doesn't make use of the idea of an Inventory very well.
Option 2 (Good)
Create an Inventory class that manages your actual inventory, including sorting items. It might look something like this:
public class Inventory_Button : MonoBehaviour
{
public Button button = default;
public void Initialize(Intenvory_Item item)
{
button.name = item.name;
// Other work here.
}
}
public class Inventory : MonoBehaviour
{
public GameObject inventoryItemPrefab = default;
public Transform inventoryParent = default;
private List<Inventory_Item> _inventory = new List<Inventory_Item>();
private List<Inventory_Button> _inventoryButtons = new List<Inventory_Button>();
public void AddItem(Intenvory_Item item)
{
_inventory.Add(item);
Inventory_Button button = GameObject.Instantiate(inventoryItemPrefab, inventoryParent).GetComponent<Inventory_Button>();
button.Initialize(item);
_inventoryButtons.Add(button);
_inventoryButtons.Sort((x, y) => x.name.CompareTo(y.name));
}
public void RemoveItem(Inventory_Item item)
{
// Do work to remove the item.
}
}
This kind of setup is useful for several reasons:
Your inventory management is now handled by a single class rather than a collection of objects. This makes it easy to interact with.
It will make removing items much easier in the future. With your current implementation, it looks like you'd have a difficult time removing an item from the player's inventory.
It separates responsibility between an Inventory class, an Inventory_Item class, and an Inventory_Button class, each of which stands on its own and works together.
A few final notes:
I've left out some details in the two classes above. You should fill them in to fit the needs of your game.
You can be more efficient with sorting by using something like Insertion Sort. This solution will get the job done.
Using prefixes for naming your variables can be quite confusing to people trying to read your code. I recommend you check out a style guide. There's a great one here.
I need to instantiate an object at runtime, where the number of objects are based on a txt file (number of lines). All objects need to be clickable (onClick() event) and when they are pressed a tooltip must appear. Tooltips are specific ( Object1 -> Tooltip1, Object2 -> Tooltip2). Tooltips are just a Panel and they consist in some other Panels and Buttons. One of these create a new Panel. Also these Panel are specific (Tooltip1 -> Panel1 and so on). I create a prefab for each of three objects.
So, Object1 - onClick() -> Tooltip1 - onClick() -> Panel1. At runtime.
How can I keep reference of an object create at runtime?
My first solution:
Create a Empty object and assign a script to it with a public variable (Object prefab).
Instantiate Object prefab:
for (int i = 0; i < numberOfObject; i++)
{
var instance = Instantiate(m_ObjectPrefab);
instance.name = "Object_" + m_nameObject[i];
Instantiate one Tooltip for each Object:
var instancePanelTooltip = Instantiate(m_panelTooltipPrefab, m_canvas.transform);
instancePanelTooltip.name = "Panel_Tooltip_" + m_nameObject[i];
Instantiate one Panel for each Tooltip:
var instancePanel = Instantiate(m_panelPrefab, m_canvas.transform);
instancePanel.name = "Panel_" + m_nameObject[i];
instancePanel.SetActive(false);
instancePanelTooltip.SetActive(false);
Add event handler for Object
DetectClickOnObject scriptDetectClickPanelTooltip = instance.AddComponent<DetectClickOnObject>();
scriptDetectClickPanelTooltip.SetTooltip(instancePanelTooltip);
Add event handler for button on Tooltip
DetectClickOnObject scriptDetectClickPanel = buttonOpenPanel.AddComponent<DetectClickOnObject>();
scriptDetectClickPanel.SetPanel(instancePanel);
}
Issue with this solution:
I will instantiate 3 object (Object, Tooltip, Panel) for each line of file. For Object it is okay, but it is not with Tooltip and Panel, because only one Tooltip is active among all (same for Panel).
I just avoid the problem of reference because I create in the same place all objects (one for each element), but what can I do if I need to get access to Tooltip2 or Panel3 without a reference (I am trying to avoid Find and similar).
Conclusion of the first solution: Solution is working, but I think there is a better way of doing that (avoid create so much object and keep reference in the right way).
My second solution (guidelines):
I am trying to create a class to keep reference of all object create at runtime.
I want to create an instance of Object for each lines, but I want just one Tooltip and Panel for all Object and changing properties according to Object clicked. So Object is create at runtime, but Tooltip and Panel are already in the scene but not active.
I need a Register Event Manager to add onClick() event at runtime on Objects and it need to handle properties to be set on Tooltip and Panel based on clicked Object.
Problems with second solution: Referring to 1) I tried to follow that, but I ended up with nothing. I am lost between singleton, static and something else. Referring to 2) I think it can be easy, I just need to cut away some of the first solution. Referring to 3) I can not do more if I do not have a class reference manager.
What I am looking for:
Is first solution so bad? If I look at code I am disgusted by it, it is far away from elegance (or something similar).
Can you suggest me how can I keep track of reference create at runtime with a Reference Manager? And how use it?
#Behnam Sattar suggestion:
As DataModell class,
public class DataModelPOI
{
public string m_namePOI { get; private set; }
public string m_locationPOI { get; private set; }
public Vector2d m_positionPOI { get; private set; }
public GameObject m_gameObject_POI;
public GameObject m_gameObjectTooltip;
public GameObject m_gameObjectPanel;
public DataModelPOI(string namePOI, string locationPOI, Vector2d positionPOI)
{
this.m_namePOI = namePOI;
this.m_locationPOI = locationPOI;
this.m_positionPOI = positionPOI;
}
}
As DataManager,
public class POIManager : MonoBehaviour
{
List<DataModelPOI> dataCollectionPOI = new List<DataModelPOI>();
void Start()
{
ReadFile();
SpawnPOI();
}
void Update()
{
int count = dataCollectionPOI.Count;
for (int i = 0; i < count; i++)
{
UpdatePOIPosition();
}
}
void ReadFile()
{
TakeDataFromFile();
for (int i = 0; i < ength; i++)
{
DataModelPOI dataPOI = new DataModelPOI(m_namePoi[i], m_namePoi[i], _locations[i]);
dataCollectionPOI.Add(dataPOI);
}
}
private void SpawnPOI()
{
for (int i = 0; i < dataCollectionPOI.Count; i++)
{
DataModelPOI dataPOI = dataCollectionPOI[i];
var instance = Instantiate(m_POIPrefab);
instance.name = "POI_" + m_namePoi[i];
dataPOI.m_gameObject_POI = instance;
dataPOI.m_gameObjectTooltip = m_panelTooltipPOI;
dataPOI.m_gameObjectPanel = m_panelPOI;
}
}
Now I need to register Event associate to GameObject instantiate before. I want to do that in my EventManager. How can I point to dataCollectionPOI in EventManager class created and feeded in DataManager? Thanks for your time.
Based on my understanding your question is mostly a design question. In first part of this answer, I'm giving you a suggestion for doing the design and keeping a reference to your objects. In second part I'll give you some tips regarding performance.
[I'm using RootObject instead of Object to refer you the main GameObject you create.]
Design
Let's break down our needs and then come up with a solution for each.
First we want to read some text file and then get some data from that. This data will be used later for creation of GameObjects. For now let's just focus on the data itself.
What we want here is a manager class which reads the file for us and stores the data in some form. We access this manager later and ask for our data in order to create the GameObjects.
This manager class stores our data in a collection of data objects [notice here we're talking about plain objects and not Unity's GameObjects]. You need to design this data class based on each line of text you have. Optionally, you can also keep the references to GameObjects here too.
Assume you're reading three string values from each line, named ValueOne, ValueTwo, and ValueThree, and you want to keep reference to three GameObjects called RootObject, ToolTip and Panel. For such purpose you can define following class:
public class DataModel {
// Values read from text file.
public string valueOne { get; private set; }
public string valueTwo { get; private set; }
public string valueThree { get; private set; }
// Placeholders for GameObjecs created at runtime.
public GameObject rootObject;
public GameObject tooltipObject;
public GameObject panelObject;
public DataModel(string valueOne, string valueTwo, string valueThree){
this.valueOne = valueOne;
this.valueTwo = valueTwo;
this.valueThree = valueThree;
}
}
Then in your manager class you can create a collection (a List for example) for holding your data. Your manager class should read the text file at some point and populate this list with instances of DataModel. It will be something like this:
public class DataManager {
List<DataModel> dataCollection = new List<DataModel>();
public void ReadFile() {
// Here you need to read the file and get the values you need.
// The actual code should be different from what I'm putting here.
foreach(string line in lines) {
// You get valueOne, valueTwo and valueThree
// from each line and maybe prepare them
// (maybe you need conversion from string to int)
DataModel data = new DataModel(valueOne, valueTwo, valueThree);
dataCollection.Add(data);
}
}
}
After you call the method on manager to read the data, you'll have your data prepared for you whenever you want to use it.
It's time to create objects based on the data and save the reference.
for (int i = 0; i++; i <= manager.dataCollection.Count) {
DataModel data = manager.dataCollection[i];
data.rootObject = instantiate() // You instantiate the root GameObject here.
data.tooltip = instantiate() // You instantiate the tooltop GameObject here.
data.panel = instantiate() // You instantiate the panel GameObject here.
}
Done. Now you have a manager class which has reference to all the data and also GameObjects which are created based on this data.
Performance
It might not be a good idea to do this all in runtime as it might cause frame drops in your game. If this is a problem you can try object pooling. If you search for that you should be able to find great tutorials on how to perform object pooling.
If you ended up not using object pooling, you can still remedy any performance drops by instantiating only one GameObject per frame. This can be done using Coroutines. You just need to do a yield return new WaitForEndOfFrame() in your loop of instantiation.
Final Note
Keep in mind that this all a suggestion and I don't think there is one single best answer to your question. Make sure you try to understand what tools are at your disposal and try them all before deciding on one solution. :)
You're basically on the right track, but you can separate (or 'objectify' ;) what scripts keep what references. Keep scripts that manage the internal workings of your prefabs in those prefabs.
A singleton-like pattern for the Tooltips is definitely the way to go. For where you can't use a singleton, such as in the clickable objects, use something more akin to dependency injection (to save on Finds) and pre-stored reference:
var obj = Instantiate(...);
obj.GetComponent<SomeManagerScript>.SomeDependency = SingletonInstance;
obj.GetComponent<StoredReferenceScript>.TextPanel.Text = "Some Text";
As to events, you can handle them a couple of ways. One, each clickable manages its own bindings/functionality; or two, each clickable notifies a global manager that it was clicked on, and the manager determines the actions to take.
Basically you need to create an object at Runtime and set the data for that specific object.
here is the simplest way to do that
first of all create scripts first one can Create an object at runtime and second one is your data setter script that attach with your prefab
so, when ever you create an object at runtime you can pick a reference of the dataSetter and set the specific data.
Hope below given code may useful to you.
GameObject object = Instantiate(gameObject,parent)
DataSetter s = object.GetComponent<DataSetter>().toolTip = "YourTooltip";
in DataSetter script tool tip is a string variable.
you can also declare text variable and assign a text to that.
I have the following code:
[OnTap ("Account")]
[Alignment (UITextAlignment.Center)]
[Entry ("Create ScanDo! Account")]
public string Login;
And I'd like to set the Cell background color dynamically, based on the contents of another field and then after the button is clicked. Could anyone point me in a direction with some samples?
Thanks,
Rick
The answer I came up with:
btnLogin = new StyledStringElement("", delegate {Account();})
To define the object, add it to the RootElement, then:
btnLogin.BackgroundColor = UIColor.Green;
To set the color! This method let me set color, font, size and caption.
Great work Miguel, Thanks!
As you're adding the button to the root collection you can set the colour. Just as you set the elements of a section.
Root = new RootElement("First Section") {
new Section ("Test"){
new StyledStringElement("Login", delegate { Account(); })
{
BackgroundColor = UIColor.Green
}
}
}
I don't like to keep pimping my projects but in this case it is the best option for you.
Check out https://github.com/RobertKozak/MonoMobile.MVVM
My project started out as adding Databinding support to MonoTouch.Dialog but has grown into a much bigger framework that is much easier to use than MonoTouch.Dialog.
Using MonoMobile.MVVM the code to do what you want looks like this:
public class ButtonView : View, INotifyPropertyChanged
{
private UIColor ButtonColor = UIColor.Red;
[Button]
[Bind("ButtonColor", "BackgroundColor")]
public void Test()
{
ButtonColor = UIColor.Green;
PropertyChanged(this, new PropertyChangedEventArgs("ButtonColor"));
}
public event PropertyChangedEventHandler PropertyChanged = (s,e)=>{};
}
There are better ways to accomplish this using a proper ViewModel but this will work as listed (I tested it before I typed it in here.)
MonoMobile.MVVM is still in beta but there is enough there to get you going. It should be in full release status in the next couple of weeks after I finish up implementing INotifyCollectionChanged and adding a few more bindings for various Element properties.