地图搭建
视频教程: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);
}
}