版权声明:

  • 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号“优梦创客”(微信号:unitymaker)
  • 您可以自由转载,但必须加入完整的版权声明!

场景搭建

  1. 将第一关的3张背景图片收尾相接

按住V键可以选中4个角进行拖拽和拼接





  1. 给它们一个共同的碰撞器作为地面
  2. 给场景中的石头添加碰撞器
  3. 给木头平台添加平台效果器

预制体的制作

  1. 木桶预制体

    1. 设置碰撞器,刚体设置为静态
    2. 添加脚本和动画控制器



    3. 制作动画

    当木桶碰到子弹则修改木桶的sprite

    木桶有两滴血,当血量等于0的时候,播放闪烁的动画

  2. 敌人预制体

    1. 设置碰撞器和刚体
    2. 添加脚本和动画控制器



    3. 制作动画

    敌人碰到子弹后会播放死亡动画

    敌人每隔5秒之后会向前移动一段距离,如果碰到玩家则会发起攻击,如果没有碰到则再过5秒之后继续移动

    敌人只有出现在Camera内的时候才会移动,否则不进行移动计时

  3. 老人预制体

    1. 设置碰撞器、触发器和刚体
    2. 添加脚本和动画控制器



    3. 制作动画









    当老人在被绑住的时候碰到子弹,则被释放,播放释放动画

    当老人在被绑住的时候碰到玩家,玩家可以穿过它

    当老人被释放后碰到玩家,则会给玩家一个礼物,玩家吃掉礼物后会改变自身子弹的sprite

    当老人给完礼物后会穿过玩家跑走

  4. 敌机预制体

    1. 设置碰撞器和刚体
    2. 添加脚本和动画控制器



    3. 制作动画

    敌机在玩家走到某个位置时才会显示,并且追踪玩家的位置

    当与玩家的位置小于0.5时,会向下投放炸弹,若玩家被炸弹击中则游戏结束

    敌机有10滴血,若血量降到0,则播放爆炸动画,动画播放完成销毁敌机

  5. 子弹预制体

    1. 设置碰撞器和刚体
    2. 添加脚本和动画控制器

    利用对象池,在游戏开始的时候就创建10个子弹,每当玩家发出子弹则改变对象池中的某个子弹的位置

    当子弹位置离开玩家5个单位以上则会重置到开始位置

    若子弹碰到碰撞体之后子弹会被重置

  6. 炸弹预制体

    1. 设置碰撞器和刚体
    2. 添加脚本和动画控制器

Player的制作

  1. 将Body和Foot进行拼接,放在一个空节点下
  2. 创建一个空节点作为子弹的发出位置,并作为玩家的子节点
  3. 在Player脚下的碰撞器之外创建两个空节点作为射线检测的开始和结束位置用于检测是否落地



4. Player动画控制器的制作



5. Player移动的脚本实现

玩家的转身是通过旋转Y轴180°实现的

通过获取按键的数值,改变对象Y轴的旋转

Y轴的速度不能为0,不然跳不起来

Y轴的在空中或地上都要判断,而X轴的移动只能在地上才能取得

只有在地上的时候才能播放walk动画

跳跃的时候要将Walk的条件置为非,否则动画会在Jump和Walk之间来回切换

在下一帧才播放shoot动画,但子弹却在这一帧出现,有点违和

解决方法:将子弹出现的位置延后 并且将渲染关掉,当子弹的X轴位置大于人物X轴位置+1时,开启渲染

当蹲下射击的时候子弹的位置为player的位置(player的位置比bulletLeftRight靠下一点,刚好满足下蹲发射降低高度的需求)

