이번엔 저번 강의에 이어서, 타워 업그레이드를 구현하도록 하겠습니다.

업그레이드 기능은 끝났지만, 실제 게임상의 재화를 소비하거나, 얻는기능은 없었습니다.

우선 업그레이드 시스템을 완료하기 위해서 게임상의 재화를 구현하도록 합니다.

이 게임에선 "골드" 를 재화라고 칭하고, 계속 골드로 설명하겠습니다.


1. 골드 시스템.

게임 내에서 골드는 타워를 짓거나, 업그레이드를 할때 필요한 요소 입니다.골드가 부족하면 타워를 짓지 못하고, 업그레이드가 불가능해서 적 유닛을 막아낼수가 없습니다.

이 골드는 게임초기에 특정 금액이 주어지고, 유닛을 제거하거나, 타워를 판매할때 획득할수 있습니다.

먼저 게임이 시작되면 시작골드를 지급하고, 현재 보유 골드를 화면에 표시하도록 하겠습니다.

GameManager.cs 파일을 열고, 다음과 같이 startGold 와, currentGold 변수를 넣어줍니다.(float로 얻거나 소비될일은 없을것 같아서, int로 생성합니다.)

바로 아래의 init()함수 안에서는 currentGold에 startedGold 를 넣어줍니다. 게임이 시작하면 정해진 startedGold만큼 지급됩니다.

화면에 현재 골드가 얼마인지 GUI를 이용해서 표시해보겠습니다.

화면을 확인해보면 아래처럼 화면 중앙상단에 현재 골드량이 표시됩니다.



GameManager에서 골드를 컨트롤 할수있는 addGold, useGild, checkGold 함수를 만들어줍니다.


각각 골드를 추가, 사용, 골드 잔고가 얼마 이상인지 체크해주는 역할을 합니다.

이제 addTower 함수를 찾아서 마지막에 다음과 같이 useGold함수를 넣어주면, 타워를 지을때마다 현재 골드가 줄어들게 됩니다.

다시 플레이해서 타워를 지어보면, 타워가 생길때마다 50 골드씩 줄어드는걸 볼수 있습니다. 하지만 돈이 부족하더라도 골드가 마이너스가 될뿐 계속 타워는 지을수 있습니다.

이번엔 타워를 짓기전에 골드량을 체크해서 골드가 충분할때만 지어지도록 하겠습니다.

표시된것처럼 현재 골드가 towerbuildPrice보다 같거나 많을때만 타워를 추가하도록 변경합니다. 이젠 골드가 부족할경우 타워는 지어지지 않습니다.

2. 타워 되팔기

이젠 타워를 되팔때 보유 골드를 추가해주는 작업을 하겠습니다.

타워의 판매 가격은 타워를 처음 짓기위해 필요한 금액과, 업그레이드시 들어갔던 모든 비용의 총합의 50% 가격으로 판매하려합니다.

타워에 관련된 기능들이니 TowerBase.cs 에 작업을 추가해주겠습니다.

먼저 타워에 사용된 모든 가격을 누적시켜주는 totalPrice를 선언해주고, init()함수에서 totalPricebuildPrice로 맞춰줍니다.
(타워를 짓자마자 init()을 하게되니 여기서 totalPrice를 초기화해주면 됩니다.)

TowerBase.cs


업그레이드 시에 totalPrice에 누적이될수있도록, 각각의 upgrade 함수도 다음과 같이 코드를 넣어줍니다.


업그레이드에 필요한 priceGameManager.checkGold를 통해 골드가 충분한지 검사하고, 충분하다면, useGold를 이용해 골드를 차감해주고, totalPrice에 사용한만큼 누적시켜줍니다.
(공경력업그레이드 함수 뿐 아니라, 공속, 공격범위 업그레이드도 잊지말고 적용해주세요.)

실제로 Tower를 추가하거나 제거하는곳은 GameManager이니, GameManager.cssellTower()라는 함수를 만들고 여기서 골드를 추가해주겠습니다.

GameManager.cs

판매하면 타워를 삭제해야하기에 가장 아랫쪽엔 removeTower()함수도 호출해줍니다.

그리고 타워판매 버튼을 눌렀을때, 기존엔 removeTower()를 호출하게 되어있었지만, 이젠 sellTower로 연결을 해줍니다.

TowerUIMenu.cs

윗쪽 주석부분이 기존코드이고, 아래 표시된부분이 변경한코드입니다. 단순히 메소드 명만 변경되었습니다.

