Unity sprite is show before position is changed - c#

I have six or more sprites that are hidden, alpha set to 0. I move the sprites to a starting position at the top of the screen before showing them. Once in the new position I show them and the moving them back to their original positions.
My issue is that the sprites are show just for a couple of milliseconds before they are moved to the starting point. Even though the order of the code is move first then show.
I tried to find a position moved callback to detect when the position change is complete before showing but I don't this it is possible.
void Start() {
int i = 0;
foreach (Transform point in drawingPoints.transform)
{
//Record points original postion
Vector3 currentPosition = point.transform.position;
//Move to new starting position
point.transform.position = stepOne.transform.position;
//Now show point
var color = point.gameObject.GetComponent<SpriteRenderer>().color;
color.a = 1;
point.gameObject.GetComponent<SpriteRenderer>().color = color;
//Move point back to original postion
point.transform.DOMove(currentPosition, 1f).SetDelay(UnityEngine.Random.Range(0f, 0.3f));
i += 1;
}
}

Consider disabling the sprite renderer till the transform is at the start point.
void Start()
{
int i = 0;
foreach (Transform point in drawingPoints.transform)
{
SpriteRenderer spriteRenderer = point.gameObject.GetComponent<SpriteRenderer>();
if(spriteRenderer == null)
continue;
// Disable the renderer.
spriteRenderer.enabled = false;
//Record points original postion
Vector3 currentPosition = point.transform.position;
//Move to new starting position
point.transform.position = stepOne.transform.position;
// Now you're at start point, enable it back.
spriteRenderer.enabled = true;
//Move point back to original postion
point.transform.DOMove(currentPosition, 1f).SetDelay(UnityEngine.Random.Range(0f, 0.3f));
i += 1;
}
}
If for whatever reason or weird behaviour of unity you wanna get a callback when something is at a position, here's a hacky way
transformToMove.DoMove(destination, 0).OnComplete(()=>
{
// Now you're at the point.
});

Related

Pan Camera moving only in one direction not in all 4 as it should

