liweihang

地图搭建

视频教程:https://learn.u3d.cn/tutorial/2d-mobile-mstudio#5fd1bf75266ffa00204d231c

素材处理

找到地图素材:


对图片进行切割:

可以给每个图片新命名

瓦片



把资源拉进去

创建Background和Platform瓦片地图


调整摄像机的大小

图层

和IOS开发一样,可以设置不同的图层,进行先后的渲染,并且不同的图层间,还可以设置,是否可以碰撞。

这里可以拖动,改变图层的渲染先后

碰撞体

给地图添加碰撞体:

给游戏中的物体添加刚体和碰撞体


对于不规则的问题,可以调整碰撞体的形状

control+左键可以删除节点
如果希望有的图层之间不发生碰撞。修改参数

增加新的图层

预制体



创建一个复制体

主角

加排序图层 和 图层


加碰撞体

创建脚本

基本的移动

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

public class PalyerController : MonoBehaviour
{
    private Rigidbody2D rd;
    public float Speed; //左右移动速度
    private bool JumpPressed;//是否跳跃
    public float jumpForce; //跳跃的力
    void Start()
    {
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckInput();
    }

    private void FixedUpdate()
    {
        Movement();
        Jump();
    }

    //检测按钮 
    void CheckInput()
    {
        if(Input.GetButtonDown("Jump"))
        {
            JumpPressed = true;
        }
    }

    void Movement()
    {
        //float horizontalInput = Input.GetAxis("Horizontal");// -1 ~ 1小数
        float horizontalInput = Input.GetAxisRaw("Horizontal");// -1 ~ 1 整数
        if(horizontalInput != 0) //人物面向
        {
            transform.localScale = new Vector3(horizontalInput, 1, 1);
        }

        rd.velocity = new Vector2(horizontalInput * Speed, rd.velocity.y);
    }

    void Jump()
    {
        //是否跳跃
        if (JumpPressed)
        {
            rd.velocity = new Vector2(rd.velocity.x, jumpForce);
            JumpPressed = false;
        }
    }
}

卡墙问题

摩擦力设置为0

检测人物是否在地面, 防止连跳


地面的layer,如果碰撞到地面的layer可以跳跃。
创建检测的空物体

标签大小

代码添加

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

public class PalyerController : MonoBehaviour
{
    private Rigidbody2D rd;
    public float Speed; //左右移动速度
    public float jumpForce; //跳跃的力

    [Header("Ground Check")]
    public Transform groundCheck; //检测物体的Transform
    public float checkRadius; //检测范围
    public LayerMask groundLayer; //和groundLayer发生检测

    [Header("States Check")]
    public bool canJump;//是否跳跃
    public bool isGround; //是否在地面

    void Start()
    {
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckInput();
    }

    private void FixedUpdate()
    {
        PhysicsCheck();
        Movement();
        Jump();
    }

    //检测按钮 
    void CheckInput()
    {
        if(Input.GetButtonDown("Jump") && isGround) //按下jump 并且在地面
        {
            canJump = true;
        }
    }

    //移动
    void Movement()
    {
        //float horizontalInput = Input.GetAxis("Horizontal");// -1 ~ 1小数
        float horizontalInput = Input.GetAxisRaw("Horizontal");// -1 ~ 1 整数
        if(horizontalInput != 0) //人物面向
        {
            transform.localScale = new Vector3(horizontalInput, 1, 1);
        }

        rd.velocity = new Vector2(horizontalInput * Speed, rd.velocity.y);
    }

    //跳跃
    void Jump()
    {
        //是否跳跃
        if (canJump)
        {
            rd.velocity = new Vector2(rd.velocity.x, jumpForce);
            canJump = false;
        }
    }

    //检测是否在地面
    void PhysicsCheck()
    {
        //有多种检测方法
        //(检测的2d坐标 范围 检测碰撞的图层)
        isGround = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);
    }

}