이대로 실행해서 테스트 해보면 타워를 판매할때 처음 비용의 50%가 다시 골드로 판매되어 현재 골드가 올라가는게 보입니다.

3.menuUI 정보 업데이트.

이번엔 타워선택시 표시되는 UI들의 정보를 업데이트 해주는 작업을 하겠습니다.

업데이트시 필요 골드와, 골드가 부족하면 버튼이 비활성화되게 하고, 업데이트에 쓰인골드도 타워 판매가격에 반영되도록 만들어줍니다.

우선 TowerMenuBtn.cs 을 좀더 보강해주겠습니다.


표시한것처럼 enable 값이 set될때 uiItem의 enabled 값도 동일하게 셋팅해줍니다.
그리고 금액을 표시할때 setLabel을 직접 써도 되지만, 약간 귀찮을것 같아서 가격만 적으면 가격을 적당히 포멧에 맞춰서 표시해주도록 setPrice함수를 추가합니다.

다음으로, TowerUIMenu.cs 파일을 수정해서, 업데이트 버튼을 누르거나, 다른 타워를 선택했을때 각각 상황에 맞는 정보를 표시해주도록 updateInfo() 함수를 추가합니다.

간단히 보면, sellBtn은 비활성화 될일이 없으니 항상 enable = true 로 활성화시켜줍니다.
가격표시는  선택된 타워의 totalPrice의 50% 이니 반으로 나눠주면 됩니다.

atkUpgradeBtn은 업그레이드 비용이 -1(업그레이드 단계가 max일경우 -1로 나옵니다.)이거나, 돈이 부족하면 비활성화로 표시되고,
업그레이드 레벨이 최고라면 "MAX"로 표시 아니라면, 각각 레벨업에 필요한 비용을 표시해주도록 되어있습니다.

다른 버튼들도 같은방법으로 되어있으니 금방 알아보실수 있습니다.

각각 upgrade 함수들 마지막에 updateInfo() 를 한번씩 호출하고, showMenu시에도 updateInfo()를 호출해주시면 됩니다.

이제 게임을 실행해보면,


버튼을 누를때마다 정보도 변하고, 판매금액도 바로바로 적용되고, 타워판매시 GOLD도 정확히 올라가고 있습니다.


이젠 마지막으로 유닛을 파괴했을때 골드를 획득할수 있도록 UnitBase.cs 파일을 약간 수정하겠습니다.

먼저 유닛을 파괴할때 지급할 gold값을 만들어주고, 

                          

유닛이 죽을때 GameManageraddGold를 통해 골드를 증가시켜주면됩니다.

 


이제 게임을 실행해서 유닛을 죽여보면 죽일때마다 설정한 골드가 지급되는걸 볼수 있습니다.
(초기 자본금이 적어서..죽이기 힘들어서 자본금과 공격력, 유닛의 체력등을 인스펙터에서 조절하면 확인할수있습니다.)

오늘은 여기까지 하고, 소스파일들을 공유 하겠습니다. 혹시 잘안되는게 있으면 한번씩 비교해보세요.

다음시간엔, 유닛들을 웨이브에따라 자동으로 등장하는걸 만들어보겠습니다.


4.소스코드

GameManager.cs


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using common;

public class GameManager : MonoBehaviour {
	private static GameManager _instance = null;
	public static GameManager instance
	{
		get{
			if(_instance == null)Debug.LogError("GameManager is NULL");
			return _instance;
		}
	}

	void Awake()
	{
		_instance = this;
		init();
	}
	//=========================================
	public float cellSize = 40.0f;
	public int[,] wallMap = 
	{{1, 1, 1, 1, 1, 11, 11, 11, 1, 1, 1, 1, 1},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{1, 1, 1, 1, 1, 111, 111, 111, 1, 1, 1, 1, 1}};
	[HideInInspector]
	public List<UnitBase> unitList = new List<UnitBase>();
	[HideInInspector]
	public Dictionary<Point, TowerBase> towerDic = new Dictionary<Point, TowerBase>();
	public BgCellDisplayer bgGrid;
	public Transform unit_field;
	public UnitBase unit_marine;
	public TowerBase tower;
	public TowerUIMenu towerMenu;
	
	public int startedGold = 100;
	public int currentGold = 0;

	public Camera mainCam;

