Unity 4.3 制作一个2D横版射击游戏

标签: unity 2d
62029人阅读 评论(31) 收藏 举报
分类:
       这是一个横版射击游戏。教程来自:http://pixelnest.io/tutorials/2d-game-unity/ 中文版教程:http://www.litpo.com/category/易学的教程/
教程文章已经详细地介绍实现过程,这里就不再复述,只做一些简单的笔记记录,以供备忘。

1.创建第一个场景

新建工程。接着在"Project"面板上创建如下文件夹:

接着在"Hierarchy"面板上创建多个空对象,形成以下结构:

这些空对象的Position保持为(0, 0, 0)即可。保存场景,名称为"Stage1"。

2.添加显示背景

将背景图片放入"Textures"文件夹,确认这张图片的纹理类型,即"Texture Type"属性为"Sprite",如下图所示:

在场景中添加一个Sprite游戏对象,设置其"Sprite"属性为刚才导入的背景图片。重命名这个对象为"Background1",将其移动到"Level -> 0 - Background"里面,设置其"Position"为(0, 0, 0)。接着添加背景元素。导入平台图片到"Textures"文件夹,选中"platforms"图片,设置其"Sprite Mode"为"Multiple",然后点击"Sprite Editor",如下图所示:

在弹出的"Sprite Editor"窗口中,进行绘制每个平台的包围矩形,以便将纹理分割成更小的部分。然后分别命名为"platform1"和"platform2",如下图所示:

创建一个新的Sprite游戏对象,设置其"Sprite"属性为"platform1"。再在创建新Sprite对象,设置其"Sprite"属性为"platform2"。将它们放置到"1 - Middleground"对象里,并且确认它们的Z坐标为0。将这两个对象从"Hierarchy"面板拖动到"Project"面板下的"Prefabs"文件夹,保存成预制对象。接着,为了避免显示顺序问题,修改下游戏对象的Z坐标,如下所示:
Layer Z Position
0 - Background 10
1 - Middleground 5
2 - Foreground 0
此时,点击"Scene"面板上的2D到3D视图切换,可以清楚看到层次:

3.创建主角和敌人

导入主角图片"Textures"文件夹,创建一个Sprite游戏对象,命名为"Player",设置其"Sprite"属性为刚才导入的主角图片。将此对象放入"2 - Foreground"层里,设置其Scale(0.2, 0.2, 1)。接着,为主角添加盒碰撞体组件,点击"Add Component"按钮,选择"Box Collider 2D",设置其Size(10, 10),虽然这还是大于实际的区域,但已比图片小多了,如下图所示:

(可以通过按住Shift键,来调整绿色碰撞范围)
接着,再为主角对象添加"Rigidbody 2D"刚体组件,现在运行可以看到如下结果:

可以看到主角往下落了,这是因为刚体带有重力,但在这个游戏不需要用到,将"Gravity Scale"属性设为0即可。另外,不想因为物理而引起的主角旋转,则将"Fixed Angles"属性勾选上。完整的设置如下图所示:

开始准备让主角移动。在"Scripts"文件夹里,创建一个C#脚本,名称为"PlayerScript",实现让方向键移动主角,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using UnityEngine;

/// <summary>
/// Player controller and behavior
/// </summary>
public class PlayerScript : MonoBehaviour
{
  /// <summary>
  /// 1 - The speed of the ship
  /// </summary>
  public Vector2 speed = new Vector2(5050);

  // 2 - Store the movement
  private Vector2 movement;

  void Update()
  {
    // 3 - Retrieve axis information
    float inputX = Input.GetAxis("Horizontal");
    float inputY = Input.GetAxis("Vertical");

    // 4 - Movement per direction
    movement = new Vector2(
      speed.x * inputX,
      speed.y * inputY);

  }

  void FixedUpdate()
  {
    // 5 - Move the game object
    rigidbody2D.velocity = movement;
  }
}
这里以改变刚体的速率来达到主角的移动,而不是通过直接改变"transform.Translate",因为那样的话,可能会不产生碰撞。将此脚本附加到主角对象上,现在运行,方向键来控制移动,如下图所示:


接下来,添加第一个敌人。导入章鱼敌人图片到"Textures"文件夹,创建一个Sprite游戏对象,命名为"Poulpi",设置其"Sprite"属性为刚才导入的图片,设置"Scale"属性为(0.4, 0.4, 1),添加"Box Collider 2D"组件,其Size为(4, 4),添加"Rigidbody 2D"组件,其"Gravity Scale"属性为0,并且勾选"Fixed Angles"属性框。将对象保存为预制。在这里只让章鱼简单地往前行,创建一个脚本,命名为"MoveScript",代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using UnityEngine;