查看检测范围


通过代码改变重力

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

public class PalyerController : MonoBehaviour
{
    private Rigidbody2D rd;
    public float Speed; //左右移动速度
    public float jumpForce; //跳跃的力

    [Header("Ground Check")]
    public Transform groundCheck; //检测物体的Transform
    public float checkRadius; //检测范围
    public LayerMask groundLayer; //和groundLayer发生检测

    [Header("States Check")]
    public bool canJump;//是否跳跃
    public bool isGround; //是否在地面

    void Start()
    {
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckInput();
    }

    private void FixedUpdate()
    {
        PhysicsCheck();
        Movement();
        Jump();
    }

    //检测按钮 
    void CheckInput()
    {
        if(Input.GetButtonDown("Jump") && isGround) //按下jump 并且在地面
        {
            canJump = true;
        }
    }

    //移动
    void Movement()
    {
        //float horizontalInput = Input.GetAxis("Horizontal");// -1 ~ 1小数
        float horizontalInput = Input.GetAxisRaw("Horizontal");// -1 ~ 1 整数
        if(horizontalInput != 0) //人物面向
        {
            transform.localScale = new Vector3(horizontalInput, 1, 1);
        }

        rd.velocity = new Vector2(horizontalInput * Speed, rd.velocity.y);
    }

    //跳跃
    void Jump()
    {
        //是否跳跃
        if (canJump)
        {
            rd.velocity = new Vector2(rd.velocity.x, jumpForce);
            canJump = false;
        }
    }

    //检测是否在地面
    void PhysicsCheck()
    {
        //有多种检测方法
        //(检测的2d坐标 范围 检测碰撞的图层)
        isGround = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);
        //是否在地面
        if (isGround)
        {
            rd.gravityScale = 1; //重力大小
        }
        else
        {
            rd.gravityScale = 3; //重力大小
        }
    }

    public void OnDrawGizmos()
    {
        //画圆 中心 半径
        Gizmos.DrawWireSphere(groundCheck.position, checkRadius);
    }

}

动画

动画调整




调整一秒播放的帧数


制做其它的动画


得到

调整动画

jump、fall、ground调整单次播放

动画控制器

打开动画器



创建动画控制脚本

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

public class PalyerAnimation : MonoBehaviour
{

    private Animator anim;
    private Rigidbody2D rd;
    void Start()
    {
        anim = GetComponent<Animator>();
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        //参数名 值
        anim.SetFloat("speed", Mathf.Abs(rd.velocity.x));
    }
}

其它动画的转换



播放完就跳转:

最后调整为

代码修改:

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

public class PalyerController : MonoBehaviour
{
    private Rigidbody2D rd;
    public float Speed; //左右移动速度
    public float jumpForce; //跳跃的力

    [Header("Ground Check")]
    public Transform groundCheck; //检测物体的Transform
    public float checkRadius; //检测范围
    public LayerMask groundLayer; //和groundLayer发生检测

    [Header("States Check")]
    public bool canJump;//是否要跳跃
    public bool isGround; //是否在地面
    public bool isJump; //正在跳跃 //+

    void Start()
    {
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckInput();
    }

    private void FixedUpdate()
    {
        PhysicsCheck();
        Movement();
        Jump();
    }

    //检测按钮 
    void CheckInput()
    {
        if (Input.GetButtonDown("Jump") && isGround) //按下jump 并且在地面
        {
            canJump = true;
        }
    }

    //移动
    void Movement()
    {
        //float horizontalInput = Input.GetAxis("Horizontal");// -1 ~ 1小数
        float horizontalInput = Input.GetAxisRaw("Horizontal");// -1 ~ 1 整数
        if (horizontalInput != 0) //人物面向
        {
            transform.localScale = new Vector3(horizontalInput, 1, 1);
        }

        rd.velocity = new Vector2(horizontalInput * Speed, rd.velocity.y);
    }

