I have almost identical classes, PaddleLeft and PaddleRight. I am tired of calling both of those classes when I need something done, I rather them be done all at once. For example, here is what I have to do:
public void pause() {
GameObject.Find("Paddle Objects/paddleRight").GetComponent<Paddle>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<Paddle>().setIsPaused(true);
}
And here is what I want to do:
public void pause() {
GameObject.Find("Paddle Objects/paddles").GetComponent<Paddle>().setIsPaused(true);
}
This seems unnecessary, however, in my game, there are times where the same line of code are copied and adjusted to up to ten similar objects.
Question Is there a way to make a super class like in Java for these objects. I have searched the internet and have found info, however I can't seem to understand how to make it work because I can't extend MonoBehavior and a superclass in Unity.
Thanks in advanced!
I have almost identical classes, PaddleLeft and PaddleRight
But your code is totally saying different stuff
GameObject.Find("Paddle Objects/paddleRight").GetComponent<Paddle>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<Paddle>().setIsPaused(true);
Maybe you want meant to write the code below?
GameObject.Find("Paddle Objects/paddleRight").GetComponent<PaddleRight>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<PaddleLeft>().setIsPaused(true);
I will assume the second code is what you meant to write.
When you have multiple GameObjects or Scripts with similar actions, you should create a central manager script that will make it easy to communicate with a those GameObjects or classes.
Since both your classes are called PaddleRight and PaddleLeft, You can simply call this class PaddleManager.
Don't forget that, of course, PaddleManager is just a script, it's not a "thing" in Unity. Naturally you will attach PaddleManager to some game object. You might ask "where should I attach it?" In a simple game, you might attach it to your camera, say. (Since you always have a camera, other developers working on your project always know to "look n the camera" for odds and ends like sound-effects, managers like this and so on.) Alternately, say that physically all your paddles are associated with (for example) an object that is the ping pong table. Then, a good place to attach PaddleManager.cs would be on the ping pong table. It doesn't matter where you attach it, so long as it is tidy. Some people like to make simply an empty object (you can refer to an empty object as a "marker"), just make an empty object named say "manager holder", put it at 0,0,0, and you can add scripts like PaddleManager.cs to that object.
Your PaddleManager.cs script:
public class PaddleManager : MonoBehaviour
{
private PaddleRight rightPaddle = null;
private PaddleLeft leftPaddle = null;
//Initialize variables
void Start()
{
//Get reference/Cache
rightPaddle = GameObject.Find("Paddle Objects/paddleRight").GetComponent<PaddleRight>();
//Get reference/Cache
leftPaddle = GameObject.Find("Paddle Objects/paddleLeft").GetComponent<PaddleLeft>();
}
//Call to pause and unpause
public void pause(bool pausePaddle)
{
rightPaddle.setIsPaused(pausePaddle);
leftPaddle.setIsPaused(pausePaddle);
}
}
Now, you can access both of your Paddles from one script, in another script.
public class YourOtherScript : MonoBehaviour{
PaddleManager paddleManager = null;
void Start()
{
//Get reference/Cache
paddleManager = GameObject.Find("GameObjectPaddleManaerIsAttchedTo") .GetComponent<PaddleManager>();
//To pause
paddleManager.pause(true);
//To un-pause
paddleManager.pause(false);
}
}
By doing this, you will avoid using static variable and also avoid using GameObject.FindGameObjectsWithTag("paddles")) in foreach loop like mentioned in the other answer. GameObject.Find... functions should NOT be used in the middle of the game because it will slow down your game. You need to use it once and cache the GameObject in the Start function, then you can re-use it without slowing down your game.
First of all paddle right and left are game-objects and not classes , the class name is paddle , and if the same script is on both the objects , the most simplest way would be to put it on another empty object and call it once and the code will work on all game-objects that the script is attached to . BUT! that is only regarding to what I cuold make out of your question , Here is what I really recommend , as you said "because I can't extend Mono-behavior and a super-class in Unity" . Ok so you have class A inheriting monobehavior , and you make class's B and C, then when you inherit them from A you will get all the abilities of a monobehaviour in class B and C and you can attach them to game objects , you can even make start and update functions as vrtual and override them in B and C and you can even call A's function use the keyword Base , So read on it , it will take time but in the long run makes you a better coder
Mm, wait. There is something wrong with your question:
YouPaddleLeft and PaddleRight are not classes. They are GameObjects existing in Unity scene. Class is Paddle to which you get reference by GetComponent<Paddle>() .
Now if you have a variable/function that affects all the instances of the class the same than you shell make them static. (Google static variables and functions if you don't know what they are).
So go to your Puddle class and change the declaration of setIsPaused(bool val) to this:
public static void setIsPaused(bool val) { /* implemenetation */ }
and then make a call to it via class token, not object:
Paddle.setIsPaused(true/false);
note that if the static function has references to class variables all those variables should be marked static as well. (e.g. if you have a bool isPaused than mark it static because it should be the same for all the objects all the time anyways)
Related
Just as title say does GetComponent() does impact a lot on performance.
I am asking this because I do not like doing it like this:
public class Player : MonoBehaviour
{
PlayerStats playerStats = this.GetComponent<PlayerStats>();
void Update()
{
var something = playerStats.Asd;
}
}
Instead of that i like using it like this:
public class Player : MonoBehaviour
{
void Update()
{
var something = this.GetComponent<PlayerStats>().Asd;
}
}
Reason for that is because i like breaking code in lot of scripts (it is easier for me to later change something if needed and also use one script for multiple objects) and so if i have a lot of scripts i need to see if i have already defined PlayerStats playerStats.... but not only this one but about a lot of them.
So is using second approach going to slow down my game a lot?
It's worth noting that your first script is invalid and won't compile. The correct way to do that is to make it a global variable but cache or initialize the script in the Start or Awake function. These functions run once and are used for initialization.
Something like this:
PlayerStats playerStats;
void Start()
{
playerStats = this.GetComponent<PlayerStats>();
}
To answer your question, the GetComponent function impacting performance is greatly over exaggerated. You read this everywhere on the internet but it depends on how often it is used. If it is used once in a while or just in few scripts then it's totally fine.
If you have hundreds instances of scripts using GetComponent in the Update function then that's when you will start noticing a little bit of performance hit because GetComponent is making call to the native side. So, it depends on how often it is called and how many instances of scripts are making this call each frame.
The main appeal of using the first approach is that you can set those variables to be public, and in turn access them directly from the Unity Editor, allowing you to drag and drop components as you feel like it.
The second instance of your GetComponent function call means that you aren't caching your variables, slowing down your code with potentially unnecessary checks. So my advice would be to stick with the first instance in which your variable is defined in memory and then altered, rather than being allocated memory each time and then altered.
And a side note. You do not need to call this.GetComponent if the script is attached to an object since the script derives from a MonoBehaviour; you can just call GetComponent<type>() and go about your merry day. :)
I don't think it really matters. I just did a check and using for loop that looped 1,000,000 times and found the exact same 0.02 time delay between both frames.
That being said, it would make your code cleaner because Player.Stats.Asd is cleaner than Player.GetComponent<PlayerStats>().Asd. It makes it more obvious what the intent is. I'm sure it is still a micro optimization to store it as a variable with a public PlayerStats Stats { get; set; }, but that's really if you're using it all the time.
You shouldn't use a variable for every Component it has, because if you do that for every script, the memory being used will start to add up.
Also, note that I'm calling it Stats not PlayerStats because Player.PlayerStats is needlessly redundant. The actual type of it should be called PlayerStats yes, to not confuse it with, say, EnemyStats, but when you go to use both, having Player.Stats and Enemy.Stats is cleaner.
I'm making a simple dart game in the console for an assignment where I am to practice using private lists and variables everywhere. The basic flow of the program for some context is as follows:
User lands in a menu
User chooses from 1-4. (1 = Add player, 2 = Add CPU, 3 = Start game, 4 = Quit)
Game starts. Players manually add their 3 throws per turn, and CPU gets theirs randomly.
When a player or CPU reaches 301 score, the loop ends and you now see every throw made by the winner.
UML diagram for class structure context: https://i.imgur.com/bL5pZV5.png
Everything is pretty much complete. I've made the program to such an extent that both players and CPUs are getting random values (are treated as CPU players), it prints out everything correctly and follows the flow to the end.
My issue now is that I want to be able to reach the is_CPU variable which is private in the Player class from the Game class and use it in an IF check, directing whether or not the values are manually added or randomly generated.
Pseudo-code:
FOREACH (var player in player_list)
IF (is_CPU == TRUE)
THEN Assign random values
ELSE
THEN Manually enter values
I tried messing around with the get-set stuff, but I don't fully understand how to use them and how they work. I have looked around on here and still don't see how I should be using them in this case, if at all.
I can think of one way to work around this and that is by making a method just for this where it checks that value and returns true/false, but that seems like a 'lazy' or improper way to do this, and comes with several downsides. I feel like there should be a better way to do this, one that won't come back to bite me in the ass later. Hopefully there is, and I can learn it by asking here.
EDIT: The variables and lists HAVE to be private. It is part of the exercise where we learn how to handle these.
I think you just want a get property on your player class.
public bool IsCpu { get { return is_CPU; }}
See also c# properties
In order to access private members of a class instance, you either have to define properties on that class with a public getter, as follows:
public class Player
{
private Boolean m_IsCPU;
public Boolean IsCPU
{
get { return m_IsCPU; }
}
// ...
}
or to change these members in order to make them public, as follows:
public class Player
{
public Boolean IsCPU;
// ...
}
Whatever you choose (I suggest you to go for the first approach), in any part of your code in which you have to check the IsCPU property/member for each instance of the Player class, you can just do as follows:
foreach (Player player in players)
{
if (player.IsCPU)
// Do Something...
else
// Do Something Else...
}
Some interesting links:
Access Modifiers
C# Properties
Why prefer Properties to public variables?
Redesign your app like this:
Class Game
List<IPlayer> Players
ShowMenu()
AddPlayer()
StartGame()
IsGameOver(): boolean
Interface IPlayer
Turn() : Score
CpuPlayer: IPlayer
Player: IPlayer
Split your logic into two different classes: you dont need to check. Treat every player the same in the game. Later if you come up with 'NetworkPlayer', 'AIPlayer', 'SuperPlayer' you can easily add to your system.
In your menu:
switch (userInput) {
case AddUser:
AddPlayer(new Player());
break;
case AddCpuPlayer:
AddPlayer(new CpuPlayer());
break;
In your gameplay:
while (!IsGameOver)
{
var nextPlayer = ... next player
nextPlayer.Turn() ...
}
I know that it's better to cache a component if you use it often during runtime. How about if I cache a component as a static variable and access it during runtime? Let me give you an example:
public class AudioManager : MonoBehaviour
{
public static AudioManager audioManager;
void Awake()
{
audioManager = this;
}
}
Then if I access it from another class, should I use AudioManager.audioManager or cache it beforehand (speaking in the terms of performance)?
P.S. Let me know if something isn't clear.
Edit: I guess I don't know what the hell I'm doing regarding Singletons, but to make it clear, this is a newbie question regarding performance:
1) _audioManager = AudioManager.audioManager in Awake and then use _audioManager.someVariable in Update
VS
2) AudioManager.audioManager.someVariable in Update
You don't need to cache your own component for speed in any case. A component won't pay a performance penalty for accessing itself.
The use case you may be thinking of is caching access to other components or objects so that you don't have to do lookup with GetComponent or GetComponentWithChildren. That does save time, but it's not a complex pattern: just do the lookup the first time you encounter the other component or gameobject, store it in a field inside this component, and you're good:
class Example: MonoBehavior
{
public GameObject _TargetCharacter;
private Transform _cachedTransform;
private Animator _cachedAnimator;
void Awake()
{
if (_TargetCharacter != null)
{
_cachedTransform = _TargetCharacter.transform;
_cachedAnimator = _TargetCharacter.GetComponent<Animator>();
}
}
void Update()
{
DoSomething (_cachedTransform, _cachedAnimator);
}
}
GetComponent and GetComponentInChildren are comparatively expensive you do don't want to do them every frame. However direct access to something set as a field is not expensive there is no need to cache it.
And making it s Singleton: in this context, you would need to make a separate class which is NOT a Component and have that be the singleton - you can't prevent somebody from attaching lots of a given MonoBehavior to things in the Unity Editor so you don't want to assume there's only one of the component floating around. In the AudioManager example, you'd have to assume that many different components might all be looking at the same AudioManager.
Here a good example comparing shared behavior using Singletons vs shared behavior in a static class. Two means to the same end, with slightly different strengths and weaknesses.
Update In response to OP's comment below:
If the point of the original code is to gain speed using the common Unity caching trick, it's not needed. If the point is, as OP suggests in comment below, to make the manager into a 'service provider' that other classes can call there are two routes to go:
The standard unity trick would be to add the caching behavior to the other classes that need to get to the AudioManager. For example:
class SomeOtherComponent: MonoBehavior
{
AudioManager _manager;
void Awake()
{
AudioManager[] AllAudioManagers = GetComponents<AudioManager>();
if (AllAudioManagers.Count == 1)
{
_manager = AllAudioManagers[0];
}
else
{
throw new RuntimeError ("Expecting one (and only one) AudioManager in scene");
}
}
}
Switching to a proper Singleton implementation more or less amounts to just taking the boilerplate in the Awake method above and centralizing into the singleton class, allowing you to replace it.
For an extended discussion of the singleton pattern in unity try this book
I live by a simple rule, if I am going to be calling a component a lot of times, more than 5, then I cache it. The same rule I apply to Singletons. If it is only one call then I just use the Singleton.getInstance().
What you should be really caching
Unity Components such as Transform.
The logic behind caching things like Transform comes from looking at the documentation. Transform is not a variable but a property, which happens to contain getters and setters. These are hidden from you, but that's the way it is implemented. This property happens to be written in C or C++. Therefore this will cost you on performance.
I have started learning Unity and already have learned JavaScript for web development so I do have some programming experience.
While programming in unity I came across a few things involving classes that I didn't quite get.
1) When I wright code as a component of a unity object I write it inside the public class shown below. (name Mover is just an example.) However I never create an instance of this class so how does this work? All I see is the class being created.
using UnityEngine;
using System.Collections;
public class Mover : MonoBehaviour {
}
2) Also shown in the code above is MonoBehaviour. I read the api and it said it is a base class. I never came across this in JavaScript. What does this mean and what does it do to the class Mover?
Try this.
Go to your project in Unity, create a c# script, name it whatever you want. Create a cube in your scene. Drag and drop this script onto the object. Open the script and you should see a start method and an update method.
Type Debug.Log("Start"); in the void Start() function, same in the void Update() method but change to the string to whatever. Click play in unity and watch the console.
You should see the console printing stuff.
Anything that is a child of Monobehaviour enables you to do a lot in which I am not going to get into here.
https://docs.unity3d.com/Documentation/ScriptReference/
At the top, you can choose the language. Get used to that page. =D
Hope this leads you somewhere!
For the first question, you may attach the script to a gameobject in the scene to use it.
For example,
public class Mover : MonoBehaviour {
private bool started = false;
void Start () {
Debug.Log ("Mover Started");
started = true;
}
}
If you attach this script to a gameobject in your scene and play the scene. The script will run and print out "Mover Started" and set the private boolean to true.
This are many other ways to interact with other objects or scripts too. Hope it clears things up a little.
If you take a look at Unity's docs for MonoBehaviour you'll see that every JS file associated with your project automatically derives from MB. If you're coding c#, understand that not everything must be a MB. Objects in the game hierarchy may only attach component scripts that inherit from MB objects. Unity handles the construction of these objects, and a MB is actually something that you are forbidden from constructing yourself.
Also, I think you might be better off at unityAnswers for Unity related help.
I have my Pacman game working, and i'm trying to go back through it and "organize" my code better. Before, I had this "TopObject" which referenced the object in game1.cs which basically referenced every object in my game (pacman, ghosts, map, etc). I made it globally available from ANYWHERE so that I could access my Pacman object from my ghost objects, or my map/tile objects from my ghost objects, or even my ContentMananger from anywhere to load content.
I know this is bad practice, so i'm trying to eliminate it. For instance, I created LoadContent() methods on all my objects which take a "ContentManager" type, which eliminated the need for me to call ContentManager using my TopObject.
Proceeding further, i'm having a really hard time doing stuff without this global reference to all my objects. For instance:
- From within my Pacman Update()..
I need to know if i'm going to run into a wall. I need references to my map/tiles.
I need to know if i've collided with a ghost, so i need references to my ghost objects.
I need to know if I collided with some food and then update the scoreboard, so i need have reference to my scoreboard object.
So essentially, it feels like i'm going to be making a giant mess passing so many object references around to all my objects, that it feels like doing a "global" topobject is much cleaner.
Does anyone know how to organize this better, so that i'm doing it cleanly? Should I even be checking for collisions inside my Pacman Update(), or should I be creating seperate "PacmanObject.CheckCollisionWith()" and calling that from my Game1 Update()? Should collision logic also be seperated out into a new class?
Thanks!
Having a central point that contain reference toward your objects isn't a bad thing per se. However, a good design will put the actions that are best related to each object in the correct class. For example, your player doesn't need to have reference towards the tiles and walls. While doing an Move method, the player could call a static method in the Map class that return true/false if the next move is valid. This way, the player doesn't have any reference toward the map itself.
public class Player
{
public void Update()
{
//stuff to find nextTile position
//Call static function toward a class that contains the map data.
if (Map.TileIsWalkable(nextTile))
Move();
}
}
public class Map
{
public static Map loadedMap; // Handling it as singleton, normally you only load one map at a time.
public static bool TileIsWalkable(Vector2 position)
{
if (loadedMap == null) // Throw assert, shouldn't happen.
return //whatever test needed in loadedMap structure
}
}
You can also have a Ghost manager that keeps reference toward the ghost. The player would only need to call a method in that manager that would loop over all the ghost to see if he collides. Even better, that method could take a position and not a reference. That way, it can be reused to see if ghosts collide between each other. (random idea)
There's plenty of way to do something. The hardest in any code design is to put the stuff at the place that make the more sense and makes it the easiest to update and modify later.