Controlling Light components C# - c#

I have a game mechanic where the player can toggle the car headlights with the L keypress and the backlights witht he S key, which also controls backwards movement.
This is shown in the code below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class headLights : MonoBehaviour {
private Light frontLight;
private Light backLight;
// Use this for initialization
void Start () {
frontLight = GetComponent<Light>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.L))
{
frontLight.enabled = !frontLight.enabled;
}
if (Input.GetKeyDown(KeyCode.S))
{
backLight = GetComponent<Light>();
backLight.enabled = !backLight.enabled;
}
}
}
The problem is when I press L or S, both the front and back lights turn on because which I assume, the GetComponent refers to all extra Light components in the Scene and generalizes them as one.
I want to get the S key to only turn on the "backLights" while it is pressed and the L key to only toggle the "frontLights".
METHODS I HAVE USED TO TRY FIX THE PROBLEM
frontLight = GameObject.Find("Player").GetComponent<Light>();
This code just gives me errors like "the gameobject player does not have any light components attached to it(although it clearly does) blah blah blah.
I have also tried using tags but they confuse me a lot and seem like the easy way out. I know in the future I will have to learn how to do object orientated syntax and coding so I would very much like to learn how to reference it!
Please help me if you can, it would make my day~~ :)
Please note, you do not have to solve the whole problem for me if you are short on time, just giving general syntax that I can just swap out would help me a great deal!

Its really easy to disambiguate the two lights. Just make the variables public and set them in the inspector. Be sure to null check them before you use them to make sure they are set.
I just realized that probably didn't make sense.
Lets say your hierarchy is set up like this with the light objects as children to the car:
car
+-FrontLight
+-RearLight
Instead of putting the custom behavior on the light gameobjects, you should put it on the car.
Then, the behavior would look like this:
public class headLights : MonoBehaviour {
public Light frontLight;
public Light backLight;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.L))
{
if(frontLight != null) {
frontLight.enabled = !frontLight.enabled;
}
}
if (Input.GetKeyDown(KeyCode.S))
{
if(backLight != null) {
backLight.enabled = !backLight.enabled;
}
}
}
This is because the lights are not Components of the car, they are Children of it.

Related

Unity OnTriggerEnter2d() Not working | Trying to switch between Scenes

I'm pretty new to unity and I've been trying to get this scene switch to work however the trigger doesn't seem to be activating when the player hits it. The debug.Log is doing nothing so I'm stumped. I know my terminology may make no sense so let me show some pictures. If youre able to help it would be extremely helpful. Thank you!
This is the inspector panel for the object I want to trigger
This is the inspector the player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneChangeScript : MonoBehaviour
{
public int iLevelToLoad;
public string sLevelToLoad;
public bool useIntegerToLoadLevel = false;
void start()
{
}
void update()
{
}
private void onTriggerEnter2D(Collider2D other)
{
if(other.CompareTag("Player"))
{
Debug.Log("Somethings Being Triggered!");
LoadScene();
}
}
void LoadScene()
{
if(useIntegerToLoadLevel)
{
SceneManager.LoadScene(iLevelToLoad);
}
else
{
SceneManager.LoadScene(sLevelToLoad);
}
}
}
Unity Monobehavior Lifecycle methods start with a capital and C# methods are case-sensitive. Therefore, the following methods need to be corrected to be used by Unity:
start => Start
update => Update
onTriggerEnter2D => OnTriggerEnter2D
Since the C# convention is that methods start with uppercase you'll less likely encounter this issue if you assume it starts with an uppercase letter rather than lower case. But it is better to confirm! Also if you are using Visual Studio, you can avoid much of these pains by investing the time to learn some shortcuts.
Hey I just spotted that you initiated the bool useIntegerToLoadLevel to be false and you are using this condition to load the scene in the if statement and the bool is never being set to true.
Try setting this bool to true when you enter the trigger, that is in the OnTriggerEnter2D method, should definitely work. It is a minor bug that anyone can make.

