If for instance I have a game which consists of just a single scene, and in that scene I make the user chose between the normal play mode or the tutorial play mode. The game has 4 different objects: a ball, 4 squares and a squarecontroller. In the tutorial mode i want to provide the user with a pointing arrow while pausing the game and continue after the user pressed the object being pointed at. Should I make a script for the normal mode and another one for the tutorial mode, make one script and check if a tutorial boolean is true or false in every function (boolean should be true if user pressed the tutorial button) or do some kind of preprocessing?
In the squarescript for example:
void OnCollisionEnter2D () {
if (isTutorial) {
PauseGame();
arrow.position = GetRelativePosition();
arrow.setActive(true);
} else {
if (canCollide) {
score++;
} else {
GameOver();
}
}
In the ballscript:
void OnMouseDown () {
if (!isTutorial) {
return;
}
ResumeGame();
}
We know nothing of your game so it's hard to answer. But as a rule of thumb: The less you have to type, the better. Also consider what will happen if you need to add new functionality to the game, will you have to go back and change tons in your code?
If so, you are most likely not writing good code.
As an attempt to give a concrete answer I'd say you should make an inheritance, create a class Level and make sub classes Tutorial and FreePlay or similar, that inherits from Level.
Then you can add all "general" functionality in the base class and the specific things goes in the sub classes
By structuring these behaviours inside if statements, it makes the code hard to understand and work with. Imagine what this will look like if you decide you want one of the squares to increase the players score AND show a tutorial arrow.
Split the behaviours into separate objects. For the square it could be something like a TutorialCollisionHandler, ScoreCollisionHandlerand HazardCollisionHandler. Then you can create different squares simply by changing which collision handlers are added to them, you don't even need to write any code!
Now depending on which mode the user picks, you can just use a different mix of squares. The same principle can be used with other tutorial or game specific behaviour.
Related
I need to show two camera display side by side. One will have the sun(directional light) on and one will have the sun off while rendering the same scene at the same time. I have tried to use sun.SetActive() inside of OnPreRender() method, for one Camera I set it sun.SetActive(false) and sun.SetActive(true) for another. It does not work, sun remains off for both camera. How can I achieve the desired output?
You need to add OnPreCull too to your initial try for versions highers than Unity 4.6.
I preserve OnPrerender for older versions, you got an advice on your log but ignore it.
Add this script to your camera:
function OnPreCull () {
if (sun != null)
sun.enabled = false;
}
function OnPreRender() {
if (sun != null)
sun.enabled = false;
}
function OnPostRender() {
if (sun != null)
sun.enabled = true;
}
Another way to do this would be to have all gameobjects duplicated and set to different layers - e.g.: 'Sunlit' and 'Shadowed'. The duplicate object needs to be nested within the original object, which can be quite messy, you'd need a script to duplicate the scene's objects at runtime.
The hierarchy would look something like this:
Your directional light's culling mask (on the light's inspector) would be set to everything but to the objects on the 'Shadowed' layer.
Then 2 cameras, culling everything but one of the layers:
I'm unsure if this is better or worse than joreldraw's solution in terms of performance. But I would guess it would depend on the amount and complexity of the models. On joreldraw's solution we're enabling/disabling the lightsource several times per frame. With this solution we have twice the gameobjects. If you don't have a lot of objects on your scene, then perhaps this solution is better.
Ok so I have this coroutine :
IEnumerator ShowCharTraits()
{
while(!hasPlayerChosen)
{
yield return null;
traitPanel.SetActive(true);
}
hasPlayerChosen = false;
traitPanel.SetActive(false);
// Debug.Log("Got called! job done");
}
It's being called like this from the awake method in my GameManager:
players = GameObject.FindGameObjectsWithTag("Player");
foreach (GameObject g in players)
{
ui_Controller.StartShowCharTraits();
g.GetComponent<PlayerToken>().isTurn = false;
}
StartShowCharTraits() is a simple method that does this :
public void StartShowCharTraits()
{
StartCoroutine("ShowCharTraits");
}
Now, I have checked the tags, no null reference exception, actually no errors or warnings are being thrown. If i load the scene in the editor and then play it everything works fine. traitPanel.SetActive(true); get called and my panel shows up. However when I load my scene from another scene using SceneManager.LoadScene(1); the above mentioned line is never reached. Any ideas why this is happening ?
Say you want to have one central place that is "like a singleton" in a Unity project. Example,
SoundEffects
LapTimer
Scores
SocialMediaConnections
All you do is this.
make your script SoundEffects.cs
recall that every Unity project must have a "preload" scene. (it's impossible to not have one)
in the preload scene, have a empty game object called "holder". make sure it is marked "DontDestroyOnLoad"
attach SoundEffects.cs to that holder
you're done.
there's just nothing more to it.
you're finished.
it's "just that simple"
So, any particular script, which happens to be attached to any particular object, in any particular scene, may need to access "SoundEffects"...
To do so, simply do this in Awake:
SoundEffects soundEffects = Object.FindObjectOfType<SoundEffects>();
then just use soundEffects anywhere in that script, for example soundEffects.PlayBoom(13) etc etc.
So in Awake()
Laps laps = Object.FindObjectOfType<Laps>();
Social social = Object.FindObjectOfType<Social>();
AI ai = Object.FindObjectOfType<AI>();
or whatever.
Unity is simple. Incredibly simple. It's just that easy.
write your script, LapTimer.cs or whatever
put it on a holder object in your preload scene (where else could it be?)
there's no "3", that's all there is. It's just that ridiculously simple.
Note that...
In the early days of Unity, someone unfortunately mentioned "singletons" on a QA board somewhere. (You can't have "singletons" in an ECS system, it's meaningless.) At the time, this led to huge discussions about how you can make a "singleton-like thingy" in Unity, which is piling confusion on confusion. Unfortunately from that day to this, you get people learning Unity, who see "singleton" mentioned here and there on the net, and it leads to endless confusion.
Once again, note that the idea of "managers" is just impossibly simple in Unity - explained above. It's trivial. It just couldn't be easier.
Note, above I mention you might want syntactic candy to avoid the incredible chore of typing Laps laps = Object.FindObjectOfType<Laps>();
There are very unfortunately no macros in Unity/c# so you need another way.
All you do is use a "Grid" script http://answers.unity3d.com/answers/1124859/view.html which has been popular for years in Unity.
But honestly, it's so simple to use Scores scores = Object.FindObjectOfType<Scores>(); that I usually just do that nowadays.
Ok how do I explain this. I have a singleton that acts as a data holder. While developing the scene with the game manager I had attached the singleton to the gamemanger object that hold a bunch of scripts. Now when I made the main menu I ofc added my singleton to it so I can carry info to the game scene and because of this my whole game manger object was being deleted. This is the culprit from the DataHolder :
void Awake()
{
if (instance == null)
instance = this;
else if (instance != this)
Destroy(gameObject);//This right here.
DontDestroyOnLoad(gameObject);
}
So I changed that line to Destroy(gameObject.GetComponent(instance.GetType()));
I'm using PhysX.NET (C# wrapper for PhysX) and I am trying to get a notification of collision between two spheres using onContact in SimulationEventCallBack.
I have created a new subclass for SimulationEventCallback and overridden the OnContact method so that it will give me a message when collision happens. I have then set the simulationEventCallback of the scene to an instance of my subclass. This does not work even though the two spheres (rigid dynamic) obviously collide. Below is my code:
// Creating subclass
public class robotCollision : SimulationEventCallback
{
public override void OnContact(ContactPairHeader pairHeader, ContactPair[] pairs)
{
base.OnContact(pairHeader, pairs);
Rhino.RhinoApp.Write("Contact!");
}
}
// Create scene
scene = engine.CreateScene(sceneDesc);
scene.SetSimulationEventCallback(myContactCallback,0);
Is there something else that needs to be considered? Any flags to be set?
I am sorry if this is a very naive question, but I have worked on this for the whole day for something that seems to be quite simple and I can't wrap my head around it.
Thanks in advance.
I'm a PhysX C++ user so I would no mark this as a solution.
In general, you need to define a contact between two actors using either PxSimulationFilterShader or PxSimulationFilterCallback.
The later is a specific callback you need to implement, so I doubt you want to do that.
A default PxSimulationFilterShader will be provided so no worries there.
In order for the filter shader to work, you must define the actors a collision group and mask. see PxSetGroup and PxSetGroupsMask.
The group is just a number ID between 0-31.
The mask is a 4 shorts (PxU16) bit set that defines "for each group, whom should I collide with".
Now the group mask is a bit finicky.. The math behind is.. annoying...
But you can implement your own collision filtering with a more simple one, using the input data in the group mask. There are samples on how to do so in the PhysX code and documentation. see Collision Filtering
Again, I'm a C++ answer, I'm sure there is something similar in the C# wrapper.
Scenario: a game with a board, and several tiles on it. Classes: Board, Tile, Player and of course, Game.
Whenever the player presses a tile, his score gets incremented by 1. Board is instantiated inside of Game, and an array of Tile is instantiated inside of Board. My first option to increment that score easily was to make a public static class with a public static field (Score). Of course, it's rather amateurish. And seemed to break the overall flow of the app.
After some thought, I changed everything to use Events; Tile raises an event when clicked; Board handles that event, and raises another event to the main Game class. Player is instantiated inside of Game; when Game handles the event received from Board, it does a PlayerOne(instance of Player).Score += 1;
Should I just go on ahead and use this flow? Do you have any other architecture/design ideas that would work better? Why would your ideas work better?
I didn't use custom made events intensively before and I feel that the whole event raising another even idea might be a bit wrong. From afar though, it looks like a good flow. And it certainly does the job correctly.
What you described looks like (is) the observer design pattern. The game should 'listen' to events from the board, the board should listen to events from the tiles etc.
You should have provided some code.
Should I just go on ahead and use this flow?
Depends on what the events look like.
Do you have any other architecture/design ideas that would work better?
Publish/Subscribe is an alternative. But the .NET events works fine here.
I didn't use custom made events intensively before and I feel that the whole event raising another even idea might be a bit wrong.
It's fine to keep encapsulation. I would do something like:
class Tile
{
public event EventHandler Clicked = delegate{};
}
class Board
{
private void OnTileClick(object source, EventArgs e)
{
var tile = (Tile)source;
//doSome
var args = new CustomEventArgs();
CustomEvent(this, args);
}
public event EventHandler<CustomEventArgs> SomeEvent = delegate{};
}
public class SomeCustomEventArgs : EventArgs
{
}
The only other possiblity that springs to mind is passing / setting in delegates from higher classes that act as callbacks - so the lower classes can check for a valid delegate and call it without any knowledge of who owns it. If you make it a list of possible delegates, it allow for multiple subscribers all benefitting from that callback.
Having said that, I find your event architecture pretty elegant.
Another way to look at it is that the Board depends on Player to function correctly. How many players are there at any one time and do players get added to and from the board during game time?
If not, you might be able to pass the player(s) to the board on creation and then the board could increment the player score. This works as long as there is no other logic that happens at the Game level which could influence the scoring.
The architecture you seem to have implemented works well for this scenario.
using the observer architecture allows the dependencies you have created through the object relationships to be easily managed.
The observer architecture here will allow you you add or remove players, tiles, boards very easily. If there was a requirement for a 'Game' to now manage multiple boards, then simply adding the object in and subscribing to its exposed events allows you to manage that elegantly. This is because a tile does not need to know that a player exists. The same way a player does not need to know that a game exists - they just do their jobs independently.
Other patterns may create unwanted dependencies, leading to the extra code that would be required to pass the information back up the chain (from tile, to player, to game) - that could very easily result in issues further down the line of your project implementation.
I am making a simple 2D game in the console in C# as a learning project. However I seem to be unable to come up with a decent design for a collision system.
The resolution of a collision presents the biggest problem for me.
Basically there can be any combination of the following 2 sets of effects:
1. The triggering object or tile is removed;
2. The remote object or tile is removed;
Or nothing can happen - the objects just stop moving(i.e. when both are invulnerable or something).
Any ideas towards that effect would be greatly appreciated.
How to detect a collision and how to respond to it are two totally different concerns and you should separate them.
The simplest way would be to have a virtual method in your base game object responding to collisions:
class GameObject
{
virtual protected void OnCollision(GameObject withObject) { }
}
In your collision detection system, whenever two objects collide, simply raise the collision event on the two objects: object1.OnCollision(object2); and object2.OnCollision(object1).
You will soon realise that this might become a mess at some point and will want to learn about multiple dispatch and how to emulate it on languages that don't support it.