	private void init()
	{
		unitList.Clear();
		towerDic.Clear();
		initPathFinder();

		currentGold = startedGold;
	}
	void addUnit()
	{
		UnitBase unit = Instantiate(unit_marine) as UnitBase;
		unitList.Add(unit);
		unit.transform.parent = unit_field;
		Point startPoint = getStartPoint();
		unit.transform.localPosition = new Vector3(startPoint.x * cellSize + cellSize/2.0f, -startPoint.y * cellSize - cellSize/2.0f);
		unit.setStartPoint(startPoint);

	}
	void addTower(Point p)
	{
		
		TowerBase tw = Instantiate(tower) as TowerBase;
		tw.transform.parent = unit_field;
		tw.transform.localPosition = new Vector3(p.x * cellSize + cellSize/2.0f, -p.y * cellSize - cellSize);
		towerDic.Add(p, tw);
		
		useGold(tw.buildPrice);
	}
	public void addGold(int g)
	{
		currentGold += g;
	}
	public void useGold(int g)
	{
		currentGold -= g;
	}
	public bool checkGold(int g)
	{
		return (currentGold>=g);
	}
	public void removeUnit(UnitBase ub)
	{
		unitList.Remove(ub);
	}
	void researchPathUnits()
	{
		foreach(UnitBase ub in unitList)
		{
			if(ub!=null)
			{
				ub.getPath();
			}
		}
	}
	Point getStartPoint()
	{
		List<Point> startPointList = getStartPointList();
		if(startPointList.Count == 0)
		{
			Debug.LogError("Not Found Start Position");
			return null;
		}
		int ranIdx = Random.Range(0,startPointList.Count);
		return startPointList[ranIdx];
	}
	List<Point> getStartPointList()
	{
		//check startPoints
		List<Point> startPointList = new List<Point>();
		int _w = wallMap.GetLength(0);
		int _h = wallMap.GetLength(1);
		int x,y;
		for (x = 0; x < _w; x++)
		{
			for(y = 0; y < _h; y++)
			{
				if(wallMap[x,y] >= 10 && wallMap[x,y] <= 100)
				{
					startPointList.Add(new Point(x,y));
				}
			}
		}
		return startPointList;
	}
	public void initPathFinder()
	{
		PathFinder.instance.setMapData(wallMap);
	}
	void OnGUI()
	{
		if(GUI.Button( new Rect( 10, 10, 100, 40), "Add Unit"))
		{
			addUnit();
		}
		GUI.Label(new Rect( (Screen.width - 200)/2.0f, 10, 200, 50), "GOLD : "+currentGold);
	}
	void Update()
	{
		if(Input.GetMouseButtonDown(0) && !towerMenu.isShow) 
		{
			Vector2 pos = Input.mousePosition;
			Vector3 mouseP = mainCam.ScreenToWorldPoint(pos) - unit_field.TransformPoint(Vector3.zero);
			Point myPos = new Point((int)(mouseP.x/cellSize), -(int)(mouseP.y/cellSize));
			if(towerDic.ContainsKey(myPos))
			{
				showMenu(towerDic[myPos]);
			}
			else 
			{
				buildTower(myPos);
			}
		}
	}
	bool checkReachAble()
	{
		PathFinder.instance.setCheckMode(true);
		foreach(Point sp in getStartPointList())
		{
			if(PathFinder.instance.getPath(sp,100+wallMap[sp.x,sp.y]) == null)
			{
				Debug.Log("StartPoint Path NULL");
				return false;
			}
		}
		foreach(UnitBase unit in unitList)
		{
			if(!unit.getPath())
			{
				Debug.Log("Unit Path NULL");
				return false;
			}
		}
		PathFinder.instance.setPath();
		return true;
	}
	void buildTower(Point p)
	{
		if(p.x<0||p.y<0 || p.x >= wallMap.GetLength(0) || p.y >= wallMap.GetLength(1))return;
		int prevIndex = wallMap[p.x, p.y];
		
		if(wallMap[p.x, p.y] == 0)wallMap[p.x, p.y] = 2;
		else return;
			
		if(checkGold(tower.buildPrice) && checkReachAble())
		{
			bgGrid.refreshDisplay();
			researchPathUnits();
			addTower(p);
		}
		else 
		{
			wallMap[p.x, p.y] = prevIndex;
		}
		PathFinder.instance.setCheckMode(false);
	}
	public void sellTower(TowerBase tw)
	{
		if(!towerDic.ContainsValue(tw))return;
		addGold(tw.totalPrice/2);
		removeTower(tw);
	}
	public void removeTower(TowerBase tw)
	{
		if(!towerDic.ContainsValue(tw))return;
		foreach(Point keyP in towerDic.Keys)
		{
			if(towerDic[keyP] == tw)
			{
				if(keyP.x<0||keyP.y<0 || keyP.x >= wallMap.GetLength(0) || keyP.y >= wallMap.GetLength(1))return;
				wallMap[keyP.x, keyP.y] = 0;
				towerDic.Remove(keyP);
				break;
			}
		}
		Destroy(tw.gameObject);
		bgGrid.refreshDisplay();
		checkReachAble();
		PathFinder.instance.setPath();
		PathFinder.instance.setCheckMode(false);
	}
	void showMenu(TowerBase tw)
	{
		towerMenu.showMenu(tw);
	}
}


