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

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" :)

Related

How can I know the retained class name or keyword when I use navigation framework in Android Studio?

The following code is from the project at https://github.com/mycwcgr/camera/tree/master/CameraXBasic
The project use the latest navigation framework, I find there are some retained class name such as CameraFragmentDirections, GalleryFragmentArgs.
The system have no prompt information for these class name, must I remember these keywords by myself?
Code
/** Method used to re-draw the camera UI controls, called every time configuration changes */
#SuppressLint("RestrictedApi")
private fun updateCameraUi() {
// Listener for button used to view last photo
controls.findViewById<ImageButton>(R.id.photo_view_button).setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(
CameraFragmentDirections.actionCameraToGallery(outputDirectory.absolutePath))
}
}
/** Fragment used to present the user with a gallery of photos taken */
class GalleryFragment internal constructor() : Fragment() {
/** AndroidX navigation arguments */
private val args: GalleryFragmentArgs by navArgs()
}
No you do not need to remember these things by yourself, if you know of a trick.
For example, if you don't remember the "keyword" Directions, but you know you want to do something related to CameraFragment, you can start typing e.g. CameraFragm in Android Studio. It will then suggest CameraFragment and CameraFragmentDirections for you. That way you can find CameraFragmentDirections easily even though you did not remember the keyword Directions.
There are not that many keywords to worry about though. After working with the Navigation framework for a while, you will remember them all.
If you are curious, you can find the generated classes here after a build:
./app/build/generated/source/navigation-args/...
e.g. after a debug build:
./app/build/generated/source/navigation-args/debug/com/android/example/cameraxbasic/fragments/CameraFragmentDirections.java
If you are even more curious, the code that generates these classes is here:
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
There you can for example find this code:
internal fun Destination.toClassName(): ClassName {
val destName = name ?: throw IllegalStateException("Destination with actions must have name")
return ClassName.get(destName.packageName(), "${destName.simpleName()}Directions")
}
which is the code that decides what name CameraFragmentDirections gets. (Note "${destName.simpleName()}Directions" at the end.)

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.

How to get text on unity 2D to display

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?

Multiple Views for a Document in MDI Application MFC

I have a MDI application in which there are some reports and the Reports are printed and print preview in way that the was given by the MFC Printing Architecture.
But now the scenario changed and the Reports need to be formatted as a HTML File and need to be shown in the different perspective, based on a preference. I have choose a solution based on the Application architecture as there are many Document/View in my CWinApp. Created all Doc/view Templates there and the new Doc/View will be created based on the setting, once the application starts.
class CMyWinApp: public CWinApp
{
public:
virtual BOOL InitInstance();
protected:
}
BOOL CMyWinApp::InitInstance()
{
// Lot of Code Here
CreateDocumentTemplates();
}
void CMyWinApp::CreateDocumentTemplates()
{
// Some Other Doc/Templates are here
if(m_bNewView) // Based on the Setting I am creating the new View and Old Doc
{
pDocTemplate = new CMultiDocTemplate(
IDR_REPORTS,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrame), // custom MDI child frame
RUNTIME_CLASS(CMyNewView));
pDocTemplate->SetContainerInfo(IDR_TYPE_CNTR_IP);
AddDocTemplate(pDocTemplate);
}
else // This is a Old View and Doc
{
pDocTemplate = new CMultiDocTemplate(
IDR_REPORTS,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrame), // custom MDI child frame
RUNTIME_CLASS(CMyView));
pDocTemplate->SetContainerInfo(IDR_TYPE_CNTR_IP);
AddDocTemplate(pDocTemplate);
}
}
Now the scenario is, this preference can be set anytime and the further Reports need to be shown in a appropriate context.
How this can be achieved on the run time? Please help me :(
In your app class, create and save both CMultiDocTemplate pointers from your CreateDocumentTemplates function and use these to create your documents on demand(e.g override ID_FILE_NEW/ID_FILE_OPEN or similar). Look at OpenDocumentFile of CDocTemplate.
Then in your OnFileNew function or similar you can use something like this:
if(m_bNewView) {
m_pNewDocTemplate->OpenDocumentFile(...);
}
else {
m_pOldDocTemplate->OpenDocumentFile(...);
}
I would integrate CMyNewView in CMyView, if you need to switch the view dynamically. If you work with at least Visuals Studio 2008 (incl. feature pack), I recommend deriving your view class from CTabView to switch the view of the document using a handy tab next to the horizontal scrollbar of the child window.

Data binding with plugins using MEF?

I have an application that has a class named: UploadItem. The application creates uploading tasks based on information it has, for example, an upload needs to be created to upload a file to sitex.com with this the application creates a new UploadItem and adds that to an ObservableCollection, the collection is bound to a listview.
Now comes the part that I cannot solve.. I decided to change the structure so that people can create their own plugins that can upload a file, the problem lies with the fact that the UploadItem class has properties such as:
string _PercentagedDone;
public string PercentageDone
{
get { return _PercentagedDone; }
set { _PercentagedDone = value + "%"; NotifyPropertyChanged("PercentageDone"); }
}
But the plugin controls on how a file is uploaded, so how would the plugin edit the PercentageDone property that is located in the UploadItem class? If there is no way to do such a thing, then is there another way to achieve the same, i.e. showing the progress on the main GUI?
You'll want to define an interface for the plugins. Something like:
public interface IUploadPlugin
{
Task<bool> Upload(IEnumerable<Stream> files);
int Progress { get; }
}
The plugins then need to implement this interface and export themselves:
[Export(typeof(IUploadPlugin))]
public class MyUploader : IUploadPlugin, INotifyPropertyChanged
{
// ...
}
Notice that this plugin implements INotifyPropertyChanged. This is an easy way to handle updating the progress. Fire PropertyChanged on the Progress property and then databind your ProgressBar control in the main view to this property. Make sure that you fire PropertyChanged on the UI thread.
Another option would be to fire a custom event when the property changes. You could handle this event in the main view logic and update the progress.
Notice that I'm using Task for the return. This allows the caller to wait until the upload task finishes. You could use a callback instead, but with the CTP of the next version of .NET, using Task<> will allow you to use the await keyword for your async programming. Check it out here and here.

Resources