    //跳跃
    void Jump()
    {
        //是否跳跃
        if (canJump)
        {
            isJump = true;//+
            rd.velocity = new Vector2(rd.velocity.x, jumpForce);
        }
    }

    //检测是否在地面
    void PhysicsCheck()
    {
        //有多种检测方法
        //(检测的2d坐标 范围 检测碰撞的图层)
        isGround = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);
        //是否在地面
        if (isGround)
        {
            isJump = false;//+
            rd.gravityScale = 1; //重力大小
        }
        else
        {
            rd.gravityScale = 3; //重力大小
            canJump = false;
        }
    }

    public void OnDrawGizmos()
    {
        //画圆 中心 半径
        Gizmos.DrawWireSphere(groundCheck.position, checkRadius);
    }

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

public class PalyerAnimation : MonoBehaviour
{

    private Animator anim;
    private Rigidbody2D rd;
    private PalyerController controller; //访问其它对象 //+

    void Start()
    {
        anim = GetComponent<Animator>();
        rd = GetComponent<Rigidbody2D>();
        controller = GetComponent<PalyerController>();//+
    }

    void Update()
    {
        //参数名 值
        anim.SetFloat("speed", Mathf.Abs(rd.velocity.x));
        anim.SetFloat("velocityY", rd.velocity.y); //+
        anim.SetBool("jump", controller.isJump); //+
        anim.SetBool("ground", controller.isGround); //+
    }
}

动画效果








效果的控制


给最后面一帧创建事件(播放完隐藏)

同理添加好jump的特效。
在palyer的代码增加调用时机就可以了。
思路就是每次跳跃时,把jumpFx移动到人物的脚下播放动画,然后播放结束会自动隐藏。


添加landFx的动画。我们在调用Player动画时,就可以调用。在PalyerController.cs
添加一个函数


避免穿墙

现在的PalyerController

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

public class PalyerController : MonoBehaviour
{
    private Rigidbody2D rd;
    public float Speed; //左右移动速度
    public float jumpForce; //跳跃的力

    [Header("Ground Check")]
    public Transform groundCheck; //检测物体的Transform
    public float checkRadius; //检测范围
    public LayerMask groundLayer; //和groundLayer发生检测

    [Header("States Check")]
    public bool canJump;//是否要跳跃
    public bool isGround; //是否在地面
    public bool isJump; //正在跳跃

    [Header("Jump FX")]
    public GameObject jumpFX;//对象 //+
    public GameObject landFX;//对象 //+

    void Start()
    {
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckInput();
    }

    private void FixedUpdate()
    {
        PhysicsCheck();
        Movement();
        Jump();
    }

    //检测按钮 
    void CheckInput()
    {
        if (Input.GetButtonDown("Jump") && isGround) //按下jump 并且在地面
        {
            canJump = true;
        }
    }

    //移动
    void Movement()
    {
        //float horizontalInput = Input.GetAxis("Horizontal");// -1 ~ 1小数
        float horizontalInput = Input.GetAxisRaw("Horizontal");// -1 ~ 1 整数
        if (horizontalInput != 0) //人物面向
        {
            transform.localScale = new Vector3(horizontalInput, 1, 1);
        }

        rd.velocity = new Vector2(horizontalInput * Speed, rd.velocity.y);
    }

    //跳跃
    void Jump()
    {
        //是否跳跃
        if (canJump)
        {
            jumpFX.SetActive(true);//+
            //跳跃时坐标 
            jumpFX.transform.position = transform.position + new Vector3(0, -0.45f, 0);//paly和jump的坐标误差 //+

            isJump = true;
            rd.velocity = new Vector2(rd.velocity.x, jumpForce);
        }
    }

    public void LandFX()//跳跃落地代码+
    {
        landFX.SetActive(true);
        landFX.transform.position = transform.position + new Vector3(0, -0.45f, 0);//paly和jump的坐标误差 //+
    }

