Тема: Чому це лайно не працює??
Прів. Є текстурка на весь екран, котра оброблюється скриптом RawImage.
В цього RawImage є uvRect, і якщо змінювати uvRect.y - то текстурка типу зрушується, такий собі offset.
Ну і так, як текстурка повторюється, то за допомогою зміни uvRect.y і за умови, що це текстурка землі, чи травички, створюється уявлення, що це камера рухається вздовж землі.
Тут ще така фігня, що uvRect містить ще змінні height і width. Якщо збільшити height, то текстурка зтискається в стільки-то разів. Якщо height = 1, то для того, аби зсунути текстурку на одне "коло", потрібно змінити uvRect.y з 0 до 1. А якщо height = 8, то для одного циклічного зсуву треба змінювати uvRect.y з 0 до 8.
І от помістив я об'єкта над цією текстуркою, об'єкт - пташка. І потрібно мені, аби ця пташка могла какулькати. Ну і я зробив от так - під дупою пташки з'являється какулька, після чого вона зменшується в 2 рази за 0.5 секунди, а потім вона падає на землю. Ну і зрозуміло, що якщо земля рухається кудись там, то й какулька, що впала на землю, повинна рухатись разом з землею. Але от в чому фігня, какулька - це об'єкт, і в нього своя система координат.
Але я це вирішив дуже просто. Висота екрана == 600. І тут є проста залежність, якщо верх в координатах текстури - це 0, а низ - 8, то в координатах екрана верх - це 0, а низ - це 600. Тобто якщо розділимо 600 на 8, то отримаємо 1 в координатах текстури. Ну і потім можна просто взяти швидкість "руху" текстури і помножити на 600/8, тобто на 75, і отримаємо ту ж саму швидкість, але вже в координатах екрану.
Я так і зробив, і воно працює гарно.
Але потім я захтів зробити приціл. І цей приціл повинен вказувати місце на текстурці, куди впаде какулька.
Для цього мені потрібно з'ясувати, яку відстань пролітає какулька за 0.5 секунди.
І тут я думаю...
Якщо кожен кадр, що продовжується Time.deltaTime, я зсуваю текстуру на speed*Time.deltaTime, то для того, аби порахувати довжину, на котру я зрушую текстурку за 0.5 секунди, потрібно зробити
(0.5/Time.deltatime)*(speed*Time.deltaTime)
тобто спочатку рахуємо кількість кадрів за 0.5 секунди, а потім просто множу speed*Time.deltaTime на це число.
Вірно ж?
І якщо це довжина в координатах текстури, то мені потрібно помножити її на 75, і тоді я переведу її в координати екрану. Ага?
І тоді виходе така формула (0.5*speed*75), тому що Time.deltaTime скорочується.
Але воно шось не працює.... Працює лише от така формула speed*75. Без 0.5.
Чому воно таке?
скрін, якщо тре
От вам всі скрипти, що я юзаю
Оце головний, тут я створюю какульки і позиціоную приціл в методі SetAimPos
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class MovementController : MonoBehaviour {
public RectTransform trans;
public float speed, speedRot;
public Transform ass, aim;
private Canvas canvas;
private float canvasHeight, canvasWidth;
private Vector2 neededPosition;
private Quaternion neededRotation;
private GameObject poopPref;
private Vector2 birdsDirection;
private Vector2 assDirection;
private Vector3 oldPosition;
// Use this for initialization
void Start () {
canvas = FindObjectOfType<Canvas>();
poopPref = Resources.Load("Poop") as GameObject;
canvasHeight = (canvas.transform as RectTransform).rect.height/2f;
canvasWidth = (canvas.transform as RectTransform).rect.width/2f;
neededPosition = trans.localPosition;
neededRotation = trans.rotation;
if (speed == 0)
speed = 1;
if (speedRot == 0)
speedRot = 1;
SetAimPos();
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, Input.mousePosition, Camera.main, out neededPosition);
//neededPosition = canvas.transform.TransformPoint(pos);
Debug.Log("needed pos: " + neededPosition);
if (neededPosition == (Vector2)oldPosition)
return;
Vector2 currPosN = Vector2.up;
Vector2 needPosN = neededPosition - (Vector2)trans.localPosition;
needPosN.Normalize();
float dot = Vector2.Dot(currPosN, needPosN);
if (dot < 0)
dot *= -1f;
float z = 90f - (dot * 90f);
z *= 0.5f;
if (needPosN.x > 0)
z *= -1f;
neededRotation = Quaternion.Euler(0, 0, z);
}
if (trans.position != oldPosition)
{
SetAimPos();
}
if (trans.position!=(Vector3)neededPosition)
{
trans.localPosition = Vector3.MoveTowards(trans.localPosition, neededPosition, Time.deltaTime * speed);
if(trans.localPosition==(Vector3)neededPosition)
{
neededRotation = Quaternion.Euler(0, 0, 0);
}
}
if(trans.rotation!=neededRotation)
{
trans.rotation = Quaternion.RotateTowards(trans.rotation, neededRotation, Time.deltaTime * speedRot);
}
if(Input.GetKeyDown(KeyCode.Space))
{
Vector2 globalPosAss;
Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(Camera.main, ass.position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(GroundController.Instance.Ground, screenPoint , Camera.main, out globalPosAss);
GameObject poop = Instantiate(poopPref, globalPosAss, Quaternion.identity, GroundController.Instance.Ground) as GameObject;
Transform poopTrans = poop.transform;
poopTrans.localScale = Vector3.one;
poopTrans.localPosition = globalPosAss;
Vector2 globalPosAim;
Vector2 screenPointAim = RectTransformUtility.WorldToScreenPoint(Camera.main, aim.position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(GroundController.Instance.Ground, screenPointAim, Camera.main, out globalPosAim);
PoopController poopController = poop.GetComponent<PoopController>();
poopController.Empty(globalPosAim);
GameObject anotherPoop = Instantiate(poopPref, globalPosAim, Quaternion.identity, GroundController.Instance.Ground) as GameObject;
Transform poopTrans1 = anotherPoop.transform;
// poopTrans.SetParent(GroundController.Instance.Ground);
poopTrans1.localScale = Vector3.one;
poopTrans1.localPosition = globalPosAss;
PoopController poopController1 = anotherPoop.GetComponent<PoopController>();
poopController1.SetPos(globalPosAss);
poopController1.move = true;
poopController1.GetComponent<Image>().color = Color.red;
GameObject anotherPoop1 = Instantiate(poopPref, globalPosAim, Quaternion.identity, GroundController.Instance.Ground) as GameObject;
Transform poopTrans2 = anotherPoop.transform;
// poopTrans.SetParent(GroundController.Instance.Ground);
poopTrans2.localScale = Vector3.one;
poopTrans2.localPosition = globalPosAss;
PoopController poopController2 = anotherPoop1.GetComponent<PoopController>();
poopController2.SetPos(globalPosAim);
poopController2.move = true;
poopController2.GetComponent<Image>().color = Color.yellow ;
}
}
void SetAimPos()
{
Vector2 assScreenPoint = RectTransformUtility.WorldToScreenPoint(Camera.main, ass.position);
Vector2 assLocalInGround;
RectTransformUtility.ScreenPointToLocalPointInRectangle(GroundController.Instance.Ground, assScreenPoint, Camera.main, out assLocalInGround);
Vector2 direction = trans.position - oldPosition;
Vector2 aimPos = assLocalInGround + (direction.normalized * MultiplyVector2D(MultiplyVector2D(GroundController.Instance.speed,GroundController.Instance.speedOfGround), Vector2.up).y);
aim.localPosition = aimPos;
oldPosition = trans.position;
}
Vector2 MultiplyVector2D(Vector2 first, Vector2 second)
{
return new Vector2(first.x * second.x, first.y * second.y);
}
}
А тута рухається земля
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System;
using Random = UnityEngine.Random;
[Serializable]
public class Path
{
public Vector2 point;
public bool isFilled;
}
public class GroundController : MonoBehaviour {
public RawImage ground;
public Vector2 speed;
public Vector2 speedOfGround;
public float height, width;
public List<Path> humanPaths;
private Rect rect;
private GameObject humanPref;
private RectTransform rootGround;
private float humanWidth, humanHeigth;
private float groundWidth;
private Vector2 oldSpeed;
private static GroundController instance;
public static GroundController Instance
{
get
{
return instance;
}
}
public RectTransform Ground
{
get
{
return rootGround;
}
}
void Awake()
{
if (instance == null)
instance = this;
}
// Use this for initialization
void Start () {
rect = ground.uvRect;
rootGround = ground.rectTransform;
humanPref = Resources.Load("Human") as GameObject;
height = rootGround.rect.height;
width = rootGround.rect.width;
CalculateSpeedOfGround();
groundWidth = rootGround.rect.width;
GameObject tempPref = Instantiate(humanPref);
humanWidth = (tempPref.transform as RectTransform).rect.width;
humanHeigth = (tempPref.transform as RectTransform).rect.height;
Destroy(tempPref);
float pathWidthF = groundWidth / humanWidth;
int pathsCount = (int)Mathf.Floor(pathWidthF);
float rest = groundWidth - pathsCount*humanWidth;
float newHumanWidth = groundWidth / pathsCount;
// Debug.Log("newHumanWidth: " + newHumanWidth);
// Debug.Log("pathWidthF: " + pathWidthF + " pathsCount: " + pathsCount + " rest: " + rest);
rest = rest / pathsCount;
//Debug.Log("rest: " + rest);
humanPaths = new List<Path>();
for(int i =0; i<pathsCount; i++)
{
Path path = new Path();
path.point = new Vector2((newHumanWidth / 2f)+(i*(newHumanWidth)) +(-(groundWidth/2f)), (height / 2f) + (humanHeigth / 2f));
path.isFilled = false;
humanPaths.Add(path);
}
oldSpeed = speed;
}
void CalculateSpeedOfGround()
{
speedOfGround.y = (height / ground.uvRect.height);
speedOfGround.x = (width / ground.uvRect.width);
}
// Update is called once per frame
void Update () {
rect.position += (speed * Time.deltaTime);
ground.uvRect = rect;
if(oldSpeed!=speed)
{
CalculateSpeedOfGround();
}
if (Input.GetKeyDown(KeyCode.P))
{
var paths = humanPaths.FindAll((v)=> { return v.isFilled == false; });
if (paths.Count==0)
return;
GameObject newHuman = Instantiate(humanPref);
var hc = newHuman.GetComponent<HumanController>();
var nhTrans = newHuman.transform as RectTransform;
nhTrans.SetParent(rootGround);
var path = paths[Random.Range(0, paths.Count)];
path.isFilled = true;
hc.Path = path;
nhTrans.localPosition = path.point;
nhTrans.localScale = Vector3.one;
}
}
}
А оце скрипт, що висить на какульці
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using DG.Tweening;
public class PoopController : MonoBehaviour {
public float timeInAir = 1f;
public bool move;
private Transform trans;
private Vector2 position;
private float destroyHeight;
void Start()
{
trans = transform;
destroyHeight = -(GroundController.Instance.height / 2f) - ((transform as RectTransform).rect.height / 2f);
}
public void SetPos(Vector2 pos)
{
position = pos;
}
public void Empty(Vector3 destination)
{
//transform.DOLocalMove(destination, timeInAir).SetEase(Ease.Linear);
transform.DOScale(0.5f, timeInAir).SetEase(Ease.Linear).OnComplete(()=> {
position = trans.localPosition;
move = true;
});
}
void Update()
{
if(move)
{
position.y -= (GroundController.Instance.speedOfGround.y* GroundController.Instance.speed.y * Time.deltaTime);
trans.localPosition = position;
if (position.y <= destroyHeight)
{
DestroyImmediate(gameObject);
}
}
}
}