TowerUIMenu.cs


using UnityEngine;
using System.Collections;

public class TowerUIMenu : MonoBehaviour {
	
	public TowerMenuBtn sellBtn; 
	public TowerMenuBtn atkUpgradeBtn; 
	public TowerMenuBtn speedUpgradeBtn; 
	public TowerMenuBtn rangeUpgradeBtn;
	
	public tk2dUIItem blinkArea;
	
	public tk2dSprite rangeSpr;
	
	private TowerBase targetTower;
	public bool isShow = false;
	// Use this for initialization
	void Start () {
		addBtnEvents();
		hideMenu();
	}
	void addBtnEvents()
	{
		sellBtn.uiItem.OnClick -= towerSell;
		sellBtn.uiItem.OnClick += towerSell;
		atkUpgradeBtn.uiItem.OnClick -= upgradeAtk;
		atkUpgradeBtn.uiItem.OnClick += upgradeAtk;
		speedUpgradeBtn.uiItem.OnClick -= upgradeSpeed;
		speedUpgradeBtn.uiItem.OnClick += upgradeSpeed;
		rangeUpgradeBtn.uiItem.OnClick -= upgradeRange;
		rangeUpgradeBtn.uiItem.OnClick += upgradeRange;
		
		blinkArea.OnClick -= hideMenu;
		blinkArea.OnClick += hideMenu;
	}
	public void showMenu(TowerBase target)
	{
		targetTower = target;
		//set position;
		this.transform.localPosition = targetTower.transform.localPosition;
		updateInfo();
		
		isShow = true;
	}
	public void hideMenu()
	{
		this.transform.localPosition = new Vector3(-90000,0,0);
		targetTower = null;
		isShow = false;
	}
	private void updateInfo()
	{
		setRange(targetTower.range);
		//sellBtnInfo
		sellBtn.enable = true;
		sellBtn.setPrice(targetTower.totalPrice/2);
		//atkBtnInfo
		atkUpgradeBtn.enable = targetTower.getLvupAtkPrice()!=-1&&GameManager.instance.checkGold(targetTower.getLvupAtkPrice());
		if(targetTower.getLvupAtkPrice()<0)atkUpgradeBtn.setLabel("MAX");
		else atkUpgradeBtn.setPrice(targetTower.getLvupAtkPrice());
		//speedBtnInfo
		speedUpgradeBtn.enable = targetTower.getLvupSpdPrice()!=-1&&GameManager.instance.checkGold(targetTower.getLvupSpdPrice());
		if(targetTower.getLvupSpdPrice()<0)speedUpgradeBtn.setLabel("MAX");
		else speedUpgradeBtn.setPrice(targetTower.getLvupSpdPrice());
		//rangeBtnInfo
		rangeUpgradeBtn.enable = targetTower.getLvupRngPrice()!=-1&&GameManager.instance.checkGold(targetTower.getLvupRngPrice());
		if(targetTower.getLvupRngPrice()<0)rangeUpgradeBtn.setLabel("MAX");
		else rangeUpgradeBtn.setPrice(targetTower.getLvupRngPrice());
	}
	private void towerSell()
	{
		Debug.Log("TowerSell");
		GameManager.instance.sellTower(targetTower);
		hideMenu();
	}
	private void upgradeAtk()
	{
		Debug.Log("upgradeAtk");
		targetTower.upgradeAtk();
		updateInfo();
	}
	private void upgradeSpeed()
	{
		Debug.Log("upgradeSpeed");
		targetTower.upgradeSpd();
		updateInfo();
	}
	private void upgradeRange()
	{
		Debug.Log("upgradeRange");
		targetTower.upgradeRng();
		updateInfo();
	}
	private void setRange(float r)
	{
		rangeSpr.scale = Vector3.one * (r/40.0f);
	}
}


