版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
个人做单机游戏的总结笔记
——类似元气骑士的2.5d游戏
移动
玩家人物移动方式:
//键盘输入控制上下左右(后期用摇杆可以不用这种方式)
horizontal = Input.GetAxisRaw("Horizontal");
vertical = Input.GetAxisRaw("Vertical");
if (Mathf.Abs(horizontal) > 0.01 || Mathf.Abs(vertical) > 0.01)
{
//记录方向
idleH=horizontal;
idleV=vertical;
//改变人物位置,moveSpeed为人物移动速度
transform.Translate(new Vector3(horizontal * moveSpeed* Time.deltaTime, vertical * moveSpeed* Time.deltaTime, 0),Space.World);
}
同样方式,做敌人自动移动方式(可以加上一些检测能使得敌人更加“精明”):
//用随机数来控制上下左右
if(IsPlayer == false)
{
horizontal = Random.Range(-1, 2);
vertical = Random.Range(-1, 2);
}
//改变敌人的位置
enemyPos.transform.Translate(new Vector3(horizontal * moveSpeed * Time.deltaTime, vertical * moveSpeed* Time.deltaTime, 0), Space.World);
人物攻击
近身攻击
可以在武器加触发器(武器大小要比较统一)或者在人物身前加触发器(要用代码控制使跟人物一起移动选择)
- 个人用第二种方式(素材在网上找比较乱,所以选择这种方式,但是感觉第一种判断比较精准,敌人与玩家类似。):
——玩家人物近攻攻击
Close_Attack.cs(挂载在武器子物体下的空物体)
void Update()
{
//攻击的时候才显示
if(!Player ._instance.isAttack )
{
this.gameObject.SetActive(false);
}
}
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.transform.tag=="Enemy")
{
Enemy enemy;
enemy = collider.GetComponentInChildren<Enemy>();
enemy.LoseHP(damge);//damge为伤害值,LoseHP为敌人脚本里面的掉血函数
}
}
Player.cs
//攻击范围方向
h=idleH;
v=idleV;
if (v == 1)
{
//相当于沿Y轴翻转
Range_Attack.localScale = new Vector3(- Mathf.Abs(Range_Attack.localScale.x), Range_Attack.localScale.y, Range_Attack.localScale.z);
//翻转后X方向会与原来不一样
h *= -1;
}
else
Range_Attack.localScale = new Vector3( Mathf.Abs(Range_Attack.localScale.x, Range_Attack.localScale.y, Range_Attack.localScale.z);
//选择攻击范围,使保持在人的正前方
float angle = Vector2.Angle(-Vector2.right, new Vector2(h, v));
Range_Attack.rotation = Quaternion.Euler(0, 0, angle);
- 第一种方法(自己想了一下,挺简单的,可能有点不完善,控制位置变化就在武器跟随部分完成):
——玩家人物近攻攻击
首先给武器加个触发器(可以用胶囊体触发器),脚本如下:
AttackRange.cs(挂载在武器子物体下的空物体)
void Update()
{
//攻击的时候才显示
if(!Player ._instance.isAttack )
{
this.gameObject.SetActive(false);
}
}
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.transform.tag=="Enemy")
{
Enemy enemy;
enemy = collider.GetComponentInChildren<Enemy>();
enemy.LoseHP(damge);//damge为伤害值,LoseHP为敌人脚本里面的掉血函数
}
}
远程攻击
—— 玩家人物远程攻击
- Player.cs
if(weapontype==“Gun”)//远程攻击
{
//实例化出子弹(bullet为做好的子弹prefab)
GameObject bullets = GameObject.Instantiate(bullet, new Vector3(transform.position.x, transform.position.y, 0), Quaternion.identity);
//给予子弹人朝向的方向一个速度,BulletSpeed为子弹飞行速度
bullets.GetComponent<Rigidbody2D>().velocity = new Vector2(idleH * BulletSpeed, idleV * BulletSpeed);
}
- Bullet.cs(挂载在子弹的脚本,加个刚体和触发器。)
void OnTriggerEnter2D(Collider2D collider)
{
switch(collider.transform.tag)
{
case "Enemy":
Enemy enemy;
enemy = collider.GetComponentInChildren<Enemy>();
enemy.LoseHP(damge);//damge为伤害值,LoseHP为敌人脚本里面的掉血函数
Destroy(this.gameObject);
break;
case "Obstacle":
//如果是可以破碎的障碍物可以当作敌人处理。
case "Wall":
Destroy(this.gameObject);
break;
}
}
——敌人远程攻击
- ShootEnemy.cs
public virtual void Attack()//用虚方法可以再其他远程攻击的敌人改变子弹发射方式
{
GameObject bullets = GameObject.Instantiate(bullet, new Vector3(transform.position.x,.transform.position.y, 0), Quaternion.identity);
//给予子弹向玩家方向一个速度,BulletSpeed为子弹飞行速度
bullets.GetComponent<Rigidbody2D>().velocity = ((PlayerPos-transform.position).normalized *BulletSpeed);
}
- Bullet_En.cs(挂载在敌人子弹的脚本,加个刚体和触发器。)
void OnTriggerEnter2D(Collider2D collider)
{
switch(collider.transform.tag)
{
case "Player":
//用获取Player或者人物作为单例模式,直接调用。因为人物就一个可以用单例,敌人有多个用单例会混乱。
Player player;
player= collider.GetComponentInChildren<Player >();
player.LoseHP(damge);//damge为伤害值,LoseHP为人物脚本里面的掉血函数
Destroy(this.gameObject);
break;
case "Obstacle":
//如果是可以破碎的障碍物可以当作人物处理。
case "Wall":
Destroy(this.gameObject);
break;
}
}
敌人追随
private void OnTriggerStay2D(Collider2D collider)
{
if (collider.tag == "Player")
{
//获取角色位置
PlayerPos = collider.transform.position;
//敌人走到一定位置就不在走了,也可以不设置
if ((PlayerPos - enemyPos.transform.position).magnitude > distance)
{
//获取x,y方向
horizontal = (PlayerPos.x - enemyPos.transform.position.x)%2;
vertical = (PlayerPos.y - enemyPos.transform.position.y)%2;
}
}
}
private void OnTriggerEnter2D(Collider2D collider)
{
if (collider.tag == "Player")
IsPlayer = true;
}
private void OnTriggerExit2D(Collider2D collider)
{
if (collider.tag == "Player")
IsPlayer = false;
}
//
武器追随
——武器适合向上并且刀锋向左(远程近程都是),这个是武器随着你控制人物的移动朝向而旋转。
- 更多武器旋转方式:https://blog.csdn.net/weixin_43701019/article/details/98533603
//武器追随
if (! isAttack )
{
//人物移动才更新位置
if( horizontal != 0 || vertical != 0)
m_mousePosition = new Vector3( horizontal, vertical, 0);
// 武器朝向角度
float m_weaponAngle = Vector2.Angle(Vector2.up, m_mousePosition);
if (0 < m_mousePosition.x)
m_weaponAngle = -m_weaponAngle;
//判断武器正反
//scale的x要为正数
if (m_weaponAngle > 0 &&WeaponPos.transform.localScale.x < 0)
{
WeaponPos.transform.localScale = new Vector3(-WeaponPos.transform.localScale.x, WeaponPos.transform.localScale.y, WeaponPos.transform.localScale.z);
}
//scale的x要为负数
else if (m_weaponAngle < 0 && WeaponPos.transform.localScale.x > 0)
{
WeaponPos.transform.localScale = new Vector3(-WeaponPos.transform.localScale.x, WeaponPos.transform.localScale.y, WeaponPos.transform.localScale.z);
}
else if ((m_weaponAngle == 0 || m_weaponAngle == 180) && WeaponPos.transform.localScale.x < 0)
{
WeaponPos.transform.localScale = new Vector3(- WeaponPos.transform.localScale.x, WeaponPos.transform.localScale.y, WeaponPos. transform.localScale.z);
}
//近攻武器竖直,如果枪横抬。
if (weaponType == "Axe")
{
if (0 < m_mousePosition.x)
m_weaponAngle = -(-m_weaponAngle - 90);
else
m_weaponAngle -= 90;
}
// 变换最终角度
transform.eulerAngles = new Vector3(0, 0, m_weaponAngle);
}
//人物攻击执行攻击效果
//近攻武器用旋转来做攻击效果
else if (weaponType == "Axe" && isAttack)
{
//获取武器现在的旋转
weaAngle = weaponObj.transform.localEulerAngles.z ;
//判断武器现在向的是左边还是右边
//左边
if (weaponObj.transform.localScale.x > 0)
{
//攻击角度,Ang为砍到最终的角度
angZ = Mathf.Lerp(angZ, Ang, Time.deltaTime* angSpeed );
weaponObj.transform.rotation = Quaternion.Euler(new Vector3(0, 0, weaAngle + angZ));
//砍到终点,停止攻击
if (Ang- angZ<1)
StopAttack();
}
//右边
else
{
//攻击角度,Ang为砍到最终的角度
angZ = Mathf.Lerp(angZ, Ang, Time.deltaTime* angSpeed);
weaponObj.transform.rotation = Quaternion.Euler(new Vector3(0, 0, weaAngle - angZ));
//砍到终点,停止攻击
if (Ang-angZ< 1)
StopAttack();
}
}
人物无敌状态
——受伤之后一段时间无敌并闪烁
//用枚举来列出人物状态,根据需求还能加入其他状态
public enum State
{
Playing, Unmatching
}
//人物现处于哪个状态
private State state = State.Playing;
public State States
{
get {
return state;
}
set {
state = value;
}
}
//用协程来实现无敌的闪烁
IEnumerator Unmatch()
{
if (hp > 0)
{
int i = 0;
//闪烁的频率为0.2秒,无敌时间为2秒。
while (i < 10)
{
spriteRen.enabled = !spriteRen.enabled;
i++;
yield return new WaitForSeconds(0.2f);
}
state = State.Playing;
}
StopCoroutine("Unmatch");
}
//给外部来调用协程
public void StartUnmatch()
{
StartCoroutine("Unmatch");
}
摇杆(参考网上的)
——这是摇杆的组成
- joystickwin是最外层的半透明圈圈。
- border是位置记录,放在内圈的边上,用来获取半径
- p-dap是最主要的,首先在其挂载一个脚本和一个事件触发器(设置如图)
脚本如下:
//虚拟方向按钮初始位置
public Vector3 initPosition;
//虚拟方向按钮可移动的半径
public float r;
//border对象
public Transform border;
public Player PlayerObj;
void Start()
{
//获取border对象的transform组件
border = GameObject.Find("border").transform;
initPosition = GetComponentInParent<RectTransform>().position;
r = Vector3.Distance(transform.position, border.position);
}
//鼠标拖拽
public void OnDragIng()
{
//如果鼠标到虚拟键盘原点的位置 < 半径r
if (Vector3.Distance(Input.mousePosition, initPosition) < r)
{
//虚拟键跟随鼠标
transform.position = Input.mousePosition;
}
else
{
//计算出鼠标和原点之间的向量
Vector3 dir = Input.mousePosition - initPosition;
//这里dir.normalized是向量归一化的意思,实在不理解你可以理解成这就是一个方向,就是原点到鼠标的方向,乘以半径你可以理解成在原点到鼠标的方向上加上半径的距离
transform.position = initPosition + dir.normalized * r;
}
PlayerObj .horizontal = (transform.position.x - initPosition.x) / r;
PlayerObj.vertical = (transform.position.y - initPosition.y) / r;
}
//鼠标松开
public void OnDragEnd()
{
//松开鼠标虚拟摇杆回到原点
transform.position = initPosition;
PlayerObj.horizontal = PlayerObj.vertical = 0;
}
}