点击判断(2d sprite)
if (Input.GetMouseButton(0))
{
//从摄像机发出射线的点
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 MousePos2D = new Vector2(mousePos.x, mousePos.y);
RaycastHit2D hit = Physics2D.Raycast(MousePos2D, Vector2.zero);
if (hit.collider!=null)
{
print("成功点击");
}
}
获取鼠标位置
Input.mousePosition
Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPosition.z = 0f;
根据鼠标位置放置prefab
if (Input.GetMouseButtonDown(0))
{
Instantiate(pfwoodHarvester, GetMouseWorldPosition(), Quaternion.identity);
}
建立scriptobject
[CreateAssetMenu(menuName ="ScriptableObjects/BuildingType")]
public class BuildingTypeSO : ScriptableObject
{
public string nameString;
public Transform prefab;
}
用resource来导入不同的scriptobject,可以嵌套已经做好了的scriptableobject
[CreateAssetMenu(menuName = "ScriptableObjects/BuildingTypeList")]
public class BuildingTypeListSO : ScriptableObject
{
public List<BuildingTypeSO> list;
}
buildingTypeList=Resources.Load<BuildingTypeListSO>(typeof(BuildingTypeListSO).Name);
buildingType = buildingTypeList.list[0];
计时器
每过一秒做一次
private float timer;
private float timerMax;
private void Awake()
{
timerMax = 1f;
}
private void Update()
{
timer -= Time.deltaTime;
if (timer <= 0f)
{
timer += timerMax;
Debug.Log("Ding");
}
}
显示自定义数据结构
[System.Serializable]
public class ResourceGeneratorData
{
public float timerMax;
public ResourceTypeSO resourceType;
}
单例模式
因为prefab可以在任何场景被建立,因此它可以取到的内容必须是一个asset,而不是场景内物件。为此,我们可以用到单例模式
比如一个资源物件,出现后会让当前全局的一个脚步数值增加数量,这个脚本就最好为单例。
public static ResourceManager Instance
{
get;
private set;
}
private void Awake()
{
Instance = this;
}
prefab中可以这样获取这个脚本:
ResourceManager.Instance.AddResource(buildingType.resourceGeneratorData.resourceType, 1);
不用prefab,直接用一个transform来做UI的模板
这个方法很好,在你有资源添加进去后,它会自动增加。
Transform resourceTemplate = transform.Find("ResourcesTemplate");
resourceTemplate.gameObject.SetActive(false);//把模板设置为看不见
int index = 0;
foreach (ResourceTypeSO resourceType in resourceTypeList.list)
{
Transform resourceTransform = Instantiate(resourceTemplate, transform);//生成一个自己。
resourceTransform.gameObject.SetActive(true);
float offsetAmount = -160f;
resourceTransform.GetComponent<RectTransform>().anchoredPosition = new Vector2(offsetAmount*index,0);
//找到模板物件下方的子物体进行更改
resourceTransform.Find("Image").GetComponent<Image>().sprite = resourceType.sprite;
resouceTypeTransformDictionary[resourceType] = resourceTransform;
index++;
}
TextMeshPro如何找到自己的脚本
resouceTransform.Find("Text").GetComponent<TMP_Text>().SetText(resourceAmount.ToString());
Event
发布者不需要直到它要干嘛只需要直到它在什么时候要做什么。
其他人可以往这个时机里添加内容。
public event EventHandler OnResourceAmountChanged;
在某时机要做什么
OnResourceAmountChanged?.Invoke(this,EventArgs.Empty);
其他人需要填充内容,表示它在这个时机是要做什么
ResourceManager.Instance.OnResourceAmountChanged += ResourceManager_OnResourceAmountChanged;
UpdateResourceAmount();
}
private void ResourceManager_OnResourceAmountChanged(object sender, System.EventArgs e)
{
UpdateResourceAmount();
}
比如,在healthsystem中设置event。它规定了何时触发
在building中进行注册,当死亡时需要对它有所效果
在血量条中对它进行注册,当损血时,它会有所变化
自定义参数的event
调用者
private void Start()
{
BuildingManager.Instance.OnActiveBuildingTypeChanged += BuildingMnager_OnActiveBuildingTypeChanged;
}
private void BuildingMnager_OnActiveBuildingTypeChanged(object sender, BuildingManager.OnActiveBuildingTypeChangedEventArgs e)
{
UpdateActiveBuildingTypeButton();
}
建立event
public event EventHandler<OnActiveBuildingTypeChangedEventArgs> OnActiveBuildingTypeChanged;
public class OnActiveBuildingTypeChangedEventArgs : EventArgs
OnActiveBuildingTypeChanged?.Invoke(this,new OnActiveBuildingTypeChangedEventArgs { activeBuildingType=activeBuildingType});
2D模式下的渲染顺序
从上到下
都是从小到大。
相机移动
用cinemachine设置跟随target,在target中挂脚本写上:
private void Update()
{
float x = Input.GetAxisRaw("Horizontal");
float y = Input.GetAxisRaw("Vertical");
Vector2 moveDir=new Vector2(x, y).normalized;
float moveSped = 5f;
transform.position += (Vector3)moveDir * moveSped * Time.deltaTime;
}
缩小场景视野大小。
也是用cinemachine
获得cinemachine
[SerializeField] private CinemachineVirtualCamera cinemachineVirtualCamera;
private void Start()
{
orthographicSize = cinemachineVirtualCamera.m_Lens.OrthographicSize;
}
private void Update()
{
float zoomAmount = 2f;
orthographicSize += Input.mouseScrollDelta.y * zoomAmount;
float minorthographicSize = 10;
float maxorthographicSize = 30;
orthographicSize = Mathf.Clamp(orthographicSize,minorthographicSize, maxorthographicSize);
cinemachineVirtualCamera.m_Lens.OrthographicSize = orthographicSize;
}
在移动时增加减速效果
targetorthographicSize = Mathf.Clamp(targetorthographicSize, minorthographicSize, maxorthographicSize);
float zoomSped = 30f;
orthographicSize = Mathf.Lerp(orthographicSize, targetorthographicSize, zoomSped * Time.deltaTime);
cinemachineVirtualCamera.m_Lens.OrthographicSize = orthographicSize;
用函数EventSystem.current.IsPointerOverGameObject()来解决ui点击层级问题
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
Instantiate(buildingType.prefab, GetMouseWorldPosition(), Quaternion.identity);
}
动态增加按钮监听函数
btnTransform.GetComponent<Button>().onClick.AddListener(() =>{
BuildingManager.Instance.SetActiveBuildingType(buildingType);
} );
缩小图片大小
arrowBtn.Find("image").GetComponent<Image>().sprite = arrowSprite;
arrowBtn.Find("image").GetComponent<RectTransform>().sizeDelta = new Vector2(0, -40);
2D-Y轴顺序
挂在物件prefab上。
public class SpritePositionSortingOrder : MonoBehaviour {
[SerializeField] private bool runOnce;
[SerializeField] private float positionOffsetY;
private SpriteRenderer spriteRenderer;
private void Awake() {
spriteRenderer = GetComponent<SpriteRenderer>();
}
private void LateUpdate() {
float precisionMultiplier = 5f;
spriteRenderer.sortingOrder = (int) (-(transform.position.y + positionOffsetY) * precisionMultiplier);
if (runOnce) {
Destroy(this);
}
}
}
让update暂停运作
if (nearbyResourceAmount == 0)
{
// No resource nodes nearby
// Disable resource generator
enabled = false;
}
用物理引擎找到周边的物体
Collider2D[] collider2DArray = Physics2D.OverlapCircleAll(transform.position, resourceGeneratorData.resourceDetectionRadius);
int nearbyResourceAmount = 0;
foreach (Collider2D collider2D in collider2DArray)
{
ResourceNode resourceNode = collider2D.GetComponent<ResourceNode>();
if (resourceNode != null)
{
// It's a resource node!
if (resourceNode.resourceType == resourceGeneratorData.resourceType)
{
// Same type!
nearbyResourceAmount++;
}
}
}
根据资源的数量,减少增加资源的冷却时间
timerMax = (resourceGeneratorData.timerMax / 2f) +
resourceGeneratorData.timerMax *
(1 - (float)nearbyResourceAmount / resourceGeneratorData.maxResourceAmount);
获取canvas的位置,按照 screen size的canvas
鼠标触发事件
简易朝着目标移动
检测碰撞
指向那个位置的小箭头
指向对象在屏幕内,消失