void FixedUpdate()
{
if (!GameControl.instance.isGameOver)
{
x = Input.GetAxis("Horizontal");
y = Input.GetAxis("Vertical");
absx = Mathf.Abs(x); ground = Physics2D.Linecast(hitlinestart.position, hitlineend.position, 1 << this.gameObject.layer); //通过获取按键的数值,改变对象Y轴的旋转,除去0 是为了让player保持之前一个方向
if (x > 0 && ground)
transform.eulerAngles = new Vector3(0, 180, 0);
else if (x < 0 && ground)
transform.eulerAngles = Vector3.zero; playerDir = transform.eulerAngles.y == 0 ? -1 : 1;//判断人物方向有没有改变,取得子弹的方向 GetComponent<Rigidbody2D>().velocity = new Vector2(x * xspeed, GetComponent<Rigidbody2D>().velocity.y);//Y轴的速度不能为0,不然跳不起来 GetComponent<Animator>().SetFloat("DirY", y);//Y轴的在空中或地上都要判断,而X轴的移动只能在地上才能取得 if (ground)//只有在地上的时候才能播放walk动画
{
GetComponent<Animator>().SetFloat("DirX", absx);
//GetComponent<Animator>().SetFloat("DirY", y);
GetComponent<Animator>().SetBool("Jump", false); if (Input.GetKeyDown(KeyCode.K))//按了空格且在地上
{
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, yspeed));
GetComponent<Animator>().SetBool("Jump", true);
GetComponent<Animator>().SetFloat("DirX", 0);//跳跃的时候要将Walk的条件置为非,否则动画会在Jump和Walk之间来回切换
}
} if (Input.GetKeyDown(KeyCode.J) && ground)//播放射击动画的逻辑
{
GetComponent<Animator>().SetBool("Shoot", true); //在下一帧才播放shoot动画,但子弹却在这一帧出现,有点违和
//解决方法:将子弹出现的位置延后 ,并且将渲染关掉,当子弹的X轴位置大于人物X轴位置+1时,开启渲染 bullets[bulletIndex].GetComponent<SpriteRenderer>().enabled = false; bullets[bulletIndex].transform.position = bulletLeftRight.position; //子弹的出现位置
bullets[bulletIndex].transform.rotation = transform.rotation;//子弹的旋转跟人物的旋转一致
bullets[bulletIndex].GetComponent<Rigidbody2D>().velocity = new Vector2(playerDir * bulletSpeed, 0);//默认子弹的朝向跟人物一致,Y轴速度为0 if (Input.GetKey(KeyCode.W)) //按住上的同时按下J,向上射击
{
bullets[bulletIndex].transform.position = transform.position + Vector3.up + playerDir * Vector3.right;//修改子弹出现的位置
bullets[bulletIndex].transform.eulerAngles = new Vector3(0, 0, -90f);//旋转子弹的角度
bullets[bulletIndex].GetComponent<Rigidbody2D>().velocity = new Vector2(0, bulletSpeed);//给子弹一个向上的速度
}
else if (Input.GetKey(KeyCode.S)) //按住下的同时按下J,蹲下射击
{
bullets[bulletIndex].transform.position = transform.position;//子弹的位置为player的位置(player的位置比bulletLeftRight靠下一点,刚好满足下蹲发射降低高度的需求)
} bulletIndex++;
bulletIndex %= bullets.Length;
}
else if (!ground && Input.GetKeyDown(KeyCode.J) && Input.GetKey(KeyCode.W))//禁止玩家在空中左右射击
{
GetComponent<Animator>().SetBool("Shoot", true); //在下一帧才播放shoot动画,但子弹却在这一帧出现,有点违和
//解决方法:将子弹出现的位置延后,并且将渲染关掉,当子弹的X轴位置大于人物X轴位置+1时,开启渲染 bullets[bulletIndex].GetComponent<SpriteRenderer>().enabled = false; bullets[bulletIndex].transform.position = transform.position + Vector3.up + playerDir * Vector3.right;//修改子弹出现的位置
bullets[bulletIndex].transform.eulerAngles = new Vector3(0, 0, -90f);//旋转子弹的角度
bullets[bulletIndex].GetComponent<Rigidbody2D>().velocity = new Vector2(0, bulletSpeed);//给子弹一个向上的速度 bulletIndex++;
bulletIndex %= bullets.Length;
}
//将射击动画改为idel动画的条件,是子弹的位置跟人物位置距离超过5
if (bulletIndex >= 1)
{
if (Mathf.Abs(bullets[bulletIndex - 1].transform.position.x - transform.position.x) > 2)
GetComponent<Animator>().SetBool("Shoot", false);
}
else
{
if (Mathf.Abs(bullets[bullets.Length - 1].transform.position.x - transform.position.x) > 2)
GetComponent<Animator>().SetBool("Shoot", false);
}
} }

Car的制作

  1. 将图片按照顺序进行拼接
  2. 将拼接好的车子放到一个空节点,给这个空节点一个刚体用于给它速度



GameOver和Win的显示

  1. 添加两个Text的UI组件,Text的内容分别为GameOver和You Win
  2. 在玩家死亡或者胜利的时候enable对应的Text



