小狐狸横版游戏开发学习笔记(上)

小狐狸横版游戏开发学习笔记(上)

目录

小狐狸横版游戏开发学习笔记(上)

1.关于如何创建Tilemap

2.关于地图格子之间出现间隙的问题

 3.如何设置自己想要的控制按键

4.如何解决玩家移动过程中造成的卡顿问题

5.如何添加动画

6.动画转换(有部分是其它项目中的截图,放在一起是为了更全面的理解)

7.如何解决,玩家与地图穿插显示在页面最前方的问题

8.如何解决下落转换为初始状态太慢的问题

9.关于镜头的移动

10.如果不想让镜头超出边界


1.关于如何创建Tilemap

2.关于地图格子之间出现间隙的问题

将地图间隙修改为-0.001

 3.如何设置自己想要的控制按键

4.如何解决玩家移动过程中造成的卡顿问题

首先需要添加一个组合碰撞体Composite Collider 2D,添加完之后会自动生成一个刚体组件

将刚体组件中的Body Type属性由原来的Dynamic改为Static,然后将Geometry Type的属性改为Polygons(相当于将碰撞体设置为了实心),若设置为outlines,当角色速度过快时,容易发生穿模。

勾选used by composite(复合碰撞体)

 

5.如何添加动画

首先需要将角色挂接上Animator组件

其次在Assets资源中新建一个Animation文件夹,用来存放Animator Controller

(这里新建了一个Animation Controller,并将其重命名为Player)并将其挂接至Animator上

 

 打开Animation窗口(ctrl+6)先点击所要挂接对象(这里是Player),再点击Create,创建动画

 

选中每帧的动作,将其像素改成相应的大小,再将其选中拖入时间轴

如果速度过快,则将Samples(帧频)的大小改小

 

 

打开Animator窗口

6.动画转换(有部分是其它项目中的截图,放在一起是为了更全面的理解)

增加一个变量,用于控制状态转换

 

取消勾选Has Exit Time,因为在这里我们需要角色立刻退出当前状态,不需要延时

把Transition Duration改成0,因为我们不需要转换时间,我们希望它立刻改变状态

 

 Runright状态转换成idle的时候,需要将greater改为less

 

 如果想要建立BlenderTree,则右键Create new BlendTree

能够根据不同的参数来调整同一状态的的不同方向动画,下面是添加参数的流程 

 

 

 这样才能将参数挂上去,如下所示

 

 然后根据代码,将数值传入

7.如何解决,玩家与地图穿插显示在页面最前方的问题

由于小狐狸和tilemap(地图)都在同一个图层,将order in layer改为负数,代表地图在小狐狸的后方,这样就不会出现小狐狸穿过梯子时,不断闪烁的问题

 

 若想查看任务状态的转换,可以开启Base Layer和Game同步,这样就可以清晰地看清楚,不同状态之间的转换,如果要看动画状态的转换,需要先选中角色

8.如何解决下落转换为初始状态太慢的问题

由于发现 通过判断纵向速度是否为0十分不便,player.velocity.y是浮点数,让其判断为0时从falling状态改为idling状态,会产生延迟现象,所以我们需要通过设置:判断当玩家处于下落状态,并碰到地面时,玩家状态便会立即转换成idling,以下是操作步骤:

我们需要利用定义LayerMask,用来获得地面的信息

Collider2D 用来获取到小狐狸的碰撞体

 将Tilemap加至ground图层

 

 将我们创建的用来获取地面信息的变量,改成Ground图层,由于Ground图层表示的是tilemap,因此我们就获得了地面信息

 将小狐狸的碰撞体挂接到coll上

然后我们通过代码,小狐狸的碰撞体是否碰到了地面图层

如果碰到地面图层,idling状态为true,falling状态为false

9.关于镜头的移动

为Main Camera添加脚本,让摄像机的位置随着角色而移动,所以我们需要让摄像机获取小狐狸的位置x与y,z不变为-10;

 若想要在一定的范围内角色不动,超过一定范围之后,镜头才随着角色的移动而移动,我们需要下载一个插件camerachine,如下图所示

 

 

将角色挂接到相机的follow对象,改变body中的Dead Zone Width和Height

能够控制角色位置移动,但相机不跟随的范围,步骤如下:

 

10.如果不想让镜头超出边界

为新添加的镜头增加扩展,CinemachineConfiner,限制镜头的位置

 

 此时会有一个Bounding Shape 2D需要挂接collider 2D(表示不能出的范围区域)

 

由于我们想要的是范围不出background,所以我们需要为background添加polygon Collider 2D

并点击Edit Collider来设置范围,摁住ctrl再点击点,可以去掉该点

 

 将Background挂接,并将is Trigger勾选,否则小狐狸会因为碰撞体相互碰撞被弹出该范围

 

下面为部分代码展示