Create animations programmatically in Unity?

In my game I have a big catalog of gear: Armors, weapons and shields. The combinations between these can be really immense.
Besides that, the player has the option of switching in-game to a different set of armor-weapon combination. In the end to solve this, I have used the following object structure.
Whenever I switch the weapons, I activate/deactivate the necessary GameObjects. The animations are set in this way:
Now, the problem is creating the animation. I first considered pre-rendering programatically all the combinations, but my catalog is so huge, that it would create 100s, if not 1000s of animations. So I opted for a different solution. Create in playtime the animation, once I knew what gear would the player select. For that, I created a script to take care of that. The problem is that I have been using APIs from UnityEditor, and now I have realized the build will not work. Specifically because of 2 different classes: EditorCurveBinding and ObjectReferenceKeyframe.
This is a couple snippets of how I was using this classes when creating the animations:
static EditorCurveBinding GetEditorCurveBinding(string path = "")
{
EditorCurveBinding spriteBinding = new EditorCurveBinding();
spriteBinding.type = typeof(SpriteRenderer);
spriteBinding.path = path;
spriteBinding.propertyName = "m_Sprite";
return spriteBinding;
}
static ObjectReferenceKeyframe GetKeyframe(float time, Sprite sprite)
{
ObjectReferenceKeyframe keyframe = new ObjectReferenceKeyframe();
keyframe.time = time / FRAMERATE;
keyframe.value = sprite;
return keyframe;
}
Now, the problem with the Curve, I think I managed to solve, replacing it with this code, replacing EditorCurveBinding with AnimationCurve:
AnimationClip clip = ...
AnimationCurve curve = new AnimationCurve();
clip.SetCurve(path, typeof(SpriteRenderer), "m_Sprite", curve);
But I have no idea how to set the sprites for each animation. I thought that using curve.AddKeycould be helpful, but I have seen no way to add a sprite there.
How could I rewrite that code to avoid using UnityEditor?
Full code
Personally, I would completely avoid built-in Animator and Animations, since this tool is for the very narrow purpose of animating a single object in a predefined way (eg: for a cutscene).
Offtopic - performance
Besides that, the player has the option of switching in-game to a different set of armor-weapon combination. In the end to solve this, I have used the following object structure.
As you probably know this is very inefficient memory-wise and will decrease performance (disabled objects still have marginal CPU overhead). And will incread load time and instantiation time of new objects.
Can I use Animator or Animation?
Because Animator has no API to access it's internals and animation type and overall you cannot do pretty mutch nothing with it except from telling it to Play or Stop.
Since I understand that your animation is "Sprite based" and not "Transform based" any sane idea is just inefficient!
Best solution that I vow against is as follows:
Create "trigger points" that you would "animate"
Based on trigger point - change sprite
public class AnimationController : MonoBehaviour
{
public int AnimationIndex;
public Sprite[] AnimationSprites;
public SpriteRenderer SpriteRenderer;
private void Update()
{
SpriteRenderer.sprite = AnimationSprites[AnimationIndex];
}
}
Better solution?
Since we already need to have custom structure that manages our sprites we might want to optimize the whole thing, since we are not using almost any of the features of Animator we could write custom controller that would replace Animator in this case. This should improve performance significantly since Animator is very heavy!
// MonoBehaviour is optional here
public class SpriteRendererAnimationHandler
{
// More fields that would control the animation timing
public Sprite[] AnimationSprites;
public SpriteRenderer SpriteRenderer;
public void OnAnimationUpdate(int index)
{
var resolvedIndex = ResolveIndex(index);
SpriteRenderer.sprite = AnimationSprites[resolvedIndex];
}
private int ResolveIndex(int index)
{
// Resolve animation index to sprite array index
}
}
// One controller per character - or global per game that synchronize all animations to locked FPS 12.
public class AnimationController : MonoBehaviour
{
private List<SpriteRendererAnimationHandler> Handlers = new List<SpriteRendererAnimationHandler>();
public void FixedUpdate()
{
foreach (var handler in Handlers)
{
// Calculate animation index
int calculatedAnimationIndex = ...;
handler.OnAnimationUpdate(calculatedAnimationIndex);
}
}
}
Add a public field named animation index to Tomasz last example, then create the animations in animator as youd normal do for animation pieces, then animate that animation index field. simple if(currentAnimationyion != lastAnimationIndex) to check if need to send to handlers and ya rocking

