(client) feat:实现热重载,实现多维度,实现武器,实现掉落物,实现状态UI,实现攻击AI #44

Merged
TheRedApricot merged 10 commits from zzdxxz/Gen_Hack-and-Slash-Roguelite-zzdxxz:temp820 into main 2025-08-27 19:56:50 +08:00
49 changed files with 11070 additions and 1571 deletions
Showing only changes of commit da93368f02 - Show all commits

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,6 @@ namespace CameraControl
{ {
public class CameraControl : Utils.MonoSingleton<CameraControl>, ITick, ITickUI public class CameraControl : Utils.MonoSingleton<CameraControl>, ITick, ITickUI
{ {
// 当前被聚焦的目标实体
public Entity.Entity focusedEntity = null;
// Camera movement variables // Camera movement variables
private Vector3 _dragOrigin; private Vector3 _dragOrigin;
private bool _isDragging = false; private bool _isDragging = false;
@ -50,12 +47,12 @@ namespace CameraControl
} }
public void Tick() public void Tick()
{ {
if (focusedEntity) if (Program.Instance.focusedEntity)
{ {
// Follow the focused entity's position // Follow the focused entity's position
var targetPosition = new Vector3( var targetPosition = new Vector3(
focusedEntity.Position.x, Program.Instance.focusedEntity.Position.x,
focusedEntity.Position.y, Program.Instance.focusedEntity.Position.y,
_camera.transform.position.z); _camera.transform.position.z);
_camera.transform.position = Vector3.Lerp( _camera.transform.position = Vector3.Lerp(
@ -86,7 +83,8 @@ namespace CameraControl
{ {
_dragOrigin = _camera.ScreenToWorldPoint(Input.mousePosition); _dragOrigin = _camera.ScreenToWorldPoint(Input.mousePosition);
_isDragging = true; _isDragging = true;
focusedEntity = null; // Clear focus when manually moving camera Program.Instance.focusedEntity.PlayerControlled = false;
Program.Instance.focusedEntity = null; // Clear focus when manually moving camera
} }
// During drag // During drag

View File

@ -271,17 +271,17 @@ namespace Configs
public static Dictionary<string, T> LoadResources<T>(string path) where T : UnityEngine.Object public static Dictionary<string, T> LoadResources<T>(string path) where T : UnityEngine.Object
{ {
// 创建一个字典来存储资源名称和加载好的资源 // 创建一个字典来存储资源名称和加载好的资源
Dictionary<string, T> resourceDict = new Dictionary<string, T>(); var resourceDict = new Dictionary<string, T>();
// 加载指定路径下的所有资源 // 加载指定路径下的所有资源
T[] resources = Resources.LoadAll<T>(path); var resources = Resources.LoadAll<T>(path);
foreach (T resource in resources) foreach (var resource in resources)
{ {
if (resource != null) if (resource != null)
{ {
// 获取资源名称并存入字典 // 获取资源名称并存入字典
string resourceName = resource.name; var resourceName = resource.name;
resourceDict[resourceName] = resource; resourceDict[resourceName] = resource;
} }
} }
@ -314,7 +314,7 @@ namespace Configs
try try
{ {
// 使用 using 自动管理 FileStream 的生命周期 // 使用 using 自动管理 FileStream 的生命周期
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{ {
fs.Seek(0, SeekOrigin.Begin); // 将游标移动到文件开头(可选) fs.Seek(0, SeekOrigin.Begin); // 将游标移动到文件开头(可选)
bytes = new byte[fs.Length]; // 创建一个字节数组来存储文件内容 bytes = new byte[fs.Length]; // 创建一个字节数组来存储文件内容
@ -328,10 +328,14 @@ namespace Configs
} }
// 创建一个默认大小的 Texture2D 对象 // 创建一个默认大小的 Texture2D 对象
Texture2D texture = new Texture2D(2, 2); // 初始大小为 2x2LoadImage 会自动调整大小 var texture = new Texture2D(2, 2, TextureFormat.RGBA32, false); // 初始大小为 2x2LoadImage 会自动调整大小
if (texture.LoadImage(bytes)) // 加载图片数据 if (texture.LoadImage(bytes)) // 加载图片数据
{ {
// 设置过滤模式为 Point (无插值)
texture.filterMode = FilterMode.Point;
texture.wrapMode = TextureWrapMode.Clamp; // 防止边缘出现意外拉伸
return texture; // 返回加载成功的 Texture2D 对象 return texture; // 返回加载成功的 Texture2D 对象
} }
else else

View File

@ -227,7 +227,7 @@ namespace Data
public class DrawNodeDef : Define public class DrawNodeDef : Define
{ {
public List<string> animationTextures = new(); public List<string> textures = new();
public List<DrawNodeDef> nodes = new(); public List<DrawNodeDef> nodes = new();
public string nodeName; public string nodeName;
public Vector2 position = new(0, 0); public Vector2 position = new(0, 0);

View File

@ -54,10 +54,8 @@ namespace Entity
return; return;
// 计算当前向上方向与目标方向之间的角度 // 计算当前向上方向与目标方向之间的角度
float angle = Mathf.Atan2(targetDirection.y, targetDirection.x) * Mathf.Rad2Deg; var angle = Mathf.Atan2(targetDirection.y, targetDirection.x) * Mathf.Rad2Deg;
// 调整角度因为默认贴图向上是0度而Atan2计算的是相对于x轴的角度
angle -= 90f;
// 应用旋转 // 应用旋转
transform.rotation = Quaternion.Euler(0f, 0f, angle); transform.rotation = Quaternion.Euler(0f, 0f, angle);

View File

@ -84,12 +84,20 @@ namespace Entity
{ {
IsChase = true; IsChase = true;
currentJob = null; currentJob = null;
if(Program.Instance.focusedEntity)
Program.Instance.focusedEntity.PlayerControlled = false;
Program.Instance.focusedEntity = this;
}
else if (PlayerControlled)
{
Program.Instance.focusedEntity = null;
} }
_isPlayerControlled = value;
} }
get => _isPlayerControlled; get => Program.Instance.focusedEntity == this;
} }
public bool IsWalking => _walkingTimer > 0;
/// <summary> /// <summary>
/// 获取实体当前位置。 /// 获取实体当前位置。
/// </summary> /// </summary>
@ -99,18 +107,16 @@ namespace Entity
/// 表示实体是否已经死亡(生命值小于等于零)。 /// 表示实体是否已经死亡(生命值小于等于零)。
/// </summary> /// </summary>
public bool IsDead => attributes.health <= 0; public bool IsDead => attributes.health <= 0;
public bool IsShowingHealthBarUI=>hitBarUIShowTimer > 0; public bool IsShowingHealthBarUI=>_hitBarUIShowTimer > 0;
public bool IsAttacking => attackCoroutine != null; public bool IsAttacking => _attackCoroutine != null;
private bool _isPlayerControlled = false;
private bool _warning = false; private bool _warning = false;
/// <summary> /// <summary>
/// 存储不同朝向下的动画节点集合。 /// 存储不同朝向下的动画节点集合。
/// </summary> /// </summary>
public Dictionary<EntityState, Dictionary<Orientation, List<ITick>>> bodyAnimationNode = new(); public Dictionary<EntityState, Dictionary<Orientation, List<ITick>>> bodyAnimationNode = new();
private List<ITick> currentAnimatorCache=new (); private List<ITick> _currentAnimatorCache=new ();
/// <summary> /// <summary>
/// 存储不同朝向下的身体节点对象。 /// 存储不同朝向下的身体节点对象。
/// </summary> /// </summary>
@ -119,30 +125,31 @@ namespace Entity
/// <summary> /// <summary>
/// 当前实体的朝向。 /// 当前实体的朝向。
/// </summary> /// </summary>
private Orientation currentOrientation = Orientation.Down; private Orientation _currentOrientation = Orientation.Down;
/// <summary> /// <summary>
/// 当前实体的状态 /// 当前实体的状态
/// </summary> /// </summary>
private EntityState currentState = EntityState.Idle; private EntityState _currentState = EntityState.Idle;
/// <summary> /// <summary>
/// 攻击动画的持续时间(秒)。 /// 攻击动画的持续时间(秒)。
/// </summary> /// </summary>
private const float attackAnimationDuration = 0.1f; private const float AttackAnimationDuration = 0.1f;
/// <summary> /// <summary>
/// 抖动的偏移量。 /// 抖动的偏移量。
/// </summary> /// </summary>
private const float shakeOffset = 0.5f; private const float ShakeOffset = 0.5f;
// 协程引用 // 协程引用
private Coroutine attackCoroutine; private Coroutine _attackCoroutine;
protected EntityDef entityDef; protected EntityDef entityDef;
public float hitBarUIShowTime = 5; [SerializeField] private float _hitBarUIShowTime = 5;
private float hitBarUIShowTimer = 0; private float _hitBarUIShowTimer = 0;
private int _walkingTimer = 1;
/// <summary> /// <summary>
@ -258,7 +265,7 @@ namespace Entity
GameObject nodeObject = null; GameObject nodeObject = null;
// 根据纹理数量创建不同类型的节点 // 根据纹理数量创建不同类型的节点
switch (drawNode.animationTextures?.Count ?? 0) switch (drawNode.textures?.Count ?? 0)
{ {
case 0: case 0:
// 无纹理节点 // 无纹理节点
@ -277,12 +284,12 @@ namespace Entity
nodeObject = Instantiate(imagePrefab.gameObject, parent.transform); nodeObject = Instantiate(imagePrefab.gameObject, parent.transform);
var texture = var texture =
Managers.PackagesImageManager.Instance?.GetSprite(drawNode.packID, Managers.PackagesImageManager.Instance?.GetSprite(drawNode.packID,
drawNode.animationTextures[0]); drawNode.textures[0]);
if (!texture) if (!texture)
{ {
Debug.LogWarning( Debug.LogWarning(
$"InitBodyPart: 无法获取纹理 (节点名: {drawNode.nodeName}, 纹理ID: {drawNode.animationTextures[0]})"); $"InitBodyPart: 无法获取纹理 (节点名: {drawNode.nodeName}, 纹理ID: {drawNode.textures[0]})");
} }
var imagePrefabCom = nodeObject.GetComponent<ImagePrefab>(); var imagePrefabCom = nodeObject.GetComponent<ImagePrefab>();
@ -316,7 +323,7 @@ namespace Entity
animator.SetFPS(drawNode.FPS); animator.SetFPS(drawNode.FPS);
var animatedSprites = new List<Sprite>(); var animatedSprites = new List<Sprite>();
foreach (var textureId in drawNode.animationTextures) foreach (var textureId in drawNode.textures)
{ {
try try
{ {
@ -386,7 +393,15 @@ namespace Entity
/// </summary> /// </summary>
public void Tick() public void Tick()
{ {
if (_isPlayerControlled) if (_walkingTimer > 0)
{
_walkingTimer -= 1;
if (_walkingTimer <= 0)
{
SetBodyTexture(EntityState.Idle, _currentOrientation);
}
}
if (PlayerControlled)
{ {
UpdatePlayerControls(); UpdatePlayerControls();
} }
@ -395,9 +410,9 @@ namespace Entity
AutoBehave(); AutoBehave();
} }
if (currentAnimatorCache!=null) if (_currentAnimatorCache!=null)
{ {
foreach (var animator in currentAnimatorCache) foreach (var animator in _currentAnimatorCache)
{ {
animator.Tick(); animator.Tick();
} }
@ -406,8 +421,8 @@ namespace Entity
if (IsShowingHealthBarUI) if (IsShowingHealthBarUI)
{ {
hitBarUIShowTimer -= Time.deltaTime; _hitBarUIShowTimer -= Time.deltaTime;
if (hitBarUIShowTimer <= 0) if (_hitBarUIShowTimer <= 0)
{ {
HideHealthBar(); HideHealthBar();
} }
@ -420,14 +435,14 @@ namespace Entity
public virtual void TryAttack() public virtual void TryAttack()
{ {
if(!IsAttacking) if(!IsAttacking)
attackCoroutine = StartCoroutine(AttackFlow()); _attackCoroutine = StartCoroutine(AttackFlow());
} }
public virtual void SetBodyTexture(EntityState state, Orientation orientation) public virtual void SetBodyTexture(EntityState state, Orientation orientation)
{ {
if (bodyNodes.TryGetValue(currentState, out var stateNode)) if (bodyNodes.TryGetValue(_currentState, out var stateNode))
{ {
if (stateNode.TryGetValue(currentOrientation, out var node)) if (stateNode.TryGetValue(_currentOrientation, out var node))
{ {
node.SetActive(false); node.SetActive(false);
} }
@ -441,14 +456,14 @@ namespace Entity
} }
} }
currentState = state; _currentState = state;
currentOrientation = orientation; _currentOrientation = orientation;
if (bodyAnimationNode.TryGetValue(currentState, out var animationNode)) if (bodyAnimationNode.TryGetValue(_currentState, out var animationNode))
{ {
if (animationNode.TryGetValue(currentOrientation, out var value)) if (animationNode.TryGetValue(_currentOrientation, out var value))
{ {
currentAnimatorCache=value; _currentAnimatorCache=value;
} }
} }
} }
@ -461,6 +476,8 @@ namespace Entity
if (IsAttacking) if (IsAttacking)
return; return;
transform.position += direction * (attributes.moveSpeed * Time.deltaTime * (IsChase ? 1 : 0.5f)); transform.position += direction * (attributes.moveSpeed * Time.deltaTime * (IsChase ? 1 : 0.5f));
SetBodyTexture(EntityState.Walking,_currentOrientation);
_walkingTimer = 2;
} }
/// <summary> /// <summary>
@ -483,7 +500,7 @@ namespace Entity
return; return;
healthBarPrefab.gameObject.SetActive(true); healthBarPrefab.gameObject.SetActive(true);
healthBarPrefab.Progress = (float)attributes.health / entityDef.attributes.health; healthBarPrefab.Progress = (float)attributes.health / entityDef.attributes.health;
hitBarUIShowTimer=hitBarUIShowTime; _hitBarUIShowTimer=_hitBarUIShowTime;
} }
public void HideHealthBar() public void HideHealthBar()
@ -521,7 +538,7 @@ namespace Entity
ori = direction.x > 0 ? Orientation.Right : Orientation.Left; ori = direction.x > 0 ? Orientation.Right : Orientation.Left;
} }
SetBodyTexture(currentState, ori); SetBodyTexture(_currentState, ori);
} }
/// <summary> /// <summary>
@ -608,7 +625,7 @@ namespace Entity
// 调用检测并攻击敌人的方法 // 调用检测并攻击敌人的方法
DetectAndAttackEnemies(); DetectAndAttackEnemies();
// 攻击流程结束,清理协程引用 // 攻击流程结束,清理协程引用
attackCoroutine = null; _attackCoroutine = null;
} }
@ -623,14 +640,14 @@ namespace Entity
StartCoroutine(ShakeInDirectionCoroutine()); StartCoroutine(ShakeInDirectionCoroutine());
// 返回检测敌人的起始时间 // 返回检测敌人的起始时间
return attackAnimationDuration; return AttackAnimationDuration;
} }
private IEnumerator ShakeInDirectionCoroutine() private IEnumerator ShakeInDirectionCoroutine()
{ {
var originalPosition = transform.position; // 记录原始位置 var originalPosition = transform.position; // 记录原始位置
transform.position += direction * shakeOffset; transform.position += direction * ShakeOffset;
yield return new WaitForSeconds(attackAnimationDuration); yield return new WaitForSeconds(AttackAnimationDuration);
transform.position = originalPosition; transform.position = originalPosition;
} }

View File

@ -110,14 +110,6 @@ namespace Entity
result.Add(("结束操控", EndControl)); result.Add(("结束操控", EndControl));
else else
result.Add(("手动操控", StartControl)); result.Add(("手动操控", StartControl));
if (CameraControl.CameraControl.Instance.focusedEntity == entity)
{
result.Add(("取消跟随", ()=>CameraControl.CameraControl.Instance.focusedEntity=null));
}
else
{
result.Add(("视角跟随", ()=>CameraControl.CameraControl.Instance.focusedEntity=entity));
}
result.Add(("杀死", () => entity.Kill())); result.Add(("杀死", () => entity.Kill()));
result.Add(("变成笨蛋", BecomeDefault)); result.Add(("变成笨蛋", BecomeDefault));
return result; return result;
@ -132,13 +124,11 @@ namespace Entity
private void StartControl() private void StartControl()
{ {
entity.PlayerControlled = true; entity.PlayerControlled = true;
CameraControl.CameraControl.Instance.focusedEntity=entity;
} }
private void EndControl() private void EndControl()
{ {
entity.PlayerControlled = false; entity.PlayerControlled = false;
CameraControl.CameraControl.Instance.focusedEntity=null;
} }
} }
} }

View File

@ -296,15 +296,19 @@ namespace Managers
var textureWidth = texture.width; var textureWidth = texture.width;
var textureHeight = texture.height; var textureHeight = texture.height;
// 如果不分割rows和cols都为1直接创建单个Sprite // 首先创建一个未分割的精灵,使用原始名称
if (!sprites.ContainsKey(packId))
sprites[packId] = new Dictionary<string, Sprite>();
// 创建未分割的精灵
var fullSpriteRect = new Rect(0, 0, textureWidth, textureHeight);
var fullSprite = Sprite.Create(texture, fullSpriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
fullSprite.name = baseName; // 使用原始名称
sprites[packId][baseName] = fullSprite;
// 如果不分割rows和cols都为1直接返回
if (rows == 1 && cols == 1) if (rows == 1 && cols == 1)
{ {
if (!sprites.ContainsKey(packId))
sprites[packId] = new Dictionary<string, Sprite>();
var spriteRect = new Rect(0, 0, textureWidth, textureHeight);
var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
sprites[packId][baseName] = sprite;
return; return;
} }
@ -316,25 +320,25 @@ namespace Managers
Debug.LogError("Texture dimensions are not divisible by the specified rows and columns."); Debug.LogError("Texture dimensions are not divisible by the specified rows and columns.");
return; return;
} }
if (!sprites.ContainsKey(packId))
sprites[packId] = new Dictionary<string, Sprite>();
// 分割纹理并创建多个精灵
for (var row = 0; row < rows; row++) for (var row = 0; row < rows; row++)
{ {
for (var col = 0; col < cols; col++) for (var col = 0; col < cols; col++)
{ {
Rect spriteRect = new(col * tileWidth, row * tileHeight, tileWidth, tileHeight); Rect spriteRect = new(col * tileWidth, row * tileHeight, tileWidth, tileHeight);
var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit); var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
var index = (rows - row - 1) * cols + col; var index = (rows - row - 1) * cols + col; // 计算索引
var spriteName = $"{baseName}_{index}"; var spriteName = $"{baseName}_{index}";
sprite.name = spriteName; sprite.name = spriteName;
// 添加到字典中
sprites[packId][spriteName] = sprite; sprites[packId][spriteName] = sprite;
} }
} }
} }
public void Reload() public void Reload()
{ {
packagesImages.Clear(); packagesImages.Clear();

View File

@ -4,7 +4,7 @@ using UnityEngine.Tilemaps;
namespace Map namespace Map
{ {
public class MapGenerator:Utils.MonoSingleton<MapGenerator> public class MapGenerator:MonoBehaviour
{ {
public DoubleMap baseLevel; public DoubleMap baseLevel;
public Tilemap buildLevel; public Tilemap buildLevel;
@ -24,10 +24,6 @@ namespace Map
{ {
return 0; return 0;
} }
protected override void OnStart()
{
}
} }
} }

View File

@ -3,5 +3,7 @@ using UnityEngine;
public class Program : Utils.Singleton<Program> public class Program : Utils.Singleton<Program>
{ {
public Entity.Entity focusedEntity = null;
public bool needLoad = true; public bool needLoad = true;
} }

View File

@ -1,183 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace Utils
{
public static class Pathfinder
{
public static List<Vector2> FindPath(Entity.Entity entity, Vector2 target, float maxDistance)
{
Vector2 start = entity.Position;
// 计算起点和终点所在的瓦片坐标
var startTile = GetTileCoord(start);
var endTile = GetTileCoord(target);
// 如果超出最大距离,直接返回直线路径或空路径
if (Vector2.Distance(start, target) > maxDistance)
{
return new List<Vector2> { start, target };
}
// A*算法数据结构
var cameFrom = new Dictionary<Vector2Int, Vector2Int>();
var gScore = new Dictionary<Vector2Int, float>();
var fScore = new Dictionary<Vector2Int, float>();
var openSet = new List<Vector2Int>();
// 初始化
gScore[startTile] = 0;
fScore[startTile] = Heuristic(startTile, endTile);
openSet.Add(startTile);
var closestNode = startTile;
var closestDist = Vector2.Distance(start, target);
while (openSet.Count > 0)
{
// 获取fScore最小的节点
var current = openSet[0];
foreach (var node in openSet)
{
if (fScore.GetValueOrDefault(node, float.MaxValue) <
fScore.GetValueOrDefault(current, float.MaxValue))
{
current = node;
}
}
// 检查是否到达目标
if (current == endTile)
{
return ReconstructPath(cameFrom, current, start, target);
}
openSet.Remove(current);
// 检查最大距离限制
var currentDist = Vector2.Distance(
new Vector2(current.x, current.y),
target);
if (currentDist < closestDist)
{
closestDist = currentDist;
closestNode = current;
}
if (gScore[current] > maxDistance)
{
return ReconstructPath(cameFrom, closestNode, start, target);
}
// 遍历邻居8方向
for (var dx = -1; dx <= 1; dx++)
{
for (var dy = -1; dy <= 1; dy++)
{
if (dx == 0 && dy == 0) continue;
var neighbor = new Vector2Int(current.x + dx, current.y + dy);
// 跳过不可通行区域
if (!Map.MapGenerator.Instance.CanPassThrough(neighbor.x, neighbor.y))
{
continue;
}
// 计算移动成本
var moveCost = GetMovementCost(current, neighbor);
var tentativeGScore = gScore[current] + moveCost;
// 跳过超出最大距离的路径
if (tentativeGScore > maxDistance)
{
continue;
}
// 发现新节点或找到更好路径
if (tentativeGScore < gScore.GetValueOrDefault(neighbor, float.MaxValue))
{
cameFrom[neighbor] = current;
gScore[neighbor] = tentativeGScore;
fScore[neighbor] = tentativeGScore + Heuristic(neighbor, endTile);
if (!openSet.Contains(neighbor))
{
openSet.Add(neighbor);
}
}
}
}
}
// 无法找到完整路径时返回局部最优解
return ReconstructPath(cameFrom, closestNode, start, target);
}
// 获取瓦片坐标每个瓦片覆盖±0.5范围)
private static Vector2Int GetTileCoord(Vector2 position)
{
return new Vector2Int(
Mathf.RoundToInt(position.x),
Mathf.RoundToInt(position.y)
);
}
// 计算启发式估值(欧几里得距离)
private static float Heuristic(Vector2Int a, Vector2Int b)
{
return Vector2.Distance(
new Vector2(a.x, a.y),
new Vector2(b.x, b.y)
);
}
// 获取移动成本
private static float GetMovementCost(Vector2Int from, Vector2Int to)
{
// 计算基础距离(正交=1对角=√2
var distance = (from.x == to.x || from.y == to.y) ? 1f : 1.4142f;
// 应用目标瓦片的速度削减率
var costModifier = Map.MapGenerator.Instance.GetTilePassCost(to.x, to.y);
// 成本 = 距离 × (1 + 速度削减率)
return distance * (1 + costModifier);
}
// 重建路径
private static List<Vector2> ReconstructPath(
Dictionary<Vector2Int, Vector2Int> cameFrom,
Vector2Int current,
Vector2 start,
Vector2 end)
{
// 构建瓦片路径
var tilePath = new List<Vector2Int>();
tilePath.Add(current);
while (cameFrom.ContainsKey(current))
{
current = cameFrom[current];
tilePath.Add(current);
}
tilePath.Reverse();
// 转换为实际坐标路径
var path = new List<Vector2>();
path.Add(start); // 添加精确起点
// 添加路径点(瓦片中心)
foreach (var tile in tilePath)
{
path.Add(new Vector2(tile.x, tile.y));
}
path.Add(end); // 添加精确终点
return path;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 586ed74166c04dae862f096bdc52f63b
timeCreated: 1754750432

View File

@ -1,5 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Define> <Define>
<ImageDef>
<defName>TestGunItem</defName>
<path>Resources\Item\TestGun.png</path>
</ImageDef>
<ImageDef>
<defName>TestGun</defName>
<path>Resources\Item\TestGunUse.png</path>
</ImageDef>
<ImageDef>
<defName>yellowBullet</defName>
<path>Resources\Item\YellowBullet_down.png</path>
</ImageDef>
<AttributesDef> <AttributesDef>
<defName>TestGun</defName> <defName>TestGun</defName>
<attack>10</attack> <attack>10</attack>
@ -26,26 +41,23 @@
<moveSpeed>20</moveSpeed> <moveSpeed>20</moveSpeed>
</attributes> </attributes>
<drawingOrder> <drawingOrder>
<texturePath>Resources\Item</texturePath> <idle_down>
<pixelsPerUnit>20</pixelsPerUnit> <textures>
<drawingOrder_down> <li>yellowBullet</li>
<node name="YellowBullet"/> </textures>
</drawingOrder_down> </idle_down>
<walk_down>
<textures>
<li>yellowBullet</li>
</textures>
</walk_down>
</drawingOrder> </drawingOrder>
<behaviorTree> <behaviorTree>
<Node className="JobGiver_ContinuousMove"/> <Node className="JobGiver_ContinuousMove"/>
</behaviorTree> </behaviorTree>
</BulletDef> </BulletDef>
<ImageDef>
<defName>TestGunItem</defName>
<path>Resources\Item\TestGun.png</path>
</ImageDef>
<ImageDef>
<defName>TestGun</defName>
<path>Resources\Item\TestGunUse.png</path>
</ImageDef>

View File

@ -2,11 +2,17 @@
<Define> <Define>
<!-- 贴图部分 --> <!-- 贴图部分 -->
<ImageDef> <ImageDef>
<defName>testPawn</defName> <defName>testPawnAnimation</defName>
<path>res:Character/Test/Body/idle_down</path> <path>res:Character/Test/Body/idle_down</path>
<wCount>5</wCount> <wCount>5</wCount>
<hCount>1</hCount> <hCount>1</hCount>
</ImageDef> </ImageDef>
<ImageDef>
<defName>testPawn</defName>
<path>Resources\Character\test.png</path>
<wCount>4</wCount>
<hCount>4</hCount>
</ImageDef>
<!-- 人物定义 --> <!-- 人物定义 -->
<CharacterDef> <CharacterDef>
@ -19,15 +25,93 @@
</attributes> </attributes>
<affiliation>player</affiliation> <affiliation>player</affiliation>
<drawingOrder> <drawingOrder>
<idle_down name="Body" FPS="2"> <!-- Idle states -->
<animationTextures> <idle_up>
<textures>
<li>testPawn_0</li> <li>testPawn_0</li>
<li>testPawn_1</li> </textures>
<li>testPawn_2</li> </idle_up>
<li>testPawn_3</li> <idle_down>
<textures>
<li>testPawn_4</li> <li>testPawn_4</li>
</animationTextures> </textures>
</idle_down> </idle_down>
<idle_left>
<textures>
<li>testPawn_8</li>
</textures>
</idle_left>
<idle_right>
<textures>
<li>testPawn_12</li>
</textures>
</idle_right>
<!-- Walk states -->
<walk_up>
<textures>
<li>testPawn_1</li>
</textures>
</walk_up>
<walk_down>
<textures>
<li>testPawn_5</li>
</textures>
</walk_down>
<walk_left>
<textures>
<li>testPawn_9</li>
</textures>
</walk_left>
<walk_right>
<textures>
<li>testPawn_13</li>
</textures>
</walk_right>
<!-- Melee Attack states -->
<meleeAttack_up>
<textures>
<li>testPawn_2</li>
</textures>
</meleeAttack_up>
<meleeAttack_down>
<textures>
<li>testPawn_6</li>
</textures>
</meleeAttack_down>
<meleeAttack_left>
<textures>
<li>testPawn_10</li>
</textures>
</meleeAttack_left>
<meleeAttack_right>
<textures>
<li>testPawn_14</li>
</textures>
</meleeAttack_right>
<!-- Ranged Attack states -->
<rangedAttack_up>
<textures>
<li>testPawn_3</li>
</textures>
</rangedAttack_up>
<rangedAttack_down>
<textures>
<li>testPawn_7</li>
</textures>
</rangedAttack_down>
<rangedAttack_left>
<textures>
<li>testPawn_11</li>
</textures>
</rangedAttack_left>
<rangedAttack_right>
<textures>
<li>testPawn_15</li>
</textures>
</rangedAttack_right>
</drawingOrder> </drawingOrder>
<behaviorTree> <behaviorTree>
<Node className="JobGiver_RandomWander"/> <Node className="JobGiver_RandomWander"/>
@ -44,10 +128,18 @@
</attributes> </attributes>
<affiliation>player</affiliation> <affiliation>player</affiliation>
<drawingOrder> <drawingOrder>
<texturePath>res:Character\Test</texturePath> <idle_down name="Body" FPS="4">
<drawingOrder_down> <textures>
<node name="Body"/> <li>testPawnAnimation_0</li>
</drawingOrder_down> <li>testPawnAnimation_1</li>
<li>testPawnAnimation_2</li>
<li>testPawnAnimation_3</li>
<li>testPawnAnimation_4</li>
<li>testPawnAnimation_3</li>
<li>testPawnAnimation_2</li>
<li>testPawnAnimation_1</li>
</textures>
</idle_down>
</drawingOrder> </drawingOrder>
<behaviorTree> <behaviorTree>
<Node className="JobGiver_RandomWander"/> <Node className="JobGiver_RandomWander"/>
@ -64,11 +156,18 @@
</attributes> </attributes>
<affiliation>player</affiliation> <affiliation>player</affiliation>
<drawingOrder> <drawingOrder>
<texturePath>res:Character\HighSpeed</texturePath> <idle_down name="Body" FPS="4">
<pixelsPerUnit>200</pixelsPerUnit> <textures>
<drawingOrder_down> <li>testPawnAnimation_0</li>
<node name="Body"/> <li>testPawnAnimation_1</li>
</drawingOrder_down> <li>testPawnAnimation_2</li>
<li>testPawnAnimation_3</li>
<li>testPawnAnimation_4</li>
<li>testPawnAnimation_3</li>
<li>testPawnAnimation_2</li>
<li>testPawnAnimation_1</li>
</textures>
</idle_down>
</drawingOrder> </drawingOrder>
<behaviorTree> <behaviorTree>
<Node className="JobGiver_Idel"/> <Node className="JobGiver_Idel"/>
@ -85,11 +184,18 @@
</attributes> </attributes>
<affiliation>player</affiliation> <affiliation>player</affiliation>
<drawingOrder> <drawingOrder>
<texturePath>res:Character\HighSpeed</texturePath> <idle_down name="Body" FPS="4">
<pixelsPerUnit>200</pixelsPerUnit> <textures>
<drawingOrder_down> <li>testPawnAnimation_0</li>
<node name="Body" /> <li>testPawnAnimation_1</li>
</drawingOrder_down> <li>testPawnAnimation_2</li>
<li>testPawnAnimation_3</li>
<li>testPawnAnimation_4</li>
<li>testPawnAnimation_3</li>
<li>testPawnAnimation_2</li>
<li>testPawnAnimation_1</li>
</textures>
</idle_down>
</drawingOrder> </drawingOrder>
<behaviorTree> <behaviorTree>
<Node className="JobGiver_Idel"/> <Node className="JobGiver_Idel"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B