    //检测是否在地面
    void PhysicsCheck()
    {
        //有多种检测方法
        //(检测的2d坐标 范围 检测碰撞的图层)
        isGround = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);
        //是否在地面
        if (isGround)
        {
            isJump = false;
            rd.gravityScale = 1; //重力大小
        }
        else
        {
            rd.gravityScale = 3; //重力大小
            canJump = false;
        }
    }

    public void OnDrawGizmos()
    {
        //画圆 中心 半径
        Gizmos.DrawWireSphere(groundCheck.position, checkRadius);
    }

}

炸弹

炸弹动画

并且把爆炸的动画设置成不循环

炸弹组件

设置炸弹的参数

碰撞关系

脚本

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

public class bomb : MonoBehaviour
{
    private Animator anim;
    public float startTime; //开始的时间
    public float waitTime;  //等待的时间
    public float bombForce; //爆炸的力

    [Header("Check")]
    public float radius; //爆炸的半径
    public LayerMask targetLayer; //爆炸影响的图层

    void Start()
    {
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void OnDrawGizmos()//画圆方便调试爆炸范围
    {
        Gizmos.DrawWireSphere(transform.position, radius);
    }
}


根据爆炸的动画设置爆炸的半径

多选

完善代码

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

public class bomb : MonoBehaviour
{
    private Animator anim;
    public float startTime; //开始的时间
    public float waitTime;  //等待的时间
    public float bombForce; //爆炸的力

    [Header("Check")]
    public float radius; //爆炸的半径
    public LayerMask targetLayer; //爆炸影响的图层

    void Start()
    {
        anim = GetComponent<Animator>();
        startTime = Time.time;
    }

    // Update is called once per frame
    void Update()
    {
        //当前时间 > 开始时间 + 等待时间 发生爆炸
        if(Time.time > startTime + waitTime)
        {
            anim.Play("bomb_explotion");
        }
    }

    public void OnDrawGizmos()//画圆方便调试爆炸范围
    {
        Gizmos.DrawWireSphere(transform.position, radius);
    }

    //爆炸开始时执行
    public void Explotion()
    {
        //获取一个对象数组 在[参数1]的半径为[参数2]的圆有交点 并且在图层[参数3]的对象
        Collider2D[] aroundObjects = Physics2D.OverlapCircleAll(transform.position, radius, targetLayer);
        foreach (var item in aroundObjects)
        {
            //获取物体的位置 给相应的力
            Vector3 pos = transform.position - item.transform.position;
            //给物体的刚体给一个力 (方向*力 希望一个向上的力,力的类型(冲击力))
            item.GetComponent<Rigidbody2D>().AddForce((-pos + Vector3.up) * bombForce, ForceMode2D.Impulse);
        }
    }

    //爆炸结束
    public void DestroyThis()
    {
        //销毁对象
        Destroy(gameObject);
    }
}



在前面我们在检测图层中勾选力bomb,我们希望它可以爆炸影响其他炸弹,当不影响自己,那么我们应该在添加力的时候,取消自己的刚体的勾选,并且重力设置为0(防止没有碰撞体,会因为有重力下落)。
完善代码

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

public class bomb : MonoBehaviour
{
    private Animator anim;
    private Collider2D coll;//碰撞体组件//+
    private Rigidbody2D rd;//+
    
    public float startTime; //开始的时间
    public float waitTime;  //等待的时间
    public float bombForce; //爆炸的力

    [Header("Check")]
    public float radius; //爆炸的半径
    public LayerMask targetLayer; //爆炸影响的图层

    void Start()
    {
        anim = GetComponent<Animator>();
        coll = GetComponent<Collider2D>();//+
        rd = GetComponent<Rigidbody2D>();//+
        startTime = Time.time;
    }

