How to get text on unity 2D to display - text

I can't display text and I get a NullReferenceException when the method is executed. On top of that the code doesn't stop running as it should.
// Use this for initialization
void Start()
{
// Default position not valid? Then it's game over
if (!isValidGridPos())
{
Text text;
text = GetComponent<Text>();
text.text = "Game Over";
Destroy(gameObject);
if (Input.GetKeyDown(KeyCode.R))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
}
The code comes from this tutorial. I just wanted to add it a restart and a Game Over message.
EDIT: Trying to display text with text = GetComponent() is not working. What's another way to display text on unity that actually works? I tried GUIText too but I can't make it visible on display.

I have looked at the tutorial and they have the following code:
if (!isValidGridPos()) {
Debug.Log("GAME OVER");
Destroy(gameObject);
}
This works because it prints to the debug log console. You obviously want to capture that and print it on the screen. This requires a canvas and a text component being added to the gameobject the script is on. Declaring a text variable here won't add one to the game object, it has to be done in the unity inspector.
The following code:
if (Input.GetKeyDown(KeyCode.R))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
Shouldn't be here, as this object will already be destroyed this code will be rendered useless unless you are holding the key down in the same frame that the object is created. It should instead be on in another script on a gameobject that won't be destroyed and it will await an r key to reload the level.

If text = GetComponent<Text>(); isn't working it could be because your Text component is not on the same gameobject that your script is attached to.
In the Unity Editor, check that the text component and your script are on the same gameobject

Did you inspect editor view while running?
Don't use destroy in Strar().
You can set delay like so Destroy(gameobject, 5.0f) and use it in some other callback function (ex. Action).
Now you just destroying whole gameobject all its scripts and components(including Text) right after it initialized. If it is in scene from beginning, then it destroyed as soon as you press Play.
Start() runs just once so what does isValidGridPos() doing?

Related

Which AnimationPlayer is currently shown in bottom panel Animation?

I'm trying to create my own plugin and I need to figure out which AnimationPlayer node is currently shown in the bottom Animation panel
and please do not suggest I use get_selection() because even if I select multiple (or none ) AnimationPlayer node(s), only one is show on the Animation Panel
so far my approach has been to try finding the node to the Animation panel using get_editor_interface() and then maybe viewing it's properties?
Edit
Based on the answer given by user #Theraot I tried this:
tool
extends EditorPlugin
func handles(object):
print('handles=>',object);
return true;
func edit(object):
print('edit=>',object);
func _enter_tree():
pass;
but using this I only get the selected nodes within the tree but even if I haven't selected any AnimationPlayer Node it still shows up in the animation panel
On your EditorPlugin implement handles to return true on any AnimationPlayer given to it, and Godot should call edit with the AnimationPlayer that is to be edited currently.
Example code:
tool
extends EditorPlugin
var edited_animation_player:AnimationPlayer
func handles(object:Object) -> bool:
return object is AnimationPlayer
func edit(object:Object) -> void:
edited_animation_player = object
print(edited_animation_player)
I was hoping the information of which AnimationPlayer is currently being edited in the Animation panel was perhaps stored in some node for the bottom panel?
Even if get the correct node from the interface:
var control:= Control.new()
var animation_player_editor:Control
add_control_to_bottom_panel(control, "puff")
for sibling in control.get_parent().get_children():
if (sibling as Control).get_class() == "AnimationPlayerEditor":
animation_player_editor = sibling
remove_control_from_bottom_panel(control)
if animation_player_editor != null:
print(animation_player_editor)
Which AnimationPlayer it is editing is not exposed to scripting. We can find a get_player method in the source code and a get_state method also in the source code, but we could only access them from C++, as they are not bound for scripting (source code).
In theory we should be able to get the EditorPlugin and call get_state on it, however it is not working for me:
var animation_player_editor_plugin:EditorPlugin
for sibling in get_parent().get_children():
if (sibling as Node).get_class() == "AnimationPlayerEditorPlugin":
animation_player_editor_plugin = sibling
if animation_player_editor_plugin != null:
print(animation_player_editor_plugin.call("get_state"))
Despite get_state being exposed on EditorPlugin, it appears to not be possible to call it.
By the way, we can see in the source code for AnimationPlayerEditorPlugin that it follows the handles and edit logic I used above.

Changes to the contents of a control variable linked to a static text box doesn't reflect in the dialog

I have a CString variable which is linked to a static text box inside one of my dialogs, lets call it controlVariable. When I click the START button inside this dialog a couple of things happen. First I update the contents of the controlVariable (to say something like "initialization begun"). I do UpdateData(FALSE) and then run an initialization of another class (which starts some threads). This initialization takes some time, so this is why the contents of the static text box need to reflect that while its running. But the changes aren't reflected until the OnBnClickedStart() function finishes. I'm having trouble having the changes to this controlVariable reflect in the dialog.
What I've tried:
UpdateData(FALSE) after changing the controlVariable using basic CString append functions (e.g. CString A = str1 + str2;) and changing the control variable using .format() (e.g. controlVariable.format(_T("some text")); )
Running OnPaint() after changing the controlVariable contents
I went into debug mode and the program runs into the BEGIN_MESSAGE_MAP section of the dialog class and just loops there until I step out of it. The contents of the static text box linked to my controlVariable aren't updated until I step out of BEGIN_MESSAGE_MAP. So the contents of my static text box don't even update at the end of my OnBnClickedStart() funciton.
Example Code:
CMyClass someClass;
CString controlVariable; // linked to some static text in the SomeDlgClass
void SomeDlgClass::OnBnClickedStart()
{
controlVariable = CString("System initialized\r\n"); // Also tried
UpdateData(FALSE); // Also tried OnPaint()
someClass.initialize(); // I would like the static text box to update before I run this
}
So when I'm running this, my main dialog seems like it's "frozen" - I can't move the window around or click any of the buttons. Suggestions?
Thanks.

Scala swing panel disappears when trying to change contents (only when running a Thread)

So I'm writing a boid simulation program as a project for school. My program supports multiple different groups of these boids that don't flock with other groups, they all have different settings which I do by adding a BoxPanel to the main GUI of the program when a new tribe is made, and those BoxPanels have a settings button that opens a new frame with the groups settings.
This works perfectly when I start the program up and add all the pre defined tribes that are in the code. Now I made a new part of the GUI that let's you make new groups of these boids and adds them while the simulation is running, and here is when the problems start for me.
For some weird reason it adds the group just fine, with the right settings in to the simulation but it wont add the BoxPanels to the main GUI. It makes the whole settings bar that I have in the side of my simulation disappear completely. I tested this out and if I add the tribes in the beginning of my calculation thread it does the same thing, so this seems to be a problem with multiple threads and swing. Any ideas what is causing this or how to fix this? I am completely perplexed by this.
tl;dr: The code below for adding tribes works fine when I haven't started the thread but if I try to use it after starting the thread the optionPanel appears empty.
Here's the code that adds the BoxPanels to the main gui:
def addTribe(tribe: Tribe) = {
tribeFrames += new TribeSettingFrame(tribe)
tribeBoxPanels += new TribeBoxPanel(tribe)
this.refcontents
}
private def refcontents = {
top.optionPanel.contents.clear()
top.optionPanel.contents += new BoxPanel(Orientation.Vertical) {
tribeBoxPanels.foreach(contents += _.tribeBoxPanel)
}
top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
contents += top.addTribeButton
}
top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
contents += top.vectorDebugButton
}
}
new Thread(BoidSimulation).start()
Oh and I tested if it really adds the contents that it should by printing out the sizes of the contents, and everything matches fine, it just won't draw them.
EDIT: After some digging around it really seems to be a thing with updating swing from a Thread. A lot of places suggest to use SwingWorker but from the info I gathered about it I don't think it would fit in my program since it is a continuous simulation and and I would have to keep making new SwingWorkers every frame.
EDIT2: Tried calling the method from the thread like this:
SwingUtilities.invokeLater(new Runnable() {
override def run() {
GUI2D.addTribe(tribe)
}
});
Didn't make any difference. I am starting to think that this is a problem with how I use TribeBoxPanel and TribeSettingFrame. These are objects that both contain only one method that returns the wanted BoxPanel or Frame. Is this implementation bad? If so what is the better way of creating dynamic BoxPanels and Frames?
Swing is not thread-safe.
Repeat after me.
Swing is not thread-safe.
Hear the chorus? Swing is not thread safe There is official documentation.
There is a very simple workaround given as well.
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
// your stuff
}
});
In Scala, this is supported as:
Swing.invokeLater(/* your stuff */)
First you should let the UI thread handle all UI manipulation.
The simple way should be following Scala-Code:
Swing.onEDT { GUI2D.addTribe(tribe) }
But as you already noted, this won't solve your problem. I had a very similar problem where I only changed the text content of a Swing.Label and it sometimes simply disappeared.
It turned out that it only disappeared, when the text was too long to display it inside the Area which the Label initially reserved for itself. So one way around your Problem could be to give the optionPanel a bigger initial size when you create it.
Swing.onEDT { top.optionPanel.preferredSize = new Dimension(width,height) }
I'm not quite sure whether this has to be set before the component is first drawn (before Frame.open() is called).