/// <summary>
/// Simply moves the current game object
/// </summary>
public class MoveScript : MonoBehaviour
{
  // 1 - Designer variables

  /// <summary>
  /// Object speed
  /// </summary>
  public Vector2 speed = new Vector2(1010);

  /// <summary>
  /// Moving direction
  /// </summary>
  public Vector2 direction = new Vector2(-10);

  private Vector2 movement;

  void Update()
  {
    // 2 - Movement
    movement = new Vector2(
      speed.x * direction.x,
      speed.y * direction.y);
  }

  void FixedUpdate()
  {
    // Apply movement to the rigidbody
    rigidbody2D.velocity = movement;
  }
}
将此脚本附加到章鱼对象上,现在运行,可以看到章鱼往前移动,如下图所示:


此时如果将主角放在章鱼前面,两个对象将会产生碰撞,互相阻塞对方的移动。

4.射击

导入子弹图片"Textures"文件夹,创建一个Sprite游戏对象,命名为"PlayerShot",设置其"Sprite"属性为刚才导入的图片,设置"Scale"属性为(0.75, 0.75, 1),添加"Rigidbody 2D"组件,其"Gravity Scale"属性为0,并且勾选"Fixed Angles"属性框,添加"Box Collider 2D"组件,其Size为(1, 1),并且勾选"IsTrigger"属性。勾选"IsTrigger"属性表示该碰撞体用于触发事件,并将被物理引擎所忽略。意味着,子弹将穿过触碰到的对象,而不会阻碍对象的移动,触碰的时候将会引发"OnTriggerEnter2D"事件。创建一个脚本,命名为"ShotScript",代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using UnityEngine;

/// <summary>
/// Projectile behavior
/// </summary>
public class ShotScript : MonoBehaviour
{
  // 1 - Designer variables

  /// <summary>
  /// Damage inflicted
  /// </summary>
  public int damage = 1;

  /// <summary>
  /// Projectile damage player or enemies?
  /// </summary>
  public bool isEnemyShot = false;

  void Start()
  {
    // 2 - Limited time to live to avoid any leak
    Destroy(gameObject, 20); // 20sec
  }
}
将此脚本附加到子弹对象上,然后将"MoveScript"脚本也附加到子弹对象上以便可以移动。保存此对象为预制。接着,让碰撞产生伤害效果。创建一个脚本,命名为"HealthScript",代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using UnityEngine;

/// <summary>
/// Handle hitpoints and damages
/// </summary>
public class HealthScript : MonoBehaviour
{
  /// <summary>
  /// Total hitpoints
  /// </summary>
  public int hp = 1;

  /// <summary>
  /// Enemy or player?
  /// </summary>
  public bool isEnemy = true;

  /// <summary>
  /// Inflicts damage and check if the object should be destroyed
  /// </summary>
  /// <param name="damageCount"></param>
  public void Damage(int damageCount)
  {
    hp -= damageCount;

    if (hp <= 0)
    {
      // Dead!
      Destroy(gameObject);
    }
  }

  void OnTriggerEnter2D(Collider2D otherCollider)
  {
    // Is this a shot?
    ShotScript shot = otherCollider.gameObject.GetComponent<ShotScript>();
    if (shot != null)
    {
      // Avoid friendly fire
      if (shot.isEnemyShot != isEnemy)
      {
        Damage(shot.damage);

        // Destroy the shot
        Destroy(shot.gameObject); // Remember to always target the game object, otherwise you will just remove the script
      }
    }
  }
}
将此脚本附加到Poulpi预制体上。现在运行,让子弹和章鱼碰撞,可以看到如下结果:


如果章鱼的生命值大于子弹的伤害值,那么章鱼就不会被消灭,可以试着通过改变章鱼对象的"HealthScript"的hp值。接着,准备可以射击。创建一个脚本,命名为"WeaponScript",代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using UnityEngine;

/// <summary>
/// Launch projectile
/// </summary>
public class WeaponScript : MonoBehaviour
{
  //--------------------------------
  // 1 - Designer variables
  //--------------------------------

  /// <summary>
  /// Projectile prefab for shooting
  /// </summary>
  public Transform shotPrefab;

  /// <summary>
  /// Cooldown in seconds between two shots
  /// </summary>
  public float shootingRate = 0.25f;