摄像机移动的脚本实现

  1. 将摄像机的X轴控制在它自身到35之内,并随着玩家位置改变(保证摄像机不能往回走)
 camerax = Mathf.Clamp(player.transform.position.x, camerax > 0 ? camerax : 0, 35.5f*level);

 playerx = Mathf.Clamp(player.transform.position.x, camerax - 8f, camerax + 8f);//将玩家位置控制在摄像机范围之内(保证玩家不能往回走)

 player.transform.position = new Vector3(playerx, player.transform.position.y, player.transform.position.z);

 mainCamera.transform.position = new Vector3(camerax, mainCamera.transform.position.y, -10);

开场动画的实现

  1. 通过时间来控制Car的移动和停止
  2. 通过MovePosition来让玩家有一个从车上跳出的效果,且在站定之后转向
    private void JumpOutOfCar()//开场动画
{
if (car.position.x >= -0.01)
{
player.SetActive(true);
time += Time.fixedDeltaTime;
if (time < 0.4f)
{
player.GetComponent<Rigidbody2D>().MovePosition(Vector2.MoveTowards(player.transform.position, new Vector2(-3f, 0f), 3.5f * Time.fixedDeltaTime));//人物跳起移动
}
else if (time > 0.4f && time < 1f)
{
player.GetComponent<Rigidbody2D>().MovePosition(Vector2.MoveTowards(player.transform.position, new Vector2(-4f, -1.65f), 3.5f * Time.fixedDeltaTime));//人物下落移动
}
else if (time > 1.5f)
{
player.transform.rotation = new Quaternion(0, 180, 0, 0);//人物转向
}
} }

敌机追踪玩家的脚本实现

  1. 判断玩家的位置是在Jet的左边还是右边,且向玩家位置移动
  2. 当与玩家位置小于0.5则扔炸弹
  3. 若血量为0 ,则在播放完成爆炸后销毁Jet
    void FixedUpdate()
{
trax = Mathf.Clamp(transform.position.x,29f,42f);
transform.position = new Vector3(trax, transform.position.y, 0); if (GameControl.instance.mainCamera.transform.position.x > 35)//摄像机的位置控制直升机的出现
GetComponent<SpriteRenderer>().enabled = true;
if(GetComponent<SpriteRenderer>().enabled == true&&hp>0)
{
if(transform.position.x > GameControl.instance.player.transform.position.x+0.5)
{
transform.eulerAngles = new Vector3(0, 0, 0);
GetComponent<Rigidbody2D>().velocity = 2*Vector2.left;
}
else if(transform.position.x < GameControl.instance.player.transform.position.x-0.5)
{
transform.eulerAngles = new Vector3(0, 180, 0);
GetComponent<Rigidbody2D>().velocity = 2 * Vector2.right;
}
else
{
GetComponent<Rigidbody2D>().velocity = Vector2.zero;
if(!boomAlive)
{
Instantiate(jetBullet, transform.position + Vector3.down, Quaternion.identity);
boomAlive = true;
}
}
}
else
GetComponent<Rigidbody2D>().velocity = Vector2.zero; if (hp == 0)
{
GetComponent<Animator>().SetBool("Explosion", true);
Invoke("DestroyThis", 3f);
Invoke("SetGameWin",3f);
} }

Older给礼物和被释放的脚本实现

  1. 老人被释放后如果不持续施加速度,那么速度会因为摩擦力而衰减,最后导致速度为0
  2. 在没被释放之前,把older的碰撞器改为触发器,使玩家可以穿过older
  3. 在没被释放之前,玩家可以穿过older,玩家离开碰撞器后还把该碰撞器改回去
    void FixedUpdate()
{
if(isRelease)
{ time += Time.fixedDeltaTime;
if (time >= 1f && time <=6f&&!isGiving)
{
GetComponent<Animator>().SetBool("run", true);
GetComponent<Rigidbody2D>().velocity = new Vector2(-4f, GetComponent<Rigidbody2D>().velocity.y);
} else if (time > 6)
Destroy(this.gameObject);
}
} public void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Bullet")
{
isRelease = true;
GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
GetComponent<Animator>().SetBool("release", true);
}
if (collision.gameObject.tag == "Player" && !isGift&&isRelease)
{
isGift = true;//防止多次给礼物
isGiving = true;//防止给礼物时还在移动
GetComponent<Rigidbody2D>().velocity = Vector2.zero;
GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
collision.gameObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
GetComponent<Animator>().SetBool("give", true); Invoke("GiveOver", 1f);
}
else if (collision.gameObject.tag == "Player"&& !isRelease)
{//
GetComponent<BoxCollider2D>().isTrigger = true;
}
}
public void OnTriggerExit2D(Collider2D collision)
{ if (collision.gameObject.tag == "Player")
{
if (isRelease)
{
GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
collision.gameObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
}
else
{//
GetComponent<BoxCollider2D>().isTrigger = false ;
} }
} private void GiveOver()
{
isGiving = false;
GetComponent<Animator>().SetBool("give", false); Instantiate(gift, transform.position + Vector3.right, Quaternion.identity);
}

