Unity3D 2018.2
So I have a canvas that gets deactivated and reactivated at users choice. I have a List filled with transforms in which I populated the Grid with. I also have another List to hold all the images that will be used to populate the Grid with, since what the grid is being populated with are buttons containing the transform. For example if I click the button and run Debug.Log("transform.name"), I should see all my different transforms.
Problem 1: Every time this canvas gets enabled or disabled, the grid
keeps adding 1 element under the initial one, and after being
enabled/disabled again, another element is instantiated under that
one.
+
Problem 2: Also none of these instantiated buttons get called. Maybe
the problem here is due to the 1st problem?
Here is the code I have for inside the button I have
public class SatelliteButton : MonoBehaviour {
[SerializeField]
private Image myIcon;
public void SetIcon(Sprite mySprite)
{
myIcon.sprite = mySprite;
}
public void OnMouseEnter()
{
Debug.Log(transform.name);
}
}
Here is the code for populating the grid
public class SatelliteGridControl : MonoBehaviour {
private List<Transform> satelliteListFromPlanet;
[SerializeField]
private GameObject buttonTemplate;
[SerializeField]
private GridLayoutGroup gridGroup;
[SerializeField]
private List<Sprite> iconSprites;
// Use this for initialization
void OnEnable()
{
getSatellitesInPlanet();
genInventory();
}
// Get Satellites
private void getSatellitesInPlanet()
{
satelliteListFromPlanet = new List<Transform>();
// Get current planet
Transform currentPlanet = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<HandleCamera>().targetToLookAt;
// Check inside for satellites
foreach (Transform satellite in currentPlanet)
{
// Check transform for tag
if (satellite.CompareTag("Satellite"))
{
// Add each transform from planet to array
satelliteListFromPlanet.Add(satellite);
}
}
}
// Handle Grid
private void genInventory()
{
if (satelliteListFromPlanet.Count < 6)
{
gridGroup.constraintCount = satelliteListFromPlanet.Count;
}
else
{
gridGroup.constraintCount = 5;
}
foreach (Transform sat in satelliteListFromPlanet)
{
GameObject newButton = Instantiate(buttonTemplate) as GameObject;
newButton.SetActive(true);
newButton.GetComponent<SatelliteButton>().SetIcon(iconSprites[Random.Range(0, iconSprites.Count)]);
newButton.transform.SetParent(buttonTemplate.transform.parent, false);
}
}
}
I appreciate the help! Learning about grid layouts with List<>!
In genInventory() you Instantiate a new button for every Transform in satelliteListFromPlanet. Since only 1 is added it seems that your list only contains 1 element.
But you never destroy/remove this Instantiated GameObjects, so the next time you re-enable the object, OnEnable will be called again and new prefabs are Instantiated.
Solution:
Make sure to store the Instantiated objects somewhere e.g.
private List<GameObject> instances = new List<GameObject>();
//....
foreach (Transform sat in satelliteListFromPlanet)
{
GameObject newButton = Instantiate(buttonTemplate) as GameObject;
newButton.SetActive(true);
newButton.GetComponent<SatelliteButton>().SetIcon(iconSprites[Random.Range(0, iconSprites.Count)]);
newButton.transform.SetParent(buttonTemplate.transform.parent, false);
instances.Add(newButton);
}
And than you can destroy them when you disable the object:
private void OnDisable()
{
foreach(var instance in instances)
{
Destroy(instance);
}
}
Problem 1: Every time this canvas gets enabled or disabled, the grid keeps adding 1 element under the initial one, and after being enabled/disabled again, another element is instantiated under that one.
Right now you're calling getSatellitesInPlanet() on SatelliteGridControl's OnEnabled() method. This method is called every time the object is set to active. If you just want to call your method once, use Start.
Problem 2: Also none of these instantiated buttons get called. Maybe
the problem here is due to the 1st problem?
I don't think the problems are related. Can you confirm that your buttonTemplate prefab has an Image element and its RaycastTarget is enabled?
Just one tip, I would set the type of buttonTemplate to SatelliteButton, not GameObject. That way you can instantiate it as type SatelliteButton and avoid the need to call:
newButton.GetComponent<SatelliteButton>()
From various questions, I know it is impossible to create DataTemplate from the code behind without using the XamlReader. So I want to ask if there is a way to programatically generates the UI for each Item in a ListView. I don't seem to find any relevant event handler or member of ListView for this purpose. Ideally, I want the ListView to invoke my handler code to generate UI for each data item it needs to display.
Imitating the official XamlTreeView sample, I have tried overriding some ListView method such as PrepareContainerForItemOverride but this won't work. The solution I found is as #JustinXL suggests: producing ListViewItem and insert them to the ListView->Items directly
//assume that items is a list of items we want to bind
myListView->Items->Clear();
for(auto i : items)
{
ListViewItem^ v = ref new ListViewItem();
v->Content = GenerateUIFor(i);
myListView->Items->Append(v); // NOTE: a wrapping ListViewItem is required!
}
To support usual data binding, it would be best to make the data structure to cache the generated UI. For example,
ref class MyDataStructure
{
public:
property ListViewItem^ Item
{
ListViewItem^ get()
{
if (_item == nullptr)
GenerateUI();
return _item;
}
}
void GenerateUI()
{
_item = ref new ListViewItem();
_text_block = ref new TextBlock(); // sample
_item->Content = _text_block;
UpdateUI();
}
// Invoke this when changing the state of this object
void UpdateUI()
{
if (_text_block != nullptr) // sample
{
_text_block->Text = this->ToString(); // sample
}
}
private:
ListViewItem^ _item;
TextBlock^ _text_block;
};
The downside of this is of course we can't make use of data virtualization. But it works properly for small set of data. For large set, one can use website's approach with Next and Prev button to load next page or go back to previous page.
ItemContainerGenerator should let you construct the entire UI for an item inside a list view. Unfortunately there doesn't appear to be much in the way of non MSDN documentation/samples for this.
Alternatively if you can maintain a list of all the DataTemplates you might need to show, you could use a DataTemplateSelector to choose which DataTemplate you want to show for each individual item.
I am quite new to Qt, so I am probably asking a pretty obvious question.
I would like to create a super type for all of my custom QML GUI elements that I want to create in C++.
This super type is supposed to add predefined states to a QML Item. Something alike to this:
import StatedGuiElement 1.0
import QtQuick 2.0
Item {
width: 300; height: 200
StatedGuiElement {
id: aStatedGuiElement
anchors.centerIn: parent
width: 100; height: 100
//some visible Custom Gui Elements
states:[
State {
name: "A_STATE"
},
State {
name: "ANOTHER_STATE"
}]
}
I know how to create a simple custom Item from this tutorial (http://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html). I guess the states could be defined by using an enum in the C++ class which inherits from QQuickItem. However, this tutorial does not show how to create more complex Qt Quick elements like the state list.
class StatedGuiElement : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
//pass States via Q_PROPERTY?
public:
//define Enum for fixed States here?
//ENUM STATES {A_STATE, ANOTHER_STATE}
StatedGuiElement( QQuickItem *parent = 0);
QString name() const;
void setName(const QString &name);
private:
QString m_name;
//Some List of States?
signals:
public slots:
};
So the questions I am wondering about are as follows:
Is it even possible to predefine QML State types and use them in multiple elements?
How do I add complex QML types like State Lists in a C++ class such as StatedGuiElement?
First you create your StatedGuiElement as a QQuickItem subclass.
Then you crate a StatedGuiElement.qml, import the package that contains the C++ element, make a StatedGuiElement {} inside, add your states in QML to it, then you can use StatedGuiElement in your project. It will be the one with the QML extra stuff predefined in it.
This assumes the element actually has things you need to implement in C++. If not then it would not make sense to have a C++ element at all. I am not sure whether old C++ state classes will work with QML, probably not, and using the QML states from C++ will be anything but convenient, so you really should do the states in QML, on top of whatever C++ stuff you may have.
It is possible to define your properties once and use them im multiple elements, if you nest your QML elements inside a super-type QML element where you have all your states defined. Child elements can access the parent parameters.
Alternatively, you can also just simply set the context property for each QML which should use the data like this in C++:
QQuickView view;
QStringList data;
// fill the list with data via append()
view.rootContext()->setContextProperty("dataList", QVariant::fromValue(data));
// now the QML can freely use and access the list with the variable name "dataList"
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
In the QML-side, you can also declare a custom property which holds the names of the states.
Item {
property variant state_list: ["element1", "element2", "element3"]
// or if you defined a list in the C++ part as a context property
// you can use this instead:
// property variant state_list: dataList
states: [
State {
name: state_list[0]
},
State {
name: state_list[1]
},
// and so on
]
}
If you need a property that is a list of elements, i..e. states being a list of State objects, then you can do this in C++ using the QQmlListProperty type.
You need a QObject derived type for the list element type.
Example
class Entry : public QObject
{
// the list entry element's API
};
class MyItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Entry> entries READ entries)
public:
QQmlListProperty<Entry> entries() const {
return QQmlListProperty<Entry>(this, m_entries);
}
private:
QList<Entry*> m_entries;
};
Register both with qmlRegisterType()
In QML
MyItem {
entries: [
Entry {
},
Entry {
}
]
}
So looking through the Sitecore code I notice multiple ways to get the children of an Item.
// Summary:
// Gets the children.
public ChildList GetChildren();
and
// Summary:
// Gets a list of child items.
public ChildList Children { get; }
Any thoughts on the differences between them?
Also do not confuse with the overloaded method:
GetChildren(ChildListOptions options)
Item.GetChildren() allows parameters to alter functionality. This flexibility is why .GetChildren() is preferred over .Children for retrieving a ChildList collection of children items.
For example, to ignore any security applied on those items, use: item.GetChildren(Sitecore.Collections.ChildListOptions.IgnoreSecurity)
Above is the code for these three methods/property
public ChildList GetChildren()
{
return this.GetChildren(ChildListOptions.None);
}
public ChildList GetChildren(ChildListOptions options)
{
return Sitecore.Diagnostics.Assert.ResultNotNull<ChildList>(ItemManager.GetChildren(this, (options & ChildListOptions.IgnoreSecurity) != ChildListOptions.None ? SecurityCheck.Disable : SecurityCheck.Enable, options));
}
public ChildList Children
{
get
{
return new ChildList(this);
}
}
There is no difference between them
They both call ItemManager.GetChildren(); in behind with ChildListOptions.None options.
And they both return ChildList object in return.
I really want to add Lua Scripting to my Game Engine. I am working with Lua and bound it to C++ using luabind, but I need help to design the way I will construct my Game Entities using Lua.
Engine Information:
Component Oriented, basically each GameEntity is a list of components that are updated in a delta T interval. Basically Game Scenes are composed by collections of Game Entities.
So, here's the dilemma:
Let's say I have this Lua file to define a GameEntity and it's components:
GameEntity =
{
-- Entity Name
"ZombieFighter",
-- All the components that make the entity.
Components =
{
-- Component to define the health of the entity
health =
{
"compHealth", -- Component In-Engine Name
100, -- total health
0.1, -- regeneration rate
},
-- Component to define the Animations of the entity
compAnimation =
{
"compAnimatedSprite",
spritesheet =
{
"spritesheet.gif", -- Spritesheet file name.
80, -- Spritesheet frame width.
80, -- Spritesheet frame height.
},
animations =
{
-- Animation name, Animation spritesheet coords, Animation frame duration.
{"stand", {0,0,1,0,2,0,3,0}, 0.10},
{"walk", {4,0,5,0,6,0,7,0}, 0.10},
{"attack",{8,0,9,0,10,0}, 0.08},
},
},
},
}
As you can see, this GameEntity is defined by 2 components, "compHealth" and "compAnimatedSprite". Those two totally different components require totally different initialization parameters. Health requiring an integer and a float ( total and regeneration ), and on the other side, animations requiring a sprite sheet name , and to define all of the animations ( the frames, durations, etc ).
I would love to make some kind of abstract class with some virtual initializer method that could be used by all my components that require Lua binding in order to facilitate initialization from Lua, but it seems difficult, because the virtual class is not going to have one virtual init method. This is because all of the component initializers (or most of them) require different init parameters (health component requires different init than Animated Sprite component, or AI component).
What do you suggest to make the Lua bindings to the constructors of this components easier ? or how would you do it ?
PS: I must use C++ for this project.
I'd suggest using a composite structure instead for your game entities. Add objects inheriting from a common game entity component to each game entity as you encounter them while parsing the Lua configuration table. This task is a perfect candidate for the factory method. Note that composing your entities in this way still requires all methods to be implemented in the GameEntity class unless you use an alternate dispatch method like message passing (see the visitor pattern)
On the Lua side, I find it is more convenient to use callback function with a single table argument instead of traversing a complex table structure in C/C++. Here is a pure Lua example of what I mean using your data.
-- factory functions
function Health(t) return { total = t[1], regeneration = t[2] } end
function Animation(t) return { spritesheet = t[1], animations = t[2] } end
function Spritesheet(t)
return { filename = t[1], width = t[2], height = t[3] }
end
function Animations(t)
return { name = t[1], coords = t[2], duration = t[3] }
end
-- game entity class prototype and constructor
GameEntity = {}
setmetatable(GameEntity, {
__call = function(self, t)
setmetatable(t, self)
self.__index = self
return t
end,
})
-- example game entity definition
entity = GameEntity{
"ZombieFighter",
Components = {
Health{ 100, 0.1, },
Animation{
Spritesheet{ "spritesheet.gif", 80, 80 },
Animations{
{"stand", {0,0,1,0,2,0,3,0}, 0.10},
{"walk", {4,0,5,0,6,0,7,0}, 0.10},
{"attack", {8,0,9,0,10,0}, 0.08},
},
},
}
}
-- recursively walk the resulting table and print all key-value pairs
function print_table(t, prefix)
prefix = prefix or ''
for k, v in pairs(t) do
print(prefix, k, v)
if 'table' == type(v) then
print_table(v, prefix..'\t')
end
end
end
print_table(entity)