Unity记录6.4-动作-移动系统优化

汇总:Unity 记录
开源地址:asd123pwj/asdGame摘要:使用派生类,对移动系统优化。
第二次优化-2023/10/05
- 目前的这个感觉还行,不过暂时还没和tags合起来。
- 大概是实现一个基类,然后子类继承。
- 把一些通用判断、状态和执行都写在基类里,然后开放几个实现接口给子类。
- 子类就是一些详细的动作,也就是独特实现的地方。
- 再用一个字典
<string, ClassBase>
来记录所有动作。
- 在实例化动作时,需要设定冷却时间,间隔时间,使用次数,持续时间。
- 冷却时间,动作执行后,当前动作等待一段时间才可执行。
- 间隔时间,动作执行后,所有动作等待一小段时间才可执行,避免一次按键把多跳全部用完。
- 使用次数,用一次少一次,达到某条件(如落地)则恢复,例如多跳。
- 持续时间,动作执行后,在这段时间内可用,否则重置,例如飞行一段时间。
- 在实现飞行的时候,本来是想作用一个力,抵消重力,但没成功。
- 向上施力
mass*gravityScale
还是会缓慢下降,再*1.25
左右能勉强悬浮,但数值持续变化,且方向不同。猜测可能是精度问题。 - 以及物理引擎的
gravity
,是9.81,但是这个数值和所受重力差的太多了,哪怕是1/0.981
都才1.02,和1.25差的有点多 - 看了别人3D里用9.81向上施力能浮空,结果我的2D会变成朝上飞。
- 最后还是设置了
gravityScale=0
来实现。
- 向上施力
动作脚本-2023/10/05
- 基类
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using UnityEngine;
using UnityEngine.Tilemaps;
using Cysharp.Threading.Tasks;
using Unity.VisualScripting;
using UnityEditor.Search;
public class ObjectAbilMoveBase{
// ---------- Config ----------
public ObjectConfig _Config;
// ---------- Init ----------
public string _name;
public bool _moving;
public bool _waiting;
public bool _cooldowning;
public string[] _wait_move;
public float _wait;
public float _cooldown;
public int _uses_init;
// ---------- Status ----------
public int _uses;
public float _duration;
public ObjectAbilMoveBase(ObjectConfig config, float cooldown, float wait, int uses, float duration){
// ---------- Config ----------
_Config = config;
// ---------- Init ----------
_wait = wait;
_cooldown = cooldown;
_uses_init = uses;
_duration = duration;
_reset();
}
public virtual bool _check(InputInfo input) { return true; }
public virtual void _act_move(InputInfo input) { }
public virtual void _act_done() { }
public virtual void _set_moving_status(bool isStart) { }
// ---------- Action ----------
public bool _act(InputInfo input){
if (check() && _check(input)){
init().Forget();
_act_move(input);
act_done();
_act_done();
return true;
}
return false;
}
public async UniTaskVoid _act_wait(float time){
_waiting = true;
await UniTask.Delay(TimeSpan.FromSeconds(time));
_waiting = false;
}
bool check() {
if (_waiting) return false;
if (_cooldowning && !_moving) return false;
if (_uses == 0) return false;
return true;
}
void act_done() {
if (_uses > 0) _uses--;
}
async UniTaskVoid init(){
_moving = true;
_set_moving_status(true);
if (_duration < 0) return;
if (_duration > 0) await UniTask.Delay(TimeSpan.FromSeconds(_duration));
_moving = false;
_set_moving_status(false);
if (_cooldown <= 0) return;
_cooldowning = true;
await UniTask.Delay(TimeSpan.FromSeconds(_cooldown));
_cooldowning = false;
}
// ---------- Status ----------
public void _reset() {
_uses = _uses_init;
_waiting = false;
_cooldowning = false;
}
// ---------- Base ----------
public void _act_force(Vector2 force, bool isInstant=false){
if (!isInstant) { // such as player move
Vector2 final_speed = new() {
x = restrict_value_by_ori_max_change(_Config._rb.velocity.x, _Config._max_move_speed.x, force.x),
y = restrict_value_by_ori_max_change(_Config._rb.velocity.y, _Config._max_move_speed.y, force.y)
};
Vector2 final_force = new(){
x = (final_speed.x - _Config._rb.velocity.x) * _Config._rb.mass / Time.fixedDeltaTime,
y = (final_speed.y - _Config._rb.velocity.y) * _Config._rb.mass / Time.fixedDeltaTime
};
_Config._rb.AddForce(final_force, ForceMode2D.Force);
} else {// such as player jump or be blown up
_Config._rb.AddForce(force, ForceMode2D.Impulse);
}
}
float restrict_value_by_ori_max_change(float v_ori, float v_max, float v_ch){
if (Mathf.Abs(v_ori + v_ch) <= v_max) return v_ori + v_ch;
int dir_ori = v_ori > 0 ? 1 : -1;
if (v_ori * dir_ori > v_max) return (v_ch * dir_ori >= 0) ? v_ori : v_ori + v_ch / 10;
else return dir_ori * v_max;
}
}
- 蹬墙跳,因为额外需要判断是否在墙上,因此重写
_check()
public class ObjectAbilMoveJumpWall: ObjectAbilMoveBase{
public ObjectAbilMoveJumpWall(ObjectConfig config, float cooldown, float wait, int uses): this(config, cooldown, wait, uses, -1){}
public ObjectAbilMoveJumpWall(ObjectConfig config, float cooldown, float wait, float duration): this(config, cooldown, wait, -1, duration){}
public ObjectAbilMoveJumpWall(ObjectConfig config, float cooldown, float wait, int uses, float duration): base(config, cooldown, wait, uses, duration){
_name = "jump wall";
_wait_move = new string[]{"walk", "jump", "jump wall"};
}
public override bool _check(InputInfo input) {
if (!_Config._StatusContact._onWall) return false;
return true;
}
public override void _act_move(InputInfo input) {
_act_force(new(- input.x_dir * _Config._move_force.x, input.y_dir * _Config._move_force.y), true);
}
}
- 飞行,因为需要设置飞行状态,所以重写
_set_moving_status()
public class ObjectAbilMoveFly: ObjectAbilMoveBase{
public ObjectAbilMoveFly(ObjectConfig config, float cooldown, float wait, int uses): this(config, cooldown, wait, uses, -1){}
public ObjectAbilMoveFly(ObjectConfig config, float cooldown, float wait, float duration): this(config, cooldown, wait, -1, duration){}
public ObjectAbilMoveFly(ObjectConfig config, float cooldown, float wait, int uses, float duration): base(config, cooldown, wait, uses, duration){
_name = "fly";
_wait_move = new string[]{ "move", "jump", "jump wall", "fly" };
}
public override void _act_move(InputInfo input) {
_act_force(new(input.x * _Config._move_force.x, input.y * _Config._move_force.y));
}
public override void _set_moving_status(bool isStart) {
_Config._AttrMoveFloat._act_float(isStart);
}
}
技能恢复-2023/10/05
- 落地时恢复技能。
void init_trigger(){
_Config._Contact._actions_float2Ground.Add(_on_float2Ground);
}
void _on_float2Ground(){
_Config._Move._moves["jump"]._reset();
_Config._Move._moves["jump wall"]._reset();
_Config._Move._moves["fly"]._reset();
}
执行-2023/10/05
- 调用时,令相关运动等待。
- 例如跳跃后一小段时间不能再次跳跃,不能蹬墙跳,但可以移动。
- 感觉直接全部等待,跳跃后一小段时间不能移动也很合理。
- 我把相关运动改成全部运动了,不过这里代码没改,反正小改动。
- 即所有设计到
_wait_move
的地方都取消了,或换成了全部动作。
- 即所有设计到
public Dictionary<string, ObjectAbilMoveBase> _moves = new();
public void init(){
_moves.Add("walk", new ObjectAbilMoveWalk(_Config, 0, 0, uses:-1));
_moves.Add("jump", new ObjectAbilMoveJump(_Config, 0, 0.25f, uses:3));
_moves.Add("jump wall", new ObjectAbilMoveJumpWall(_Config, 0, 0.25f, uses:-1));
_moves.Add("fly", new ObjectAbilMoveFly(_Config, 5, 0.25f, duration:5f));
}
public bool _walk(InputInfo input) { return move(input, "walk"); }
public bool _jump(InputInfo input) { return move(input, "jump"); }
public bool _jump_wall(InputInfo input) { return move(input, "jump wall"); }
public bool _fly(InputInfo input) { return move(input, "fly"); }
bool move(InputInfo input, string movement){
if (_moves[movement]._act(input)){
foreach (var mov in _moves[movement]._wait_move){
if (_moves.ContainsKey(mov))
_moves[mov]._act_wait(_moves[movement]._wait).Forget();
}
return true;
}
return false;
}
调用-2023/10/05
public void _horizontal(InputInfo input_info){
if (_Config._Move._walk(input_info)) return;
if (_Config._Move._fly(input_info)) return;
}
public void _vertical(InputInfo input_info){
if (_Config._Move._jump(input_info)) return;
if (_Config._Move._jump_wall(input_info)) return;
if (_Config._Move._fly(input_info)) return;
}
第一次优化-2023/10/04
- 所以的动作都经过判断可用,执行,到结束。
- 但是动作很难保持一致的流程,有一些特殊的,比如蹬墙比走和跳要多一个在墙上的判断。
- 所以这次的优化又放弃了,虽然比之前的简洁了许多,但是动作一多肯定又是个问题。
执行脚本-2023/10/04
bool move(InputInfo input_info, string movement, _input_action move_action){
if (_Config._StatusMove._check_can_move(movement)){
move_action(input_info);
foreach (var mov in _Config._StatusMove._movements_info[movement].cooldown_movement)
_Config._StatusMove._use_move(mov);
return true;
}
return false;
}
public bool _walk(InputInfo input_info) { return move(input_info, "walk", walk); }
public bool _jump(InputInfo input_info) { return move(input_info, "jump", jump); }
public bool _jump_wall(InputInfo input_info) { return move(input_info, "jump wall", jump_wall); }
// ---------- Move Action ----------
void walk(InputInfo input_info) { add_force(new(input_info.x * _Config._move_force.x, 0)); }
void jump(InputInfo input_info) { add_force(new(0, input_info.y_dir * _Config._move_force.y), true);}
void jump_wall(InputInfo input_info) { add_force(new(-input_info.x_dir * _Config._move_force.x * 2, input_info.y_dir * _Config._move_force.y * 2), true);}
状态脚本-2023/10/04
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using UnityEngine;
using UnityEngine.Tilemaps;
using Cysharp.Threading.Tasks;
using Unity.VisualScripting;
using UnityEditor.Search;
public struct MovementInfo{
public int times;
public bool onCooldown;
public float cooldown_time;
public List<string> cooldown_movement;
}
public class ObjectStatusMove{
// ---------- Config ----------
ObjectConfig _Config;
// ---------- Status ----------
public bool _onFly;
public bool _moving { get {return check_moving("moving"); } }
public bool _movingX { get {return check_moving("x"); } }
public bool _movingY { get {return check_moving("y"); } }
public bool _movingUp { get {return check_moving("up"); } }
public bool _movingDown { get {return check_moving("down"); } }
public bool _movingLeft { get {return check_moving("left"); } }
public bool _movingRight { get {return check_moving("right"); } }
// ---------- Init ----------
Dictionary<string, MovementInfo> _init_movements_info = new();
// ---------- Internal ----------
public Dictionary<string, MovementInfo> _movements_info = new();
public ObjectStatusMove(ObjectConfig config){
// ---------- Config ----------
_Config = config;
_Config._StatusMove = this;
// ---------- Init ----------
init();
init_status();
init_trigger();
}
void init(){
_init_movements_info.Add("walk", new() { times = -1, cooldown_movement = new(){ } });
_init_movements_info.Add("jump", new() { times = 3, cooldown_time = 0.25f, cooldown_movement =new() { "jump", "jump wall" } });
_init_movements_info.Add("jump wall", new() { times = -1, cooldown_time = 0.25f, cooldown_movement = new() { "walk", "jump", "jump wall" } });
_init_movements_info.Add("fly", new() { times = -1, cooldown_time = 0.25f, cooldown_movement = new() { "fly", "walk", "jump", "jump wall" } });
}
void init_status(string movement="all"){
if (movement == "all") _movements_info = new(_init_movements_info);
else{
_movements_info[movement] = _init_movements_info[movement];
}
}
void init_trigger(){
_Config._Contact._actions_float2Ground.Add(_onFloat2Ground);
}
public void _use_move(string movement) {
var movement_info = _movements_info[movement];
if (movement_info.times > 0) movement_info.times--;
_movements_info[movement] = movement_info;
cooldown_move(movement).Forget();
}
public bool _check_can_move(string movement){
if (_movements_info[movement].onCooldown) return false;
if (_movements_info[movement].times == 0) return false;
if (movement == "jump wall" && !_Config._StatusContact._onWall) return false;
return true;
}
bool check_moving(string direction){
if (direction == "moving") return _Config._rb.velocity.magnitude != 0;
else if (direction == "x") return _Config._rb.velocity.x != 0;
else if (direction == "y") return _Config._rb.velocity.y != 0;
else if (direction == "up") return _Config._rb.velocity.y > 0;
else if (direction == "down") return _Config._rb.velocity.y < 0;
else if (direction == "left") return _Config._rb.velocity.y < 0;
else if (direction == "right") return _Config._rb.velocity.x > 0;
return false;
}
async UniTaskVoid cooldown_move(string movement){
var movement_info = _movements_info[movement];
movement_info.onCooldown = true;
_movements_info[movement] = movement_info;
await UniTask.Delay(TimeSpan.FromSeconds(movement_info.cooldown_time));
movement_info = _movements_info[movement];
movement_info.onCooldown = false;
_movements_info[movement] = movement_info;
}
void _onFloat2Ground(){
init_status("jump");
init_status("jump wall");
}
}
调用行为-2023/10/04
public void _horizontal(InputInfo input_info){
_Config._Move._walk(input_info);
}
public void _vertical(InputInfo input_info){
if (_Config._Move._jump(input_info)) return;
if (_Config._Move._jump_wall(input_info)) return;
}
文章目录
关闭
共有 0 条评论