tank battle
- game introduction
-
- development process
-
- Background import and material processing
- Formation of prefab and 2D animation
- Control the player's movement and its direction
- Add a collider to solve the jitter
- Tank's attack CD, mobile priority problem, level rendering
- Tank attack method, invincible protection time
- Death and Explosion of Tanks
- bullet script
- Enemy Scripting
- Tank spawn effects
- Base (heart) explosion and death
- map creation
- Creation of player state management
- UI production
- add sound effects
game introduction
Unity development, by controlling the movement and attack of tanks, protecting the base and destroying enemy tanks.
development process
Background import and material processing
Select the backgrand in the material Graphics as the background.
If the material has not been divided and needs to be divided manually, click the material to be divided, select Multiple in Sprite Mode, click the Sprite Editor at the bottom right , select Apply to enter the segmentation page, click Slice at the upper left corner, select Slice, the system will automatically divide, and click Apply.
Formation of prefab and 2D animation
The formation of the prefab
Create a Prafads folder under the Project panel and drag the textures under the Hierarchy panel back to the Prafabs folder to form a prefab.
The formation of 2D animation
Hold down ctrl and drag multiple pictures into the Hierarchy panel, create an Animation folder, name it and save it to the Animation folder.
Control the player's movement and its direction
public void Move()
{
float i = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * i * MoveSpeed * Time.fixedDeltaTime, Space.World);//施加一个向右的力随时间的变化而变化乘以移速
if (i < 0)
{
sr.sprite = tanksprite[3];
bulletsprite = new Vector3(0, 0, 90);
}
else if (i > 0)
{
sr.sprite = tanksprite[1];
bulletsprite = new Vector3(0, 0, -90);
}
if (i != 0)
{
return;
}
float j = Input.GetAxis("Vertical");
transform.Translate(Vector3.up * j * MoveSpeed * Time.fixedDeltaTime, Space.World);
if (j < 0)
{
sr.sprite = tanksprite[2];
bulletsprite = new Vector3(0, 0, 180);
}
else if (j > 0)
{
sr.sprite = tanksprite[0];
bulletsprite = new Vector3(0, 0, 0);
}
}
player master code
public class Player : MonoBehaviour
{
//属性
public float MoveSpeed = 2;
private Vector3 bulletsprite;
private float time;
private float defenttime=5;
private bool isdefended=true;
//引用方法
public AudioClip attackAudio;//添加攻击音效
public AudioClip explorAudio;//添加爆炸音效
public SpriteRenderer sr;
public Sprite[] tanksprite;//上,右,下,左
public GameObject bulletPro;
public GameObject explortank;
public GameObject Shield0;
private void Awake()
{
sr = GetComponent<SpriteRenderer>();
}
Add a collider to solve the jitter
Add a rigid body and a collider to the player, and add a collider to other obstacles.
Click Constraints under the rigid body component to lock the Z axis to solve the rotation during movement.
Put the code in the FiexedUpdate life cycle function, because the fixed frame number can be Fix jitter
Tank's attack CD, mobile priority problem, level rendering
private void FixedUpdate()//固定物理帧
{
if(Playerstate.Instance.isDefent)
{
return;
}
Move();
//攻击CD
if (time >= 0.4f)
{
Attack();
}
else
{
time += Time.fixedDeltaTime;
}
}
The larger the Oorder in Layer, the higher the rendering level.
Tank attack method, invincible protection time
private void Attack()
{
if(Input.GetKeyDown(KeyCode.Space))//输入空格攻击
{
Instantiate(bulletPro, transform.position, Quaternion.Euler(transform.eulerAngles+bulletsprite));
AudioSource.PlayClipAtPoint(attackAudio, transform.position);
time = 0;
}
}
void Update()
{
//保护时间
if(isdefended)
{
Shield0.SetActive(true);
defenttime -= Time.deltaTime;
if(defenttime<=0)
{
isdefended = false;
Shield0.SetActive(false);
}
}
}
Death and Explosion of Tanks
private void Die()
{
if(isdefended)
{
return;
}
Playerstate.Instance.dieplayer = true;
//爆炸
Instantiate(explortank, transform.position,transform.rotation);
AudioSource.PlayClipAtPoint(explorAudio, transform.position);
//死亡
Destroy(gameObject);
}
bullet script
public class Bullet : MonoBehaviour
{
private float moveSpeed = 10;//子弹的移动速度
public bool bulletplayer;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);
}
public void OnTriggerEnter2D(Collider2D collision)
{
switch(collision.tag)
{
case "Player1":
{
if(!bulletplayer)
{
collision.SendMessage("Die"); Destroy(gameObject); }
}
break;
case "Heart":
{
collision.SendMessage("Die"); //发送Die方法
Destroy(gameObject);
}
break;
case "Wall":
{
Destroy(collision.gameObject);
Destroy(gameObject);
}
break;
case "Barriar":
{
if (bulletplayer)
{
collision.SendMessage("PlayerAudio");
}
Destroy(gameObject);
}
break;
case "Eneray":
{
if(bulletplayer)
{
collision.SendMessage("Die");
Destroy(gameObject);
}
}
break;
default:break;
}
}
}
Enemy Scripting
public class Enemys : MonoBehaviour
{
public float MoveSpeed = 2;
private Vector3 bulletsprite;
private float time;
//private float defenttime = 3;
private float timeChange=4;
private float i;
private float j=-1;
//引用方法
public SpriteRenderer sr;
public Sprite[] tanksprite;//上,右,下,左
public GameObject bulletPro;
public GameObject explortank;
private void Awake()
{
sr = GetComponent<SpriteRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//攻击CD
if (time >= 3)
{
Attack();
}
else
{
time += Time.deltaTime;
}
}
private void FixedUpdate()//固定物理帧
{
Move();
}
//坦克的攻击
private void Attack()
{
Instantiate(bulletPro, transform.position, Quaternion.Euler(transform.eulerAngles + bulletsprite));
time = 0;
}
//移动方法
public void Move()
{
if (timeChange >= 4)
{
int num = Random.Range(0, 8);
if (num >= 4)
{
i = 0;
j = -1;
}
else if (num == 0)
{
j = 1;
i = 0;
}
else if (num > 0 && num <= 2)
{
i = 1;
j = 0;
}
else if (num > 2 && num < 4)
{
i = -1;
j = 0;
}
timeChange = 0;
}
else
timeChange += Time.fixedDeltaTime;
transform.Translate(Vector3.right * i * MoveSpeed * Time.fixedDeltaTime, Space.World);//施加一个向右的力随时间的变化而变化乘以移速
if (i < 0)
{
sr.sprite = tanksprite[3];
bulletsprite = new Vector3(0, 0, 90);
}
else if (i > 0)
{
sr.sprite = tanksprite[1];
bulletsprite = new Vector3(0, 0, -90);
}
if (i != 0)
{
return;
}
transform.Translate(Vector3.up * j * MoveSpeed * Time.fixedDeltaTime, Space.World);
if (j < 0)
{
sr.sprite = tanksprite[2];
bulletsprite = new Vector3(0, 0, 180);
}
else if (j > 0)
{
sr.sprite = tanksprite[0];
bulletsprite = new Vector3(0, 0, 0);
}
}
//坦克死亡方法
private void Die()
{
Playerstate.Instance.score++;
//爆炸
Instantiate(explortank, transform.position, transform.rotation);
//死亡
Destroy(gameObject);
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag=="Eneray")
{
timeChange = 4;
}
}
}
Tank spawn effects
public class Born : MonoBehaviour
{
public GameObject BornPlayer;
public GameObject[] EnemyBorn;
public bool creatPlayer;
public AudioClip bornAudio;
// Start is called before the first frame update
void Start()
{
Invoke("BornTank", 1.2f); //延时特效
AudioSource.PlayClipAtPoint(bornAudio, transform.position);
Destroy(gameObject, 1.2f); //延时销毁
}
// Update is called once per frame
void Update()
{
}
private void BornTank()
{
if (creatPlayer)
{
Instantiate(BornPlayer, transform.position, Quaternion.identity);
}
else
{
int num = Random.Range(0, 2);
Instantiate(EnemyBorn[num], transform.position, Quaternion.identity);
}
}
}
Base (heart) explosion and death
public class Heart : MonoBehaviour
{
public AudioClip dieAudio;
public SpriteRenderer sr;
public Sprite Borken;
public GameObject Explorer;
// Start is called before the first frame update
void Start()
{
sr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
//void Update()
//{
//}
public void Die()
{
sr.sprite = Borken;
Instantiate(Explorer,transform.position,transform.rotation);
Playerstate.Instance.isDefent = true;
AudioSource.PlayClipAtPoint(dieAudio,transform.position);
}
}
map creation
public class MapCreat : MonoBehaviour
{
private List<Vector3> itemlist = new List<Vector3>();
//用来装饰地图
//0,老家,1墙,2障碍,3出生,4河流,5草
public GameObject[] item;
private void Awake()
{
//老家
GreateItem(item[0],new Vector3(0,-8,0),Quaternion.identity);
//老家的墙
GreateItem(item[1], new Vector3(-1, -8, 0), Quaternion.identity);
GreateItem(item[1], new Vector3(1, -8, 0), Quaternion.identity);
for(int i=-1;i<2;i++)
{
GreateItem(item[1], new Vector3(i, -7, 0), Quaternion.identity);
}
//初始化边界
for(int i=-11;i<=10;i++)
{
GreateItem(item[6], new Vector3(i, -9, 0), Quaternion.identity);
}
for (int i = -11; i <=10; i++)
{
GreateItem(item[6], new Vector3(i, 9, 0), Quaternion.identity);
}
for (int i = -9; i <= 8; i++)
{
GreateItem(item[6], new Vector3(-11,i , 0), Quaternion.identity);
}
for (int i = -9; i <= 8; i++)
{
GreateItem(item[6], new Vector3(11, i, 0), Quaternion.identity);
}
//地图
for(int i=0;i<60;i++)
{
GreateItem(item[1], CreateRandom(), Quaternion.identity);
}
for (int i = 0; i < 19; i++)
{
GreateItem(item[2], CreateRandom(), Quaternion.identity);
}
for (int i = 0; i < 18; i++)
{
GreateItem(item[4], CreateRandom(), Quaternion.identity);
}
for (int i = 0; i < 20; i++)
{
GreateItem(item[5], CreateRandom(), Quaternion.identity);
}
//玩家
GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity);
go.GetComponent<Born>().creatPlayer = true;
//产生敌人
GreateItem(item[3], new Vector3(-10, 8, 0), Quaternion.identity);
GreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity);
GreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity);
//随时间产生
InvokeRepeating("CreateEnemy",4,5);
}
private void GreateItem(GameObject CreategameObject,Vector3 Creatvector,Quaternion Craetquaternion)
{
GameObject itemgo = Instantiate(CreategameObject,Creatvector,Craetquaternion);
itemgo.transform.SetParent(gameObject.transform);
itemlist.Add(Creatvector);
}
//产生随机物
private Vector3 CreateRandom()
{
//不产生边缘障碍
while (true)
{
Vector3 Creatvector = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8), 0);
if (!HasPosition(Creatvector))
{
return Creatvector;
}
}
}
private bool HasPosition(Vector3 Creatpos)
{
for(int i=0;i<itemlist.Count;i++)
{
if(Creatpos==itemlist[i])
{
return true;
}
}
return false;
}
//随机产生敌人
private void CreateEnemy()
{
int h = Random.Range(0, 3);
Vector3 EnemyPos = new Vector3();
if(h==0)
{
EnemyPos= new Vector3(-10, 8, 0);
}
else if(h==1)
{
EnemyPos = new Vector3(10, 8, 0);
}
else if(h==2)
{
EnemyPos = new Vector3(0, 8, 0);
}
GreateItem(item[3], EnemyPos , Quaternion.identity);
}
}
Creation of player state management
Define the life value and score, which can be reflected in the UI interface in real time, death status, failure status, and call the corresponding method.
public class Playerstate : MonoBehaviour
{
public int life = 3;
public int score = 0;
public bool dieplayer;
public GameObject born;
public GameObject isDefentUI;
public bool isDefent;
public Text playerLifeText;
public Text playerScoreText;
// Start is called before the first frame update
//
private static Playerstate instance;
public static Playerstate Instance {
get => instance; set => instance = value; }
private void Awake()
{
Instance = this;
}
void Start()
{
}
// Update is called once per frame
void Update()
{
if(isDefent)
{
isDefentUI.SetActive(true);
Invoke("ReturnMenu", 3);
}
if(dieplayer)
{
Reverce();
}
playerLifeText.text = life.ToString();
playerScoreText.text = score.ToString();
}
private void Reverce()
{
if (life <= 0)
{
//游戏失败
isDefent = true;
Invoke("ReturnMenu", 3);
}
else
{
life--;
GameObject go = Instantiate(born, new Vector3(-2, -8, 0), Quaternion.identity);
go.GetComponent<Born>().creatPlayer = true;
dieplayer = false;
}
}
private void ReturnMenu()
{
SceneManager.LoadScene(1);
}
}
UI production
public class Image : MonoBehaviour
{
public Transform poseone;
public Transform posetwo;
private float h = 1;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.W))
{
h = 1;
transform.position = poseone.position;
}
else if(Input.GetKeyDown(KeyCode.S))
{
h = 2;
transform.position = posetwo.position;
}
if (Input.GetKeyDown(KeyCode.Space) && h ==1)
{
SceneManager.LoadScene(0);
}
}
}
add sound effects
Audio Source components can be added by dragging and dropping.