using RichCreator.Utility;
|
using RichCreator.Utility.InputControl;
|
using RichCreator.Utility.Structs;
|
using RichCreator.Jobs.StateMachines;
|
using RichCreator.Maps;
|
using RichCreator.Utilitys;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading;
|
using System.Threading.Tasks;
|
using static RichCreator.Jobs.StateMachines.KillMonsterStateMachine;
|
using Utils = RichCreator.Utilitys.Utils;
|
|
namespace RichCreator.StateMachines
|
{
|
public class MoveState
|
{
|
private const Int32 PaddingLeft = 140;//左边框内边距
|
private const Int32 PaddingRight = 140;//右边框内边距
|
|
public MoveState(ZTRectangle gameRect, MapHouse house)
|
{
|
this.gameRect = gameRect;
|
this.house = house;
|
|
minCenterLineY = this.gameRect.End.Y + this.house.HouseCenterMoveLine - centerLineErrorRange;
|
maxCenterLineY = this.gameRect.End.Y + this.house.HouseCenterMoveLine + centerLineErrorRange;
|
}
|
|
|
|
/// <summary>
|
/// 步行速度,每100毫秒
|
/// </summary>
|
public static readonly ZTSizeDouble SpeedOfStep = new ZTSizeDouble(0.29d, 0.24d);
|
|
/// <summary>
|
/// 跑速度,每100毫秒
|
/// </summary>
|
public static readonly ZTSizeDouble SpeedOfRun = new ZTSizeDouble(0.66d, 0);
|
|
/// <summary>
|
/// 开始跑的阀值
|
/// </summary>
|
public static readonly double RunThresold = SpeedOfStep.Width*RandomUtils.KeyPressDurationMax+SpeedOfRun.Width*RandomUtils.KeyPressDurationMax;
|
|
/// <summary>
|
/// 左侧随机移动距离
|
/// </summary>
|
public static readonly Int32 LeftRandomMoveDistance = 600;
|
|
/// <summary>
|
/// 左侧随机移动毫秒数
|
/// </summary>
|
public static readonly double LeftRandomMoveMillSecond = LeftRandomMoveDistance / SpeedOfStep.Width;
|
|
/// <summary>
|
/// 上边随机移动距离
|
/// </summary>
|
public static readonly Int32 TopRandomMoveDistance = 300;
|
|
/// <summary>
|
/// 上边随机移动毫秒数
|
/// </summary>
|
public static readonly double TopRandomMoveMillSecond = TopRandomMoveDistance / SpeedOfStep.Height;
|
|
/// <summary>
|
/// 右侧随机移动距离
|
/// </summary>
|
public static readonly Int32 RightRandomMoveDistance = 600;
|
|
/// <summary>
|
/// 右侧随机移动毫秒数
|
/// </summary>
|
public static readonly double RightRandomMoveMillSecond = RightRandomMoveDistance / SpeedOfStep.Width;
|
|
/// <summary>
|
/// 下边随机移动距离
|
/// </summary>
|
public static readonly Int32 BottomRandomMoveDistance = 300;
|
|
|
/// <summary>
|
/// 下边随机移动毫秒数
|
/// </summary>
|
public static readonly double BottomRandomMoveMillSecond = BottomRandomMoveDistance / SpeedOfStep.Height;
|
|
|
|
private Int32 minCenterLineY;
|
private Int32 maxCenterLineY;
|
private Int32 centerLineErrorRange = 35;//中间性可允许的误差
|
|
private MapHouse house;
|
private ZTRectangle gameRect = ZTRectangle.Empty;
|
|
private HIDCode moveKey = HIDCode.NoEvent;
|
private MoveIntent movingIntent = MoveIntent.ToAttack;//移动意图
|
private MoveMethod movingMethod= MoveMethod.Vertical;//移动方式,默认垂直移动
|
private ZTSize movingDistance;//移动距离
|
|
|
/// <summary>
|
/// 按下的键,0:横向,1:纵向
|
/// </summary>
|
private HIDCode[] pressKeys = new HIDCode[] { HIDCode.NoEvent, HIDCode.NoEvent };
|
private bool isRuning = false;
|
|
|
/// <summary>
|
/// 移动方式
|
/// </summary>
|
public enum MoveMethod
|
{
|
Vertical,//默认垂直移动
|
ToLeft,//左移动
|
ToRight,//右移动
|
Fixed//固定离动距离
|
}
|
|
/// <summary>
|
/// 移动意图
|
/// </summary>
|
public enum MoveIntent
|
{
|
None,//没移动
|
ToAttack,//去攻击
|
ToFindDoor,//去找门
|
ToFindRole,//找主角
|
ToPickup//去拾取
|
}
|
|
/// <summary>
|
/// 是否移动中
|
/// </summary>
|
public bool IsMoving
|
{
|
get
|
{
|
return pressKeys[0]!=HIDCode.NoEvent||pressKeys[1]!=HIDCode.NoEvent;
|
}
|
}
|
|
/// <summary>
|
/// 是否正在攻击移动
|
/// </summary>
|
/// <returns></returns>
|
public bool IsAttackMoving
|
{
|
get
|
{
|
if (IsMoving && movingIntent == MoveIntent.ToAttack)
|
{
|
return true;
|
}
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 是否正在查门移动
|
/// </summary>
|
/// <returns></returns>
|
public bool IsFindDoorMoving
|
{
|
get
|
{
|
if (IsMoving && movingIntent == MoveIntent.ToFindDoor)
|
{
|
return true;
|
}
|
return false;
|
}
|
}
|
|
|
/// <summary>
|
/// 是否正在查找主角移动
|
/// </summary>
|
/// <returns></returns>
|
public bool IsFindRoleMoving
|
{
|
get
|
{
|
if (IsMoving && movingIntent == MoveIntent.ToFindRole)
|
{
|
return true;
|
}
|
return false;
|
}
|
}
|
|
|
/// <summary>
|
/// 是否正在去拾取移动
|
/// </summary>
|
/// <returns></returns>
|
public bool IsPickupMoving
|
{
|
get
|
{
|
if (IsMoving && movingIntent == MoveIntent.ToPickup)
|
{
|
return true;
|
}
|
return false;
|
}
|
}
|
|
|
/// <summary>
|
/// 攻击移动
|
/// </summary>
|
/// <param name="moveDistance"></param>
|
public void AttackMove(ZTSize moveDistance)
|
{
|
PutKey(moveDistance);
|
movingIntent = MoveIntent.ToAttack;
|
}
|
|
private Int32 RandomDirRun = 0;//随机行走的方向
|
private const Int32 FindRoleMaxDelayMillSecond = 1000;//找角色开始移动最大延迟
|
private DateTime FindRoleMoveTimeout = DateTime.MinValue;//方向移动过期时间
|
private DateTime FindRoleStartTimeout = DateTime.MinValue;//开始查找主角移动过期时间
|
/// <summary>
|
/// 查找主角移动
|
/// </summary>
|
/// <param name="moveDistance"></param>
|
public void FindRoleMove()
|
{
|
bool recomputationTimeoutTime = false;
|
//延迟开始找角色
|
if (!IsMoving)
|
{
|
if (FindRoleStartTimeout == DateTime.MinValue)
|
{
|
//开始计时
|
FindRoleStartTimeout = DateTime.Now.AddMilliseconds(FindRoleMaxDelayMillSecond);
|
return;
|
}
|
|
if (DateTime.Now < FindRoleStartTimeout)
|
{
|
//未超过延迟时间
|
return;
|
}
|
|
//计算超时
|
recomputationTimeoutTime = true;
|
}
|
|
if (DateTime.Now>=FindRoleMoveTimeout)
|
{
|
//转换方向,计算超时
|
RandomDirRun++;
|
recomputationTimeoutTime = true;
|
}
|
|
HIDCode dirKey = HIDCode.NoEvent;
|
switch (RandomDirRun % 4)
|
{
|
case 0:
|
dirKey = HIDCode.LeftArrow;
|
if (recomputationTimeoutTime)
|
{
|
FindRoleMoveTimeout = DateTime.Now.AddMilliseconds(LeftRandomMoveMillSecond);
|
}
|
|
//movingDistance = new ZTPoint(-MoveMonitor.LeftRandomMoveDistance, 0);
|
break;
|
case 1:
|
dirKey = HIDCode.UpArrow;
|
if (recomputationTimeoutTime)
|
{
|
FindRoleMoveTimeout = DateTime.Now.AddMilliseconds(TopRandomMoveMillSecond);
|
}
|
|
//movingDistance = new ZTPoint(0, -MoveMonitor.TopRandomMoveDistance);
|
break;
|
case 2:
|
dirKey = HIDCode.RightArrow;
|
if (recomputationTimeoutTime)
|
{
|
FindRoleMoveTimeout = DateTime.Now.AddMilliseconds(RightRandomMoveMillSecond);
|
}
|
|
//movingDistance = new ZTPoint(MoveMonitor.RightRandomMoveDistance, 0);
|
break;
|
case 3:
|
dirKey = HIDCode.DownArrow;
|
if (recomputationTimeoutTime)
|
{
|
FindRoleMoveTimeout = DateTime.Now.AddMilliseconds(BottomRandomMoveMillSecond);
|
}
|
|
//movingDistance = new ZTPoint(0, MoveMonitor.BottomRandomMoveDistance);
|
break;
|
}
|
|
|
|
if (!IsMoving || (IsMoving && dirKey != moveKey))
|
{
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, dirKey);
|
moveKey = dirKey;
|
}
|
movingIntent = MoveIntent.ToFindRole;
|
}
|
|
|
/// <summary>
|
/// 拾起物品移动
|
/// </summary>
|
public void PickupMove(ZTPoint rolePosition,ZTPoint thingItemPosition)
|
{
|
ZTSize moveDistance = new ZTSize(thingItemPosition.X - rolePosition.X, thingItemPosition.Y - rolePosition.Y - 97);
|
if (Math.Abs(moveDistance.Width) < 100 && Math.Abs(moveDistance.Height)<100)
|
{
|
//距离允许,就近距离移动并X
|
G.Instance.DebugWriter("distance ok");
|
SyncMove(moveDistance);
|
G.Instance.InputControl.PressKey(RandomUtils.G(400, 500), HIDCode.X);
|
return;
|
}
|
|
//G.Instance.DebugWriter("pickup distance:" + moveDistance.ToString());
|
PutKey(moveDistance);
|
movingIntent = MoveIntent.ToPickup;
|
}
|
|
/// <summary>
|
/// 找门找怪移动
|
/// </summary>
|
/// <param name="rolePosition"></param>
|
public void FindDoorMove(ZTPoint rolePosition)
|
{
|
ComputeMoveInfo(rolePosition);
|
|
HIDCode dirKey = HIDCode.NoEvent;
|
switch (movingMethod)
|
{
|
case MoveMethod.ToLeft:
|
dirKey = HIDCode.LeftArrow;
|
break;
|
case MoveMethod.ToRight:
|
dirKey = HIDCode.RightArrow;
|
break;
|
case MoveMethod.Vertical:
|
dirKey = movingDistance.Height > 0 ? HIDCode.DownArrow : HIDCode.UpArrow;
|
break;
|
case MoveMethod.Fixed:
|
SyncMove(movingDistance);
|
ReleaseKey();
|
return;
|
}
|
|
PutKey(movingDistance);
|
movingIntent = MoveIntent.ToFindDoor;
|
}
|
|
|
private ZTPoint roleLastPosition = ZTPoint.Empty;
|
private bool StaticTimerIsStart = false;//静止计时是否开始
|
private Int32 StaticTimerCounter = 0;//静止计时计数器
|
private DateTime DetectLastNoMoveTime = DateTime.MaxValue;//最后没移动时间
|
private const Int32 NoMoveMaxMillSecond = 2000;//最大未移动容忍毫秒数
|
|
/// <summary>
|
/// 得到循环移动的距离
|
/// </summary>
|
/// <returns></returns>
|
private void ComputeMoveInfo(ZTPoint rolePosition)
|
{
|
ZTRectangle limitRect = ZTRectangle.Empty;
|
|
//达到未移动阀值,可能有障碍物,先攻击,如果攻击后还是无效则上下左右移
|
if (rolePosition == this.roleLastPosition)
|
{
|
if (StaticTimerIsStart)
|
{
|
if ((DateTime.Now - DetectLastNoMoveTime).TotalMilliseconds > NoMoveMaxMillSecond)
|
{
|
G.Instance.DebugWriter($"find door not move,role position:{rolePosition.ToString()}");
|
this.StopMove();
|
if (StaticTimerCounter==0)
|
{
|
//清除障碍物
|
G.Instance.InputControl.PressKey(RandomUtils.KeyPressDuration, HIDCode.X);
|
}
|
else
|
{
|
//无法清除障碍物,随机移动一下
|
switch (StaticTimerCounter % 4)
|
{
|
case 0:
|
G.Instance.DebugWriter("random up");
|
//上
|
movingDistance = new ZTSize(0, -TopRandomMoveDistance);
|
break;
|
case 1:
|
//右
|
movingDistance = new ZTSize(RightRandomMoveDistance, 0);
|
|
break;
|
case 2:
|
//下
|
movingDistance = new ZTSize(0, BottomRandomMoveDistance);
|
break;
|
case 3:
|
//左
|
movingDistance = new ZTSize(-LeftRandomMoveDistance, 0);
|
break;
|
}
|
|
movingMethod = MoveMethod.Fixed;
|
}
|
StaticTimerCounter++;
|
DetectLastNoMoveTime = DateTime.Now;
|
if (StaticTimerCounter > 1)
|
{
|
return;
|
}
|
}
|
|
}
|
else if (!StaticTimerIsStart)
|
{
|
//没开始计时 则 开始计时
|
StaticTimerIsStart = true;
|
DetectLastNoMoveTime = DateTime.Now;
|
}
|
}
|
else
|
{
|
//移动了 取消计时
|
this.roleLastPosition = rolePosition;
|
StaticTimerIsStart = false;
|
StaticTimerCounter = 0;
|
}
|
|
if (!IsMoving)
|
{
|
//刚开始移动
|
movingMethod = MoveMethod.Vertical;
|
}
|
|
if (movingMethod == MoveMethod.Vertical && rolePosition.Y >= minCenterLineY && rolePosition.Y <= maxCenterLineY)
|
{
|
//不需要上下移动,计算左右
|
if (this.house.DoorDirection[0] == Direction.Left)
|
{
|
movingMethod = MoveMethod.ToLeft;
|
}
|
else if (this.house.DoorDirection[0] == Direction.Right)
|
{
|
movingMethod = MoveMethod.ToRight;
|
}
|
else
|
{
|
//计算是向左还是右,哪边大往哪边
|
if (rolePosition.X > (this.gameRect.Start.X + (this.gameRect.End.X - this.gameRect.Start.X) / 2))
|
{
|
//左边空间大
|
movingMethod = MoveMethod.ToLeft;
|
}
|
else
|
{
|
movingMethod = MoveMethod.ToRight;
|
}
|
}
|
}
|
|
if (movingMethod == MoveMethod.ToLeft)
|
{
|
//计算左边界范围
|
limitRect = new ZTRectangle(gameRect.Start.X, gameRect.Start.Y, gameRect.Start.X + PaddingLeft, gameRect.End.Y);
|
//判断是否到左边界
|
if (Utils.IsInRect(rolePosition, limitRect))
|
{
|
//到左边界就向右走
|
movingMethod = MoveMethod.ToRight;
|
movingDistance = new ZTSize(gameRect.End.X - rolePosition.X, 0);
|
}
|
else
|
{
|
//没到继续向左走
|
movingMethod = MoveMethod.ToLeft;
|
movingDistance = new ZTSize(limitRect.Start.X - rolePosition.X, 0);
|
}
|
}
|
else if (movingMethod == MoveMethod.ToRight)
|
{
|
//计算右边界范围
|
limitRect = new ZTRectangle(gameRect.End.X - PaddingRight, gameRect.Start.Y, gameRect.End.X, gameRect.End.Y);
|
//判断是否到右边界
|
if (Utils.IsInRect(rolePosition, limitRect))
|
{
|
//到右边界就向左走
|
G.Instance.InfoWriter($"in limit rect,role position:{rolePosition.ToString()},limit:{limitRect.ToString()}");
|
movingMethod = MoveMethod.ToLeft;
|
movingDistance = new ZTSize(gameRect.Start.X - rolePosition.X, 0);
|
}
|
else
|
{
|
//没到继续向右走
|
movingMethod = MoveMethod.ToRight;
|
movingDistance = new ZTSize(gameRect.End.X - rolePosition.X, 0);
|
}
|
}
|
else
|
{
|
//向点移动
|
Int32 targetY = gameRect.End.Y + this.house.HouseCenterMoveLine;
|
movingDistance = new ZTSize(0, targetY - rolePosition.Y);
|
}
|
}
|
|
/// <summary>
|
/// 停止移动
|
/// </summary>
|
public void StopMove()
|
{
|
if (IsMoving)
|
{
|
//停止
|
ReleaseKey();
|
}
|
}
|
|
/// <summary>
|
/// 同步移动指定距离
|
/// </summary>
|
/// <param name="distance"></param>
|
public void SyncMove(ZTSize distance)
|
{
|
HIDCode horizontal = HIDCode.NoEvent;
|
HIDCode vertical = HIDCode.NoEvent;
|
bool isRun = false;
|
int runms, stepms;
|
Int32 xsig = Math.Sign(distance.Width);
|
Int32 ysig = Math.Sign(distance.Height);
|
|
if (Math.Abs(distance.Width) >= RunThresold)
|
{
|
isRun = true;
|
}
|
|
if (distance.Height > 0)
|
{
|
vertical = HIDCode.DownArrow;
|
}
|
|
if (distance.Height < 0)
|
{
|
vertical = HIDCode.UpArrow;
|
}
|
|
if (distance.Width > 0)
|
{
|
horizontal = HIDCode.RightArrow;
|
}
|
|
if (distance.Width < 0)
|
{
|
horizontal = HIDCode.LeftArrow;
|
}
|
|
PutKey(out stepms, out runms, horizontal, vertical, isRun);
|
if (stepms > 0)
|
{
|
Int32 mdistance = (Int32)(stepms * SpeedOfStep.Width);
|
if (runms > 0)
|
{
|
mdistance += (Int32)(runms * SpeedOfRun.Width);
|
}
|
distance = new ZTSize(distance.Width - xsig*mdistance, distance.Height);
|
}
|
|
int ytime = (Int32)(Math.Abs(distance.Height) / SpeedOfStep.Height);
|
Int32 xtime = (Int32)(Math.Abs(distance.Width) / SpeedOfStep.Width);
|
if (isRun)
|
{
|
xtime = (Int32)(Math.Abs(distance.Width) / SpeedOfRun.Width);
|
}
|
|
|
|
Int32 mintime = Math.Min(xtime, ytime);
|
if (xtime <= 0)
|
{
|
mintime = ytime;
|
}
|
if (ytime <= 0)
|
{
|
mintime = xtime;
|
}
|
Thread.Sleep(mintime);
|
|
xtime -= mintime;
|
ytime -= mintime;
|
if (xtime > 0)
|
{
|
PutKey(out stepms, out runms, horizontal, HIDCode.NoEvent, isRun);
|
Thread.Sleep(xtime);
|
}
|
if (ytime > 0)
|
{
|
PutKey(out stepms, out runms, HIDCode.NoEvent, vertical, isRun);
|
Thread.Sleep(ytime);
|
}
|
StopMove();
|
}
|
|
/// <summary>
|
/// 同步移动指定距离
|
/// </summary>
|
/// <param name="distance"></param>
|
public void SyncMove(ZTPoint distance)
|
{
|
SyncMove(new ZTSize(distance.X, distance.Y));
|
}
|
|
|
#region 八方向移动
|
/// <summary>
|
/// 按下按键
|
/// </summary>
|
/// <param name="distance"></param>
|
private void PutKey(ZTSize distance)
|
{
|
HIDCode horizontal = HIDCode.NoEvent;
|
HIDCode vertical = HIDCode.NoEvent;
|
bool isRun = false;
|
if (distance.Width < 0)
|
{
|
horizontal = HIDCode.LeftArrow;
|
}
|
if (distance.Width > 0)
|
{
|
horizontal = HIDCode.RightArrow;
|
}
|
|
if (Math.Abs(distance.Width) >= RunThresold)
|
{
|
isRun = true;
|
}
|
|
|
if (distance.Height < 0)
|
{
|
vertical = HIDCode.UpArrow;
|
}
|
if (distance.Height > 0)
|
{
|
vertical = HIDCode.DownArrow;
|
}
|
|
Int32 stepms, runms;
|
PutKey(out stepms,out runms,horizontal, vertical, isRun);
|
}
|
|
|
/// <summary>
|
/// 按下按键
|
/// </summary>
|
/// <param name="horizontal"></param>
|
/// <param name="vertical"></param>
|
private void PutKey(out Int32 stepMS,out Int32 runMS,HIDCode horizontal, HIDCode vertical,bool isRun)
|
{
|
stepMS = 0;
|
runMS = 0;
|
if (horizontal == vertical)
|
{
|
return;
|
}
|
if (horizontal == pressKeys[0] && vertical == pressKeys[1])
|
{
|
return;
|
}
|
|
int keyCount = horizontal != HIDCode.NoEvent && vertical != HIDCode.NoEvent ? 2 : 1;
|
Int32 tempwait = 0;
|
if (isRun)
|
{
|
//跑
|
if (!isRuning || horizontal != pressKeys[0])
|
{
|
//如果之前没有跑,或跑的方向不一样,则开始跑
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal);
|
tempwait = RandomUtils.KeyPressDuration;
|
stepMS += tempwait;
|
Thread.Sleep(tempwait);
|
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false);
|
Thread.Sleep(RandomUtils.KeyPressDuration);
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal);
|
isRuning = true;
|
|
if (keyCount == 2)
|
{
|
tempwait = RandomUtils.KeyPressDuration;
|
runMS += tempwait;
|
Thread.Sleep(tempwait);
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal, vertical);
|
}
|
|
}
|
else
|
{
|
//奔跑方向不变
|
int afterKeyCount = pressKeys[0] != HIDCode.NoEvent && pressKeys[1] != HIDCode.NoEvent ? 2 : 1;
|
if (afterKeyCount != keyCount)
|
{
|
//如果跟原来按键数量不一样
|
if (keyCount == 1)
|
{
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal);
|
}
|
else
|
{
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal, vertical);
|
}
|
|
}
|
|
}
|
}
|
else
|
{
|
//走
|
if (keyCount == 1)
|
{
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal != HIDCode.NoEvent?horizontal:vertical);
|
}
|
else
|
{
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false, horizontal, vertical);
|
}
|
|
}
|
|
pressKeys[0] = horizontal;
|
pressKeys[1] = vertical;
|
}
|
|
/// <summary>
|
/// 释放按键
|
/// </summary>
|
private void ReleaseKey()
|
{
|
G.Instance.InputControl.PutDown(false, false, false, false, false, false, false, false);
|
pressKeys[0] = HIDCode.NoEvent;
|
pressKeys[1] = HIDCode.NoEvent;
|
isRuning = false;
|
}
|
|
|
|
#endregion
|
|
|
}
|
}
|