  //--------------------------------
  // 2 - Cooldown
  //--------------------------------

  private float shootCooldown;

  void Start()
  {
    shootCooldown = 0f;
  }

  void Update()
  {
    if (shootCooldown > 0)
    {
      shootCooldown -= Time.deltaTime;
    }
  }

  //--------------------------------
  // 3 - Shooting from another script
  //--------------------------------

  /// <summary>
  /// Create a new projectile if possible
  /// </summary>
  public void Attack(bool isEnemy)
  {
    if (CanAttack)
    {
      shootCooldown = shootingRate;

      // Create a new shot
      var shotTransform = Instantiate(shotPrefab) as Transform;

      // Assign position
      shotTransform.position = transform.position;

      // The is enemy property
      ShotScript shot = shotTransform.gameObject.GetComponent<ShotScript>();
      if (shot != null)
      {
        shot.isEnemyShot = isEnemy;
      }

      // Make the weapon shot always towards it
      MoveScript move = shotTransform.gameObject.GetComponent<MoveScript>();
      if (move != null)
      {
        move.direction = this.transform.right; // towards in 2D space is the right of the sprite
      }
    }
  }

  /// <summary>
  /// Is the weapon ready to create a new projectile?
  /// </summary>
  public bool CanAttack
  {
    get
    {
      return shootCooldown <= 0f;
    }
  }
}
将这个脚本附加到主角对象上,设置其"Shot Prefab"属性为"PlayerShot"预制体。打开"PlayerScript"脚本,在Update()方法里面,加入以下片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Update()
  {
    // ...

    // 5 - Shooting
    bool shoot = Input.GetButtonDown("Fire1");
    shoot |= Input.GetButtonDown("Fire2");
    // Careful: For Mac users, ctrl + arrow is a bad idea

    if (shoot)
    {
      WeaponScript weapon = GetComponent<WeaponScript>();
      if (weapon != null)
      {
        // false because the player is not an enemy
        weapon.Attack(false);
      }
    }

    // ...
  }
当收到射击的按钮状态,调用Attack(false)方法。现在运行,可以看到如下结果:


接下来,准备创建敌人的子弹。导入敌人子弹图片"Textures"文件夹,选中"PlayerShot"预制体,按下Ctrl+D进行复制,命名为"EnemyShot1",然后改变其Sprite为刚才导入的图片,设置其Scale(0.35, 0.35, 1)。接着,让章鱼可以射击。将"WeaponScript"脚本附加到章鱼对象上,拖动"EnemyShot1"预制体到其"Shot Prefab"属性,创建一个脚本,命名为"EnemyScript",用来简单地每一帧进行自动射击,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using UnityEngine;

/// <summary>
/// Enemy generic behavior
/// </summary>
public class EnemyScript : MonoBehaviour
{
  private WeaponScript weapon;

  void Awake()
  {
    // Retrieve the weapon only once
    weapon = GetComponent<WeaponScript>();
  }

  void Update()
  {
    // Auto-fire
    if (weapon != null && weapon.CanAttack)
    {
      weapon.Attack(true);
    }
  }
}
将此脚本附加到章鱼对象上,如下图所示:

现在运行,可以看到如下结果:


可以看到章鱼向右射击了子弹,这是因为代码就是让它那么做的。实际上,应该做到可以朝向任何方向射击子弹。在这里,创建一个空对象,命名为"WeaponObject",删除章鱼预制体身上的"WeaponScript"脚本,将"WeaponScript"脚本附加到"WeaponObject"对象上,并且拖动"EnemyShot1"预制体到其"Shot Prefab"属性,设置"WeaponObject"对象的"Rotation"属性为(0, 0, 180),然后保存为预制,如下所示:
接着,修改"EnemyScript",代码为如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Enemy generic behavior
/// </summary>
public class EnemyScript : MonoBehaviour
{
  private WeaponScript[] weapons;

  void Awake()
  {
    // Retrieve the weapon only once
    weapons = GetComponentsInChildren<WeaponScript>();
  }

  void Update()
  {
    foreach (WeaponScript weapon in weapons)
    {
      // Auto-fire
      if (weapon != null && weapon.CanAttack)
      {
        weapon.Attack(true);
      }
    }
  }
}
可以适当调整子弹的移动速度,它应该快于章鱼的移动速度。现在运行,如下图所示:


按这种方式,可以轻易实现多个方向的射击。复制添加一个"WeaponObject"对象,让这两个"WeaponObject"对象的旋转不同即可。现在主角被章鱼攻击到,但是没有任何伤害。将"HealthScript"脚本附加到主角对象上,确保"Is Enemy"属性不被勾选。现在运行,可以看到如下结果:


目前,当主角和章鱼碰撞时,仅仅只是阻碍对方的移动而已,在这里改成互相受到伤害。打开"PlayerScript"文件,添加如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//PlayerScript.cs
//....

void OnCollisionEnter2D(Collision2D collision)
  {
    bool damagePlayer = false;

    // Collision with enemy
    EnemyScript enemy = collision.gameObject.GetComponent<EnemyScript>();
    if (enemy != null)
    {
      // Kill the enemy
      HealthScript enemyHealth = enemy.GetComponent<HealthScript>();
      if (enemyHealth != null) enemyHealth.Damage(enemyHealth.hp);

      damagePlayer = true;
    }

    // Damage the player
    if (damagePlayer)
    {
      HealthScript playerHealth = this.GetComponent<HealthScript>();
      if (playerHealth != null) playerHealth.Damage(1);
    }
  }
至此,一个基本的射击游戏完成。下一篇,将进行增强表现,完善游戏。
查看评论

unity 2D中的向着鼠标点击方向进行射击

在做一个地牢游戏时,我的玩家原型是一个魔法师一样的角色,他的攻击方向是由鼠标点击方向决定的。然而在这个问题上,我犯了很多错误,自己也很焦躁,到最后,才发现,其实只需要知道鼠标在屏幕上的点击位置(用In...
  • jack_lion
  • jack_lion
  • 2017-07-21 09:00:03
  • 675

unity学习之子弹发射

欢迎来到unity学习教育专区,这里有丰富的unity资源,相信一定可以给你带来收获 今天我们根据昨天的知识讲了怎样发射子弹,并让子弹把墙打到 效果图如下: ...
  • jingjingcrystal
  • jingjingcrystal
  • 2014-12-19 22:10:18
  • 5716

Unity3D实现再鼠标单击的方向发射子弹

我的思路就是在鼠标指向的地方生成一条射线,然后在射线的方向上添加一个力然后就轻松实现在鼠标单击的方向上发射子弹但是不要忘了要给newoblect实例化一个物体 #pragma strict funct...
  • u013174702
  • u013174702
  • 2015-03-24 11:29:32
  • 6667

【Unity2D游戏实战 之 2D滚屏射击】1.背景滚动 (一)

利用unity开展一些小游戏,总结游戏开发中的小技巧: 2D滚屏射击 1.滚动屏幕 例子中使用了比较取巧的垂直方向的UV纹理动画,这就需要以下几点: 1.1 背景图片是垂直二方连续的 最底...
  • teng_ontheway
  • teng_ontheway
  • 2016-04-25 00:07:53
  • 1303

Unity3D学习之飞机发射子弹。

欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,我们致力于打造业内unity3d培训、学习第一品牌...
  • caoboya
  • caoboya
  • 2014-12-24 10:55:11
  • 6071

Unity 4.3 制作一个2D横版射击游戏(2)

在上一篇《Unity 4.3 制作一个2D横版射击游戏》时,已经完成一个基本的射击游戏了。在这一篇将继续完善。 1.视差卷轴效果 为了达到这种视差卷轴的效果,可以让背景层以不同的速度进行移...
  • akof1314
  • akof1314
  • 2014-04-09 13:05:19
  • 20982

Unity5之2D游戏开发入门及进阶项目实战 射击游戏

-
  • 2016年08月15日 00:52

Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏

Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏
  • u014621518
  • u014621518
  • 2014-10-17 10:32:48
  • 2837

「Unity2D」使用Unity创建一个2D游戏系列-1

「Unity2D」使用Unity创建一个2D游戏系列-1 安装unity并且创建你的第一个场景 在第一章,你将会学习到一些非常基本的内容:首先是unity的下载和安装,其次...
  • s556699
  • s556699
  • 2017-02-14 21:34:28
  • 2923

Unity 2D游戏制作

调试背景 2D游戏的制作最重要的是层的设置 先设置两个层①Layers②Edit Layers③Sorting Layers添加两个层BackGround和Front 调试大雁 创建2D ob...
  • qq_39736751
  • qq_39736751
  • 2017-09-05 11:19:42
  • 460
    个人资料
    等级:
    访问量: 361万+
    积分: 3万+
    排名: 138
    文章存档
    最新评论