    // Update is called once per frame
    void Update()
    {
        //当前时间 > 开始时间 + 等待时间 发生爆炸
        if(Time.time > startTime + waitTime)
        {
            anim.Play("bomb_explotion");
        }
    }

    public void OnDrawGizmos()//画圆方便调试爆炸范围
    {
        Gizmos.DrawWireSphere(transform.position, radius);
    }

    //爆炸开始时执行
    public void Explotion()
    {
        coll.enabled = false; //组件勾选取消//+
        rd.gravityScale = 0;//重力=0 //+
        //获取一个对象数组 在[参数1]的半径为[参数2]的圆有交点 并且在图层[参数3]的对象
        Collider2D[] aroundObjects = Physics2D.OverlapCircleAll(transform.position, radius, targetLayer);
        foreach (var item in aroundObjects)
        {
            //获取物体的位置 给相应的力
            Vector3 pos = transform.position - item.transform.position;
            //给物体的刚体给一个力 (方向*力 希望一个向上的力,力的类型(冲击力))
            item.GetComponent<Rigidbody2D>().AddForce((-pos + Vector3.up) * bombForce, ForceMode2D.Impulse);
        }
    }

    //爆炸结束
    public void DestroyThis()
    {
        //销毁对象
        Destroy(gameObject);
    }
}

这里我们发现一个问题:就是爆炸给不了player力。原
因为:

player每秒都在刷新这个函数,没有运动,水平的速度会更新为0。

放置炸弹

player按下j,在脚下放置炸弹。并且设置一个CD时间。下次放下个炸弹的时间。

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

public class PalyerController : MonoBehaviour
{
    private Rigidbody2D rd;
    public float Speed; //左右移动速度
    public float jumpForce; //跳跃的力

    [Header("Ground Check")]
    public Transform groundCheck; //检测物体的Transform
    public float checkRadius; //检测范围
    public LayerMask groundLayer; //和groundLayer发生检测

    [Header("States Check")]
    public bool canJump;//是否要跳跃
    public bool isGround; //是否在地面
    public bool isJump; //正在跳跃

    [Header("Jump FX")]
    public GameObject jumpFX;//对象
    public GameObject landFX;//对象

    //放炸弹 //+
    [Header("Attack Settings")]
    public GameObject bombPrefabs; //炸弹
    public float nextAttack = 0; //下一次可以攻击的时间
    public float attackRate; //CD

    void Start()
    {
        rd = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckInput();
    }

    private void FixedUpdate()
    {
        PhysicsCheck();
        Movement();
        Jump();
    }

    //检测按钮 
    void CheckInput()
    {
        if (Input.GetButtonDown("Jump") && isGround) //按下jump 并且在地面
        {
            canJump = true;
        }
        //放炸弹//+
        if (Input.GetKeyDown(KeyCode.J))
        {
            Attack();
        }
    }

    //移动
    void Movement()
    {
        //float horizontalInput = Input.GetAxis("Horizontal");// -1 ~ 1小数
        float horizontalInput = Input.GetAxisRaw("Horizontal");// -1 ~ 1 整数
        if (horizontalInput != 0) //人物面向
        {
            transform.localScale = new Vector3(horizontalInput, 1, 1);
        }

        rd.velocity = new Vector2(horizontalInput * Speed, rd.velocity.y);
    }

    //跳跃
    void Jump()
    {
        //是否跳跃
        if (canJump)
        {
            jumpFX.SetActive(true);
            //跳跃时坐标 
            jumpFX.transform.position = transform.position + new Vector3(0, -0.45f, 0);//paly和jump的坐标误差 //+

            isJump = true;
            rd.velocity = new Vector2(rd.velocity.x, jumpForce);
        }
    }

    public void LandFX()//跳跃落地代码+
    {
        landFX.SetActive(true);
        landFX.transform.position = transform.position + new Vector3(0, -0.45f, 0);//paly和jump的坐标误差 //+
    }

