Preamble
I am currently making a game where a player can go from third person view, walking around to transition into a vehicle.
I have thought about using a transmitter/receiver type set up, but I think my way of simplifying it isn't correct.
I am using assets from third parties for controllers that use inputs. My plan was to enable/disable the appropriate script and camera from the object I want to control. I've gotten as far as being able to disable the previous controller and enable the next, though I can't go back to enabling since the script obviously doesn't run anymore.
Question/Request
I'd like to be able to reference the pawn's input component script in a different component script on the same gameobject to then be able to enable/disable the aformentioned component, though the issue is that the input controllers have variable names (Different names depending on the third party on each pawn).
Here's how I have it set up:
I have a PlayerTransmitter that handles the basics of turning things on and off. I tried making this where all of the inputs are being handled, but I don't want to have to change the original controller scripts to look at this script. This is on an empty game object and handles the 'state' of the player, (walking or in which vehicle).
on each pawn gameobject (The walking pawn CleanerPawn and the vehicle TractorPawn), I've added a script called InputReceiver. This was originally intended to pass the inputs from the PlayerTransmitter to the actual controller on the object itself.
Right now, the walking pawn has a component called AdvancedWalkerController (You may know the one I'm talking about) that controls the player walking movement and the vehicle has a component called VehicleController which controls how the vehicle moves and handles.
CleanerPawn
TractorPawn
The two images above show that I am using the same InputReceiver component on both pawns. My plan was to pass in each pawn's input controller (temporarily named CleanerController) and then enable/disable that input controller depending on the PlayerTransmitter 'state'.
The InputReceiver currently looks like this:
public bool isEnabled;
public Component CleanerController;
public void TurnOffControls()
{
isEnabled = false;
}
public void TurnOnControls()
{
isEnabled = true;
}
In each pawn's input controller, I added a line to the Update() function:
enabled = gameObject.GetComponent<InputReceiver>().isEnabled;. Two problems with this; 1. I don't want to change any code in the input scripts (I hope this is possible) and 2. Once it's disabled, it won't read an update to enable itself again.
I was hoping I could just use the reference to the component CleanerController to say CleanerController.enabled = true; or false with that reference being just that one component, though I'm missing something here.
My final thought which I am going to try is to allow/disallow the input controls within each input script depending on my isEnabled boolean. Though again, I would have to change the original scripts to accommodate this.
What speaks against
public Behaviour CleanerController;
and then
CleanerController.enabled = false; // or true accordingly
See
Behaviour
Behaviours are Components that can be enabled or disabled.
Behaviour.enabled
Enabled Behaviours are Updated, disabled Behaviours are not.
or in other words: If a Behaviour is set to enabled = false then it's Update (and similar event methods) is not called anymore.
I would recommend you to have a Controller Script. This named "CameraController" for example and has a Method to switch between the Modes. This would also make it possible to have even more Options. For Example you could use an Enum to define which modes exist:
enum CameraMode {
Player,
Car
}
public SwitchMode(CameraMode mode) {
switch(mode) {
case CameraMode.Player:
TurnOnControls();
break;
case CameraMode.Car:
TurnOffControls();
break;
default:
throw new NotSupportedException();
}
}
You could even go further and create an Interface/Abstract which allows all of this and just has an execute method doing different stuff. In the end you just need that controller which allowes to swtich between the modes and handles the key input.
Related
I'm working a game in Unity and I've got a Script where I save a lot of values in multiple variables, which I then use in other scripts. You could say its my GameState. The Script itself is not a GameObject, it purely exists to save values. When I start my game the "GameState" has some basic values like Name, TeamName, Money and tons of more variables which are static and filled with pre-set values.
Now comes my problem. If the player plays through the game and picks some options, functions get triggered which change the values in the GameState, like for example he'll receive more money, so the value for money in the GameState changes. But the player also has the option to completely "restart" the game by going back to the main menu (where I use a LoadScene Function). Problem is that the values in the GameState remain changed when he goes back, so when he starts a new game, he doesn't got the pre-set values, but the ones from his last game.
So my question would be, is there an easy way to reset my GameState completely to its original values? I know I could save the default values somewhere and then make a check to see if the game is reloaded to then use them, but I've already got like 60-70 variables in there and don't really want to create another 60-70 just for the default values (unless there is no other option). So does anyone have an idea how I could do that?
I don't think showing the code of the GameState does much, since its really just looking like:
public class GameState
{
//Team
public int TeamID;
public string TeamName;
public string TeamColor;
etc...
}
GameState is a class to contain data. An easy way to create default is to serialize it : add [System.Serializable] on top of the class declaration.
Now you can have say an object in your main scene called default values which has a public/serialized field of type GameState. You can set those in the editor save the scene and bam. Now to reset all the values to default you just copy the default to the current/active set of data.
If you want to expand a bit on that you can also turn the class into a scriptableObject but I don't think you need that.
I'm trying to synchronize a canvas with photon engine so every player can see it. This canvas will be kind of a tv that any player can turn on and the rest can watch it. I could synchronized a cube adding the PhotonView and the PhotonRigidBody components to the prefab but when I tried the same with the canvas it didn't work at all.
Can anyone tell me what components are required to do this and if it needed it what should I handle with an extra script (i.e transfer ownership).
There is nothing special about the canvas, but it could be locked in place.
There are two solutions I have for you:
Observable Component:
You could write a custom observable component, and add it to the PhotonView:
To make use of this function, the script has to implement the IPunObservable interface.
public class CustomObservable : MonoBehaviourPunCallbacks, IPunObservable
{
[SerializeField] PlayerController playerController;
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
stream.SendNext(playerController.playerNumber);
stream.SendNext(playerController.playerScore);
}
else
{
playerController.playerNumber = (int)stream.ReceiveNext();
playerController.playerScore = (float)stream.ReceiveNext();
}
}
}
Custom Properties:
You could also use custom properties to sync the data across all players.
Photon's Custom Properties consist of a key-values Hashtable which you can fill on demand. The values are synced and cached on the clients, so you don't have to fetch them before use. Changes are pushed to the others by SetCustomProperties().
How is this useful? Typically, rooms and players have some attributes that are not related to a GameObject: The current map or the color of a player's character (think: 2d jump and run). Those can be sent via Object Synchronization or RPC, but it is often more convenient to use Custom Properties.
PhotonNetwork.CurrentRoom.SetCustomProperties(Hashtable propsToSet)
You can write a script that uses Photons callback, and updated the UI elements.
OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
After reading the API info here:
https://docs.unity3d.com/ScriptReference/TrailRenderer-colorGradient.html
I am wondering if I can "tune in" my trail renderer in the normal unity interface, print those complicated code parameters, then use that code in my script to change color on triggers, etc.
To clarify, how do I get the information here presented in code:
[]
I guess I am approaching this from a CSS background. Is there a Unity colorgradient version of this website:
https://www.colorzilla.com/gradient-editor/
Can I make the script print the characteristics of the trail renderer (for the purpose of replicating it elsewhere in my code)?
1
Much appreciate the help!
I'm still not 100% sure if I understood the question but I'll give it a shot.
As I understand you want to have a component on every trigger object where you can define different gradient settings for each.
And I assume by Unity interface you mean the Inspector.
So something like e.g.
public class GradientSetter : MonoBehaviour
{
public GradientColorKey[] colorKeys;
public GradientAlphaKey[] alphaKeys;
}
Put this on the trigger object(s) and adjust the settings via the Inspector. At beginning they should be empty arrays so to add elements just enter the wanted element count in the size property of both arrays.
And wherever you have the Collision implemented on your TrailRenderer object
void OnTriggerEnter(Collider other)
{
var gradientSetter = other.GetComponent<GradientSetter>();
if(!gradientSetter) return;
gradient.SetKeys(gradientSetter.colorKeys, gradientSetter.alphaKeys);
...
}
I'm assuming GradientColorKey and GradientAlphaKey are Serializable. If you implement this but they don't show up in the Inspector let me know, then you'll have to make a wrapper class for them. (I can't test it right now)
Note: Typed on smartphone so no warranty but I hope the idea gets clear
I can't seem to make my trigger function work only for a specific group or object in unity. Plus it activates whenever I hit play which is an issue.
Check out the Tags and Layers pages on the Unity Docs, they should provide you with everything you need. The basic gist is that you can group a bunch of Game Objects by tagging them (or adding them to a layer). Then later when you are interacting with a Game Object or behaviour, you can check to see if it belongs to a certain group.
Below is a simple example of checking an Object's tag:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Fruit"))
{
Debug.Log("You've found a piece of fruit!");
} else {
Debug.Log("You've found something else :(");
}
}
Good luck!
I'm attempting to write my own Entity/Component System from scratch in C# and I'm stuck on where/how to implement some functionality.
Edit: I figured out how where I'm going to add functions like Move() and Jump().
public static class Actions
{
public static void MoveUp(EntityManager entityManager, int EGUID) {}
public static void MoveDown(EntityManager entityManage, int EGUID {}
}
I can add them to a collection like so:
KeyboardController kbController = entityManager.GetComponent<KeyboardController(1);
kbController.KeyBindings.Add(Keys.Right, new Dictionary<KeyStateES, Action<EntityManager, int>());
kbController.KeyBindings[Keys.Right].Add(KeyStateES.Held, Actions.MoveUp);
And now I'm able to move the Entity around quite easily with key bindings. However, it's still not quite ideal because:
I can't bind more than one Method to a Key.
I'm forced to pass the Method Arguments in the InputManager class.
This is a problem because sometimes I'll want a key to perform multiple unrelated tasks and because it seems really silly for my InputManager to be the one passing the arguments for the methods. Ideally, I would like it so that a KeyDown, KeyHeld, or KeyReleased event is fired and only the Controllers with the particular key(s) bound respond to the event and execute their associated Methods.
After that you changed X and Y coordinates o the Entity using specific component, you just redraw scene, and Entity will appear into the a new position. Where is actually the problem. ?
You have an Entity that is transformed in any possible way with (say) PositionComponent, RotationComponent, ScalComponent, TextureComponent and so on, but have simple Redraw() method which renders all Entites on the scene in visible frustrum within a current state of each one.
How about a tree of types focused on these high-level behaviors?: i.e. a Jump class would, given an object, know how to make it jump. Jump might be derived from Move if there is sufficient commonality, etc. More complex behaviors would then be composed of simpler behaviors heirarchically.