AnimationPlayer animations do not play in Godot

Forewords
Firstly, I know posting graphical resources for codes is not encouraged in this platform. I will also post the code but, in this particular case, I think posting a video about it is much more helpful than just posting some arbitrary code because the structuring of game projects really vary depending on their requirements. However, I still respect the platform's rules so if a mod asks me to format my question according to the community rules, I can do that or they also can simply delete my question. I respect that.
The Issue
It's actually a simple issue but it's driving me crazy because of its simplicity. I just want to fade in when I load a scene and then fade out whenever I click a button. As to how I do that, this is the video about it.
To sum up, I load another scene called "Fader" which contains a ColorRect with a black color and AnimationPlayer to change ColorRect's alpha value.
The code is below with extra comments on relevant parts:
using Godot;
using System;
public class TitleScreen : Control
{
private Button[] buttons;
private Control fader; // the scene that I inject
public override void _Ready() // when title screen gets ready
{
GD.Print("Preparing TitleScreen...");
InitButtons();
InitFader(); // initialize fader
FadeIn(); // do fade in animation
}
private void InitFader() // initializing fader
{
GD.Print("Initializing fader...");
var faderScene = (PackedScene)ResourceLoader.Load("res://components/Fader.tscn"); // load external fader scene
fader = (Control)faderScene.Instance(); // instantiate the scene
fader.SetSize(OS.WindowSize); // set the size of fader scene to the game window, just in case
var rect = (ColorRect)fader.GetNode("rect"); // get "rect" child from fader scene
rect.SetSize(OS.WindowSize); // set "rect" size to the game window as well, just in case
fader.Visible = false; // set the visibility to false
AddChild(fader); // add initialized fader scene as a child of title screen
}
private void InitButtons()
{
GD.Print("Initializing buttons...");
buttons = new Button[3]{
(Button)GetNode("menu_container/leftmenu_container/menu/start_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/continue_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/exit_button"),
};
GD.Print("Adding events to buttons...");
buttons[0].Connect("pressed", this, "_StartGame");
buttons[2].Connect("pressed", this, "_QuitGame");
}
private void FadeIn()
{
GD.Print("Fading in...");
fader.Visible = true; // set visibility of fader to true
var player = (AnimationPlayer)fader.GetNode("player"); // get animation player
player.Play("FadeIn"); // play FadeIn animation
fader.Visible = false; // set visibility of fader to false
}
private void FadeOut()
{
// similar to FadeIn
GD.Print("Fading out...");
fader.Visible = true;
var player = (AnimationPlayer)fader.GetNode("player");
player.Play("FadeOut");
fader.Visible = false;
}
public void _StartGame() // whenever I click start game button
{
FadeOut(); // fade out
GetTree().ChangeScene("res://stages/Demo01.tscn");
}
public void _QuitGame() // whenever I click quit game button
{
FadeOut(); // fade out
GetTree().Quit();
}
}
Seems like I can't see something. Why does it not fade in and out?
Environment
Manjaro 19.0.2
Mono JIT Compiler 6.4.0 (if it is relevant)
Godot 3.2
So, the issue was Play method on AnimationPlayer object kinda runs like async (dunno if this is the correct term for it).
Luckily, there is a feature called signals in Godot. There are animation_started and animation_finished signals on AnimationPlayer objects. Basically, I created a C# script for Fader scene, hooked the signals from player to fader as in:
animation_started to _FaderAnimationStart
animation_finished to _FaderAnimationEnd
At the end, my script looks like below:
using Godot;
using System;
public class Fader : Control
{
private ColorRect rect;
private AnimationPlayer player;
public override void _Ready()
{
GD.Print("Initializing Fader...");
rect = (ColorRect)GetNode("rect");
player = (AnimationPlayer)GetNode("player");
SetSize(OS.WindowSize);
rect.SetSize(OS.WindowSize);
Visible = false;
}
private void _FaderAnimationStart(String anim_name)
{
Visible = true;
}
private void _FaderAnimationEnd(String anim_name)
{
Visible = false;
}
}
I solved it thanks to njamster's answer and Hans Passant's comment.
However, this only solves half of the problem. Yes, the scene now fades in when it loads but it does not fade out. Given that it executes kinda-async (again, I'm not sure if this is the correct term), changing scene interrupts while running the animation. I will update the answer when I solve that problem as well.
Update
Well, I cannot seem to solve the fade out part because it requires to access parent node from initialized child scene. There are some methods I can think of.
First one is to somehow parameterize "Fader" scene. This can be done in many ways but at the end, when you initialize it from another scene, you need to cast it to Fader and I don't know if this is a valid way to do it. Another concern is standardizing this in the codebase. A similar method is discussed in here.
Second one is to write it as a plugin which has it benefits and drawbacks. C# is not really battle-tested in this particular area.
Third one is to use a state management system. Here is a redux implementation for Godot. And you need to somehow integrate it for signals, which seems like a hassle.
So, overall, I still do not know how to fade out.

A collision triggers an animation

I am trying to make my player hit an object, destroying the object and triggering an animation, but everything I try causes an error. I am relatively new at c# so the answer may be obvious but I need help. How can I set it up so that the collision will cause the object to disappear and the player to play an animation? Here is the script I am currently trying.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class succ : MonoBehaviour
{
public float speed = .15f;
public static float jumpSpeed = 170f;
void Start()
{
GetComponent<ConstantForce2D>().enabled = false;
GameObject.Find("goal");
}
public bool animation_bool;
private object coll;
private object other;
void Update()
{
OnCollisionStay2D(Collision2D coll);
{
if (coll.gameObject.tag == "succ") ;
{
animation_bool = true;
GetComponent<Animator>().SetBool("succ", animation_bool);
GetComponent<ConstantForce2D>().enabled = true;
Destroy(other.object);
}
}
}
private void Destroy(object gameObject)
{
throw new NotImplementedException();
}
private void OnCollisionStay2D(Collision2D collision2D, object coll)
{
throw new NotImplementedException();
}
}
There are a few things I can see that are wrong, but I'll start by answering your question.
I suggest you change your MonoBehaviour method OnCollisionStay2D to OnCollisionEnter2D. OnCollisionStay2D is "sent each frame where a collider on another object is touching this object's collider". OnCollisionEnter2D is "sent when an incoming collider makes contact with this object's collider".
I believe you are looking for the latter since you only want to trigger this once during the collision. You are also destroying the other object, making it impossible to call OnCollisionStay2D anymore even if you wanted to do so.
You should also remove your Update method. I honestly do not understand what you are trying to achieve there now. All of the OnCollision methods get called automatically; you do not have to call them yourself.
Then you can use the Awake and OnCollisionEnter2D methods as follows
public class Succ : MonoBehaviour
{
private Animator animator;
private void Awake()
{
// You can already get a reference to the Animator on Awake
// This way you do not have to do it on every collision
animator = GetComponent<Animator>();
}
// Use OnCollisionEnter2D instead since the code
// needs to be excecuted only once during the collision
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("succ")
{
// Assuming that you only want to trigger an animation once
// to reflect attacking or colliding, you could use SetTrigger
// instead. Otherwise you need to use SetBool again to set it
// back to false. You should then change the Animator parameter
// accordingly, from a bool to a trigger.
animator.SetTrigger("succ");
Destroy(collision.gameObject);
}
}
}
Apart from this, I have a few things I would like to comment on:
I am not sure what you are trying to achieve by setting your ConstantForce2D component to false on Start and then setting it to true on collision.
You seem to be using GameObject.Find on Start. GameObject.Find is something that should be very rarely used. It can be extremely expensive, especially if your Scene has a lot of GameObjects in it; this is because it simply goes through the Hiearchy, comparing the parameter string to names of GameObjects until it either finds a match or runs out of GameObjects.
Moreover, you are using GameObject.Find on Start to look for a GameObject, but then you do not store that anywhere, making the whole finding process completely pointless.
Overall, I recommend you to take a look at all of the different learning resources offered by Unity themselves. Your question is about fairly basic functionality that is certainly covered during all of the different tutorials.