    //放炸弹//+
    public void Attack()
    {
        if(Time.time > nextAttack)
        {
            //生成一个对象(对象, 坐标,旋转角度)
            Instantiate(bombPrefabs, transform.position, bombPrefabs.transform.rotation);
            //计算下一次可以放炸弹的时间
            nextAttack = Time.time + attackRate;
        }
    }

    //检测是否在地面
    void PhysicsCheck()
    {
        //有多种检测方法
        //(检测的2d坐标 范围 检测碰撞的图层)
        isGround = Physics2D.OverlapCircle(groundCheck.position, checkRadius, groundLayer);
        //是否在地面
        if (isGround)
        {
            isJump = false;
            rd.gravityScale = 1; //重力大小
        }
        else
        {
            rd.gravityScale = 3; //重力大小
            canJump = false;
        }
    }

    public void OnDrawGizmos()
    {
        //画圆 中心 半径
        Gizmos.DrawWireSphere(groundCheck.position, checkRadius);
    }

}

设置弹力

希望在放炸弹是时候炸弹会有弹力,那么在空中放落到地面会跳动
添加物理2D材质


这个时候,会一个bug,就是炸弹爆炸的时候

Land FX存在,那么获取到Land FX给它添加力的时候,没有刚体,会报错,所以我们把2个FX放在一个新图层FX中。
并且设置FX不和其他图层碰撞。

敌人

吹灭炸弹

动画


注意的是在制做受伤和死亡的动画的时候,白色要交错出现

并且10和11做成一个动画

给怪物添加一些组件


并且修改为NPC层,给玩家添加一个新层player。设置碰撞关系如下:


Cucumber、pointA,pointB:空物体
CheckArea一个空问题加碰撞体,逻辑是在A-B游走,Cucumber为视野。
并且为CheckArea新创建一个图层:CheckArea
视野只需要检测炸弹和玩家

代码


更改


代码

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

public class Enemy : MonoBehaviour
{
    [Header("Movement")]
    public float speed;//速度
    public Transform pointA, pointB;//左右的点
    public Transform targetPoint;//目标点
    public List<Transform> attackList = new List<Transform>(); //目标的集合
    
    void Start()
    {
        SwitchPoint();
    }

    void Update()
    {
        //移动到目标点
        if(Mathf.Abs(transform.position.x - targetPoint.position.x) < 0.01f)
        {
            SwitchPoint();
        }
        MoveToTarget();
    }

    //移到目标
    public void MoveToTarget()
    {   //从[参数1] 运动到 [参数2] 速度为 [参数3] Time.deltaTime在每个机型速度一致
        transform.position = Vector2.MoveTowards(transform.position, targetPoint.position, speed * Time.deltaTime); ;
        FilpDiection();
    }

    //攻击玩家
    public void AttackAction()
    {

    }

    //对炸弹使用技能
    public void SkillAction()
    {

    }

    //左右翻转
    public void FilpDiection()
    {
        if(transform.position.x < targetPoint.position.x)
        {
            transform.rotation = Quaternion.Euler(0f, 0f, 0f);
        }
        else
        {
            transform.rotation = Quaternion.Euler(0f, 180f, 0f);
        }
    }

    //切换目标点
    public void SwitchPoint()
    {
        //距离谁远,切换到谁
        if(Mathf.Abs(pointA.position.x - transform.position.x) > Mathf.Abs(pointB.position.x - transform.position.x))
        {
            targetPoint = pointA;
        }
        else
        {
            targetPoint = pointB;
        }
    }

    //在碰撞体内一直调用
    public void OnTriggerStay2D(Collider2D collision)
    {
        if (!attackList.Contains(collision.transform))
        {
            attackList.Add(collision.transform);
        }
    }

    //离开碰撞体调用
    public void OnTriggerExit2D(Collider2D collision)
    {
        Debug.Log("!!!");
        attackList.Remove(collision.transform);
    }
}

分类:

技术点:

相关文章: