Unity general questions

Comments

  • edited
    @dislekcia Thanks for the detailed assist, super appreciate it ^^

    1. I'm casting a ray from the camera because I thought
    Ray ray = Camera.main.ScreenPointToRay (whereScreen);

    casts a ray from the camera's position to the screen point. So to debug the ray it should originate from the camera's position, no?

    2. Actually, orthographic camera, the unit's worked out 1 unit to 1 BLOCK WIDTH - not 1 pixel. So I'm not sure if 1 block should still be breaking the game?

    3. I've done more searching around and I think I know what I need to do (I tracked my Input.mousePosition and indeed it shouldn't work against the world positions, so indeed it's not right...

    So here's my new plan, which I've already hit a wall with...

    Using this (where is passed from the variable, which in this case is Input.mousePosition) :

    Physics.RayCast(Camera.main.transform.position, Camera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0), etc);


    With the camera as the point of origin, with the point destination translated from screen to world.

    z = 0 because all my 2D objects are on that plane - with a z of 0. I should be able to get a ray from the Camera (sitting at z of -10) to the destination and get an intersection with the object under my mouse.

    EXCEPT. I can't draw a ray with a destination, I haven't been able to find a RayCast method with a destination point - I can only draw a ray with a direction. Can't I draw a ray knowing the destination???

    Am I on the right track, does this make sense?
  • edited
    A few things here:

    Firstly, the z you pass in to ScreenToWorldPoint isn't z in world space, it's z in screen space as implied by the method name. Z=0 in this space is a plane right at your camera position which, in your case will be a plane at -10z. It's also important because when you cast rays with an ortho camera, they work a little differently to perspective in the sense that, strictly speaking, the origin of the ray isn't necessarily the camera's position, but rather the screen point on the near clip plane. The ray then passes through through the same screen point on the far clip plane. This is true with perspective as well, of course, but for all intents and purposes, in that case it's the same as the camera position because, y'know. Perspective.

    So if you're trying to debug rays, make sure you draw the line starting at ray.origin, not at your camera. This is important so you can properly see what's going on.

    Secondly, it looks like you need a little crash course on vectors. Strictly speaking, vectors represent directions. Most game engines, like Unity, use them to represent points too (arguably a mathematically incorrect notion, but it's convenient to not need point structures to represent something that has (some of) the same components as a vector), because points are, in some ways, just a vector from the origin to that point.

    Long story short, though, it's also convenient because you can get a direction to one point from another by simply subtracting their vectors:

    Vector3 toPointA = pointA - pointB;


    You can then use that vector (which doesn't normally need to be normalised) as a direction! Handy!

    All this said, though - and this is perhaps naive advice due to not knowing the greater context of what you're trying to achieve - I would still recommend you place a spacial representation of your blocks (which I assume fit conveniently on a grid) into a data structure from which you can trivially and simply lookup their positions. If I understand what you're doing properly, from your questions here, a really straightforward 2D array will do what you want. Check if things are at certain positions.

    EDIT:
    Piccytchas, to illustrate the raycasts

    Ortho raycast:
    image

    Perspective raycast:
    image

    EDIT EDIT:
    So all in all, if it's easier for you to understand, you can construct the ray yourself by using two points created by ScreenToWorldPoint, with the same X and Y values, and with Z=nearclip and Z=farclip.
    Thanked by 2dislekcia Tuism
  • Thanks so much, I think I'm understanding it... In principle.

    Now I've gotten this far, but I'm not sure if I'm getting screwed by syntax or if there's just no METHOD for what I need...

    Ray rayTest;
    RaycastHit rayHit;
    rayTest = Physics.Raycast (Camera.main.transform.position, 
                               Camera.main.ScreenToWorldPoint (new Vector3 (whereScreen.x, whereScreen.y, -10f)) - Camera.main.transform.position,
                               rayHit);
    Debug.DrawLine(rayTest.origin, rayTest.direction);
    //RaycastHit2D hit = Physics2D.GetRayIntersection (ray, Mathf.Infinity);
    if (rayHit.collider != null) 
    {
    	if (rayHit.collider.transform.tag == "block_dropping") 
    	{
    		return true;
    	} else
    		return false;
    } else
    	return false;


    I've been looking... I see a Physics.Raycast method for including "ray" variable for naming the ray, and a "RaycastHit" variable for including the hit, but not both???? What?? Why?! :/

    The error from this code is "Assets/MasterController.cs(150,44): error CS0165: Use of unassigned local variable `rayHit'"

    But rayHit *is* assigned. It's there. Or do I need to fill it with something first? what???
  • edited
    OK I scrapped everything I had and started again, with an example from unity references. And hit another wall :/
    Ray ray = Camera.main.ScreenPointToRay(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 11f));
    		RaycastHit hit;
    		Debug.DrawRay (ray.origin, ray.direction*11);
    		if (Physics.Raycast (ray, out hit, 100)) 
    		{
    			Debug.DrawLine (ray.origin, hit.point, Color.red);
    			return true;
    		} else return false;


    This is what I have so far, I can see the white debug ray, and it's shooting exactly in the right place, but it's never returning true. even if I can visually see the ray intersecting the block (with boxCollider2D). So I suspect that Raycast method doesn't return true when hitting 2D colliders? Is this true?

    image

    GOING. INSANE :/
    unity_pointpic.jpg
    1216 x 784 - 321K
  • Use Physics2D for 2D colliders, instead of Physics which is for 3D objects. They use completely different engines, AFAIK, so they don't interact well (or at all?) with each other. I'm not sure, but I expect that they simply won't work when used together.

    You can also look at using Physics2D.OverlapPoint, which sounds like it should do a lot of what you want, especially for 2D picking in world space. If you want to do it with mousey stuff, you can just use ScreenToWorldPoint to project for that.
    Thanked by 1Tuism
  • dislekcia said:
    How does a mathematical construct retain any space information other than the reference frame in which you calculate it?
    That is exactly my point, but when you say the following with regards to ray casting you are actually opposing that same statement:
    dislekcia said:
    So if you calculate a thing using transform.localposition values, it's in local space.
    To use local position in a calculation the object has to be space aware first.

    Let's say you have an object at height 1 (world space) and a child object at height 2 (world space). The child would have a local position of (0,1,0) that is based off of the parent transform. If you were to use transform.localposition of the child as the origin of your ray, it would never be at the child's position, but instead would start at position (0,1,0) in world space. Thus, using local coordinate systems is folly, and will never work correctly with Ray casting - and should probably not be mentioned in this context at all as this creates confusion...

    ...Unless, of course, you had found a way to make it work and I was just uninitiated (hence my original question).
  • farsicon said:
    To use local position in a calculation the object has to be space aware first.
    Nope. It's up to you to make sure you use things in the right space.
    farsicon said:
    Let's say you have an object at height 1 (world space) and a child object at height 2 (world space). The child would have a local position of (0,1,0) that is based off of the parent transform. If you were to use transform.localposition of the child as the origin of your ray, it would never be at the child's position, but instead would start at position (0,1,0) in world space. Thus, using local coordinate systems is folly, and will never work correctly with Ray casting - and should probably not be mentioned in this context at all as this creates confusion...
    The bold assumption is incorrect. There's nothing about the the resulting ray that forces you to use it in world space, you're just deciding that you have to. Yes, if you use a local space calculated ray in world space, it's not especially meaningful (so it's probably not useful for collision tests in world space, which Unity's physics is in) but it's still useful if you use it in the correct reference frame, like to pass to a particle system that's a child of the same parent object, for instance.

    If you wanted to correctly visualise that ray, you'd have to convert it to a world space reference frame, basically just multiply it by its parent's transform (or whatever functionality Unity exposes that does the same thing). But that doesn't make it useless, just able to be used wrong if you suddenly change reference frames on it without converting.

    As for usefulness being discussed here: Both @Chippit and I saw that @Tuism didn't understand the underlying systems he was poking at. Explaining vectors seems to have helped, I'm glad @Chippit did that. Now all that's needed is more building on top of the stuff that's been figured out since :)
  • edited
    I am having trouble with the rotation of 2D objects and I hope that someone here can tell me where I am going wrong. I am working on a shotgun behaviour for a 2D side-scrolling platformer. I have created an empty game object called shotgun, which has 3 children Muzzle, Muzzle2 and Muzzle3. On an input by the player (C Button), I am instantiating a bullet at each of the 3 muzzles' position and rotation. The first muzzle I rotated up 45 degrees (Z-axis), the second is aiming level (right/0 on z) and the 3rd is rotated down 45 degrees.

    However, the bullets are instantiating at the muzzle's position but not the rotation. All 3 bullets just moves straight to the right. Here is my code:

    public class RoboShootShotgun : MonoBehaviour {
    
    	private Animator anim;
    	public float shootForce = 10000.0f;
    	public GameObject bulletPrefab;
    	public Transform myMuzzle;
    	public Transform myMuzzleTwo;
    	public Transform myMuzzleThree;
    	private bool facingLeft = false;
    	private bool facingRight = true;
    	
    	// Use this for initialization
    	void Start () 
    	{
    		anim = GetComponent<Animator>();
    	}
    	
    	void Update()
    	{
    		float moveDirection = Input.GetAxis("Horizontal");
    		
    		if(moveDirection > 0)
    		{
    			facingLeft = false;
    			facingRight = true;
    		}
    		else if (moveDirection < 0)
    		{
    			facingLeft = true;
    			facingRight = false;
    		}
    	}
    	
    	// Update is called once per frame
    	void FixedUpdate () 
    	{
    		float move = Input.GetAxis("Horizontal");
    		
    		if(Input.GetKeyDown(KeyCode.C)  && move > 0)
    		{
    			anim.SetBool("Shoot",true);
    			GameObject bulletInstance = Instantiate(bulletPrefab,myMuzzle.transform.position,myMuzzle.transform.rotation) as GameObject;
    			bulletInstance.rigidbody2D.AddForce(transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceTwo = Instantiate(bulletPrefab,myMuzzleTwo.transform.position,myMuzzleTwo.transform.rotation) as GameObject;
    			bulletInstanceTwo.rigidbody2D.AddForce(transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceThree = Instantiate(bulletPrefab,myMuzzleThree.transform.position,myMuzzleThree.transform.rotation) as GameObject;
    			bulletInstanceThree.rigidbody2D.AddForce(transform.right * shootForce * Time.deltaTime);
    		}
    		else if(Input.GetKeyDown(KeyCode.C)  && move < 0)
    		{
    			anim.SetBool("Shoot",true);
    			GameObject bulletInstance = Instantiate(bulletPrefab,myMuzzle.transform.position,myMuzzle.transform.rotation) as GameObject;
    			bulletInstance.rigidbody2D.AddForce(-transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceTwo = Instantiate(bulletPrefab,myMuzzleTwo.transform.position,myMuzzleTwo.transform.rotation) as GameObject;
    			bulletInstanceTwo.rigidbody2D.AddForce(-transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceThree = Instantiate(bulletPrefab,myMuzzleThree.transform.position,myMuzzleThree.transform.rotation) as GameObject;
    			bulletInstanceThree.rigidbody2D.AddForce(-transform.right * shootForce * Time.deltaTime);
    		}
    		else if(Input.GetKeyDown(KeyCode.C)  && facingRight)
    		{
    			anim.SetBool("Shoot",true);
    			GameObject bulletInstance = Instantiate(bulletPrefab,myMuzzle.transform.position,myMuzzle.transform.rotation) as GameObject;
    			bulletInstance.rigidbody2D.AddForce(transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceTwo = Instantiate(bulletPrefab,myMuzzleTwo.transform.position,myMuzzleTwo.transform.rotation) as GameObject;
    			bulletInstanceTwo.rigidbody2D.AddForce(transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceThree = Instantiate(bulletPrefab,myMuzzleThree.transform.position,myMuzzleThree.transform.rotation) as GameObject;
    			bulletInstanceThree.rigidbody2D.AddForce(transform.right * shootForce * Time.deltaTime);
    		}
    		else if(Input.GetKeyDown(KeyCode.C)  && facingLeft)
    		{
    			anim.SetBool("Shoot",true);
    			GameObject bulletInstance = Instantiate(bulletPrefab,myMuzzle.transform.position,myMuzzle.transform.rotation) as GameObject;
    			bulletInstance.rigidbody2D.AddForce(-transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceTwo = Instantiate(bulletPrefab,myMuzzleTwo.transform.position,myMuzzleTwo.transform.rotation) as GameObject;
    			bulletInstanceTwo.rigidbody2D.AddForce(-transform.right * shootForce * Time.deltaTime);
    			GameObject bulletInstanceThree = Instantiate(bulletPrefab,myMuzzleThree.transform.position,myMuzzleThree.transform.rotation) as GameObject;
    			bulletInstanceThree.rigidbody2D.AddForce(-transform.right * shootForce * Time.deltaTime);
    		}
    		else if(Input.GetKeyUp(KeyCode.C)  && move == 0)
    		{
    			anim.SetBool("Shoot",false);
    		}
    	}
    }


    can someone please explain to me why the bullets are not moving along the muzzles' rotation i.e. 45 degrees up or down. Any help will be greatly appreciated
  • edited
    @fanieg, the force applied to the bullets are the same for all three. Keep in mind that force is directional, regardless of the rotation of the rigidbody itself. So, instead of using transform.right, try to use the transform of each muzzle instead. To keep things simple, I always try to ensure that the barrel's forward direction is the direction the bullet needs to go, so in your case I would use mymuzzle.transform.forward * force - for each barrel. Note: forward is useful in 3D, using muzzle.transform.right may be more relevant in 2D.

    another alternative for shotgun effects which is quite useful, is to have only one barrel, just for the primary direction, and then based off of that you can "generate" other barrels randomly at run time - this also has the benefit of adding some variation to each shot.
  • @farsicon - thanks for the response. I tried transform forward, however this instantiated the bullets but then they would simply float in front of my character. I thought it may be that they were moving into the screen, but if I change my scene to 3d mode it seems this is not the case. Its like the force is then removed from the bullets?
  • @fanieg: it's not necessarily transform.forward, but the point is to use the muzzle's transform and not the weapon transform. I forgot you worked in 2D - so use muzzle.transform.right instead.

    the trick is to let the hierarchy of objects do the work for you so that you don't need to calculate these things yourself.
  • edited
    @farsicon thanks for the help. That does make more sense. I will try it.

    [EDIT] - Thanks for explaining that to me. It did indeed sort out my problem and have the bullets move along the rotation of the muzzles as I wanted. +1 for community knowledge.
  • Hi guys!

    After Ludum Dare and my gambit with Unity, I have a few questions that I hope have "non-difficult" answers from you pros, all these I'd researched during LD but couldn't find answers to them...

    1. The Time.timescale thing makes awesome bullet time :P But then the physics don't resolve at a big enough resolution and everything goes steppy... I found the timestep value in the physics manager, but it's a fixed value and can't be changed through during the game... Annnd while I was typing @manikin suggested something, I'll try it out :D

    2. Sprites that always face the camera a la Duke Nukem - do I really have to use LookAt every update per sprite? That seems super resource heavy. How do I render an object as a particle? Or, can I instantiate single particles and manipulate them like GameObjects? I don't want to billboard them since I'm not using terrain.

    3. On the flip side, can I put GameObjects as particles, so they're in 3D polygons?

    4. Is there a way to reference to a single polygon/plane/quad? Like, I want to know what the angle/normal of the face the shark sits on is. Right now I'm referencing the entire GameObject, wondering if I can automate it to know about the face itself.

    Thanks guys! :D
  • @Tuism

    1. What @manikin said is correct. You'll need to set the fixedDeltaTime as well.

    2. The Unity docs give an example of creating billboards using a Quad. Billboards are just 'flat' surfaces, and not dependent on terrain/ You'll still need to make them face the camera every frame, either by using lookAt, or a shader.

    3. In the standard Unity Particle System (post 3.4), you can specify a mesh as the shape to emit in the shape Module. You can also add the collision module which will make your particles collide with other things in your game. Ref

    4. I would imagine there is, but it's way beyond my Unity knowledge and minimal time to find you an answer now. However, if you're doing collisions with the shark and whatever plane/gameobject it's on, this might be what you're looking for.

    HTH
  • Yay thanks @DrDeth!

    Wait, on 2, I understand billboarding, and I was asking if I could achieve the effect by using just sprites that aren't rendered in 3D without having to use lookAt - like... like 2D sprites in 3D space. Like those old games XD So I guess it's not possible?

    And on 4. Thanks! That link looks exactly like what I'd need - the insight that it only works on mesh colliders is a super valuable one! Thanks! :D

    Oooh then on surface normals and angles and things, this problem plagued a bunch of us (well me, but I asked everyone and noone knew) the whole weekend:

    What do you do to turn a quaternion 90 degrees in a particular direction? For example I have a quaternion that points in relative down (not absolute/world down), an I want to turn it 90 degrees towards "forward". What's the operation needed there?

    Thanks again guys :)
  • @Tuism: regarding point 2 - those old games are actually using billboard sprites, so you are already on the right track.
  • Tuism said:
    Wait, on 2, I understand billboarding, and I was asking if I could achieve the effect by using just sprites that aren't rendered in 3D without having to use lookAt - like... like 2D sprites in 3D space. Like those old games XD So I guess it's not possible?
    @DrDeth's suggestion of using a shader for this is, strictly speaking, the best way to billboard stuff. I didn't look too deeply into the linked shader, but it seems logically sound, so it should do what you want. Otherwise, yes, LookAt() every frame is your other option.
    Tuism said:
    What do you do to turn a quaternion 90 degrees in a particular direction? For example I have a quaternion that points in relative down (not absolute/world down), an I want to turn it 90 degrees towards "forward". What's the operation needed there?
    I'm a bit confused about this question. If you know where forward is (is this local forward again?), then 90 degrees from local down to local forward is the same as local forward. If you mean global forward, you can use RotateTowards, probably. If what you're really looking for is a binormal or tangent (and you can calculate the other half), then what you want is some fancy vector math called the cross product. If that source is too mathy for you, but you remember some high school physics, then 'right-hand rule' is all you need to know to understand the cross product.
  • Yeah I think RotateTowards will work! I'll give it a test and see :D But during the jam guys were like "Yes you should use cross product" and a few maths-heads tried it and noone could work it out so I abandoned that... So let me give it another good ol' go :)

    Shader..... I had a look at that link, will try it a few more times... But I think I'm in need of that Shader workshop XD

    Thanks! :D
  • Erm, this keeps happening to me, and I don't have a clue why, it feels like a bug, but I'd like to ask if anyone had the same problems:

    I'd open a script in Unity, edit it, and save. Go back to editor, play the game. Nothing's changed. I keep making changes. Save. Nothing changes in editor in play.

    So I got frustrated and just hacked an entire half of the script out, save, go back to editor, it should crash by all rights, and it still can play. WTF?!

    So just to make sure, I close the script, go back to editor, find the object, double click on script component, find it in assets, double click that to make sure. Hack out half the script, and the game still will run.

    REBOOT UNITY.

    Seems ok now. But that was fucking madness. Does it happen often? Did I do something to cause it? It's mad frustrating. No warning!
  • edited
    Hiya, while on the topic of rotation...

    I have been struggling to get a simple 2D sprite turret from tracking the player smoothly...
    The code below flips the sprite on its side making it disappear instead of rotating toward the player?
    I was expecting it to rotate on the Z (forward) axis?

    private void Track()
    {
    //This works but is instant, we want a smooth motion...
    //this.transform.LookAt(transform.position + new Vector3(0,0,1), target.transform.position - transform.position);

    var direction = target.transform.position - transform.position;
    float rotateSpeed = 35f;
    float step = rotateSpeed * Time.deltaTime;
    var targetRotation = Quaternion.LookRotation(direction, Vector3.forward);
    transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, step);
    }

    What am i missing? Any help would be appreciated! :)

    UPDATE: nevermind...fixed :)

    private void Track()
    {
    var direction = target.transform.position - transform.position;
    float rotateSpeed = 100f;
    float step = rotateSpeed * Time.deltaTime;
    var targetRotation = Quaternion.LookRotation(direction, Vector3.back);
    targetRotation.x = 0.0f;
    targetRotation.y = 0.0f;
    transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, step);
    }
  • @Tuism are you in play mode when you make the changes? Unity will not save any changes made during playtesting. Or am I misunderstanding the question.
  • Well no I was editing the script in MonoDevelop, tabbing back to Unity, and starting the game again. And again XD
  • OK on that vector question... I've looked at rotate towards and it's not working because I A) don't have a target to rotate towards and B) The camera's rotation is in Quaternion and my sharkGravity is a Vector3 (the one piece of info I have about the new angle)... The maths is exploding my brain... Help? XD

    I think I'm supposed to rotate it by the Z axis, cos x and y control the camera as normal, it now orbits around the shark in a separate object that's no longer child of the shark (that's how it used to be and was quite nauseating I must say, so I took it out and it's a lot more managable)

    Thanks guys!!!

    image
    shark_angle_problem.jpg
    1476 x 630 - 161K
  • @Tuism: It took me a while to understand what you're trying to accomplish, thanks for the images! ... It sounds like what you want to mess with isn't rotating the camera itself, but changing the vectors that make up the camera's view calculations. In particular, you want to poke at the camera's Up vector, which determines how the camera sees "up" in the game world when rendering. It sounds like you could just set your Up vector to be opposite the sharkGravity vector and go from there (or lerp towards -1 * sharkGravity so that it was a smooth transition instead of a jerk).
    Thanked by 1Tuism
  • WHAT. REALLY!? WHAT!? SERIOUSLY!? OMG that is a superb piece of information, and makes so much sense!!

    I've now narrowed it down to "fixing" the unity's built in MouseLook to cater to my vector.up (I tried changing the transform.up but it seemed to be always overridden by the MouseLook script. I've already tried turning the MouseLook script over and trying to see if changing transform.up works, and it indeed works! Now I just gotta go hack that MouseLook script...

    Thanks thanks thanks!! :D
  • I have an object that I want to face the camera always. So, billboard. Got the lookat code working... BUT.

    The object is a child of another object as a child object. So it doesn't lookAt properly. I've tested it, it works if it's outside but not when inside. I do need it to follow the parent object so it must be childed... Or it's best if it's childed, I don't feel like it's the most efficient to make it set position every frame...

    So how do I compensate, in a child, to lookAt the camera in global space and not be flopping around in local space?

    gameObject.transform.LookAt (Camera.main.transform.position);


    I've googled a few threads and the best fit is this, but this looks insanely complex, is it the only way? http://answers.unity3d.com/questions/204017/want-to-child-object-facing-to-camera.html

    Thanks all!
  • I've never had problems with LookAt for children, but an alternative is to bruteforce it with absolute positions. PseudoCode ho:

    In your billboard's Update or LateUpdate method:

    transform.rotation = Quaternion.lookRotation(transform.position - Camera.main.transform.position);


    That should alleviate any issues.
  • edited
    Unfortunately it doesn't work... It does work with an object that's not parented to an object, but when childed it behaves the same as regular LookAt code... When the parent object rotates and things it doesn' work.

    Where is this absolute position stuff that you meant?

    Screenie attached - the leftmost triangle is not the child of anything, the ones that are flopping all over the place are the instantiated ones and are children of the hoomans. Sorry about the flashing thing, that's bandicam capturing on unity that's weird.

    The triangles are all running the same code.

    image
    triangleerror.gif
    787 x 474 - 1M
  • edited
    An alternative, then, is not to parent, but to keep a reference to the parent hyoomon's transform in the bracket, and explicitly match positions with the referenced transform every frame. That way you can be sure it won't be affected by any rotational silliness.
  • Yeah that was what I was gonna do if I couldn't find an easier way (was in the original post :P), but damn I can't understand why there isn't :P

    Thanks!
  • edited
    Yeah, sorry, as a fellow Unity nublet, I was under the impression that the transform.rotation was a global thing, and unaffected by parent transforms. Clearly that's not the case. I suppose you can try multiplying with the inverse of the parent rotation to cancel out the effect of the parent...

    transform.rotation = Quaternion.lookRotation(transform.position - Camera.main.transform.position) * Quaternion.Inverse(transform.parent.rotation);
  • Gazza_N said:
    Yeah, sorry, as a fellow Unity nublet, I was under the impression that the transform.rotation was a global thing, and unaffected by parent transforms. Clearly that's not the case. I suppose you can try multiplying with the inverse of the parent rotation to cancel out the effect of the parent...

    transform.rotation = Quaternion.lookRotation(transform.position - Camera.main.transform.position) * Quaternion.Inverse(transform.parent.rotation);
    Thanks for trying, but that one doesn't work either :) It's ok, thanks! I'll go back to the bruteforce solution :) Thanks thanks!
  • See my request on the Twits. I'm missing something here...
  • I wasn't following any conversations that may have happened on Twitter, so ignore me if this has been resolved.

    Based on the information here, it sounds like you're simply running into execution order issues. I assume the parent object has its own script that affects its movement. It appears as if it is running after the child is setting rotation. Either try move the LookAt code into LateUpdate in the child, or adjust the script execution order to force the child script to run after default time.
  • Ooooh thanks for that, didn't know "LateUpdate" was a thing - I've currently solved it by unparenting the targeting thing from its target and setting its position every frame, which also works. For now. I'll try lateupdate if I ever need it again :) Thanks!
  • OK this one is not so general - it's about a shader:

    So I was looking for a "silhouette" look for my shark under the ground, and came across this, and it works great:
    http://wiki.unity3d.com/index.php?title=Silhouette-Outlined_Diffuse

    Except...

    1) I wanted it to be only silhouetted behind one plane - in my case the planes in the "surfaces" layer. As you can see right now it goes over EVERYTHING, which isn't quite what I want. The person on top of the shark should be visible on top of the shark.

    2) I would like to be able to make the colour of the silhouette a function of the plane it's on - like 50% darker (adding black) or something, right now it 's a hard-coded colour, so if I swim the shark onto a white surface, the silhouette will still be dark green.

    Can I get assist on this shader thing, can someone point me in the right direction where I can read up on what bits in shaders mean? I've tried tweaking it a million times and it's frankly all gibberish to me :/

    Thannnnks!
    shaderQ.png
    685 x 372 - 74K
  • edited
    So there are no easy or quick solutions for any of those problems, they all require a bit of tricksy shader magic, and they're all fairly technical. There's a reason that shader workshop thing was only the basics and would still take a whole day :P

    The best option I can think of is something of a three-step thing:
    • Your ground will need a custom shader with its own render queue, so that it is drawn first.
    • Your shark will need a custom shader with its own render queue too, just after the ground. This will be a two pass render. First pass will render the shark with an inverse z-test and no z-write, and a multiply (or subtractive?) blend mode that will darken the ground if it's behind it. The second pass will be a straightforward copy of whatever its current material is.
    • Everything else will render as normal, and it should work as you expect from here.
    If that means nothing to you, I can write up the two shaders sometime this evening when I get home, or perhaps someone else here can offer a simpler solution. Surely an easier option has slipped my mind.
    Thanked by 1Tuism
  • Speaking of Shader workshop :P When when when? :D @Fengol said he'd chat and setup... yesterday :P

    And while quick or easy solutions are preferable, I don't mind the non-quick and non-easy, just somewhere I can get some understanding from and hopefully apply it myself... Where do I find how to set render queue? Do the two different shaders need to talk to each other for that to happen? How would they? I went into the shader I used (linked previously, but here it is again: http://wiki.unity3d.com/index.php?title=Silhouette-Outlined_Diffuse) and searched for words that could indicate some kind of queuing, and found "Queue"... but it's a string and not a keyword so I'm guessing it's not the right thing to look for :/

    I do kind of understand what you mean by your words, but I have no idea how that works in shaderspeak :/ Is there somewhere I could look up shaderspeak?

    Does it make it easier if you looked at the existing shader? (linked above)

    Thanks man, so much appreciated :D
  • Tuism said:
    @Fengol said he'd chat and setup... yesterday :P
    Thanks for the reminder ;) Let me speak to some people and make some posts.

  • edited
    I've been looking into the camera up vector problem I had earlier, and I'm stumped - I don't think I can set the transform.up of the object while manipulating its rotation... Every time I set its up it resets to face the same direction forward.

    I'm using the MouseLook script in the Unity packages, and I've inserted transform.up = -sharkGravity at various places and tried looking for ways to do eulerAngles while considering an up... To no avail :/

    Any ideas?

    void Update ()
    {
    transform.up = - sharkObjectScript.sharkGravity;
    //sticking it here soft locks the camera - I can move it but it immediately snaps back to the direction, plus the angle no longer turns when i'm on the wall

    float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;

    rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
    rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);

    transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
    transform.up = - sharkObjectScript.sharkGravity;
    //sticking it here works but the mouse look is completely negated, locking the angle one way only


    The up is tilted correctly, just as I wanted, but it can't turn with the mouse now :/

    image
    sharkland.jpg
    670 x 384 - 23K
  • This doesn't work because your mouse look script is working in absolutes. It's assuming the camera behaviour operates on the same ground plane, but it seems your gameplay doesn't work that way. You're going to have to write a smarter camera.

    Good luck :)

    You can start by manipulating its rotation by using relative transformations around the camera's local up, using something like Rotate(). Camera controls are very much a problem unique to your game (and all games), though, so we probably need a bit more info as to how it actually works in order to give you better, more informed help.
  • Thanks for looking at it :)

    The only thing that's really unique to my setup is a downward vector of gravity - it's a Vector3 that points directly downwards that I set whenever the shark goes gets OnCollisionEnter towards the plane, and the gravity of the shark is a custom AddForce towards that Vecto3 in its Update().

    So all I really need are mouse controls that takes that vector into consideration and rotates an object taking into consideration a variable transform.up...

    Is that enough information?

    Tonight I'll try and use transform.Rotate, but Rotate doesn't use an up vector? It has a "Space" variable, does that mean that each frame I'd set transform.up to be opposite of the gravity vector, then Rotate relative to mouse values in Space.local space?
  • edited
    Tuism said:
    Tonight I'll try and use transform.Rotate, but Rotate doesn't use an up vector? It has a "Space" variable, does that mean that each frame I'd set transform.up to be opposite of the gravity vector, then Rotate relative to mouse values in Space.local space?
    Exactly that.

    Similarly, you might also try using LookAt in a similar way, but the maths for working out look direction is probably a bit more complicated.
  • OK here's another deceptively simple question. Deceptively cos I thought I could answer it. But I can't :/

    When my shark lands, it lands at a slight angle into the ground. Therefore when I press forward for it to go - well - forwrad, its forward vector points into the ground and therefore generates a downward vector into the ground.

    I want to convert that vector (when it's landed, I already have that sorted) and turn it "upwards" to the horizon, effectively removing the downward vector component allowing the shark to move "forward" without too much trouble - right now it tries to go into the ground for a bit and impedes movement rather than move off - I'd like it to move off without "faceplanting" and self-correcting for a while.

    I tried to use the global forward but that's always the same direction regardless of how my object rotates so it can never turn. And I tried to do a subtraction from the object's world rotation, which... doesn't work. Results were bizarre and I didn't understand it.

    Sooo, is this *hard*? :/

    image
    vectorproblem.jpg
    525 x 270 - 13K
  • edited
    This is a fun issue. Quick solutions to this problem can cause interesting problems, like how running at a 45-degree angle against a wall in Quake makes you move faster!

    But we don't want that.

    So anyway, the Quake solution is to take your local vector, reflect it around the normal of the ground vector (which I'm assuming isn't always up - because if it is you can just take your vector and set its y to 0 and you're done), and then add the two vectors together. You'll get a new vector that points forward perpendicular to the ground.

    But coming back to the Quake problem, this new vector is LONGER than your forward, so you'll need to normalize it if you care about length. If your ground is always flat, and you just set y to 0, you'll have to normalize that one too or it'll be shorter. But that should do what you want, and it's both mathy and straightforward, so you get to feel all smaht (yes, smaht) for implementing it.
  • edited
    You can get the normal of the surface, and use it to reflect your local forward vector to get a new vector that bounces away from the ground. If you add the reflected vector and the forward vector together, you get a vector pointing in your desired vector direction. Its magnitude will be too large, but you can use the normalize version of it (makes its length one) and multiply it by the magnitude you desire to get your desired vector.

    Ohlol, ninja'd by the guy I stole the solution from in the first place. XD
  • OMG YOU GENIIII (pronounced "gee-nee-eye") :D I love how you two basically said the same thing. It's good to know I'm hearing industry standards :P
  • edited
    Tuism said:
    OMG YOU GENIIII (pronounced "gee-nee-eye") :D I love how you two basically said the same thing. It's good to know I'm hearing industry standards :P
    It's more that I walked over to Jon's desk to find him mulling over this problem, and I offerred that solution to him :P

    So before you take that as an industry standard solution, I should disclaim that it's just mine.
  • You could also calculate the cross product of your surface normal and the shark's forward, then get the cross of that against the surface normal to create a surface forward, then normalise that and multiply by the length of the shark's forward.

    OR you could make your shark have various invisible physics "balloons" that stayed above any physical surface, like 3 or 4 along its length. If you made them frictionless, you'd get something like the shark diving into the surface and leveling out quite naturally.
    Thanked by 1Chippit
  • edited
    dislekcia said:
    You could also calculate the cross product of your surface normal and the shark's forward, then get the cross of that against the surface normal to create a surface forward, then normalise that and multiply by the length of the shark's forward.
    Ooh, yeah, that's a good way to get the surface tangent, nice!
Sign In or Register to comment.