TowerMenuBtn.cs


using UnityEngine;
using System.Collections;

public class TowerMenuBtn : MonoBehaviour {
	public tk2dUIItem uiItem;
	public tk2dSprite btnSpr;
	public tk2dSprite disableSpr;
	public tk2dTextMesh label;
	
	private bool _enable = true;
	public bool enable
	{
		get{return _enable;}
		set{
			_enable = value;
			uiItem.enabled = _enable;
			setSprite();
		}
	}
	public void setPrice(int p)
	{
		setLabel(string.Format("$ {0:N0}", p));
	}
	public void setLabel(string msg)
	{
		label.text = msg;
	}
	void Start()
	{
		setSprite();
	}
	private void setSprite()
	{
		btnSpr.gameObject.SetActive(enable);
		disableSpr.gameObject.SetActive(!enable);
	}
}


TowerBase.cs


using UnityEngine;
using System.Collections;

public class TowerBase : MonoBehaviour {
	public UnitBase target;
	public float attack = 10.0f;
	private string spriteAtkNameFormat = "tower_a_{0:d2}";
	private string spriteNormalNameFormat = "tower_n_{0:d2}";
	public float range = 100;
	public float shotDelay = 3.0f;
	private float reloadTime = 0;
	private tk2dSprite spr;

	public int totalPrice = 0;
	public int buildPrice = 50;
	private int atkLv = 1;
	private int spdLv = 1;
	private int rngLv = 1;

	public UpgradeInfo[] attackUpgradeInfoArr = new UpgradeInfo[]
	{
		new UpgradeInfo(1, 0, 20), new UpgradeInfo(2, 10, 25), new UpgradeInfo(3, 20, 30), new UpgradeInfo(4, 30, 35), new UpgradeInfo(5, 40, 40)
	};
	public UpgradeInfo[] speedUpgradeInfoArr = new UpgradeInfo[]
	{
		new UpgradeInfo(1, 0, 2.5f), new UpgradeInfo(2, 10, 2.1f), new UpgradeInfo(3, 20, 1.7f), new UpgradeInfo(4, 30, 1.3f), new UpgradeInfo(5, 40, .9f)
	};
	public UpgradeInfo[] rangeUpgradeInfoArr = new UpgradeInfo[]
	{
		new UpgradeInfo(1, 0, 100), new UpgradeInfo(2, 10, 130), new UpgradeInfo(3, 20, 160), new UpgradeInfo(4, 30, 190), new UpgradeInfo(5, 40, 220)
	};
	private UpgradeInfo getInfo(int lv, UpgradeInfo[] infoArr)
	{
		foreach(UpgradeInfo ui in infoArr)
		{
			if(ui.level == lv)return ui;
		}
		return null;
	}
	public int getLvupAtkPrice() { return getLvupAtkPrice(atkLv + 1); }
	public int getLvupAtkPrice(int lv)
	{
		UpgradeInfo info = getInfo(lv, attackUpgradeInfoArr);
		if(info== null)return -1;
		return info.price;
	}
	public int getLvupSpdPrice() { return getLvupSpdPrice(spdLv + 1); }
	public int getLvupSpdPrice(int lv)
	{
		UpgradeInfo info = getInfo(lv, speedUpgradeInfoArr);
		if(info== null)return -1;
		return info.price;
	}
	public int getLvupRngPrice() { return getLvupRngPrice(rngLv + 1); }
	public int getLvupRngPrice(int lv)
	{
		UpgradeInfo info = getInfo(lv, rangeUpgradeInfoArr);
		if(info== null)return -1;
		return info.price;
	}
	public void upgradeAtk(){upgradeAtk(atkLv+1);}
	public void upgradeAtk(int lv)
	{
		UpgradeInfo info = getInfo(lv, attackUpgradeInfoArr);
		if(info== null)return;
		if(!GameManager.instance.checkGold(info.price))return;
		GameManager.instance.useGold(info.price);
		totalPrice += info.price;
		atkLv = info.level;
		attack = info.value;
	}
	public void upgradeSpd(){upgradeSpd(spdLv+1);}
	public void upgradeSpd(int lv)
	{
		UpgradeInfo info = getInfo(lv, speedUpgradeInfoArr);
		if(info== null)return;
		if(!GameManager.instance.checkGold(info.price))return;
		GameManager.instance.useGold(info.price);
		totalPrice += info.price;
		spdLv = info.level;
		shotDelay = info.value;
	}
	public void upgradeRng(){upgradeRng(rngLv+1);}
	public void upgradeRng(int lv)
	{
		UpgradeInfo info = getInfo(lv, rangeUpgradeInfoArr);
		if(info== null)return;
		if(!GameManager.instance.checkGold(info.price))return;
		GameManager.instance.useGold(info.price);
		totalPrice += info.price;
		rngLv = info.level;
		range = info.value;
	}
	// Use this for initialization
	void Start () {
		spr = this.GetComponentInChildren<tk2dSprite>();
		init();
	}