Why in following code in unity is the X coordinate of vector3 move always 0?
Camera.main.ScreenToWorldPoint method returns X -component always as 0, even though Input.mounsPosition provides X!=0.
private void Pan() {
// save initial position of mouse whenn RMB pressed for first time
if (Input.GetMouseButtonDown(1)) {
mouseWorldPosStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
// calculate distance between initial mouse position and current mouse position
if (Input.GetMouseButton(1)) {
var newMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 mouseWorldPosDiff = mouseWorldPosStart - newMousePosition;
Debug.Log("Initial position: " + mouseWorldPosStart + " Delta = " + mouseWorldPosDiff + " New Position: " + newMousePosition);
//move the camere by the distance
transform.position += mouseWorldPosDiff;
}
}
The goal is to write code for Camera Pan function.
I think the main issue will be that while you move the camera the ScreenToWorldPoint already returns a new value even without moving the cursor further.
You rather need to store the original point and use a delta to move the camera. I think maybe something like e.g.
// in general cache the reference
[SerializeField] private Camera camera;
// world space point where we started to pan
private Vector3 panStart;
private Vector3 initialPosition;
private void Awake()
{
if(!camera) camera = Camera.main;
}
void Update ()
{
// only true the first frame of the panning
if (Input.GetMouseButtonDown(1))
{
initialPosition = camera.transform.position;
panStart = camera.transform.InverseTransformPoint(camera.ScreenToWorldPoint(Input.mousePosition));
}
if (Input.GetMouseButton(1))
{
var pan = panStart - camera.transform.InverseTransformPoint(camera.ScreenToWorldPoint(Input.mousePosition));
camera.transform.position = initialPosition + camera.transform.TransformVector(pan);
}
}
the trick here is that we use the local space to calculate the pan then convert it back into global space in order to add this delta to the initial world space position. This way the movement of the camera itself won't affect the ScreenToWorldPoint delta directly

How to draw latitude/longitude lines on the surface of a Sphere in Unity 3D?

I'm a beginner of Unity 3D. And I'm trying to create a globe with Unity 3D as shown below. I created a Sphere game object on a scene and set the radius as 640. Then, I want to draw latitude/longitude lines (every 10 degree) on the surface of this Sphere in C# script.
I tried to draw each lat/long line by using LineRender, but did not get it work.
My code:
public class EarthController : MonoBehaviour {
private float _radius = 0;
// Use this for initialization
void Start () {
_radius = gameObject.transform.localScale.x;
DrawLatLongLines();
}
// Update is called once per frame
void Update()
{
}
private void DrawLatLongLines()
{
float thetaStep = 0.0001F;
int size = (int)((2.0 * Mathf.PI) / thetaStep);
// draw lat lines
for (int latDeg = 0; latDeg < 90; latDeg += 10)
{
// throw error here.
// seems I cannot add more than one component per type
LineRenderer latLineNorth = gameObject.AddComponent<LineRenderer>();
latLineNorth.startColor = new Color(255, 0, 0);
latLineNorth.endColor = latLineNorth.startColor;
latLineNorth.startWidth = 0.2F;
latLineNorth.endWidth = 0.2F;
latLineNorth.positionCount = size;
LineRenderer latLineSouth = Object.Instantiate<LineRenderer>(latLineNorth);
float theta = 0;
var r = _radius * Mathf.Cos(Mathf.Deg2Rad * latDeg);
var z = _radius * Mathf.Sin(Mathf.Deg2Rad * latDeg);
for (int i = 0; i < size; i++)
{
var x = r * Mathf.Sin(theta);
var y = r * Mathf.Cos(theta);
Vector3 pos = new Vector3(x, y, z);
latLineNorth.SetPosition(i, pos);
pos.z = -z;
latLineSouth.SetPosition(i, pos);
theta += thetaStep;
}
}
}
}
What's the correct way to do this?
I don't want to write custom shader (if possible) since I know nothing about it.
The usual way to customize the way 3d objects look is to use shaders.
In your case, you would need a wireframe shader, and if you want control on the number of lines, then you might have to write it yourself.
Another solution is to use a texture. In unity, you will have many default materials that will apply a texture on your object. You can apply an image texture that contains your lines.
If you don't want a texture and really just the lines, you could use the line renderer. LineRenderer doesn't need a 3D object to work. You just give it a number of points and it is going to link them with a line.
Here is how I would do it:
Create an object with a line renderer and enter points that create a
circle (You can do it dynamically in c# or manually in the editor on
the line renderer).
Store this as a prefab (optional) and duplicate it in your scene
(copy paste. Each copy draws a new line
Just be modifying the rotation, scale and position of your lines you
can recreate a sphere
If your question is "What is the equation of a circle so I can find the proper x and y coord?" here is a short idea to compute x and y coord
for(int i =0; i< nbPointsOnTheCircle; ++i)
{
var x = Mathf.Cos(nbPointsOnTheCircle / 360);
var y = Mathf.Sin(nbPointsOnTheCircle / 360);
}
If your question is "How to assign points on the line renderer dynamicaly with Unity?" here is a short example:
public class Circle : MonoBehavior
{
private void Start()
{
Vector3[] circlePoints = computePoints(); // a function that compute points of a circle
var lineRenderer = GetComponent<LineRenderer>();
linerenderer.Positions = circlePoints;
}
}
EDIT
You can only have one per object. This is why the example above only draws one circle. You already have a earth controller, but this controller can't add many LineRenderes to itself. Instead, the idea would be that the earth object has a script that does the something like following:
private void Start()
{
for(int i=0; i<nbLines;++i)
{
GameObject go = new GameObject();
go.AddComponent<LineRenderer>();
go.AddCOmponent<Circle>();
go.transform.SetParent = transform;
go.name = "Circle" + i;
}
}
Then you will see several objects created in you scene, each having exactly one LineRenderer and one Circle component
From there you should be able to do what you want (for instance, pass parameters to the Circle so each Circle is a bit different)

Repeating graphics withing view

In Unity2D, I have made a script to repeat the background sprite just before the camera can see the end.
Here's my code:
using UnityEngine;
using System.Collections;
[RequireComponent (typeof(SpriteRenderer))]
public class Tiling : MonoBehaviour {
public int offsetX = 2; // the offset so that we don't get any weird errors
// these are used for checking if we need to instantiate stuff
public bool hasARightBuddy = false;
public bool hasALeftBuddy = false;
public bool reverseScale = false; // used if the object is not tilable
private float spriteWidth = 0f; // the width of our element
private Camera cam;
private Transform myTransform;
private float localSc;
void Awake () {
cam = Camera.main;
myTransform = transform;
localSc = transform.localScale.x;
}
// Use this for initialization
void Start () {
SpriteRenderer sRenderer = GetComponent<SpriteRenderer>();
spriteWidth = sRenderer.sprite.bounds.size.x * transform.localScale.x;
}
// Update is called once per frame
void Update () {
// does it still need buddies? If not do nothing
if (hasALeftBuddy == false || hasARightBuddy == false) {
// calculate the cameras extend (half the width) of what the camera can see in world coordinates
float camHorizontalExtend = cam.orthographicSize * Screen.width/Screen.height;
// calculate the x position where the camera can see the edge of the sprite (element)
float edgeVisiblePositionRight = (myTransform.position.x + spriteWidth/2) - camHorizontalExtend;
float edgeVisiblePositionLeft = (myTransform.position.x - spriteWidth/2) + camHorizontalExtend;
// checking if we can see the edge of the element and then calling MakeNewBuddy if we can
if (cam.transform.position.x >= edgeVisiblePositionRight - offsetX && hasARightBuddy == false)
{
MakeNewBuddy (1);
hasARightBuddy = true;
}
else if (cam.transform.position.x <= edgeVisiblePositionLeft + offsetX && hasALeftBuddy == false)
{
MakeNewBuddy (-1);
hasALeftBuddy = true;
}
}
}
// a function that creates a buddy on the side required
void MakeNewBuddy (int rightOrLeft) {
// calculating the new position for our new buddy
Vector3 newPosition = new Vector3 (myTransform.position.x + spriteWidth * rightOrLeft, myTransform.position.y, myTransform.position.z);
// instantating our new body and storing him in a variable
Transform newBuddy = Instantiate (myTransform, newPosition, myTransform.rotation) as Transform;
newBuddy.parent = myTransform.parent;
// if not tilable let's reverse the x size on our object to get rid of missmatches
if (reverseScale == true) {
newBuddy.localScale = new Vector3 (localSc*-1 , 1, 1);
}
if (rightOrLeft == 1) { //if this function was called to make a right buddy (1)
newBuddy.GetComponent<Tiling>().hasALeftBuddy = true;
}
else { //else we just made a left buddy, so it has a right copy
newBuddy.GetComponent<Tiling>().hasARightBuddy = true;
}
}
Now, the script is attached to the background sprite and it works fine.
You'll see that there's a bool reverseScale to reverse the image.
This is because if the image is not repeatable, (the end and the start to not match on a pixel level) we can mirror it by reverting (* -1) the x scale.
The strange thing is, if I launch this with reverseScale disabled, eveything works as I said. If I enable reverseScale, it becomes a mess. Infinite loop of overlapping, badly scaled sprites, crashing the game.
What am I missing? Worst case (but still shouldn't happen), that code snippet should make an image that doesn't match, why is it breaking the program?
EDIT:
I found a solution thanks to Enfyve answer. I was flipping the scale of the whole graphic component instead oa single one for come reason. the flipX field should be used instead. Also, only one every two tiles has to be flipped, to avoid missmatches.
SpriteRenderer already contains a property to draw a sprite flipped, use flipX instead.

How to stop a method after it done in Update() function? - C# - Unity3D

Recently I'm making a chess game which has animation when the chess move. I used two method, RotateTowards and Translate(). RotateTowards() only run in Update() function. Here is my code:
using UnityEngine;
using System.Collections;
public class OnTouch : MonoBehaviour {
public GameObject cube;
public GameObject sphere;
int clicked;
Quaternion lastRot;
// Use this for initialization
void Start () {
clicked = 0;
}
// Update is called once per frame
void Update () {
if(clicked == 1)
{
var rotation = Quaternion.LookRotation(cube.transform.position - transform.position);
print(rotation);
rotation.x = 0;
rotation.z = 0;
cube.transform.rotation = Quaternion.RotateTowards(cube.transform.rotation, rotation, 100 * Time.deltaTime);
if(cube.transform.rotation = ???? <- No Idea){
clicked = 0;
}
}
}
void OnMouseDown()
{
print("clicked");
clicked = 1;
}
}
I attach that code to all chess tile. So, after the cube stop rotating, I tried to click another tile. But, the previous RotateTowards() method keep running, so it ran both. I've try to make IF logic, but I have no idea for
if(cube.transform.rotation == ??? <-- No idea){
clicked = 0;
}
Any solution? Thank you!
it will never reaches your final rotation, it will get very close though so you can check if the angle between your destination rotation and current rotation is smaller than a small degree then you can say it reached.
float DestAngle = 1.0f; //here we take 1 degree as the near enough angle
float angle = Quaternion.Angle(transform.rotation, target.rotation);//we calculate the angle between current rotaion and destination
if (Mathf.Abs (angle) <= DestAngle ) { //we reached }
if (cube.transform.rotation == rotation)

C# Enemy doesn't follow player in Windows Form (not XNA)

UPDATE
I managed to figure the answer out myself, what was happening was that my movement function was only registering the players original static position instead of the dynamic coordinates as the player moved around the screen. What I did was create a 'God' class to publicly store the players current X and Y coordinates, and then reference the 'god' class coordinates in my enemy's movement function.
Now, not only does the enemy detect when the player is within it's sights, it will follow the player changing directions accordingly, until it can't 'see' them anymore :D
If anyone wants to see the updated code just ask :)
I'm trying to make a program that contains player and enemy sprites, but I'm having a little trouble with the code for the 'Enemy'. Most of the coding problems on here deal with XNA, which I'm not using, so I was wondering if I could have a little help.
Basically, when the player moves within a certain distance, the movement function for the enemy should activate and it will move towards the players location as long as they're in the 'detection zone'. The enemy's sprite also has a walk animation for each direction, and it should flip through frames depending on whether it's currently moving or not.
The movement function is within a timer, so that it'll update with every tick. I have two separate functions for updating its location, one to physically change it's coordinates in the Form based on the data received from the movement function, and another to update the current frame from my sprite sheet.
The problem is that the enemy doesn't move whatsoever, if I get rid of it's detection and the code to follow the player, and instead just move it across the screen, it works perfectly fine. But unfortunately that's not what I'm trying to achieve.
The code works perfectly fine for my player sprite (albeit, it's controlled by the user and the keyboard keys), so I'm not sure what I'm doing wrong.
I believe the problems lies within the Movement function, but I'm not sure what that problem is exactly.
Here's my code for the relevant functions:
public void Movement() //This function is in a timer, and determines which direction the sprite will move and face
{
//The sprite rectangle is the position of the player sprite, and detection is the area where the enemy would 'see' the player if they entered it
sprite = new Rectangle(charX - 1, charY + 1, charWidth * 2 + 2, charHeight * 2 + 2);
Detection = new Rectangle(curX - 25, curY - 25, Enemy.Width * 6, Enemy.Height * 6);
if (Detection.IntersectsWith(sprite)) //Checks to see if the player is within range
{
//Moves the enemy based on the players position and changes direction accordingly
if (curX > charX)
{
curDirection = RIGHT;
dX = -1;
dY = 0;
numUpdates = 0;
curAnimation = MOVING;
}
else if (curX < charX)
{
curDirection = LEFT;
dX = 1;
dY = 0;
numUpdates = 0;
curAnimation = MOVING;
}
if (curY > charY)
{
curDirection = UP;
dY = -1;
dX = 0;
numUpdates = 0;
curAnimation = MOVING;
}
else if (curY < charY)
{
curDirection = DOWN;
dY = 1;
dX = 0;
numUpdates = 0;
curAnimation = MOVING;
}
}
//If not within range, don't move the sprite
else
{
dY = 0;
dX = 0;
curAnimation = FINISHED;
}
}
These are the updating functions that move the enemy and change the current frame
public void Follow() //Physcially moves the enemy across the form
{
int xMod = 0;
int yMod = 0;
if (dX != 0)
xMod = dX / Math.Abs(dX) * 2;
if (dY != 0)
yMod = dY / Math.Abs(dY) * 2;
//Moves the sprite across the x and y axis
curX += xMod;
dX += -xMod;
curY += yMod;
dY += -yMod;
}
public void UpdateFrame(int direction = DOWN)
{
numUpdates++;
switch (curAnimation)
{
//Stops the animation if the sprite stops moving
case FINISHED:
curFrame = 0;
break;
//Moves to the next frame when movement is found
case MOVING:
curFrame = (curFrame + 1) % 3;
Follow();
//check if done animation
if (dX == 0 && dY == 0) curAnimation = FINISHED;
break;
}
}
If you need more code just ask, any help is appreciated :)

Categories

Resources