小狐狸:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour
{
    //[SerializeField]Rigidbody2D player; 前面加上SerializeField能够将该变量显示出来,但是无法更改
    Rigidbody2D player;
    public float speed = 5.0f;
    public float jumpforce = 3.0f;
    Animator anim;
    public LayerMask ground;
    public Collider2D coll;
    private int cherry = 0;
    private int gem = 0;
    public Text charryNumber;
    public Text gemNumber;
    private bool isHurt;//默认是false
    public AudioSource jump;
    public AudioSource cherrySound;
    public AudioSource gemSound;
    public AudioSource hitSound;

    float horizontalmove;//只有三种情况会出现:1、-1、0,右为正,左为负,不动为零
    float facedirection;
    // Start is called before the first frame update
    void Start()
    {
        player = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        if(!isHurt)//当玩家没有受伤时,才调用Movement,防止角色碰到敌人后不会被弹开
        {
            Movement();
        }
        Getposition();//每次刷新时都获取位置
        Switchanim();
        charryNumber.text = cherry + "";//将charry的值转变为字符串型赋给charryNumber的text,同时能够使用cherry.ToString()
        gemNumber.text = gem.ToString();//利用了另一种表达,将int类型变为字符串类型
    }

    private void FixedUpdate()
    {
       
    }

    void Getposition()//获取位置
    {
       horizontalmove = Input.GetAxis("Horizontal");//获取水平移动
       facedirection = Input.GetAxisRaw("Horizontal");//获取面朝的方向,左为-1,将该值给到scale的x,即可改变面朝像
       //if (Input.GetButtonDown("Jump"))
       //{
       //    player.velocity = new Vector2(player.velocity.x, 5);
       //}
    }
    void Movement()
    {
        if (horizontalmove!=0)
        {
            player.velocity = new Vector2(horizontalmove*speed, player.velocity.y);//player.velocity表示玩家的速度,第一个是水平方向,第二个是竖直方向
            anim.SetFloat("running",Mathf.Abs(horizontalmove));
        }
        if(facedirection!=0)
        {
            player.transform.localScale = new Vector3(facedirection,1,1);//将该值给到scale的x,即可改变面朝像
        }
        //跳跃
        //coll.IsTouchingLayers(ground)可换成anim.GetBool("idling")|| anim.GetBool("running")
        if (Input.GetButtonDown("Jump")&& coll.IsTouchingLayers(ground))
        {
            player.velocity = new Vector2(player.velocity.x, 8);
            jump.Play();
            anim.SetBool("jumping",true);
        }
       

        //Vector2 position = player.position;
        //position.x = player.position.x + horizontalmove * speed * Time.deltaTime;
        //player.MovePosition(position);//等于player.position=position;

    }

    void Switchanim()
    {
        if (player.velocity.y < 0.1f && !coll.IsTouchingLayers(ground))
        {
            anim.SetBool("falling", true);
        }
        anim.SetBool("idling",false);
        if (anim.GetBool("jumping"))
        {
            if( player.velocity.y < 0)
            {
                anim.SetBool("jumping", false);
                anim.SetBool("falling", true);
            }
            
        }
        else if (isHurt)//必须要加在else if (coll.IsTouchingLayers(ground))之前,因为人物一直挨着地面,就不会进行到下一个的if条件判断
        {
            if (Mathf.Abs(player.velocity.x) < 0.1f)
            {
                isHurt = false;
                anim.SetBool("hurt", false);
                anim.SetBool("idling",true);
            }
        }
        else if (coll.IsTouchingLayers(ground))
        {
            anim.SetBool("idling", true);
            anim.SetBool("falling", false);
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.tag=="collection")
        {
            cherrySound.Play();
            Destroy(collision.gameObject);
            cherry += 1;
        }
        if (collision.tag == "collection2")
        {
            gemSound.Play();
            Destroy(collision.gameObject);
            gem += 1;
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)//由于不能将敌人勾选is trigger,如果勾选,敌人将会直接掉出地图之外,所以这个地方不能使用OnTriggerEnter2D函数
    {
        if (collision.gameObject.tag == "Enemies")//OnCollisionEnter2D与OnTriggerEnter2D不同,它需要先取到它本身,再取出tag,所以写为collision.gameObject.tag
        {//当小狐狸碰撞到敌人时
            Enemy enemy = collision.gameObject.GetComponent<Enemy>();
            if (anim.GetBool("falling"))//同时当小狐狸处于下落状态时,碰撞敌人后,敌人消失
            {
                enemy.Death();
                player.velocity = new Vector2(player.velocity.x, 7);//敌人消失后,做一个跳跃的动作丰富场景
                //anim.SetBool("jumping", true);我认为这句话没什么用,因为在动画转换中根本没有下落转跳跃的箭头
            }
            //下面是教程中给的方法
            else if (transform.position.x > collision.gameObject.transform.position.x)
            {
                hitSound.Play();//当小狐狸不是下落碰撞时,会被弹走
                player.velocity = new Vector2(5, player.velocity.y);
                isHurt = true;//由于程序是在不断刷新的,Movement不断地在被调用,不摁住键盘输入指令,小狐狸就不会动,也不会被弹开,所以需要用isHurt来控制Movement是否执行(在update与Switchanim中用if语句控制)
                anim.SetBool("hurt", true);
                anim.SetFloat("running", 0);
            }
            else if (transform.position.x < collision.gameObject.transform.position.x)
            {
                hitSound.Play();
                player.velocity = new Vector2(-5, player.velocity.y);
                isHurt = true;//由于程序是在不断刷新的,Movement不断地在被调用,不摁住键盘输入指令,小狐狸就不会动,也不会被弹开,所以需要用isHurt来控制Movement是否执行(在update与Switchanim中用if语句控制)
                anim.SetBool("hurt", true);
                anim.SetFloat("running", 0);
            }
            //以下是我自己的方法
            //else
            //{
            //    hitSound.Play();
            //    player.velocity = new Vector2(-5.0f * facedirection, player.velocity.y);//弹走的方向与小狐狸面朝的方向相反
            //    isHurt = true;
            //    anim.SetBool("hurt", true);
            //    anim.SetFloat("running", 0);
            //}   
        }
        
    }
}

敌人父类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    protected Animator anim;
    protected AudioSource death;
    // Start is called before the first frame update
    protected virtual void Start()//virtual代表虚拟的,相当于这个父级是可以被子级重新编写的
    {
        anim = GetComponent<Animator>();
        death = GetComponent<AudioSource>();
    }
    public void Death()
    {
        death.Play();
        anim.SetTrigger("death");
    }

    public void Jumpup()
    {
        Destroy(gameObject);
    }
    // Update is called once per frame
    void Update()
    {
        
    }
}