Unity - How to write a "Behaviour" or script for entire scene (in C#)?

I am starting to learn Unity.
As I understand, We can write scripts(behaviors) in the form of C# files and apply them to each objects on the scene.
But how to write a script for the entire scene? I know this is a obvious question - there has to be a script for the entire scene so that all my objects "behave" in a synchronized way and it's gotta be pretty basic, but preliminary Google searches has not borne much fruit.
Can someone give me a quick guide?
Taking your "boxes" example comment I would do the following:
Create an empty gameobject, let's call it BoxesController...
Attach below BoxesController.cs script to it
In the editor inspector reference all boxes
BoxesController.cs
public class BoxesController: MonoBehaviour
{
public Transform box1, box2, box3;
void Update() {
// change boxes position
}
}
Now imagine you will need to have > 30 boxes in current scene... You will have a lot of work to reference each box. So you could change your script if you add a Tag to all boxes. Let's say you create a new tag inside Unity Tag Manager called "Box" and give it to all boxes.
You now can change BoxesController.cs script to the above and you will not have to reference all boxes in the Editor Inspector because they will be searched and referenced inside Start method.
BoxesController.cs
public class BoxesController: MonoBehaviour
{
public GameObject[] boxes;
void Start()
{
boxes = GameObject.FindGameObjectsWithTag("Box");
}
void Update() {
// change boxes position
foreach (GameObject go in boxes)
{
//get box name
string box_name = go.Name;
// get box transform property
Transform t = go.transform;
}
}
}
Please note that GameObject.FindGameObjectsWithTag is a heavy operation and that's why I did it in the Start method and saved the result to reuse it in Update method calls.
what you can do is create an empty GameObject and add a script to it and use one of the techniques described in the link to get access to the 3 boxes you want to move.
http://docs.unity3d.com/412/Documentation/ScriptReference/index.Accessing_Other_Game_Objects.html
In this case you probably want to use "1. Through inspector assignable references." which just means create a public Transform variable in the script, save, then in the Inspector drag the box in the slot that appeared in the script-component
edit: for further reading i'd suggest googling the term "Game Manager" in combination with "Singelton" and "Unity" :)

how to redirect system output to my gui app (qt, linux)?

I need to develop a GUI program which will be run some external bash script. This script are working about 30-40 minutes and I want to see system output in my application in real time.
How can I provide this? Should I use QTextStream?
Please give me some examples.
If you launch the script via QProcess, you can get the output by connecting to the readyRead signal. Then it's just a matter of calling any of the read functions to get the data and then displaying it on any type of widget you want, such as a QTextEdit which has an append function for adding text.
Something like this: -
// Assuming QTextEdit textEdit has been created and this is in a class
// with a slot called updateText()
QProcess* proc = new QProcess;
connect(proc, SIGNAL(readyRead()), this, SLOT(updateText()));
proc->start("pathToScript");
...
// updateText in a class that stored a pointer to the QProcess, proc
void ClassName::updateText()
{
QString appendText(proc->readAll());
textEdit.append(appendText);
}
Now, every time the script produces text, your updateText function is called and you are adding it to the QTextEdit object.

Resources