	void init()
	{
		totalPrice = buildPrice;
		reloadTime = shotDelay;
		upgradeAtk(1);
		upgradeSpd(1);
		upgradeRng(1);
	}

	// Update is called once per frame
	void Update () {
		spr.SortingOrder = -(int)this.transform.localPosition.y;
		checkRangeTarget();
		lookAtTarget();
		autoShot();
		attackSprAnim();
		updateSprite();
	}

	void checkRangeTarget()
	{
		if(target != null)
		{
			if(range < Vector2.Distance((Vector2)target.transform.localPosition, (Vector2)this.transform.localPosition))target = null;
		}
		if(target == null)
		{
			foreach(UnitBase ub in GameManager.instance.unitList)
			{
				if(range > Vector2.Distance((Vector2)ub.transform.localPosition, (Vector2)this.transform.localPosition))
				{
					target = ub;
					return;
				}
			}
		}
		
	}

	void lookAtTarget()
	{
		if(target == null)return;
		float anglePI = Mathf.Atan2(this.transform.localPosition.y - target.transform.localPosition.y, target.transform.localPosition.x - this.transform.localPosition.x) + Mathf.PI/2.0f;
		int angle = (int)((anglePI/Mathf.PI * 18.0f) + 36)%36;
		spriteN = 18 -Mathf.Abs(angle - 18);
		int spriteDir = angle<18?1:-1;
		spr.scale = new Vector3(spriteDir, 1,1);
		
	}

	void autoShot()
	{
		reloadTime -= Time.deltaTime;
		if(target == null || reloadTime>0)return;
		attackTarget();
		
	}
	bool isAtkSpr = false;
	bool isAttacking = false;
	float attackTimeCount = 0f;
	float attackDuration = .1f;
	float attackDelay = .13f;
	int attackRepeat = 3;
	int attackedCount = 0;

	void attackTarget()
	{
		if(target == null || isAttacking)return;
		attackTimeCount = 0;
		attackedCount = 0;
		isAtkSpr = true;
		isAttacking = true;
		reloadTime = shotDelay;

		target.attackMe(attack);
	}

	void attackSprAnim()
	{
		if(!isAttacking)return;
		attackTimeCount += Time.deltaTime;
		if(isAtkSpr)
		{
			if(attackDuration<attackTimeCount)isAtkSpr = false;
		}
		else if(attackDelay<attackTimeCount)
		{
			attackedCount++;
			if(attackedCount<attackRepeat)
			{
				isAtkSpr = true;
				attackTimeCount -= attackDelay;
			}
			else isAttacking = false;
		}
	}

	private int spriteN = 0;
	void updateSprite()
	{
		string spriteName = string.Format(isAtkSpr?spriteAtkNameFormat:spriteNormalNameFormat, spriteN);
		spr.spriteId = spr.GetSpriteIdByName(spriteName);
	}

}
[System.Serializable]
public class UpgradeInfo
{
	public int level = 0;
	public int price = 0;
	public float value = 0;
	
	public UpgradeInfo(int _level, int _price, float _value)
	{
		level = _level;
		price = _price;
		value = _value;
	}
}


UnitBase.cs

using UnityEngine;
using System.Collections;
using common;

public class UnitBase : MonoBehaviour {
	public float maxHp = 100;
	public float curHp = 100;
	public int gainGold = 5;

	public float moveSpeed = 1.0f;
	public tk2dSpriteAnimator spr;