Unity - Resizing one GameObject to match another

I'm working on a project in Unity that involves regions that teleport any non-static object from one to the paired. That part's fine, but for convenience, I'm trying to write a part of the script that will resize one object if its pair is resized, such that they will always be of equal size. And so far it works - mostly. The only problem I encounter is when trying to resize through the Transform component - as in, typing in numbers in Inspector, or using the value sliders on X or Y or Z. The handles work fine. It's not a big deal, I suppose, but if I could figure out why this isn't working, so I can learn what to do in the future, I'd be very glad. Here's the code:
[ExecuteInEditMode]
public class TransferRegion : MonoBehaviour {
// Unrelated code...
public bool scaleManuallyAltered {
get; private set;
}
[SerializeField]
private TransferRegion pair;
private Vector3 scale;
// Called whenever the scene is edited
void Update () {
if (scale != gameObject.transform.localScale) {
scaleManuallyAltered = true;
scale = gameObject.transform.localScale;
}
if (pair && scaleManuallyAltered && !pair.scaleManuallyAltered) {
pair.transform.localScale = scale;
}
}
// Called AFTER every Update call
void LateUpdate () {
scaleManuallyAltered = false;
}
// Unrelated code...
}
If anyone can see some major logical failure I'm making, I'd like to know. If my code's a bit hard to understand I can explain my logic flow a bit, too, I know I'm prone to making some confusing constructs.
Thanks folks.
If you want one object to be the same scale as another, why not just simplify your code by setting the scale of the re sizing game object, directly to the scale of the game object it is based off of? For example, this script re sizes an object to match the scale of its pair while in edit mode:
using UnityEngine;
using UnityEditor;
using System.Collections;
[ExecuteInEditMode]
public class tester : MonoBehaviour
{
public Transform PairedTransform;
void Update()
{
if (!Selection.Contains(gameObject))
{
gameObject.transform.localScale = PairedTransform.localScale;
}
}
}
I tested this on two cubes in my scene. I was able to resizing using gizmos as well as manually typing in numbers to the transform edit fields in the inspector.
Edit: By taking advantage of Selection you can apply the scale change only to the object in the pair that is not selected in the hierarchy. This way the pairs wont be competing with each other to re scale themselves.
So I figured it out.
I'm not sure what was wrong with my original code, but eventually I decided to slip into the realm of good old handy events:
[ExecuteInEditMode]
public class TransferRegion : MonoBehaviour {
//...
[SerializeField]
private UnityEvent rescaled;
//...
void Update() {
if (scale != gameObject.transform.localScale) {
scale = gameObject.transform.localScale;
rescaled.Invoke();
}
}
//...
public void OnPairRescaled() {
gameObject.transform.localScale = pair.transform.localScale;
scale = gameObject.transform.localScale;
}
}
And just set the OnPairRescaled event to be the listener for the paired object's rescaled event.
Ta-da!

Categories