最近刚开始看unity3d游戏开发,感觉2d游戏似乎简单些,所以先从2d游戏入手试试看吧。
2d游戏大约要分为背景,角色(需要控制的己方角色car,敌机enemy,奖励物品prop),ui(分数显示,暂停继续等),音乐(背景音乐,攻击音乐,死亡音乐等)
大约长这样,emmm,原视频是主角是小飞机,背景是天空,也给有素材,但起初学习的时候想稍微更改下,就自己制作了小汽车主角和马路的背景,之后。。。觉得有点麻烦还是用了源素材,所以忽略这种突兀的感觉吧!
1.首先背景移动,需要两张背景交替向下移动,实现背景连续移动的效果。挂在背景图片上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class move : MonoBehaviour { //背景移动
public float speed = 2f; //速度
// Update is called once per frame
void Update ()
{
this.transform.Translate (Vector3.down * speed * Time.deltaTime); //每帧向下移动
Vector3 postion = this.transform.position;
if (postion.y <= -20.48f) { //如果移动超过。。则向上移动,实现循环
this .transform .position = new Vector3 (postion .x,postion .y + 20.48f*2,postion .z);
}
}
}
2.主角car(好吧假装是个飞机)实现发射子弹与主角的移动
创建两个空物体作为主角的子对象,放在子弹发射的起始位置,这样子弹就会相对主角的位置移动,只用实现子弹生成与移动就好了。为子弹添加2d碰撞检测器,当子弹碰到敌机时调用敌机的死亡脚本
子弹生成
public class gun : MonoBehaviour {
public float rate = 0.1f; //子弹生成时间间隔
public float speed = 2f; //子弹生成速度
public GameObject bullet;
// Use this for initialization
public void fire ()
{
GameObject .Instantiate (bullet,transform .position ,Quaternion .identity );
}
public void openfire(){
InvokeRepeating ("fire",1,rate); //1秒后开始生成子弹,之后每隔rate个时间生成一个
}
public void stopfire ()
{
CancelInvoke ("fire");
}
}
子弹移动
public class bullet : MonoBehaviour { //子弹移动
public float speed = 5f;
void Update ()
{
transform.Translate (Vector3.up * speed * Time.deltaTime);
if (transform.position.y >= 8.5f) { //如果子弹移动出屏幕范围,销毁
Destroy (this .gameObject );
}
}
void OnTriggerEnter2D (Collider2D other)
{
if (other.tag == "enemy") { //击中敌机,调用敌机的BeHit方法并将自身删除
if (!other.GetComponent
other.gameObject.SendMessage ("BeHit");
GameObject.Destroy (this.gameObject);
}
}
}
}
将子弹生成脚本挂在空物体上,在Bullet后找到相应的子弹物体
将子弹移动脚本挂在子弹物体上
对于主角car,通过切换两张图片实现主角的动画(我记得sprite有个直接把2d序列帧图片放在一张图片上会自动裁切并且按序列帧播放的,但是没有尝试,之后再说吧),通过检测鼠标按下时的位置来对car进行移动(需要将屏幕坐标转换为世界坐标),判断car在世界坐标中的位置来控制car不移出背景。
public class car : MonoBehaviour
{
public bool animation = true;
//动画控制开关
public int frameCountPersconds = 10;
//每秒播放10帧
public Camera TempC;
public float timer = 0;
//计时器
public Sprite[] sprites;
public float superGunTime = 10f;
public gun gunRight;
public gun gunLeft;
private float resetSuperGunTime;
private bool isMouseDown = false;
private Vector3 lastMoustPosition = Vector3.zero;
// private Transform hero;
private int gunCount = 1;
void Start ()
{
// spreteRender = this .GetComponent
// hero = GameObject .FindGameObjectWithTag ("hero").transform ; //利用标签找物体
// TempC = this.GetComponent
resetSuperGunTime = superGunTime;
superGunTime = 0;
gunLeft .openfire ();
}
void Update ()
{
if (animation) { //切换两张图片实现动画
timer += Time.deltaTime; //计时
int frameIndex = (int)(timer / (1f / frameCountPersconds)); //图片切换几次
int frame = frameIndex % 2; //将图片切换次数循环
this.GetComponent
}
if (Input.GetMouseButtonDown (0)) { //检测鼠标是否按下
isMouseDown = true;
}
if (Input.GetMouseButtonUp (0)) {
isMouseDown = false;
// lastMoustPosition = Vector3 .zero ;
}
if (isMouseDown && scoreShow .instance .gameState == GameState.Runing ) { //鼠标按下且游戏是运行状态(非暂停)
if (lastMoustPosition != Vector3.zero) {
// Camera .main .ScreenToWorldPoint (Input .mousePosition ) 将屏幕坐标转化为世界坐标
// Debug .Log ("Camera.main.ScreenToWorldPoint(Input .mousePosition"+TempC .ScreenToWorldPoint(new Vector3 ( //Input .mousePosition.x,Input .mousePosition .y,10.0f )));
Vector3 offset = TempC.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f)) - lastMoustPosition; //坐标不能为0
transform.position = transform.position + offset; //移动
checkPosition ();
}
lastMoustPosition = TempC.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f));
}
superGunTime -= Time.deltaTime;
if (superGunTime > 0) { //切换超级子弹
if (gunCount == 1) {
transformToSuperGun ();
}
} else {
if (gunCount == 2) {
transformToNormalGun ();
}
}
}
private void transformToSuperGun ()
{
gunCount = 2;
gunRight.openfire ();
gunLeft.stopfire ();
}
private void transformToNormalGun ()
{
gunCount = 1;
gunRight.stopfire ();
gunLeft.openfire ();
}
private void checkPosition () //检测car移动的位置防止移动出背景
{
//check -2.1
float x = pos.x;
float y = pos.y;
if (x < -2.1f) {
x = -2.1f;
}
if (x > 2.1f) {
x = 2.1f;
}
if (y < -3.23f) {
y = -3.23f;
}
if (y > 2.84f) {
y = 2.84f;
}
transform.position = new Vector3 (x, y, 0);
}
public void OnTriggerEnter2D (Collider2D collider) //如果碰撞到标签是prop的物体,切换超级子弹(初始化superGunTime,并逐渐减少)
{
if (collider.tag == "prop") {
prop prop = collider.GetComponent
if (prop.type == 0) {
superGunTime = resetSuperGunTime;
Destroy (collider .gameObject );
}
}
}
}
3.敌机与奖励物品生成和移动
创建空物体,放在屏幕外稍微靠上的部位用于敌机和奖励物品的生成。利用随机数控制敌机生成的位置
public class spawn : MonoBehaviour { //敌机和奖励的生成
public GameObject enemy0;
public GameObject enemy1;
public GameObject enemy2;
public GameObject prop0;
public GameObject prop1;
public float rate0 = 1f;
public float rate1 = 5f;
public float rate2 = 8f;
public float rateProp0 = 3f;
public float rateprop1 = 5f;
// Use this for initialization
void Start () {
InvokeRepeating ("createnemy0",1,rate0);
InvokeRepeating ("createnemy1",3,rate1);
InvokeRepeating ("createnemy2",5,rate2);
InvokeRepeating ("creatprop0",5,rateProp0);
InvokeRepeating ("creatprop1",8,rateprop1);
}
// Update is called once per frame
void Update ()
{
}
public void createnemy0(){
float x0 = Random .Range (-2.3f,2.3f);
GameObject .Instantiate (enemy0 ,new Vector3 (x0,this .transform .position .y,0),Quaternion .identity );
}
public void createnemy1(){
float x1 = Random .Range (-2.2f,2.2f);
GameObject .Instantiate (enemy1 ,new Vector3 (x1,this .transform .position .y,0),Quaternion .identity );
}
public void createnemy2(){
float x2 = Random .Range (-1.8f,1.8f);
GameObject .Instantiate (enemy2 ,new Vector3 (x2,this .transform .position .y,0),Quaternion .identity );
}
public void creatprop0(){
float x0 = Random .Range (-2.2f,2.2f);
GameObject .Instantiate (prop0 ,new Vector3 (x0,this .transform .position .y,0),Quaternion .identity );
}
public void creatprop1(){
float x1 = Random .Range (-2.1f,2.1f);
GameObject .Instantiate (prop1 ,new Vector3 (x1,this .transform .position .y,0),Quaternion .identity );
}
}
奖励物品比较简单,只用移动,检测到于主角car碰撞后将自身删除就可以了
public class prop : MonoBehaviour { //奖励物品移动
public float speed = 1.5f ;
public GameObject award;
public int type = 1;
public float posY;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
this .transform .Translate (Vector3 .down *speed *Time .deltaTime );
if (this .transform .position .y <= posY ){
Destroy (this.gameObject );
}
}
}
敌机的状态较为复杂,三种敌机分别设置不同的移动速度,有不同的hp值和分数,当子弹碰撞到敌机时切换敌机状态为BeHit状态,hp递减且播放受伤动画(不知道为什么这里的受伤动画一直没弄好)当hp为0时切换为toDie,调用isDeath方法并且增加分数。isDeath为true时播放死亡动画,动画播放完后删除此物体
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum EnumyType{
smallEnemy,
middleEnemy,
bigEnemy
}
public class enemy : MonoBehaviour {
public int hp = 1;
public float speed = 2f;
public int score = 100;
public float posY;
public EnumyType type = EnumyType.smallEnemy ;
public bool isDeath = false ;
public Sprite [] explosionSprites;
private float timer = 0;
public int frameCountPersconds = 20;
private SpriteRenderer render;
public float hitTimer = 0.2f;
private float resetHitTime;
public Sprite [] hitSprites;
// Use this for initialization
void Start () {
render = this.GetComponent
resetHitTime = hitTimer ;
hitTimer = 0f;
}
// Update is called once per frame
void Update ()
{ //敌机移动
this.transform.Translate (Vector3.down * speed * Time.deltaTime);
if (transform.position.y <= posY) {
Destroy (this.gameObject);
}
if (isDeath == true) { //播放死亡动画
timer += Time.deltaTime;
int frameIndex = (int)(timer / (1f / frameCountPersconds));
if (frameIndex >= explosionSprites.Length) {
Destroy (this.gameObject);
} else {
render.sprite = explosionSprites [frameIndex];
}
}
// else { //播放受伤动画
// if(type == EnumyType .middleEnemy || type == EnumyType .bigEnemy ){
// if (hitTimer >0 ){
//// Debug .Log ("hitTime" +hitTimer );
// hitTimer -=Time .deltaTime ;
//// Debug .Log ("resetHitTime"+resetHitTime);
// int frameIndex = (int)((resetHitTime - hitTimer )/(1f/frameCountPersconds ));
// int frame = frameIndex %2;
//// Debug .Log ("frame" + frame );
// render.sprite = hitSprites [frame];
// }
// }
// }
}
public void BeHit () //被击中
{
hp -= 1;
if (hp <= 0) {
toDie ();
}
// else {
// hitTimer = resetHitTime ;
// }
}
private void toDie ()
{
if (!isDeath) {
isDeath = true;
scoreShow .instance.score += score;
}
}
}
4.分数的记录显示与游戏的暂停
public enum GameState {
Runing,
Pause
}
public class scoreShow : MonoBehaviour {
public static scoreShow instance ;
public int score = 0; //分数
private GameObject findscrShow;
private Text txt_score;
public GameState gameState = GameState.Runing;
// Use this for initialization
void Start () {
instance = this;
// txt_score = this.GetComponent
findscrShow = GameObject.Find("scoreShow"); //法2 获取scroeShow后获取Text
txt_score = findscrShow.GetComponent
}
// Update is called once per frame
void Update () {
txt_score.text = "score:" + score;
}
public void transformGameState() {
if (gameState == GameState.Runing ) {
pauseGame();
}
else if (gameState==GameState.Pause ) {
resumeGame();
}
}
public void pauseGame() {
Time.timeScale = 0;
gameState = GameState.Pause;
}
public void resumeGame() {
Time.timeScale = 1;
gameState = GameState.Runing;
}
}
暂停
public class gamePause : MonoBehaviour {
private void OnMouseUpAsButton()
{
scoreShow .instance.transformGameState();
}
}