I am currently trying to create an ghosting trail similar to the one given in this gif.
I have tried creating multiple instances of my Player object based on the previous frame sequentially (ghostimage = player; on the current frame, ghostimage2 = afterimage; afterimage = player; on the next frame, etc.), but to no avail.
I even tried using the solution here, but localized (only encompassing the needed areas). It didn't work.
Drawing new Player objects with transparency (multiplying Color.White by some float value between 0f and 1f) didn't work well either.
How do I create this effect?
Related
I would like to use a characters tongue so instead of shooting a bullet, it goes toward the enemy, licks it, and comes back. I got this wording from this question: Unity shooting with Tongue 2d game (hasn't been answered and is 4+ years old). The only difference is my character moves.
I have this code from looking at a shooting tutorial so when you click the tongue prefab generates and is at the correct angle. I need it to grow on click and shrink back.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LineController : MonoBehaviour
{
public GameObject player;
private Vector3 target;
public GameObject crosshairs;
public GameObject tonguePrefab;
// Start is called before the first frame update
void Start()
{
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
target = transform.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z));
crosshairs.transform.position = new Vector2(target.x, target.y);
Vector3 difference = target - player.transform.position;
float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
if (Input.GetMouseButtonDown(0))
{
shootTongue(rotationZ);
}
}
IEnumerator shootTongue(float rotationZ)
{
GameObject t = Instantiate(tonguePrefab) as GameObject;
t.transform.position = new Vector2(target.x, target.y);
t.transform.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);
yield return new WaitForSeconds(2000);
t.SetActive(false);
}
}
I was also trying to make it disappear after whatever time and with that it doesn't work at all?
If the prefab is just a line with a simple texture I suggest using a line renderer:
Create an empty transform that starts on the mouth and then it move untill it reaches the crosshair. The movement is done using Vector2.MoveTowards.
Your tongue will no be a line renderer component. This line renderer will have 2 points, the start which is static, and the end which you have to update on the Update() for example, to correspond to the positions of the empty transform in item 1.
If you really wish to expand a tongue gameobject instead, then you are going to need a bit of math, this answer has what you need but in 3D:
https://answers.unity.com/questions/473076/scaling-in-the-forward-direction.html
1) I suggest creating sprite/sprite sheet animations with Mecanim or relatively new Skeletal Animation with Anima2D. With these systems you can create nice animations, transitions, even animate the sphere collider to trigger collisions and actions, change active state of your objects, etc. and control the animation with very little code. This way you can get best effects in my opinion.
As tongue is not a bullet... :) You only need one. I don't think you want to Instantiate/Create prefabs every time you press the lick button. Instead you should just turn your tongue object on/off (gameObject.SetActive). You can also change your object active state within the animation. So if you don't know how to code it you can do most of it in the Animation window and use very simple code to play the animation when you press the lick button. Whenever a sphere collider touches something you can tell the Animator Controller to play a 'roll back' animation and it will transition nicely to the start position.
There are many tutorials about Mecanim, Animations, 2D Animations, Anima2D, Animator Controller out there.
2) If you need very good control over the tongue you could create a custom mesh and control it via script but this is far more difficult.
3) The reason why your object is not turning off is probably because you wrote WaitForSeconds(2000) so it will turn off after 2000 seconds - more than half an hour. You should also call it with StartCoroutine(shootTongue()) as it is a Coroutine. Again if you want to turn off the object don't create new ones every time. If you want to keep creating new objects you should Destroy the objects instead. Otherwise you will end up with a lot of deactivated tongues in your scene and I don't think you needs that many tongues.
The main camera's output is set to a render texture, which is applied to a material, which is applied to a quad that's scaled up to 128x72. The secondary camera is set to only see what is rendered to the child quad, who has the material with the render texture on it.
However Camera.main.ScreenToWorldPoint(Input.mousePosition) is returning values that aren't even close to the GameObject. I.E. The GameObject is instantiated at (0, 0, 0), and hovering over it shows the mouse at (307, 174). Moving the Rotating Object to the right edge of the screen will only return an x position of 64 (half of the 128px wide quad) so I'm not sure where the 300+ is coming from. Not sure if the quad/camera set up is responsible for this.
EDIT: Using a single orthographic camera, all properties the same except for using a render texture, instead of the setup I have now results in accurate ScreenToWorldPoint output.
The Input.mousePosition property will only return the x and y axis of the mouse position in pixels.
ScreenToWorldPoint requires the z axis too which Input.mousePosition doesn't provide. The z-axis value supposed to be the nearClipPlane of the camera. It will give you a position that's right in front of the camera.
Depending on the size of the 3D object you want to instantiate where mouse button is pressed, you will need to apply an offset to it to make it totally visible to the screen. For a simple cube created in Unity, an offset of 2 is fine. Anything bigger than that, you will need to increase the offset.
Below is a complete example of how to properly use ScreenToWorldPoint with Camera.nearClipPlane and an offset to instantiate a 3D object where mouse is clicked:
public GameObject prefab;
public float offset = 2f;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Camera cam = Camera.main;
Vector2 mousePos = Vector3.zero;
mousePos.x = Input.mousePosition.x;
mousePos.y = Input.mousePosition.y;
Vector3 worldPoint = cam.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, cam.nearClipPlane + offset));
Instantiate(prefab, worldPoint, Quaternion.identity);
}
}
You may not be calling the Camera.ScreenToWorldPoint method correctly. In particular, the z position of the screen position parameter that's passed to this method should be defined as world units from the camera. See the Unity documentation on Camera.ScreenToWorldPoint.
Instead of Camera.main.ScreenToWorldPoint(Input.mousePosition), I think this is the correct way to call Camera.ScreenToWorldPoint:
var cameraPosition = Camera.main.transform.position;
// assuming `transform` is the transform "Virtual Screen Quad"...
float zWorldDistanceFromCamera = transform.position.z - cameraPosition.z;
var screenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, zWorldDistanceFromCamera);
var worldPoint = Camera.main.ScreenToWorldPoint(screenPoint);
Debug.LogFormat("mousePosition: {0} | zWorldDistanceFromCamera: {1} | worldPoint: {2}",
Input.mousePosition,
zWorldDistanceFromCamera,
worldPoint.ToString("F3"));
(If this isn't working, could you update your question or reply to this post with a comment with details showing the values that are logged at each step?)
I was just struggling with this problem and this question helped me find the answer, so thank you for posting it!
The issue has nothing to do with the z axis or how you're calling Camera.ScreenToWorldPoint. The issue is that the camera you're calling it on is rendering to a RenderTexture, and the dimensions of the RT don't match the dimensions of your game window. I wasn't able to find the implementation of the method in the reference source, but whatever it's doing is dependent on the resolution of the RenderTexture.
To test this, click the stats button in the game window to display the game window's screen size. The coordinates you get will match the ratio between that and the RenderTexture resolution.
Solutions:
Don't call this method on a camera targeting a rendertexture, either target the screen (none) or create a child camera that matches the position of the camera you need
Match the RT resolution to the screen. Obviously this may have performance implications, or cause issues if the screen size changes.
Don't use Camera.ScreenToWorldPoint. Depending on the use case, using a raycast may be simpler or more reliable.
Since using a default camera was returning the correct values, I simply added another one to detect the mouse position independent of the render texture/quad setup.
Super basic question that I cant seem to find an answer to:
All I've done is create a new 2D unity project and added a single sprite to the scene. I add a C# script to the sprite and set its position to a new Vector2(0,0). When run, the sprite moves its center point to the center of the screen, as opposed to the bottom left corner. This is also the case when I set the position of the spite to 0,0 in the editor. I've tried making the sprite a child of the camera, and I've tried using WorldToScreenPoint(). It's been awhile since I've used Unity so I must not be understanding something.
Thanks for the help
Edit:
As suggested here's the single line of code in question, don't think this will add much clarity.
public class NewBehaviourScript : MonoBehaviour {
// Use this for initialization
void Start () {
this.transform.position = new Vector2 (0, 0);
}
// Update is called once per frame
void Update () {
}
}
Unity renders based on the camera's frustum, not an arbitrary screen pixel position (unless you translate such to the frustum through a script).
By default, the camera will "look" at the scene-space origin (0, 0), and if you put your sprite there, of course it will be centered on screen on play.
[EDIT]
BTW, from...
I've tried making the sprite a child of the camera, and I've tried
using WorldToScreenPoint().
... it seems you're trying to put a sprite somewhere in relation to the camera. If that's for GUI, the correct way to do it is not as a child of the camera. Instead, use a screen-space Canvas. Screen-space canvasses, unlike cameras, work based on pixel position, too! =)
I'm creating simple game and I need to create extending cylinder. I know how to normally do it - by changing objects pivot point and scaling it up, but now I have texture on it and I don't want it to stretch.
I fought about adding small segments to the end of the cylinder when it has to grow, but this wont work smooth and might affect performance. Do you know any solution to this?
This the rope texture that I'm using right now(but it might change in the future):
Before scaling
After scaling
I don't want it to stretch
This is not easy to accomplish but it is possible.
You have two ways to do this.
1.One is to procedurally generate the rope mesh and assign material real-time. This is complicated for beginners. Can't help on this one.
2.Another solution that doesn't require mesh procedurally mesh generation. Change the tiles while the Object is changing size.
For this to work, your texture must be tileable. You can't just use any random texture online. Also, you need a normal map to actually make it look like a rope. Here is a tutorial for making a rope texture with normal map in Maya. There are other parts of the video you have to watch too.
Select the texture, change Texture Type to Texture, change Wrap Mode to Repeat then click Apply.
Get the MeshRenderer of the Mesh then get Material of the 3D Object from the MeshRenderer.Use ropeMat.SetTextureScale to change the the tile of the texture. For example, when changing the xTile and yTile value of the code below, the texture of the Mesh will be tiled.
public float xTile, yTile;
public GameObject rope;
Material ropeMat;
void Start()
{
ropeMat = rope.GetComponent<MeshRenderer>().material;
}
void Update()
{
ropeMat.SetTextureScale("_MainTex", new Vector2(xTile, yTile));
}
Now, you have to find a way to map the xTile and yTile values to the size of the Mesh. It's not simple. Here is complete method to calculate what value xTile and yTile should be when re-sizing the mesh/rope.
In my game I want to make the player object transparent for 2 seconds by scripting at run time if the player collided with a specific object during the game ... is it possible ?
Check for collision. When the collision that you want is triggered then you can change the transparency.
GameObject g;
// 50% Transparency.
g.renderer.material.color.a = 0.5f; // a is the alpha value.
// 100% Transparency.
g.renderer.material.color.a = 1.0f;
You can do just this to make your program wait time: http://docs.unity3d.com/Documentation/Manual/Coroutines.html
You will notice the example is exactly your question.
Try this extension method:
public static void ChangeAlpha(this Material mat, float alphaValue)
{
Color oldColor = mat.color;
Color newColor = new Color(oldColor.r, oldColor.g, oldColor.b, alphaValue);
mat.SetColor("_Color", newColor);
}
You can then call it by:
gameObject.renderer.material.ChangeAlpha( Your Alpha Value );
In Unity 5, the best way (TO MAKE AN OBJECT INVISIBLE) that worked for me was to:
Set all of the game object's materials you want to be invisible to transparent under the rendering mode.
Then, click on the small round button next to albedo and scroll down on the list of items given until you find one called UIMask.
Highlight it and press enter.
* Note that this is a hard fix and I'm not sure if you can change this with code.
** This was made for boundaries in roll-a-ball with a player jump function included. I needed to make the walls invisible but also collision-able to stop the air born player object.
This can be simply done with shaders, which you can quickly and efficiently change at runtime:
Create new material and set the shader to use the
Unlit/Transparent Cutout
Assign your game object to use this new material
Turn off all of the stuff in the mesh render of the game object: set cast shadows to off, receive shadows disabled, contribute to global illumination to disabled, turn off your light probes and reflections, set motion vectors to 'force no motion', turn off dynamic occlusion.
Also don't forget to remove the mesh collider of the game object.