Unity经典游戏教程之:合金弹头的更多相关文章

  1. Unity经典游戏教程之:雪人兄弟

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  2. Unity经典游戏教程之:贪吃蛇

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  3. Unity经典游戏教程之:是男人就下100层

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  4. Unity经典游戏教程之:冒险岛

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  5. Unity经典游戏教程之:弓之骑士

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  6. Unity经典游戏编程之:球球大作战

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  7. C#开发Unity游戏教程之Unity中方法的参数

    C#开发Unity游戏教程之Unity中方法的参数 Unity的方法的参数 出现在脚本中的方法,无论是在定义的时候,还是使用的时候,后面都跟着一对括号“( )”,有意义吗?看起来最多也就是起个快速识别 ...

  8. C#开发Unity游戏教程之Scene视图与脚本的使用

    C#开发Unity游戏教程之Scene视图与脚本的使用 Unity中Scene视图的快捷操作 Scene视图是开发者开发游戏时,操作最频繁的视图.因为一旦一个游戏对象被添加到游戏的场景中,就需要首先使 ...

  9. Unity实战案例教程之:不免费的PacMan(初级→中级)

    课程内容介绍: 本套课程适合以下人士: - 免费资料没教会你游戏开发的: - 学了Unity基础不知道怎么用在游戏项目里的: - 想快速开发一款好玩的游戏的: - 想学游戏不知道如何入门的: - 对游 ...

随机推荐

  1. Jenkins Email Extension插件模板

    Jenkins Email Extension插件模板 <!DOCTYPE html> <html> <head> <meta charset="U ...

  2. 设计模式-观察者模式(Observer)

    观察者模式是行为模式的一种,它的作用是当一个对象的状态发生变化时,能够自动通知关联对象,自动刷新对象状态. 观察者模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步. ...

  3. Spring的<context:annotation-config>和<annotation-driven>

    <context:annotation-config>  相对于注册 AutowiredAnnotationBeanPostProcessor.CommonAnnotationBeanPo ...

  4. Touch Bar 废物利用系列 | 在触控栏上显示 Dock 应用图标

    都说 Intel 第八代 CPU 对比上代是牙膏不小心挤多了,而配备第八代 CPU 的 MacBook Pro,只有 Touch Bar 版本,虽然贵了一点,但就一个字 -- 买! 收到电脑后,兴冲冲 ...

  5. Android开发-百度地图之电子围栏

    功能实现:根据经纬度创建一个坐标,判断该坐标是否在指定圆形覆盖范围内 两个计算方法,直接套用: /** * 地球半径 */private static double EARTH_RADIUS = 63 ...

  6. EnjoyingSoft之Mule ESB开发教程系列第五篇:控制消息的流向-数据路由

    目录 1. 使用场景 2. 基于消息头的路由 2.1 使用JSON提交订单的消息 2.2 使用XML提交订单的消息 2.3 使用Choice组件判断订单格式 3. 基于消息内容的路由 4. 其他控制流 ...

  7. sql server 2008 NULL值

    SQL支持用NULL符号来表示缺少的值,它使用的是三值谓词逻辑,计算结果可是以TURE.FALSE或UNKNOWN. SQL中不同语言元素处理NULL和UNKNOWN的方式也有所不同,如果逻辑表达式只 ...

  8. 【题解】P2916 [USACO08NOV]安慰奶牛Cheering up the Cow-C++

    原题传送门 这道题用最小生成树来完成,我选用的是kruskal(克鲁斯卡尔)来完成.这道题目在克鲁斯卡尔模板的基础上,有变动的地方只有2处:1.因为必须从一个点出发,而最小生成树最后会让所有点都连通, ...

  9. python安装及typora使用

    第一章 环境搭建 1.1Python安装 1.1.1python官网www.python.org 1.1.2根据电脑系统选择下载 1.1.3确定电脑系统属性,此处我们以win10的64位操作系统为例 ...

  10. 个人永久性免费-Excel催化剂功能第62波-单元格区域内数据加解密处理,最有效地保护数据方式

    Excel的数据保护能力有限,诸如之前提及过的工作表保护.工作薄保护等,都是十分微弱的保护措施,而对于强保护的工作薄打开密码来说,它像是个总开关一样,要么全不能看,要么就全看到.有这样的场景需求,一份 ...