Copy childhood FC classic game – tank war
I am participating in the nuggets Community game creative submission Contest. For details, please see: Game Creative Submission Contest
You must have played an FC game – Tank War when you were a child. My favorite game was this game when I was a child. Today, I will write a single-player version of tank War and try it online.
Development process:
- Start interface
- Randomly generated map
- Create tank classes (handle tank sound, birth, death, fire, movement, etc.)
- Enemy AI handling
- End of game logic
1. Start screen
The logic of the start screen is simple, just add an option to select P1 and P2 and a start button, and listen for input.
public class Option : MonoBehaviour
{
private int option = 0;
public Transform pos1;
public Transform pos2;
void Update()
{
if(Input.GetKeyDown(KeyCode.W))
{
transform.position = pos1.position;
option = 0;
}
if (Input.GetKeyDown(KeyCode.S))
{
transform.position = pos2.position;
option = 1;
}
if(option == 0 && Input.GetKeyDown(KeyCode.Space))
{
SceneManager.LoadScene(1); }}}Copy the code
2. Random map generation
- Load and save each map block resource
- Use random numbers to control random map block types
- The for loop generates each segment of the map.
public class MapCreation : MonoBehaviour
{
// 0: Old home 1: wall 2: Obstacle 3: Birth Effect 4: River 5: Grass 6: Air Wall
public GameObject[] item;
private Vector3 heartPosition;
private Vector3[] defendHeartWallPosition = new Vector3[5];
private List<Vector3> existPosition = new List<Vector3>();
private void Awake()
{
CreateHeart();
CreateAirBarriar();
CreatePlayer();
existPosition.Add(new Vector3(- 10.8.0));
existPosition.Add(new Vector3(0.8.0));
existPosition.Add(new Vector3(10.8.0));
CreateRandomMap();
InvokeRepeating("createEnemy".0.5);
}
private Vector3 createEnemyPosition()
{
int positionIndex = Random.Range(0.3);
Vector3[] list = new Vector3[3] { new Vector3(- 10.8.0), new Vector3(10.8.0), new Vector3(0.8.0)};return list[positionIndex];
}
private void createEnemy()
{
if (PlayerManager.Instance.enemyNum <= 0)
{
return;
}
GameObject enemy = CreateItem(item[3], createEnemyPosition(), Quaternion.identity);
enemy.GetComponent<Born>().createPlayer = false;
}
private GameObject CreateItem(GameObject createGameObject, Vector3 position, Quaternion rotation)
{
GameObject gb = Instantiate(createGameObject, position, rotation);
gb.transform.SetParent(gameObject.transform);
if(! HasPosition(position)) { existPosition.Add(position); }return gb;
}
private void CreateRandomMap()
{
for (int i = 0; i < 20; i++)
{
CreateItem(item[2], CreateRandomPosition(), Quaternion.identity);
CreateItem(item[4], CreateRandomPosition(), Quaternion.identity);
CreateItem(item[5], CreateRandomPosition(), Quaternion.identity);
}
for (int i = 0; i < 50; i++)
{
CreateItem(item[1], CreateRandomPosition(), Quaternion.identity); }}private void CreatePlayer()
{
CreateItem(item[3].new Vector3(2 -.- 8 -.0), Quaternion.identity);
}
private void CreateHeart()
{
// instantiate the old home
heartPosition = new Vector3(0.- 8 -.0);
defendHeartWallPosition[0] = new Vector3(- 1.- 8 -.0);
defendHeartWallPosition[1] = new Vector3(1.- 8 -.0);
for (int i = 2; i <= 4; i++)
{
defendHeartWallPosition[i] = new Vector3(i - 3.7 -.0);
}
CreateItem(item[0], heartPosition, Quaternion.identity);
for (int i = 0; i < defendHeartWallPosition.Length; i++)
{
CreateItem(item[1], defendHeartWallPosition[i], Quaternion.identity); }}private void CreateAirBarriar()
{
for (int i = - 10; i < 11; i++)
{
CreateItem(item[6].new Vector3(i, 9.0), Quaternion.identity);
CreateItem(item[6].new Vector3(i, 9 -.0), Quaternion.identity);
}
for (int i = - 8 -; i < 9; i++)
{
CreateItem(item[6].new Vector3(- 11, i, 0), Quaternion.identity);
CreateItem(item[6].new Vector3(11, i, 0), Quaternion.identity); }}private Vector3 CreateRandomPosition()
{
while (true)
{
Vector3 newPosition = new Vector3(Random.Range(- 10.11), Random.Range(8.9 -), 0);
if(! HasPosition(newPosition)) {returnnewPosition; }}}private bool HasPosition(Vector3 position)
{
for (int i = 0; i < existPosition.Count; i++)
{
if(existPosition[i] == position)
{
return true; }}return false; }}Copy the code
3. Player birth logic
This one is easier, initialize the player’s prefab and play the birth animation.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Born : MonoBehaviour
{
public GameObject playerPrefab;
public GameObject[] enemyPrefabs;
public bool createPlayer;
// Start is called before the first frame update
void Start()
{
Invoke("PlayerBorn".0.8 f);
Destroy(gameObject, 0.8 f);
}
private void PlayerBorn()
{
if(createPlayer)
{
Instantiate(playerPrefab, transform.position, transform.rotation);
}
else
{
int index = Random.Range(0.2); Instantiate(enemyPrefabs[index], transform.position, transform.rotation); }}}Copy the code
4. Create player classes and enemy classes
Here are some things to implement:
- Tank movement, firing, death
- Enemy Ai
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float moveSpeed = 3;
public Sprite[] tankSprite;
public GameObject bulletPrefab;
public GameObject explosionPrefab;
public GameObject shieldPrefab;
public AudioClip attackAudio;
public AudioSource moveAudio;
public AudioClip[] tankAudio;
private SpriteRenderer sr;
private Vector3 bulletEulerAngle;
private float attackTime;
private float isDefendedTimeVal = 3f;
private bool isDefended = true;
// Start is called before the first frame update
private void Awake()
{
sr = GetComponent<SpriteRenderer>();
}
void Start(){}// Update is called once per frame
void Update()
{
if(isDefended)
{
shieldPrefab.SetActive(true);
isDefendedTimeVal -= Time.deltaTime;
if(isDefendedTimeVal <= 0)
{
isDefended = false;
shieldPrefab.SetActive(false); }}}private void FixedUpdate()
{
if(! PlayerManager.Instance.isDefeat) { Move();if (attackTime >= 0.4 f)
{
Attack();
}
else{ attackTime += Time.fixedDeltaTime; }}}private void Attack()
{
if (Input.GetKeyDown(KeyCode.Space))
{
AudioSource.PlayClipAtPoint(attackAudio, transform.position);
Instantiate(bulletPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bulletEulerAngle));
attackTime = 0; }}private void Move()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
if(v ! =0&& h ! =0)
{
return;
}
if (h > 0)
{
sr.sprite = tankSprite[1];
bulletEulerAngle = new Vector3(0.0.- 90.);
}
else if (h < 0)
{
sr.sprite = tankSprite[3];
bulletEulerAngle = new Vector3(0.0.90);
}
if (v > 0)
{
sr.sprite = tankSprite[0];
bulletEulerAngle = new Vector3(0.0.0);
}
else if (v < 0)
{
sr.sprite = tankSprite[2];
bulletEulerAngle = new Vector3(0.0.- 180.);
}
if (Mathf.Abs(v) > 0.05 f || Mathf.Abs(h) > 0.05 f)
{
moveAudio.clip = tankAudio[1];
moveAudio.volume = 0.1 f;
if (!moveAudio.isPlaying)
{
moveAudio.Play();
}
}
else
{
moveAudio.clip = tankAudio[0];
moveAudio.volume = 0.1 f;
if(! moveAudio.isPlaying) { moveAudio.Play(); } } transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); }private void Die()
{
if(! isDefended) { Instantiate(explosionPrefab, transform.position, transform.rotation); Destroy(gameObject); PlayerManager.Instance.isDead =true; PlayerManager.Instance.life--; }}}Copy the code
The enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float moveSpeed = 3;
public Sprite[] tankSprite;
public GameObject bulletPrefab;
public GameObject explosionPrefab;
private SpriteRenderer sr;
private Vector3 bulletEulerAngle;
private float attackTime;
private float turnDirectionTime;
private float v;
private float h;
// Start is called before the first frame update
private void Awake()
{
sr = GetComponent<SpriteRenderer>();
}
void Start(){}// Update is called once per frame
void Update()
{
if (attackTime >= 3)
{
Attack();
}
else{ attackTime += Time.deltaTime; }}private void FixedUpdate()
{
Move();
}
private void Attack()
{
Instantiate(bulletPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bulletEulerAngle));
attackTime = 0;
}
private void Move()
{
if (turnDirectionTime >= 4)
{
int randomDirection = Random.Range(0.8);
if (randomDirection >= 5)
{
v = - 1;
h = 0;
}
else if (randomDirection >= 3)
{
v = 0;
h = 1;
}
else if (randomDirection >= 1)
{
v = 0;
h = - 1;
}
else
{
v = - 1;
h = 0;
}
turnDirectionTime = 0;
}
else
{
turnDirectionTime += Time.deltaTime + 0.05 f;
}
if (h > 0)
{
sr.sprite = tankSprite[1];
bulletEulerAngle = new Vector3(0.0.- 90.);
}
else if (h < 0)
{
sr.sprite = tankSprite[3];
bulletEulerAngle = new Vector3(0.0.90);
}
if (v > 0)
{
sr.sprite = tankSprite[0];
bulletEulerAngle = new Vector3(0.0.0);
}
else if (v < 0)
{
sr.sprite = tankSprite[2];
bulletEulerAngle = new Vector3(0.0.- 180.);
}
transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);
transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);
}
private void Die()
{
Instantiate(explosionPrefab, transform.position, transform.rotation);
Destroy(gameObject);
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.transform.tag == "Enemy")
{
turnDirectionTime = 5; }}}Copy the code
5. Handle bullet logic
This is where you deal with the sound and effects of bullets hitting bricks, tanks, and steel
public class Bullet : MonoBehaviour
{
public float moveSpeed = 10;
public bool isPlayerBullet;
public AudioClip barriarAudio;
void Update()
{
transform.Translate(transform.up * moveSpeed * Time.deltaTime, Space.World);
}
private void OnTriggerEnter2D(Collider2D collision)
{
switch (collision.tag)
{
case "Tank":
if(! isPlayerBullet) { collision.SendMessage("Die");
Destroy(gameObject);
}
break;
case "Heart":
collision.SendMessage("Die");
Destroy(gameObject);
break;
case "Wall":
Destroy(collision.gameObject);
Destroy(gameObject);
break;
case "Enemy":
if (isPlayerBullet)
{
collision.SendMessage("Die");
Destroy(gameObject);
PlayerManager.Instance.score++;
PlayerManager.Instance.enemyNum--;
}
break;
case "Barriar":
if(isPlayerBullet)
{
AudioSource.PlayClipAtPoint(barriarAudio, transform.position);
}
Destroy(gameObject);
break;
default:
break; }}}Copy the code
6. Generate hometowns and handle game end logic
The game ends when the home is attacked
public class Heart : MonoBehaviour
{
private SpriteRenderer sr;
public Sprite brokenHeart;
public GameObject explosionPrefab;
public AudioClip dieAudio;
// Start is called before the first frame update
void Start()
{
sr = GetComponent<SpriteRenderer>();
}
private void Die()
{
AudioSource.PlayClipAtPoint(dieAudio, transform.position);
Instantiate(explosionPrefab, transform.position, transform.rotation);
sr.sprite = brokenHeart;
PlayerManager.Instance.isDefeat = true; }}Copy the code
The code is relatively simple, to achieve the most basic game logic, you can expand some tank weapons, such as rocket launcher, mines and other game props, to create your own tank war.