	private enum CHAR_ANI {UP, DOWN, LEFT, RIGHT, DESTROY};
	private string[] charAniStr = new string[]{"walk_up","walk_down","walk_left","walk_right","destroy"};
	// Use this for initialization
	void Start () {
		curHp = maxHp;
	}
	private bool isMoveAble = false;
	// Update is called once per frame
	void Update () {
		if(!isMoveAble)return;
		float cellSize = GameManager.instance.cellSize;
		float _speed = cellSize * Time.deltaTime * moveSpeed;
		float rx = (nextPoint.x * cellSize + cellSize/2.0f) - this.transform.localPosition.x;
		float ry = (-nextPoint.y * cellSize - cellSize/2.0f) - this.transform.localPosition.y;
		float dx = _speed * makeNomal(rx);
		float dy = _speed * makeNomal(ry);
		bool isCloseX = false;
		bool isCloseY = false;
		if(Mathf.Abs(dx)>Mathf.Abs(rx)||dx==0){dx = rx;isCloseX = true;}
		if(Mathf.Abs(dy)>Mathf.Abs(ry)||dy==0){dy = ry;isCloseY = true;}
		this.transform.localPosition += new Vector3(dx , dy , 0);
		spr.Sprite.SortingOrder = -(int)this.transform.localPosition.y;
		if(isCloseX && isCloseY)
		{
			if(pathArr.Length <= pathIndex + 1)
			{
				isMoveAble = false;
				GameManager.instance.removeUnit(this);
				Destroy(this.gameObject);
				return;
			}
			setNextPoint();
		}
	}
	int makeNomal(float f)
	{
		float k = 0.1f;
		if(f>k)return 1;
		else if(f<-k)return -1;
		else return 0;
	}
	private Point[] pathArr;
	private Point startPoint;
	private Point nextPoint;
	private int pathIndex =0;
	public void setStartPoint(Point p)
	{
		startPoint = p;
		getPath();
		nextPoint = pathArr[pathIndex];
		showCharDir();
		isMoveAble = true;
	}
	public bool getPath()
	{
		float cellSize = GameManager.instance.cellSize;
		startPoint = new Point((int)(this.transform.localPosition.x/cellSize),-(int)(this.transform.localPosition.y/cellSize) );
		int wallMapIndex = GameManager.instance.wallMap[startPoint.x,startPoint.y];
		if(wallMapIndex > 0 && wallMapIndex < 10)return true;

		Point[] pArr = PathFinder.instance.getPath(startPoint, 111);
		if(pArr == null){Debug.Log("NULL path");return false;}
		pathArr = pArr;

		if(nextPoint != null && pathArr.Length > 1 && nextPoint.isEqual(pathArr[1]))pathIndex = 1;
		else pathIndex = 0;
		nextPoint = pathArr[pathIndex];
		showCharDir();
		return true;
	}
	public void attackMe(float dmg)
	{
		curHp -= dmg;
		if(curHp < 0)
		{
			isMoveAble = false;
			spr.Play ("destroy");
			GameManager.instance.addGold(gainGold);
			GameManager.instance.removeUnit(this);
			spr.AnimationCompleted = unitDestoryAniComplete;
		}
	}
	private void unitDestoryAniComplete(tk2dSpriteAnimator sprite, tk2dSpriteAnimationClip clip)
	{
		Destroy(this.gameObject);
	}
	private void setNextPoint()
	{
		startPoint = nextPoint;
		pathIndex++;
		nextPoint = pathArr[pathIndex];
		showCharDir();
	}
	private void showCharDir()
	{
		
		float cellSize = GameManager.instance.cellSize;
		float nx = (nextPoint.x * cellSize + cellSize/2.0f);
		float ny = (-nextPoint.y * cellSize - cellSize/2.0f);
		if(this.transform.localPosition.x<nx)
			spr.Play (charAniStr[(int)CHAR_ANI.RIGHT]);
		else if(this.transform.localPosition.x>nx)
			spr.Play (charAniStr[(int)CHAR_ANI.LEFT]);
		else if(this.transform.localPosition.y<ny)
			spr.Play (charAniStr[(int)CHAR_ANI.UP]);
		else if(this.transform.localPosition.y>ny)
			spr.Play (charAniStr[(int)CHAR_ANI.DOWN]);
		spr.ClipFps *= moveSpeed;
	}
}



신고
Posted by andwhy

블로그 이미지
andwhy 개인 블로그.
andwhy

공지사항

Yesterday23
Today7
Total108,449

달력

 « |  » 2017.12
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

글 보관함