I often need to pass invalid location to functions that optionally can use location (eg. RTS unit action). But this does not compile:
public abstract void CastSpell(Spell spell, Vector3 targetLocation = null);
So how can I make a proper invaid Vector3 to determine invalid/"don't care" locations? I've seen things like vector with -999999 coordinates - but that's a nasty trick that might cause bugs (eg. on huge maps).
I had a similar problem in the past, I found there was two solutions. The first solution was to create a wrapper for the class.
Class Vector3Wrapper
{
Vector3 vector;
}
Then I would simply set the Vector3Wrapper to null then if it wasnt null access its vector. A better method would be making it a Nullable type. A example is below.
http://unitypatterns.com/nullable-types/
public class Character : MonoBehaviour
{
//Notice the added "?"
Vector3? targetPosition;
void MoveTowardsTargetPosition()
{
//First, check if the variable has been assigned a value
if (targetPosition.HasValue)
{
//move towards targetPosition.Value
}
else
{
//targetPosition.Value is invalid! Don't use it!
}
}
Related
This is my code:
transform.localPosition = new Vector3(transform.localPosition.x, Mathf.PingPong(Time.time * movementSpeed, movementRange), transform.localPosition.z);
Can you help me to short it?
Like
transform.localPosition = Vector3.up * Mathf.PingPong(Time.time * movementSpeed, movementRange)
I am constantly encountering a Vector3 abbreviation of this form, but can't write this code any better
Perfect use-case for Extension Methods
public static class Vector3Extensions {
public static Vector3 SetY(this Vector3 vector, float y) {
//This works as-is because structs, such as Vector_ in Unity, are pass-by-value
vector.y = y;
return vector;
}
}
Usage:
//You have to assign the result of the method because, again, pass-by-value...
//..So the vector that was modified inside the method is a different object from the original
transform.localPosition = transform.localPosition.SetY(Mathf.PingPong(Time.time * movementSpeed, movementRange));
Your second example is functionally different from the first. In it, the X and Z will be zero instead of inheriting the original transform's values. If your intention is that, then your example's code is already pretty much as small as it gets, without another extension method to the Transform class, ie transform.SetLocalPositionY(y).
If you need inheritance of the X and Z values, AND using SetY would still be too verose to your liking, then use a Transform Extension Method as I said above:
public static class TransformExtensions {
public static void SetLocalPositionY(this Transform transform, float y) {
transform.localPosition = transform.localPosition.SetY(y);
}
}
Usage:
//Assignment not needed in this case, as transform is a class...
//..and assignment of localPosition is handled inside the extension method.
transform.SetLocalPositionY(Mathf.PingPong(Time.time * movementSpeed, movementRange));
There is a slight performance cost to extensions methods for struct types, due to the pass-by-value nature of structs. Which are the types being used in this case. But it's negligible in this case specifically, and should be negligible for all structs in general, if you are using structs correctly.
On pass-by-reference types, there should be no performance cost any different to any standard static method modifying the data.
Note that the operation does not need to be inline, and if you're willing to spread it across a few lines, you can use the same principle of the extension method, of modifying a cached clone of the original vector and then (re)assigning it back to the transform, to achieve this with shorter lines and without the extra struct instance from passing as parameter and then returning (one instance creation instead of two):
var localPos = transform.localPosition; //Creates temp/cached instance
localPos.y = Mathf.PingPong(Time.time * movementSpeed, movementRange); //Modification
transform.localPosition = localPos; //(Re)Assignment.
But with exception to cases requiring extreme performance, the extension will be fine. In fact, anything short of a case verified in the debugger, doing it this way just for the performance concern is going to be premature-optimization.
I have a 2D game made in Unity in which I want the characters to be able to shoot bullets and when a bullet hits a player to push him back destroying the bullet. Due to server not syncing perfectly there are some cases in which the bullet is destroyed locally, but not on all clients so I want to make it a [Command] to destroy it on server and on all clients too.
The code for local looks like this:
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "bullet")
{
Explode (Mathf.Sign (col.attachedRigidbody.velocity.x));
Destroy(col.gameObject);
}
}
And I tried to make it for multiplayer like this
[Command]
void CmdOnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "bullet")
{
Explode (Mathf.Sign (col.attachedRigidbody.velocity.x));
Network.Destroy(col.gameObject);
}
}
But it doesn't work.. it tells me that
CmdOnTriggerEnter2D parameter [col] is of the type [Collider2D] which is a Component. You cannot pass a Component to a remote call. Try passing data from within the component.
I understand that I should use another parameter, but how..? How can I do this function to work for my server?
As your output says you can not pass the Collider component reference as parameter since the Network does not know, where this reference belongs to on other instances.
In the Unity Documentation for Command you can find which values are allowed as parameter:
The allowed argument types are;
Basic type (byte, int, float, string, UInt64, etc)
Built-in Unity math type (Vector3, Quaternion, etc),
Arrays of basic types
Structs containing allowable types
NetworkIdentity
NetworkInstanceId
NetworkHash128
GameObject with a NetworkIdentity component attached.
=> Note especially the most bottom element in the list:
You can simply pass in the col.gameObject as long as it has a NetworkIdentity component on it!
Than I would make the check if the Tag Matches already before stressing the bandwidth of the networking. Meaning: Do the tab check local and only call the Command with the valid GameObject reference.
So your code should than look like
//local
void OnTriggerEnter2D(Collider col)
{
if (col.gameObject.tag != "bullet") return;
CmdOnTriggerEnter2D(col.gameObject);
}
// This is executed only on the server
[Command]
void CmdOnTriggerEnter2D(GameObject col)
{
// Depending on what Explode does you might want to pass it pack to all clients as well
// Since currently this will only happen on the server itself!
Explode (Mathf.Sign (col.attachedRigidbody.velocity.x));
Network.Destroy(col);
}
Requirement as said before is that you bullet object has a NetworkIdentity component but I assume this is already the case if this is a Network spawned prefab as I guess.
Note
As I mentioned in a comment I also guess Explode is something that should probably happen on all clients instead of only on the server. In this case you can do the following
//local
void OnTriggerEnter2D(Collider col)
{
if (col.gameObject.tag != "bullet") return;
// Already get the value needed for the Explode method
var value= Mathf.Sign (col.attachedRigidbody.velocity.x)
// Also pass the value so we can provide it to all clients later
CmdOnTriggerEnter2D(col.gameObject, value);
}
// This is executed only on the server
[Command]
void CmdOnTriggerEnter2D(GameObject col, float value)
{
// Tell all clients to Explode using the passed value
RpcExplode(value);
Network.Destroy(col);
}
// This is called by the server but executed by ALL clients
[ClientRpc]
void RpcExplode(float value)
{
Explode (value);
}
As I don't know what you Explode needs to work: Be careful with destroying the bullet object if it is needed to execute Explode ;)
I have a motion-capture system that I use to animate a character (non-mecanim) so obviously I have to map the motion data onto the character's bones and segments.
Here is how I do it, but since the joints names are only used within the mapBones() method, I get quite a few amber warnings at the Unity console that warning CS0219: The variable JtHips is assigned but its value is never used.
I get one for each bone! It does not look professional, so I am wondering if there is any way I could get rid of them? All the posts I have checked out, of course recommend using them, but in this case, they are being used internally by the mapping function...
private Dictionary<MoCapSegment, ChrBones> jointsDict;
public enum MoCapSegment
{
Pelvis = 0,
// many more ...
Neck = 48,
Head = 49
}
public enum ChrBones
{
JtHips = 0,
// many more ...
JtNeckA = 48,
JtSkullA = 49
}
protected void mapBones()
{
jointsDict = new Dictionary<MoCapSegment, ChrBones>();
GameObject JtHips = transform.Find("CharacterRoot/JtJtHips").gameObject;
jointsDict.Add(MoCapSegment.Pelvis, ChrBones.JtHips);
// all the rest
}
You CAN do the following, but be careful
#pragma warning disable 0414
Specifically,
#pragma warning disable 0168// variable declared but not used.
#pragma warning disable 0219// variable assigned but not used.
#pragma warning disable 0414// private field assigned but not used.
I agree with you that this problem is infuriating.
Another thing you can do is this...
public void check<T>(T x){}
and then you can
private Whatever JtHips = whatever; // throws warning since never used
check(JtHips); // avoid warning like this
As always it's a great chance to use an extension
public static class YourExtensions
{
public static void Nothing<T>(this T x) {}
and then you can
JtHips.Nothing();
JtNeck.Nothing();
JtSkull.Nothing();
etc...
All that being said, it's a very bad idea to suppress warnings, of course. Take care.
I am currently playing around in Unity trying to make/test a 2D game. I keep getting the following error when I attempt to access CharacterMotor.playerx from inside camerafollow.js:
An instance of type "CharacterMotor" is required to access non static member "playerx"
Here are my two scripts:
camerafollow.js
#pragma strict
function Start () {
transform.position.x = CharacterMotor.playerx;
}
CharacterMotor.js
#pragma strict
#pragma implicit
#pragma downcast
public var playerx : float = transform.position.x;
You could change playerx to static, but I don't think that's what you want to do (there's probably only one player object, but this would prevent you from ever having multiple CharacterMotors). I think you want/need to retrieve the instance of CharacterMotor that is attached to this gameObject.
#pragma strict
function Start () {
var charMotor : CharacterMotor = gameObject.GetComponent(CharacterMotor);
transform.position.x = charMotor.playerx;
}
An instance of type "CharacterMotor" is required to access non static member "playerx"
The above error message describes precisely what is happening. You are just trying to access a variable without first creating an instance of it. Keep in mind that UnityScript != JavaScript.
To fix this issue, simply change
public var playerx : float = transform.position.x;
to
public static var playerx : float = transform.position.x;
Though this fixes your immediate problem I do not recommend continuing down this path. I suggest that you learn other aspects of the language first (such as classes) so that you can better organize and construct your data.
See: http://forum.unity3d.com/threads/34015-Newbie-guide-to-Unity-Javascript-(long)
CharacterMotor is the type, there can be multiple instantiations of your type in memory at the same time so when you call the type name you are not referencing any instance in memory.
to get an instance of the type that is connected to you current gameobject try this:
var charactorMotor : CharacterMotor = gameObject.getComponent("CharacterMotor");
Now you have access to that instances properties
transform.position.x = characterMotor.playerx;
I'm new to unity and am having a bit of trouble getting my head around the architecture.
Lets say I have a C# script component called 'component A'.
I'd like component A to have an array of 100 other components of type 'component B'.
How do I construct the 'component B's programmatically with certain values?
Note that 'component B' is derived from 'MonoBehaviour' as it needs to be able to call 'StartCoroutine'
I'm aware that in unity you do not use constructors as you normally would in OO.
Note that 'component B' is derived from 'MonoBehaviour' as it needs to
be able to call 'StartCoroutine'
I'm aware that in unity you do not use constructors as you normally
would in OO.
That's true. A possibility is to istantiate components at runtime and provide a method to initialize them ( if initialization requires arguments, otherwise all initialization can be done inside Start or Awake methods ).
How do I construct the 'component B's programmatically with certain
values?
Here's a possible way:
public class BComponent : MonoBehavior
{
int id;
public void Init(int i)
{
id = i;
}
}
}
public class AComponent : MonoBehavior
{
private BComponent[] bs;
void Start()
{
bs = new BComponent[100];
for (int i=0; i < 100; ++i )
{
bs[i] = gameObject.AddComponent<BComponent>().Init(i);
}
}
}
Note that in the example above all components will be attached to the same GameObject, this might be not what you want. Eventually try to give more details.