敌人—青蛙(子类):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy_Frog : Enemy
{
    private Rigidbody2D fg;
    //private Animator anim;
    public Transform left;//获取左侧物体的位置
    public Transform right;//获取右侧物体的位置
    private float leftx;//左侧物体的x坐标
    private float rightx;//右侧物体的x坐标
    public float speed,jumpForce;//设置速度(外部可更改)
    private bool faceleft=true;//用来判断朝向是否向左
    private Collider2D coll;
    public LayerMask ground;
    // Start is called before the first frame update
    protected override void Start()
    {
        base.Start();
        coll = GetComponent<Collider2D>();
        //anim = GetComponent<Animator>();
        fg = GetComponent<Rigidbody2D>();
        //由于左右两个物体是敌人的子物体,所以如果敌人移动那么两个子物体也会跟着一起移动
        //永远也到不了左侧物体的左边,敌人会一直向左移动,所以需要利用DetachChildren()方法断绝父子关系
        transform.DetachChildren();
        leftx = left.position.x;//获取左侧物体的位置
        rightx = right.position.x;//获取右侧物体的位置
        //断绝父子关系后子物体会在Hierarchy出现,当敌人多了之后就会有很多子物体出现在Hierarchy中,影响观感和性能
        Destroy(left.gameObject);//所以在这里,我们直接将两个子物体销毁
        Destroy(right.gameObject);
    }

    // Update is called once per frame
    void Update()
    {
        Switch();
    }
    void Movement()
    {
        if (faceleft)//当面朝左侧的时候
        {
            if (coll.IsTouchingLayers(ground))
            {
                anim.SetBool("jumping", true);
                fg.velocity = new Vector2(-speed, jumpForce);
            }
            //向左移动
            if (transform.position.x < leftx)//当敌人的x坐标小于左侧的坐标时,青蛙朝向向右
            {
                transform.localScale = new Vector3(-1, 1, 1);
                fg.velocity = new Vector2(speed, fg.velocity.y);//为了防止青蛙面朝右侧,却还向左跳的bug
                faceleft = false;//向左的标志为false;
            }
        }
        else
        {
            if (coll.IsTouchingLayers(ground))
            {
                anim.SetBool("jumping", true);
                fg.velocity = new Vector2(speed, jumpForce);
            }
            if (transform.position.x > rightx)
            {
                transform.localScale = new Vector3(1, 1, 1);
                fg.velocity = new Vector2(-speed, fg.velocity.y);
                faceleft = true;
            }
        }
    }

    void Switch()
    {
        if (anim.GetBool("jumping")&&fg.velocity.y < 0)
        {
            anim.SetBool("jumping", false);
            anim.SetBool("falling", true);//跳跃转换为下落
        }
        if (anim.GetBool("falling") && coll.IsTouchingLayers(ground))
        {
            anim.SetBool("falling", false);//下落转换成idle的条件
        }
    }
    
}

(想要获得全部项目资源或代码请在下方留言或私信)

猜你喜欢

转载自blog.csdn.net/weixin_53777651/article/details/128762228