Unity combat UFO game
overall description
Use unity to realize a simple flying saucer game, and score when you hit the corresponding target. There are five arrows in one game.
Design ideas
The UML diagram is as follows
Define components
-
bow and arrow
Consists of two parts: the arrowhead and the arrow body.
The arrow is a relatively small capsule that mounts the collider. The arrow body is a free material downloaded from the Assets Store
-
target
Consisting of five concentric cylinders with different heights, each cylinder is mounted
RingData
and corresponds to a different score
Code
CCShootAction
: Implement the launch event of the arrow
public class CCShootAction : SSAction
{
Vector3 force;
Vector3 wind;
private CCShootAction(){}
// Start is called before the first frame update
public override void Start()
{
gameObject.transform.parent = null;
gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
// force = new Vector3(0, 0, 30);
// Impulse:向此刚体添加瞬时力冲击,考虑其质量。
gameObject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().AddForce(wind, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().isKinematic = false;
}
// Update is called once per frame
public override void Update()
{
}
public override void FixedUpdate(){
// 箭飞到场外或者中靶
if(this.transform.position.z > 35 || this.transform.tag == "onTarget"){
Debug.Log("回调");
this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this, SSActionEventType.Completed, 0, null, gameObject);
}
}
public static CCShootAction GetSSAction(Vector3 wind){
CCShootAction shoot = CreateInstance<CCShootAction>();
shoot.force = new Vector3(0, 0, 40);
shoot.wind = wind;
return shoot;
}
}
CCShootActionManager
: Realize archery action management
public class CCShootActionManager : SSActionManager
{
public FirstController firstController;
public CCShootAction shoot;
// Start is called before the first frame update
protected void Start()
{
firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
firstController.actionManager = this;
}
public void Shoot(GameObject arrow, Vector3 wind){
Debug.Log("Shoot");
shoot = CCShootAction.GetSSAction(wind);
this.RunAction(arrow, shoot, this);
}
}
TrembleAction
: The trembling action after the arrow hits, called in the callback function
public class TrembleAction : SSAction
{
float tremble_radius = 0.05f;
float tremble_time = 0.5f;
GameObject arrow;
Vector3 arrow_pos;
private TrembleAction(){}
public static TrembleAction GetSSAction()
{
TrembleAction tremble_action = CreateInstance<TrembleAction>();
return tremble_action;
}
// Start is called before the first frame update
public override void Start()
{
//得到箭中靶时的位置
arrow_pos = gameObject.transform.position;
// this.transform.Translate(new Vector3(0, 0, 0.5f));
Debug.Log(gameObject.transform.name);
}
// Update is called once per frame
public override void Update()
{
tremble_time -= Time.deltaTime;
//需要继续颤抖
if(tremble_time > 0){
// gameObject.transform.Translate(new Vector3(0.02f, 0, 0));
Vector3 head_pos = gameObject.transform.position;
float x = arrow_pos.x + Random.RandomRange(-0.05f, 0.05f);
float y = arrow_pos.y + Random.RandomRange(-0.05f, 0.05f);
float z = arrow_pos.z;
gameObject.transform.position = new Vector3(x, y, z);
}
else{
gameObject.transform.position = arrow_pos;
}
// else{
// transform.position = arrow_pos;
// this.destroy = true;
// this.callback.SSActionEvent(this);
// }
}
}
Specific application SSActionManager
in
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Completed,
int intParam = 0,
string strParam = null,
GameObject arrow = null){
TrembleAction trembleAction = TrembleAction.GetSSAction();
this.RunAction(arrow, trembleAction, this);
}
ArrowFactory
: Arrow factory, used to produce and release bows and arrows
public class ArrowFactory : MonoBehaviour
{
private List<GameObject> used;
private List<GameObject> free;
public GameObject arrow;
FirstController firstController;
// Start is called before the first frame update
void Start()
{
firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
used = new List<GameObject>();
free = new List<GameObject>();
arrow = null;
}
// Update is called once per frame
void Update()
{
}
public GameObject GetArrow(){
if(free.Count > 0){
arrow = free[0];
free.Remove(free[0]);
if(arrow.tag == "onTarget")//箭在靶子上
{
arrow.GetComponent<Rigidbody>().isKinematic = false;
arrow.tag = "arrow";
arrow.transform.GetChild(0).gameObject.SetActive(true);
}
arrow.SetActive(true);
}
else{
arrow = Instantiate(Resources.Load<GameObject>("Prefabs/arrow1"));
arrow.GetComponent<Rigidbody>().isKinematic = false;
// arrow.AddComponent<Rigidbody>();
}
// firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
// Transform pos = firstController.bow.transform.GetChild(0);
// arrow.transform.position = pos.transform.position;
arrow.transform.parent = firstController.bow.transform; // 把arrow附加在bow上,跟随着bow移动
arrow.transform.position = firstController.bow.transform.position;
used.Add(arrow);
return arrow;
}
public void FreeArrow(GameObject arrow){
foreach(GameObject aa in used){
Debug.Log("befreed");
if(aa.gameObject.GetInstanceID() == arrow.GetInstanceID()){
arrow.SetActive(false);
used.Remove(aa);
aa.tag = "arrow";
break;
}
}
}
public void Clear(){
foreach(GameObject dd in used){
dd.transform.position = new Vector3(0, 0, 100);
Destroy(dd);
}
foreach(GameObject dd in free){
dd.transform.position = new Vector3(0, 0, 100);
Destroy(dd);
}
used.Clear();
free.Clear();
}
}
RingData
: Mounted on each ring, used to define the scores of different rings
public class RingData : MonoBehaviour {
public int score;
public void Start(){
if(this.gameObject.name=="1"){
score = 5;
}
else if(this.gameObject.name=="2"){
score = 4;
}
else if(this.gameObject.name=="3"){
score = 3;
}
else if(this.gameObject.name=="4"){
score = 2;
}
else{
score = 1;
}
}
}
RingController
: Control ring impact events, scoring, callback trembling action
public class RingController : MonoBehaviour
{
public ScoreRecorder scoreRecorder;
public ISceneController sceneController;
// Start is called before the first frame update
void Start()
{
sceneController = SSDirector.GetInstance().CurrentScenceController as FirstController;
scoreRecorder = Singleton<ScoreRecorder>.Instance;
this.gameObject.AddComponent<RingData>();
}
// Update is called once per frame
void OnTriggerEnter(Collider arrowCollider){
Debug.Log("碰撞!");
Transform arrow = arrowCollider.gameObject.transform.parent;
Debug.Log(arrow.gameObject.name);
if(arrow == null){
Debug.Log("null");
return;
}
scoreRecorder.RecordScore(this.gameObject.GetComponent<RingData>().score);
Debug.Log("Score:"+this.gameObject.GetComponent<RingData>().score);
arrow.GetComponent<Rigidbody>().isKinematic = true;
arrow.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
arrowCollider.gameObject.SetActive(false);
arrow.tag = "onTarget";
}
}