关于Unity的入门游戏飞机大战的开发(下)
开发思路:
1: 修改测试模式,去掉开始按钮方便开发,加入敌机的资源
2: 创建敌机 添加刚体,碰撞器组件,添加帧动画播放组件;
3: 创建敌机出现的队形;
4: 根据队形随机 生成我们的敌机,调整敌机的速度,和敌机出去后,删除;
5: 碰撞配置分组,TAG 标记不同对象, 刚体加上trigger;
6: 玩家被敌人击中,爆炸与恢复;
7: 子弹打死敌人后删除自己,敌人也要做爆炸;
8: 加上玩家得分的情况;
9: 打开menu主页, 做好GUI 适配
步骤一>>>>>>修改测试模式,去掉开始按钮方便开发,加入敌机的资源
1.把menu_root节点隐藏起来,在game_scene脚本里面的Start函数里直接调用on_start_click()函数,这样游戏就不用菜单的开始按钮触发,而是自己触发开始了,比较好调试。
2.在Resources文件夹下面的tex文件夹中,添加进敌机的资源(9种)和敌机爆炸的动画资源文件夹dead
步骤二>>>>>>创建敌机 添加刚体,碰撞器组件,添加帧动画播放组件
1.创建一个叫enemy_root的敌机空节点,作为Canvas节点的子节点。节点大小设置为0。
2.给enemy_root创建一个叫e1的Image子节点,把敌机e1的贴图拖进去,set native size,缩放设置为X为2,Y为2。
3.由于有很多敌机(8种)要添加碰撞形状和物理刚体组件,所以可以手动添加组件,也可以用脚本代码实现组件的添加,比较轻松。
4.创建一个叫enemy的脚本用来对每个敌机添加刚体和碰撞组件,以及对他们进行一些初始化,记得是先写好脚本再挂载到e1到e8下面,不然先挂载再写脚本这里会出错。
using UnityEngine;
using System.Collections;
using System; //用代码添加刚体组件和形状碰撞组件
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))] public class enemy : MonoBehaviour {
public int e_type; // 敌机的类型; private BoxCollider2D box;
private Rigidbody2D body; // Use this for initialization
void Start () { this.body = this.GetComponent<Rigidbody2D>();
this.box = this.GetComponent<BoxCollider2D>(); //设置敌机碰撞器的形状的大小
RectTransform r_trans = (RectTransform) this.transform;
r_trans.localScale = new Vector3(, , );//放大节点两倍
Vector2 size = r_trans.sizeDelta;//取出节点的大小 this.box.size = size;//设置好碰撞器大小
this.box.isTrigger = true; // 只做碰撞触发;只触发不产生碰撞效果
this.body.freezeRotation = true; // 不让他旋转;刚体不旋转
} // Update is called once per frame
void Update () { }
}
5.记得把Rigidbody2D组件的Is Trigger打钩,只做碰撞触发,其实不打钩也没事,在脚本里面有写。
6.给每个敌机创建一个节点,把自己的贴图拖进自己的贴图属性中,set native size,记得填写enemy脚本的公开属性E_type,第几个类型的就填第几编号。
7.由于等下要生成非常多的敌机,所以要把这些敌机设置成预制体,就在prefabs文件夹下面再创建一个叫enemies的文件夹,然后把e1到e8的敌机节点拖进enemies变成蓝色预制体,删除原来的e1到e8节点。
步骤三>>>>>>创建敌机出现的队形
1.开始排飞机的队形,在enemy_root下面创建一个group1的空子节点,然后把prefabs里面的前三个敌机预制体拖进group1,修改三个敌机的坐标位置,排成一排或者其他的。
2.排好之后先把这三台敌机取消预制体形态,还原成普通节点GameObject-->Break Prefab Instance,然后把整个group1拖进prefab文件夹里面当作一个预制体。
3.每次制作好预制体之后,都可以把原来的那个节点删除,这样重复制作组合大概5、6组就可以。
4.最后只剩一个enemy_root空节点,下面什么也没有。
步骤四>>>>>>根据队形随机 生成我们的敌机,调整敌机的速度,和敌机出去后,删除
我们首先是做了敌机的group,这个group下面可能有三驾敌机e1e2e3,每驾敌机都有相对于group相对偏移的位置pos1pos2pos3,接下来把所有的group都从一个很高很高的位置如(0,912,0)开始,当我们产生敌机的时候,把敌机的初始位置设置为(0,912,0)
保证了敌机可以从那个高度开始移动,接下来我们遍历每个group下面的孩子,有几个孩子就产生几个enemy,每个enemy的位置就是912+pos,这样再把新创建的enemy加到enemy_root空节点下面,这样我们就生成了一个group实例。所以我们在enemy_root下其实是不直接生成group实例,因为group里面的每一个enemy位置都是写死的,我们希望里面的每个敌机的位置是随机的。所以我们新产生一个enemy,位置等于grooup的初始位置912+每个敌机相对group的偏移位置pos。
1.有了队形之后就是怎么随机产生这些队形和移动这些队形,以及最后超出屏幕后删除的操作。
2.写一个脚本gen_enemy挂载在enemy_root节点下面实现第一点
3.打开gen_enemy脚本,其实里面对预制体的实例化并不是对group的实例化,而是对一个一个enemy敌机的实例化。
而且产生的飞机的位置也是随机的,队形是一个一个随机的,而且具体哪个位置哪台飞机是随机的。并不是我刚开始以为的对整个group进行实例化。如果那样的话位置和飞机就会对应,不灵活。
记得在enemy_root的Inspector面板里面把对应的属性绑定好,自己手动拖进去。
using UnityEngine;
using System.Collections;
using UnityEngine.UI; public class gen_enemy : MonoBehaviour {
public GameObject[] group_set; // 敌机组的集合
public GameObject[] enemy_set; // 敌机的集合 // Use this for initialization
void Start () {
}
public void start_gen_enemy() {
this.Invoke("gen_one_group", );
}
void gen_one_group() {
// [0, this.group_set.Length) 随机数,生成一个0到敌机组总数-1的随机数
int group_index = Random.Range(, this.group_set.Length); //设置一个初始位置,敌机组从这里生成并开始移动
Vector3 start_pos = new Vector3(, , ); // 循环遍历group下面的孩子数目;遍历随机到的那一个敌机组,遍历里面的每一个敌机
for (int i = ; i < this.group_set[group_index].transform.childCount; i++) { //生成一个0到敌机总数-1的随机数,随机取1到8敌机类型的一种类型
int e_type = Random.Range(, this.enemy_set.Length); //获得孩子的位置,获得当前指定敌机的位置
Transform group_enemy = this.group_set[group_index].transform.GetChild(i); // 随机的生成了一个敌人,开始随机生成一架敌机
GameObject e_item = GameObject.Instantiate(this.enemy_set[e_type]);
e_item.transform.SetParent(this.transform, false);
Vector3 pos = start_pos + group_enemy.localPosition;
e_item.transform.localPosition = pos;
} // [0.0, 3.0f]
this.Invoke("gen_one_group", + Random.Range(0.0f, 3.0f));
} // Update is called once per frame
void Update () { }
}
4.在enemy脚本中,由于每一个敌机我们给它一个向下的初速度,这个速度的设置是写在原来的enemy脚本中的Start函数里面
this.body.velocity = new Vector2(0, -8);
还要写实现敌机飞出屏幕后删除的代码,这个和子弹删除的原理是一样的
void Start () {
...
float scale = 640.0f / (float)Screen.width;
this.dead_line_y = -(Screen.height * scale * 0.5f + 100);
}
void Update () {
if (this.transform.localPosition.y < this.dead_line_y) {
MonoBehaviour.Destroy(this.gameObject);
}
}
5.在game_scene脚本中,为了开始生成敌机队列,首先要在里面的Start函数中获得enemy_root下的脚本
this.gen_enmey_ctrl = this.transform.Find("game_root/enemy_root").GetComponent<gen_enemy>();
然后在game_realy_started函数里面调用gen_enmey脚本里面的start_gen_enemy函数开始生成敌机
this.gen_enmey_ctrl.start_gen_enemy();//记得要在gen_enmey脚本中把start_gen_enemy函数的权限改为public才可以访问
步骤五>>>>>>碰撞配置分组,TAG 标记不同对象, 刚体加上trigger
1.给plane添加碰撞器形状组件,大小设置为飞机的大小128X128,为了准确也可以做一个多边形的Collider,那样就必须使用Polygon Collider 2D组件,然后编辑。
2.把Box Collider 2D的Is Trigger打钩,表示不发生碰撞效果,但是还是有碰撞响应。
3.编辑右上角的层,把游戏内的物体分成3个层,plane,plane_bullet,enemy,给每个节点这里设置plane节点及其子节点和resources/prefabs/enemies里面所以预制体和resources/prefabs/plane_bullet预制体都设置对应的层。
4.对每个层的碰撞情况进行编辑,Edit-->project Settings-->Physics 2D,在Layer Collision Matris碰撞矩阵里面编写打钩碰撞的情况,不打钩的意思是连碰撞响应都不发生。
5.编辑左上角的标记,把游戏内的物体进行标记,这里分成3个标记plane,plane_bullet,enemy,给每个节点和预制体都设置对应的标记,有了标记后面才能知道是谁和谁在碰撞。
步骤六>>>>>>玩家被敌人击中,爆炸与恢复
1.由于plane,plane_bullet,enemy的碰撞类型都是trigger,所以我们要在相应的脚本里面写Trigger的响应函数。
2.我们还需要一个帧动画的组件,在第22的文件里面,里面的frame_anim.cs,把它拷贝到项目的scripts文件夹下面
3.在飞机plane节点下面添加frame_anim.cs组件,因为飞机爆炸有7张图,属性size就写7,并把每一张爆炸图都拖进去。
4.在OnTriggerEnter2D函数里面调用frame_anim.cs的play_once函数,记得把play_once改成public才能调用,而且我们还要改写一下frame_anim.cs的函数play_once,使得它变成一个回调函数,这样爆炸结束的时候还能自动调用别的函数。
改写的frame_anim.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System; // 我们当前代码强制要求要加入一个Image组件,
// 如果没有Image组件,那么自动加上,如果有就使用;
// 如果你的代码要求这个节点必须挂某个组件,那么
// 使用RequireComponent
[RequireComponent(typeof(Image))] public class frame_anim : MonoBehaviour {
// 我们这个动画所需要的画面;
public Sprite[] sprite_frames;
// 帧动画的间隔时间
public float duration = 0.1f;
// 是否循环播放
public bool is_loop = false;
// 是否在加载的时候开始播放;
public bool play_onload = false; private float played_time;
private bool is_playing = false; private Image img;
Action end_func = null;//----补充----加一个结束的动作 // Use this for initialization
void Start () {
this.img = this.GetComponent<Image>();
if (this.play_onload) {
if (this.is_loop) {
this.play_loop();
}
else {
this.play_once(null);//----补充----改写成传递参数的调用
}
}
} // 只播放一次
public void play_once(Action end_func) {//----补充----改写成传递参数的调用
if (this.sprite_frames.Length <= ) {
return;
} this.end_func = end_func;//----补充----赋值 this.played_time = ;
this.is_playing = true;
this.is_loop = false;
} // 循环播放
void play_loop() {
if (this.sprite_frames.Length <= ) {
return;
}
this.played_time = ;
this.is_playing = true;
this.is_loop = true;
}
// 停止当前的动画播放
void stop_anim() {
this.is_playing = false;
}
// Update is called once per frame
void Update () {
if (this.is_playing == false) {
return;
} //
float dt = Time.deltaTime;
this.played_time += dt;
// 向下取整;
int index = (int)(this.played_time / this.duration);
if (this.is_loop == false) {
// 结束了
if (index >= this.sprite_frames.Length) { // 停止播放
this.is_playing = false;
this.played_time = ;
if (this.end_func != null) {//----补充----停止播放的时候执行结束函数
this.end_func();
}
}
else {
this.img.sprite = this.sprite_frames[index];
}
}
else {
// 超过了范围,减掉一个周期
while (index >= this.sprite_frames.Length) {
this.played_time -= (this.duration * this.sprite_frames.Length);
index -= this.sprite_frames.Length;
} this.img.sprite = this.sprite_frames[index];
}
// end
}
}
改写的plane.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI; //定义两个飞机的状态用来后面判断是否播放爆炸动画
enum State
{
NORMAL = ,
DEADED = ,
}; public class plane : MonoBehaviour
{
//播放帧动画要用的变量
private frame_anim bomb_anim;
public Sprite ship_idle;
private Image ship_icon;
private State state; //碰撞器
private BoxCollider2D box;
//飞机随着鼠标运动需要定义飞机坐标和鼠标坐标
Vector3 start_plane_pos; // 按钮按下的时候飞机的开始的坐标
Vector3 start_mouse_pos; // 鼠标开始的坐标; //子弹预制体
public GameObject bullet_prefab;//预制体子弹节点
public Transform bullet_root;//预制体子弹节点的父节点
public float shoot_rate = 0.2f; // 子弹发射的频率;我感觉是一个时间间隔,设定的子弹发射时间间隔
private float shoot_time = 0.0f; // 距离上一次发射过去的时间
private bool is_shooting = false;//是否处于发射子弹的状态 //-----优化-----
private bool is_touch = false;//是否点到飞机
private bool is_super = false;//是否处于无敌状态 // Use this for initialization
void Start()
{
//帧动画播放初始化
this.bomb_anim = this.transform.Find("anim").GetComponent<frame_anim>();
this.ship_icon = this.bomb_anim.GetComponent<Image>();
this.state = State.NORMAL; //获得碰撞器
this.box = this.GetComponent<BoxCollider2D>();
} public void start_game()
{
this.is_shooting = true; } void shoot_bullet()
{
//使用预制体生成一颗子弹
GameObject bullet = GameObject.Instantiate(this.bullet_prefab);
// 注意这个参数要使用false
bullet.transform.SetParent(this.bullet_root, false); //使用localPosition是因为子弹和plane都有相同的父节点,两者之间是相对坐标
Vector3 offset = new Vector3(, , );
bullet.transform.localPosition = this.transform.localPosition + offset;
} // 响应我们的鼠标事件,GetMouseButton(0)
void Update()
{
//鼠标按下的情况
if (Input.GetMouseButtonDown())
{
//-----修改-----
this.is_touch = false;//每次鼠标点下去,不管有没有点到飞机,初始化为没点到
Ray myRay = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机发出一条射线
RaycastHit2D hit = Physics2D.Raycast(new Vector2(myRay.origin.x, myRay.origin.y), Vector2.zero);//射线从鼠标点击屏幕的那个点出发,射到以当前点击位置为原点的坐标系中的垂直于(0,0)的位置,
//如果从3D的视角看就是摄像机的射线垂直射到Canvas上
if (hit.collider)//如果碰到有Collider2D组件的物体,就做一些事情
{
if (hit.transform.gameObject.name == "plane")//如果碰到的是飞机
{
//Debug.Log(hit.transform.name);//打印出碰撞到的节点的名字
this.is_touch = true;//点到飞机
}
} if (is_touch)//如果点到飞机
{
//获得鼠标的初始点击位置
this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//获得飞机的初始位置
this.start_plane_pos = this.transform.position;
}
} //鼠标滑动的情况
else if (Input.GetMouseButton() && this.is_touch)
{
Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//获得偏移量
Vector3 offset = w_pos - this.start_mouse_pos;
//设置飞机偏移后的位置
this.transform.position = this.start_plane_pos + offset;
} // 子弹发射逻辑控制,update里面嵌套自定义的update,自定义刷新函数
this.shoot_update(Time.deltaTime);
} void shoot_update(float dt)
{
if (!this.is_shooting)
{
return;
} this.shoot_time += dt;
if (this.shoot_time < this.shoot_rate)
{
return;
} this.shoot_time = ;
this.shoot_bullet();
} //写一个触发器来响应碰撞
void OnTriggerEnter2D(Collider2D c)
{
if (this.state == State.DEADED)
{
return;
} if (!is_super)//飞机不是超级状态
{
this.state = State.DEADED; this.box.enabled = false;// 把物理碰撞区域给隐藏,这样他就不会触发碰撞了。
this.is_shooting = false; // 不能发射子弹了 this.bomb_anim.play_once(this.on_bomb_anim_ended);//回调函数
}
} //写一个爆炸后调用的函数
void on_bomb_anim_ended()
{
//Debug.Log("on_bomb_anim_ended called");
this.bomb_anim.gameObject.SetActive(false);//把飞机的形状隐藏起来,不参与碰撞,也可以把刚体隐藏起来,也不参与碰撞
this.Invoke("plane_relive", 3.0f);
} //写一个爆炸后调用的函数的定时函数
void plane_relive()
{
this.state = State.NORMAL;
this.is_shooting = true;
this.shoot_time = ; this.ship_icon.sprite = this.ship_idle;//图像
this.bomb_anim.gameObject.SetActive(true);//把飞机的形状显示出来,参与碰撞
this.ship_icon.color = Color.red;//图像颜色变红
this.is_super = true;//设置为超级状态
this.box.enabled = true;//显示碰撞器
this.Invoke("enable_collider", 3.0f);// 允许3秒的无敌状态,3秒后再打开我们的碰撞无敌区域
} //写一个爆炸后调用的函数的定时函数的定时函数
void enable_collider()
{
this.is_super = false;//再设置回正常状态
this.ship_icon.color = Color.white;//图像颜色变原色
}
}
步骤七>>>>>>子弹打死敌人后删除自己,敌人也要做爆炸
1.由于子弹要在碰到敌机后马上删除,所以它自己也要写一个OnTriggerEnter2D的函数,在发生碰撞的时候调用,在plane_bullet.cs里面写OnTriggerEnter2D函数并直接Destroy自己的节点。
// 子弹如果碰到了敌机,那么马上删除;
void OnTriggerEnter2D(Collider2D c) {
MonoBehaviour.Destroy(this.gameObject);
}
2.由于敌机要在碰到子弹后自爆,所以它自己也要写一个OnTriggerEnter2D的函数,在发生碰撞的时候调用。
3.在敌机e1到e8预制节点下面分别添加frame_anim.cs组件,因为敌机爆炸有7张图,属性size就写7,并把每一张爆炸图都拖进去。
改写后的enemy.cs
using UnityEngine;
using System.Collections;
using System; //用代码添加刚体组件和形状碰撞组件
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))] public class enemy : MonoBehaviour {
//敌机爆炸所需要的变量
private frame_anim bomb_anim;
//委托
public event Action dead_event; //敌机的类型
public int e_type; private BoxCollider2D box;
private Rigidbody2D body;
private float dead_line_y; // Use this for initialization
void Start () { this.body = this.GetComponent<Rigidbody2D>();
this.box = this.GetComponent<BoxCollider2D>(); //设置敌机碰撞器的形状的大小
RectTransform r_trans = (RectTransform)this.transform;
r_trans.localScale = new Vector3(, , );//放大节点两倍
Vector2 size = r_trans.sizeDelta;//取出节点的大小 this.box.size = size;//设置好碰撞器大小
this.box.isTrigger = true;//只触发不产生碰撞效果
this.body.freezeRotation = true;//刚体不旋转
this.body.velocity = new Vector2(, -);//给敌机一个初始向下的速度 //敌机飞出屏幕后删除
float scale = 640.0f / (float)Screen.width;
this.dead_line_y = -(Screen.height * scale * 0.5f + ); //获得播放动画的组件
this.bomb_anim=this.GetComponent<frame_anim>(); } // Update is called once per frame
void Update () {
if (this.transform.localPosition.y < this.dead_line_y) {
MonoBehaviour.Destroy(this.gameObject);
}
} //写一个触发器来响应碰撞,碰到子弹后自爆,碰到飞机一点事情都没有
void OnTriggerEnter2D(Collider2D c) {
// 敌人碰到玩家的子弹,敌人碰到玩家,敌人不爆炸,玩家爆炸,敌人碰到子弹,敌人爆炸
if (!c.gameObject.tag.Equals("plane_bullet")) { // 飞机碰到玩家,玩家爆炸;
return;
}
// 敌机就不能有碰撞区域
this.box.enabled = false;
// 子弹打到敌人
this.bomb_anim.play_once(this.on_bomb_anim_end);
// end
} //写一个回调函数来等触发函数执行后来调用
void on_bomb_anim_end() {
this.dead_event(); // 触发事件
MonoBehaviour.Destroy(this.gameObject);
}
}
步骤八>>>>>>加上玩家得分的情况
1.我们需要一个统计分数的节点,我们在Canvas节点下面再创建一个空节点叫game_ui,Hierarchy视图中要放在game_root和menu_root之间。
2.把game_ui的节点大小设置为640X960,同时把菊花分开,让父亲有多大,孩子就有多大。
3.在tex文件夹下面创建一个美术字资源create-->Custom Font,把它的名字命名地和我们的字体资源一样的名字,是win_score.fontsettings。这个资源需要有个材质属性。于是我们创建一个字体材质create-->Material,名字命名地和字体资源的名字是一样的,叫win_score.mat。把材质的Shader设置为Mobile/Diffuse,然后把我们的原始字体资源win_score.png文件拖进去,再把材质球win_score.mat拖进刚才创建的Custom Font字体资源win_score.fontsettings。
4.我们还需要导入字模,在第24的文件夹里面,在Resources文件夹下面创建一个叫做Editor的文件夹,表示里面的东西是对Unity编辑器的扩展。然后把24里面的CreateFontEditor.cs脚本拷贝进去。
5.对win_score.fnt文件右键-->create-->CreateFBMFont,然后字模就导入进刚才的字体资源文件了,注意这里的文件是那个全是字的文件,不是我们刚才创建的win_score.fontsettings文件。
6.在game_ui节点下,创建一个Text类型的叫score的UI节点,把它的菊花设置为左上角对齐,然后设置具体坐标位置让它在左上角x,y(32,-32)
7.在enemy_root节点下的gen_enemy脚本里面写一个public的score对象属性,然后把刚才的score节点拖进去绑定。(绑定我的理解是:绑定不是赋值,而是引用,所以会同步发生变化)
8.字体颜色设置为白色,字体居中,把刚才我们创建的那个字体资源文件win_score.fontsettings拖进去Text组件的Character的Font属性中。
8.写一个事件委托,在enemy里面敌机爆炸的那个函数里面,触发事件,然后在gen_enemy脚本里面对事件进行响应,调用add_score函数,每次有事件发生就调用add_score函数。
改写后的gen_enemy脚本
using UnityEngine;
using System.Collections;
using UnityEngine.UI; public class gen_enemy : MonoBehaviour {
public GameObject[] group_set; // 分组的集合
public GameObject[] enemy_set; // 敌人的集合 //分数统计
public Text score;
int score_value; // Use this for initialization
void Start () {
this.score.text = "";
this.score_value = ;
} //开始生成敌机的函数
public void start_gen_enemy() {
this.score.text = "";
this.score_value = ;
this.Invoke("gen_one_group", );
}
void gen_one_group() {
// [0, this.group_set.Length) 随机数,生成一个0到敌机组总数-1的随机数
int group_index = Random.Range(, this.group_set.Length); //设置一个初始位置,敌机组从这里生成并开始移动
Vector3 start_pos = new Vector3(, , ); // 循环遍历group下面的孩子数目;遍历随机到的那一个敌机组,遍历里面的每一个敌机
for (int i = ; i < this.group_set[group_index].transform.childCount; i++) { //生成一个0到敌机总数-1的随机数,随机取1到8敌机类型的一种类型
int e_type = Random.Range(, this.enemy_set.Length); //获得孩子的位置,获得当前指定敌机的位置
Transform group_enemy = this.group_set[group_index].transform.GetChild(i); // 随机的生成了一个敌人,开始随机生成一架敌机
GameObject e_item = GameObject.Instantiate(this.enemy_set[e_type]);
e_item.transform.SetParent(this.transform, false);
Vector3 pos = start_pos + group_enemy.localPosition;
e_item.transform.localPosition = pos;
//-----非常重要的一句话-----这句话就是把委托和响应函数进行了关联
e_item.GetComponent<enemy>().dead_event += this.add_score; } // [0.0, 3.0f]
this.Invoke("gen_one_group", + Random.Range(0.0f, 3.0f));
} //增加分数的函数
void add_score() {
this.score_value ++;
this.score.text = "" + this.score_value;
} // Update is called once per frame
void Update () { }
}
改写后的enemy脚本在步骤7里面,上次写的超前了
步骤九>>>>>>打开menu主页, 做好GUI 适配
1.把步骤1里面的对menu_root的隐藏显示出来,打钩。再注释掉game_scene里面的Start函数的this.on_game_start_click();这样只有按了按钮之后才会真正地开始游戏。
2.把menu_root节点的菊花也是设置为最右下角那个图案,使得父节点怎么变化,子节点就怎么变化。
3.把menu_root节点下面的menu_bg背景图节点的菊花设置为正下方那个图案,使得它可以随着分辨率的变化而上下拉伸。
4.屏幕适配完成。
关于Unity的入门游戏飞机大战的开发(下)的更多相关文章
- 关于Unity的入门游戏飞机大战的开发(上)
每个组件都是一个类的实例,要获得某个组件,要先创建一个同类型的组件类实例,然后把实例传引用过去,就可以对想要的组件实例进行操作. 做游戏一般创建一个逻辑节点,里面只管逻辑,再创建一个动画节点,里面有好 ...
- unity案例入门(二)(坦克大战)
1. 案例简述 这个案例实现一个简单的坦克对战游戏,两个玩家在一个地图上PK. 2. 控制坦克移动 与案例一中小球的移动方式不同,坦克在横向上不能是平移,因此横向按键控制的应该是坦克旋转. publi ...
- iOS传感器集锦、飞机大战、开发调试工具、强制更新、Swift仿QQ空间头部等源码
iOS精选源码 飞机大作战 MUPhotoPreview -简单易用的图片浏览器 LLDebugTool是一款针对开发者和测试者的调试工具,它可以帮... 多个UIScrollView.UITable ...
- 微信demo小游戏:飞机大战从无到有
微信demo游戏飞机大战从无到有 现在创建新项目会默认给飞机大战的demo,这里给大家从基础开始讲解游戏的从无到有是怎么实现的. 具体实现步骤: 创建背景图->背景图运动起来->创建飞机并 ...
- Cocos2d-x 3.0final 终结者系列教程16-《微信飞机大战》实现
看到cocos2d-x推出了3.1版本号,真是每月一次新版本号,速度. 另一个好消息就是http://cn.cocos2d-x.org/上线了,祝贺!啥时候把我的视频和教程放上去呢?!! . 视频下载 ...
- 【Web前端Talk】无聊吗?写个【飞机大战】来玩吧(上篇)
01前言介绍 微信小游戏是基于微信客户端的游戏,它即点即玩,无需下载安装,体验轻便,可以和微信内的好友一起玩,比如PK.围观等,享受小游戏带来的乐趣.那如何开发一款属于自己的小游戏呢? 源码地址: h ...
- python飞机大战简单实现
小游戏飞机大战的简单代码实现: # 定义敌机类 class Enemy: def restart(self): # 重置敌机的位置和速度 self.x = random.randint(50, 400 ...
- 一、利用Python编写飞机大战游戏-面向对象设计思想
相信大家看到过网上很多关于飞机大战的项目,但是对其中的模块方法,以及使用和游戏工作原理都不了解,看的也是一脸懵逼,根本看不下去.下面我做个详细讲解,在做此游戏需要用到pygame模块,所以这一章先进行 ...
- 猜数字和飞机大战(Python零基础入门)
前言 最近有很多零基础初学者问我,有没有适合零基础学习案例,毕竟零基础入门的知识点是非常的枯燥乏味的,如果没有实现效果展示出来,感觉学习起来特别的累,今天就给大家介绍两个零基础入门的基础案例:猜数字游 ...
随机推荐
- C 标准库IO缓冲区和内核缓冲区的区别
1.C标准库的I/O缓冲区 UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也 ...
- shell 获取不同目录下指定文件,并把文件复制到一个文件夹下面
resource_dir=/tmp/jobs20170711/jobs/*/config.xmltarget_dir=/tmp/jobs20170711/bakefilelist=`ls $resou ...
- 自己动手写shell命令之write
Linux下write命令同意用户跟其它终端上的用户对话.用c语言实现shell命令write.代码例如以下: #include <stdio.h> #include <fcntl. ...
- 使用cat命令添加或附加多行文本
覆盖原有文本: cat>test<<EOF the 1 line the 2 line the 3 line EOF 追加的原有文本尾部: cat>>test<&l ...
- C# 使用Nlog记录日志到数据库
[摘要]Nlog是一个很不错的.NET日志记录组件,它可以将日志输出到控件台,保存到文本,也可以很方便的记录到数据库中.本文为你介绍C# 使用Nlog记录日志到数据库. Nlog是一个很不错的.NET ...
- iOS_20_微博Dock的尾随切换
终于效果图:Dock尾随HomeVC一起切换 要求: 当点击HomeVC里面的微博列表的某一行时候, push到StatusDetail微博详情控制器,而且Dock也一起消失 当点击StatusDet ...
- MD5加密 时间差 流水号等方法
/// <summary> /// 使用TimeSpan计算两个时间差 /// </summary> /// <param name="DateTime1&qu ...
- linq语法之select distinct Count Sum Min Max Avg
原文来自:http://www.50cms.com/Pages_13_72.aspx 本篇详细说明linq中的Select和Count/Sum/Min/Max/Avg等的用法. Select/Dist ...
- nyoj138 哈希的简单应用(查找)
找球号(二) 时间限制:1000 ms | 内存限制:65535 KB 难度:5 描述 在某一国度里流行着一种游戏.游戏规则为:现有一堆球中,每个球上都有一个整数编号i(0<=i<=1 ...
- hdoj1171 Big Event in HDU
Big Event in HDU Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...