untiy
https://assetstore.unity.com/packages/essentials/asset-packs/2d-beginner-tutorial-resources-140167
移动对象:
Assets/Scripts/PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//transform.Translate(transform.right * speed * Time.deltaTime);
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
Vector2 position = transform.position;
position.x += moveX * speed * Time.deltaTime;
position.y += moveY * speed * Time.deltaTime;
transform.position = position;
}
}
Tile瓦片部署场景
# 切割图片
Sprite Mode : Multiple
Sprite Editor
Pixels Per Unit : 64*3
# 自己的调色板
/Windows/2D/Tile Palette
# 部署场景
丰富场景
# 层级
Order in Layer : -1
# 克隆预制体
/Assets/Prefabs : 拖入目录存,拖出克隆
# 缸体
Rigidbody 2D
Gravity Scale : 0 重力
# 碰撞
Box Collider 2D
Edit Collider : 腰部以下,碰撞
# Y轴排序
Edit -- Project Settings -- Graphics
Coustom Axis : x0 y1 z0
# z轴禁用旋转
Ruby对象/Rigidbody 2D/Constraints/Freeze Rotation :把z勾上
# 创建空目录容纳对象
backGround -- 将物体托入目录
处理抖动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5f;
Rigidbody2D rbody; //刚体组件
// Start is called before the first frame update
void Start()
{
rbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
//transform.Translate(transform.right * speed * Time.deltaTime);
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
Vector2 position = rbody.position;
position.x += moveX * speed * Time.deltaTime;
position.y += moveY * speed * Time.deltaTime;
rbody.MovePosition(position);
}
}
相机跟随
Windows -- Packge Manger -- All -- Cinemachine -- install
Cinemachine -- Create 2D Camera
CM vcam1 -- Follow : 角色对象
#窗口大小
CM vcam1 -- Lens -- Orthographic Sixe : 5
水面禁行
Tilemap -- Add Component -- Tilemap Collider 2D
Tiles -- 选中除了水面以外的所有瓦片 -- Collider Type : None
Tilemap -- Add Component -- Composite Collider 2D
Tilemap -- Rigidbody 2D -- Gravity Scale : 0 去掉瓦片的重力
Tilemap -- Tilemap Collider 2D -- Used By Composite : 勾选合并
Tilemap -- Rigidbody 2D -- Body Type : static 钢体设置为静态不受物理作用
地图范围(相机边界)
CM vanm1 -- Add Extension : Cinemachine Confiner 选择添加相机控制
右键 -- Create Empty : 起名 CinemachineConfiner 添加空对象
CinemachineConfiner -- Add Component -- Polygon Collider 2D (可编辑的碰撞体,4个点) 给空对象加入4个点的碰撞体
CM vanm1 -- Bounding Shape 2D : 拖动CinemachineConfiner到此 边界形状绑定空碰撞体对象
CinemachineConfiner -- Polygon Collider 2D -- Is Trigger : 勾选只是触发。 不然相机把人物挤出去了。
草莓加血
草莓挂载: Collectible.cs 英汉:收藏
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 草莓拾取
/// </summary>
public class Collectible : MonoBehaviour
{
/// <summary>
/// 碰撞检测相关
/// </summary>
/// <param name="other"></param>
void OnTriggerEnter2D(Collider2D other)
{
PlayerController pc = other.GetComponent<PlayerController>();
if (pc != null)
{
if (pc.MyCurrentHealth < pc.MyMaxHealth) {
pc.ChangeHealth(1);
Destroy(this.gameObject);
}
//Debug.Log("玩家碰到了草莓!");
}
}
}
玩家挂载: PlayerController.cs 英汉:玩家控制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5f; //移动速度
private int maxHealth = 5; //最大生命值
private int currentHealth; //当前生命值
public int MyMaxHealth { get { return maxHealth; } }
public int MyCurrentHealth { get { return currentHealth; } }
Rigidbody2D rbody; //刚体组件
// Start is called before the first frame update
void Start()
{
currentHealth = 2;
rbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
//transform.Translate(transform.right * speed * Time.deltaTime);
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
Vector2 position = rbody.position;
position.x += moveX * speed * Time.deltaTime;
position.y += moveY * speed * Time.deltaTime;
rbody.MovePosition(position);
}
/// <summary>
/// 改变玩家的生命值
/// </summary>
/// <param name="amount"></param>
public void ChangeHealth(int amount)
{
//把玩家生命值约束在0和max之间
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
Debug.Log(currentHealth+"/"+maxHealth);
}
}
陷阱减血
陷阱挂载: Damagebale.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 伤害陷阱相关
/// </summary>
public class Damagebale : MonoBehaviour
{
private void OnTriggerStay2D(Collider2D other)
{
PlayerController pc = other.GetComponent<PlayerController>();
if (pc != null)
{
pc.ChangeHealth(-1);
}
}
}
玩家挂载: PlayerController.cs 英汉:玩家控制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5f; //移动速度
private int maxHealth = 5; //最大生命值
private int currentHealth; //当前生命值
public int MyMaxHealth { get { return maxHealth; } }
public int MyCurrentHealth { get { return currentHealth; } }
private float invincibleTime = 2f; //无敌时间2秒
private float invincibleTimer; //无敌计时器
private bool isInvincible; //是否无敌
Rigidbody2D rbody; //刚体组件
// Start is called before the first frame update
void Start()
{
currentHealth = 2;
invincibleTimer = 0;
rbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
//transform.Translate(transform.right * speed * Time.deltaTime);
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
Vector2 position = rbody.position;
position.x += moveX * speed * Time.deltaTime;
position.y += moveY * speed * Time.deltaTime;
rbody.MovePosition(position);
//无敌记时---------------------------------------------
if (isInvincible)
{
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0)
{
isInvincible = false; //无敌时间结束
}
}
}
/// <summary>
/// 改变玩家的生命值
/// </summary>
/// <param name="amount"></param>
public void ChangeHealth(int amount)
{
if (amount < 0) //玩家收到伤害
{
if (isInvincible == true) //玩家收到伤害时是无敌:跳出ChangeHealth
{
return;
}
isInvincible = true; //玩家受到伤害时不是无敌:先改成无敌
invincibleTimer = invincibleTime; //不是无敌:再改设置计时时间再正常走ChangeHealth
}
//把玩家生命值约束在0和max之间
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
Debug.Log(currentHealth+"/"+maxHealth);
}
}
关系陷阱备注:
#玩家钢体持续监测属性修改: (不动也掉血)
Ruby -- Sleeping Mode : Never Sleep
#陷阱平铺: (不变形)
Damagebale (Texture 2D) import Settings -- Mesh Type : Full Rect (这个图片可以平铺)
Damagebale -- Draw Mode -- Tiled (这个对象可以T箱拖动屏蔽)
机器人移动转向碰撞
EnemyController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 敌人控制相关
/// </summary>
public class EnemyController : MonoBehaviour
{
public float speed = 3;
private Rigidbody2D rbody;
public bool isVertical; //是否垂直方向移动
private Vector2 moveDirection; //移动方向
public float changeDirectionTime = 3; //切换方向时间2秒
private float changeTimer;
// Start is called before the first frame update
void Start()
{
rbody = GetComponent<Rigidbody2D>(); //获取刚体
moveDirection = isVertical ? Vector2.up : Vector2.right; //如果时垂直移动,设定向上,否则设定向右
changeTimer = changeDirectionTime;
}
// Update is called once per frame
void Update()
{
changeTimer -= Time.deltaTime;
if (changeTimer < 0 )
{
moveDirection *= -1; //切换方向
changeTimer = changeDirectionTime;
}
Vector2 position = rbody.position; //敌人移动
position.x += moveDirection.x * speed * Time.deltaTime;
position.y += moveDirection.y * speed * Time.deltaTime;
rbody.MovePosition(position);
}
// 敌人与玩家碰撞
private void OnCollisionEnter2D(Collision2D other)
{
PlayerController pc = other.gameObject.GetComponent<PlayerController>();
if (pc != null)
{
pc.ChangeHealth(-1);
}
}
}
草莓动画
选中一个草莓 – Ctrl+6(或Window/Animation/Animation) – Create – (Assets目录/Animatior/Items/idle.anim) – 修改帧数 – 设置关键帧属性
敌人动画
选中一个机器人 -- 没个方向拖入4帧的图片组成动画(创建4个目录上下左右)
缺一个向右的动画 :选中一个机器人 -- Ctrl+6 -- Create New Clip -- 起名walk_right -- 托入向左的4个图像然后做X轴翻转: Add Property -- Sprite Renderer -- Flip X -- 都勾起。
回到敌人Robot属性 -- Animator -- Controller -- Robot -- 创建一个混合树Walk,把Entry的默认动画设置为混合树
混合树Base Layer -- Walk -- Inspector -- Blend Type : 2D simple Directoional
混合树Base Layer -- Walk -- Inspector -- 把上面的上下左右四个动画Add到混合树,分别赋值+1或-1。 完事这4个动画可以删除了,有混合树就行了。
混合树Base Layer : 添加两个参数moveX,moveY,fix
混合树Base Layer -- Walk->Fixed链接修理好的状态 -- 把过度时间去掉: Has Exit Time的勾选去掉 , Settings -- Fixed Duration的勾选去掉,Transtion Duration:0秒
敌人移动动画脚本:EnemyController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 敌人控制相关
/// </summary>
public class EnemyController : MonoBehaviour
{
public float speed = 3;
private Rigidbody2D rbody; //刚体定义
public bool isVertical; //是否垂直方向移动
private Vector2 moveDirection; //移动方向
public float changeDirectionTime = 3; //切换方向时间2秒
private float changeTimer;
private Animator anim; //动画定义
// Start is called before the first frame update
void Start()
{
rbody = GetComponent<Rigidbody2D>(); //获取刚体
anim = GetComponent<Animator>(); //获取动画
moveDirection = isVertical ? Vector2.up : Vector2.right; //如果时垂直移动,设定向上,否则设定向右
changeTimer = changeDirectionTime;
}
// Update is called once per frame
void Update()
{
changeTimer -= Time.deltaTime;
if (changeTimer < 0 )
{
moveDirection *= -1; //切换方向
changeTimer = changeDirectionTime;
}
Vector2 position = rbody.position; //敌人移动
position.x += moveDirection.x * speed * Time.deltaTime;
position.y += moveDirection.y * speed * Time.deltaTime;
rbody.MovePosition(position);
//敌人移动动画
anim.SetFloat("moveX",moveDirection.x);
anim.SetFloat("moveY", moveDirection.y);
}
// 敌人与玩家碰撞
private void OnCollisionEnter2D(Collision2D other)
{
PlayerController pc = other.gameObject.GetComponent<PlayerController>();
if (pc != null)
{
pc.ChangeHealth(-1);
}
}
}
玩家移动动画
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5f; //移动速度
private int maxHealth = 5; //最大生命值
private int currentHealth; //当前生命值
public int MyMaxHealth { get { return maxHealth; } }
public int MyCurrentHealth { get { return currentHealth; } }
private float invincibleTime = 2f; //无敌时间2秒
private float invincibleTimer; //无敌计时器
private bool isInvincible; //是否无敌
private Vector2 lookDirection = new Vector2(1, 0); //默认朝向右方
Rigidbody2D rbody; //刚体组件
Animator anim; //获取动画组
// Start is called before the first frame update
void Start()
{
currentHealth = 2;
invincibleTimer = 0;
rbody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
//transform.Translate(transform.right * speed * Time.deltaTime);
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
//角色方向更具前后左右来选中方向
Vector2 moveVector = new Vector2(moveX, moveY);
if (moveVector.x != 0 || moveVector.y != 0)
{
lookDirection = moveVector;
}
anim.SetFloat("Look X",lookDirection.x);
anim.SetFloat("Look Y",lookDirection.y);
//方向移动动画
anim.SetFloat("Speed",moveVector.magnitude);
//基础移动------------------------------------------------
Vector2 position = rbody.position;
//position.x += moveX * speed * Time.deltaTime;
//position.y += moveY * speed * Time.deltaTime;
position += moveVector * speed * Time.deltaTime;
rbody.MovePosition(position);
//无敌记时---------------------------------------------
if (isInvincible)
{
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0)
{
isInvincible = false; //无敌时间结束
}
}
}
/// <summary>
/// 改变玩家的生命值
/// </summary>
/// <param name="amount"></param>
public void ChangeHealth(int amount)
{
if (amount < 0) //玩家收到伤害
{
if (isInvincible == true) //玩家收到伤害时是无敌:跳出ChangeHealth
{
return;
}
isInvincible = true; //玩家受到伤害时不是无敌:先改成无敌
invincibleTimer = invincibleTime; //不是无敌:再改设置计时时间再正常走ChangeHealth
}
//把玩家生命值约束在0和max之间
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
Debug.Log(currentHealth+"/"+maxHealth);
}
}
子弹
子弹脚本: BulletlconController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 控制子弹的移动、碰撞
/// </summary>
public class BulletlconController : MonoBehaviour
{
Rigidbody2D rbody;
// Start is called before the first frame update
void Awake()
{
rbody = GetComponent<Rigidbody2D>();
Destroy(this.gameObject,2f); //多长时间后消失
}
/// <summary>
/// 子弹移动
/// </summary>
/// <param name="moveDirection"></param>
/// <param name="moveForce"></param>
public void Move(Vector2 moveDirection, float moveForce)
{
rbody.AddForce(moveDirection * moveForce);
}
/// <summary>
/// 子弹碰撞检测
/// </summary>
/// <param name="other"></param>
void OnCollisionEnter2D(Collision2D other)
{
EnemyController ec = other.gameObject.GetComponent<EnemyController>();
if (ec != null)
{
Debug.Log("子弹碰到了敌人");
ec.Fixed(); //修复敌人
}
Destroy(this.gameObject); //碰撞后消失
}
}
机器人脚本(被修复)Damagebale.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 敌人控制相关
/// </summary>
public class EnemyController : MonoBehaviour
{
public float speed = 3;
private Rigidbody2D rbody; //刚体定义
public bool isVertical; //是否垂直方向移动
private Vector2 moveDirection; //移动方向
public float changeDirectionTime = 3; //切换方向时间2秒
private float changeTimer;
private Animator anim; //动画定义
private bool isFixed ; //被修理过
// Start is called before the first frame update
void Start()
{
rbody = GetComponent<Rigidbody2D>(); //获取刚体
anim = GetComponent<Animator>(); //获取动画
moveDirection = isVertical ? Vector2.up : Vector2.right; //如果时垂直移动,设定向上,否则设定向右
changeTimer = changeDirectionTime;
isFixed = false;
}
// Update is called once per frame
void Update()
{
if (isFixed) return; //如果被修复了就不执行下面的代码
changeTimer -= Time.deltaTime;
if (changeTimer < 0 )
{
moveDirection *= -1; //切换方向
changeTimer = changeDirectionTime;
}
Vector2 position = rbody.position; //敌人移动
position.x += moveDirection.x * speed * Time.deltaTime;
position.y += moveDirection.y * speed * Time.deltaTime;
rbody.MovePosition(position);
//敌人移动动画
anim.SetFloat("moveX",moveDirection.x);
anim.SetFloat("moveY", moveDirection.y);
}
// 敌人与玩家碰撞
private void OnCollisionEnter2D(Collision2D other)
{
PlayerController pc = other.gameObject.GetComponent<PlayerController>();
if (pc != null)
{
pc.ChangeHealth(-1);
}
}
// 敌人与子弹的碰撞,被修复
public void Fixed()
{
isFixed = true;
rbody.simulated = false; //禁用物理
anim.SetTrigger("fix"); //播放被修复的动画
}
}
玩家控制子弹脚本:PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5f; //移动速度
private int maxHealth = 5; //最大生命值
private int currentHealth; //当前生命值
public int MyMaxHealth { get { return maxHealth; } }
public int MyCurrentHealth { get { return currentHealth; } }
private float invincibleTime = 2f; //无敌时间2秒
private float invincibleTimer; //无敌计时器
private bool isInvincible; //是否无敌
private Vector2 lookDirection = new Vector2(1, 0); //默认朝向右方
public GameObject bulletPrefab; //获取子弹
Rigidbody2D rbody; //刚体组件
Animator anim; //获取动画组
// Start is called before the first frame update
void Start()
{
currentHealth = 2;
invincibleTimer = 0;
rbody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
//transform.Translate(transform.right * speed * Time.deltaTime);
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
//角色方向更具前后左右来选中方向
Vector2 moveVector = new Vector2(moveX, moveY);
if (moveVector.x != 0 || moveVector.y != 0)
{
lookDirection = moveVector;
}
anim.SetFloat("Look X",lookDirection.x);
anim.SetFloat("Look Y",lookDirection.y);
//方向移动动画
anim.SetFloat("Speed",moveVector.magnitude);
//基础移动------------------------------------------------
Vector2 position = rbody.position;
//position.x += moveX * speed * Time.deltaTime;
//position.y += moveY * speed * Time.deltaTime;
position += moveVector * speed * Time.deltaTime;
rbody.MovePosition(position);
//无敌记时---------------------------------------------
if (isInvincible)
{
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0)
{
isInvincible = false; //无敌时间结束
}
}
//按下J键,创建发射子弹
if (Input.GetKeyDown(KeyCode.J))
{
anim.SetTrigger("Launch"); //播放发射动画
GameObject bullet = Instantiate(bulletPrefab, rbody.position + Vector2.up * 0.5f,Quaternion.identity);
BulletlconController bc = bullet.GetComponent<BulletlconController>();
if (bc != null)
{
bc.Move(lookDirection, 300);
}
}
}
/// <summary>
/// 改变玩家的生命值
/// </summary>
/// <param name="amount"></param>
public void ChangeHealth(int amount)
{
if (amount < 0) //玩家收到伤害
{
if (isInvincible == true) //玩家收到伤害时是无敌:跳出ChangeHealth
{
return;
}
isInvincible = true; //玩家受到伤害时不是无敌:先改成无敌
invincibleTimer = invincibleTime; //不是无敌:再改设置计时时间再正常走ChangeHealth
}
//把玩家生命值约束在0和max之间
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
Debug.Log(currentHealth+"/"+maxHealth);
}
}
玩家挂载子弹设置
Roby -- Player Controller -- Bullet Prefab : UIBulletlcon //挂载上子弹预制体
Roby -- Layer -- Add Layer -- User Layer8 : Player //第8层添加一个player层
预制体UIBulletlcon -- Layer -- Add -- User Layer9 : Bullet //第9层子弹
再各自选层(不要Default)
Edit -- Project Settings -- Physics 2D -- Layer Collision Matrix //去掉层级碰撞勾选2个