AIR用户离开状态和返回状态

本文介绍了一种通过设置闲置阈值来判断用户离线和在线状态的方法,类似于QQ中使用鼠标键盘动作判断用户是否活跃的功能。通过调整闲置阈值并监听特定事件,可以实现对用户活动状态的有效监测。

通过idleThreshold=10;(秒)

USER_IDLE、USER_PRESENT事件

可以对用户离开状态和返回状态进行处理.

例如QQ的5分钟没有鼠标键盘动作,进入离开状态, 有了鼠标键盘动作就回到在线状态.

 

NativeApplication.nativeApplication.idleThreshold = idleTime;
NativeApplication.nativeApplication.addEventListener(Event.USER_IDLE,onIdle);
NativeApplication.nativeApplication.addEventListener(Event.USER_PRESENT,onPresence);

 

转自:www.cnblogs.com/xxcainiao/archive/2008/10/16/1312918.html

class_name Player extends CharacterBody2D # 角色状态枚举 enum State { IDLE, # 闲置状态 WALK, # 行走状态(当前逻辑复用RUNNING,可后续扩展) RUNNING,# 奔跑状态 JUMP, # 跳跃状态 FALL, LANDING, # 下落状态 WALL_SLIDING, WALL_JUMP, ATTACK_1, ATTACK_2, ATTACK_3, DYING, HURT } # 地面状态集合(用于判断是否从地面状态切换) const GROUND_STATES := [State.IDLE, State.RUNNING,State.LANDING, State.ATTACK_1,State.ATTACK_2,State.ATTACK_3,] const WALL_JUMP_VELOCITY := Vector2(380,-320) # 移动参数配置 const RUN_SPEED := 160.0 # 奔跑速度 const FLOOR_ACCELERATION := RUN_SPEED / 0.2 # 地面加速度(0.2秒加速到全速) const AIR_ACCELERATION := RUN_SPEED / 0.01 # 空中加速度(更灵敏) const KNOCKBACK_AMOUNT :=512.0 const JUMP_VELOCITY := -320.0 # 跳跃初速度(负值表示向上) var default_gravity := ProjectSettings.get("physics/2d/default_gravity") as float# 重力 var is_first_tick:= false var is_combo_requested := false var pending_damage:Damage # 节点引用 @onready var graphics: Node2D = $Graphics # 角色精灵 @onready var animation_player: AnimationPlayer = $AnimationPlayer # 动画播放器 @onready var coyote_timer: Timer = $CoyoteTimer # Coyote时间计时器(离开地面后短时间仍可跳) @onready var jump_request_timer: Timer = $JumpRequestTimer # 跳跃输入缓冲计时器 @onready var state_machine: Node = $StateMachine @onready var stats: stats = $stats @onready var invincible_timer: Timer = $invincibleTimer @onready var headcheker: RayCast2D = $Graphics/Headcheker @onready var footchecker: RayCast2D = $Graphics/footchecker @export var can_combo:= false # 状态机变量 var current_state: State = State.IDLE # 初始状态设为闲置 var is_attack_finished := false func _on_animation_finished(anim_name: String) -> void: if anim_name in ["attack_1", "attack_2", "attack_3"]: # 确保动画名称与实际匹配 is_attack_finished = true # 处理跳跃输入(按下/松开) func _unhandled_input(event: InputEvent) -> void: # 按下跳跃键时,启动跳跃请求计时器(缓冲输入) if event.is_action_pressed("jump"): jump_request_timer.start() # 松开跳跃键时,停止计时器并实现短跳逻辑 if event.is_action_released("jump"): jump_request_timer.stop() # 若仍在上升阶段,减半上升速度(缩短跳跃高度) if velocity.y < JUMP_VELOCITY / 2: velocity.y = JUMP_VELOCITY / 2 if event.is_action_pressed("attack") and can_combo: is_combo_requested = true # 物理帧主循环:驱动状态移动逻辑 #func _physics_process(delta: float) -> void: ## 1. 计算下一状态 #var next_state = get_next_state(current_state) ## 2. 状态变化时执行过渡逻辑(播放动画、修改状态变量等) #if next_state != current_state: #transition_state(current_state, next_state) #current_state = next_state ## 3. 执行当前状态的物理逻辑(移动、重力等) #tick_physics(current_state, delta) # 各状态的物理逻辑处理 # 各状态的物理逻辑处理 func tick_physics(state: State, delta: float) -> void: if invincible_timer.time_left > 0: graphics.modulate.a = sin(Time.get_ticks_msec()) *0.5+0.5 else: graphics.modulate.a = 1 match state: State.IDLE: move(default_gravity, delta) State.RUNNING: move(default_gravity, delta) State.JUMP: # 传递重力参数,首次跳跃重力为0 move(0.0 if is_first_tick else default_gravity, delta) State.FALL: move(default_gravity, delta) State.LANDING: stand(default_gravity, delta) State.WALL_SLIDING: move(default_gravity /30, delta) # 滑墙时实时更新朝向(根据墙壁法线反向) update_wall_slide_facing() # 替换原有的scale.x设置 State.WALL_JUMP: if state_machine.state_time < 0.1: stand(0.0 if is_first_tick else default_gravity, delta) graphics.scale.x = get_wall_normal().x else: move(default_gravity, delta) State.ATTACK_1, State.ATTACK_2, State.ATTACK_3: stand(default_gravity,delta) State.HURT,State.DYING: stand(default_gravity,delta) # 攻击未结束时保持当前攻击状态,无需返回任何值 is_first_tick = false # 新增:更新滑墙时的朝向(核心逻辑) func update_wall_slide_facing() -> void: var wall_normal = get_wall_normal() # 朝向与墙壁法线相反(面向墙壁):右墙(法线x=1)→ 向左(scale.x=-1);左墙(法线x=-1)→ 向右(scale.x=1) graphics.scale.x = -wall_normal.x # 修正:move函数接受重力参数 func move(gravity_value: float, delta: float) -> void: var direction := Input.get_axis("move_left", "move_right") var acceleration := FLOOR_ACCELERATION if is_on_floor() else AIR_ACCELERATION velocity.x = move_toward(velocity.x, direction * RUN_SPEED, acceleration * delta) # 应用传入的重力值adadd velocity.y += gravity_value * delta if not is_zero_approx(direction): graphics.scale.x = -1 if direction < 0 else +1 move_and_slide() # stand 函数:处理角色的站立逻辑 func stand(gravity: float, delta: float) -> void: var acceleration := FLOOR_ACCELERATION if is_on_floor() else AIR_ACCELERATION velocity.x = move_toward(velocity.x, 0.0, acceleration * delta) velocity.y += gravity * delta move_and_slide() func die() -> void: get_tree().reload_current_scene() func can_wall_slide() -> bool: return is_on_wall() and headcheker.is_colliding() and footchecker.is_colliding() # 状态切换逻辑:根据当前状态计算下一状态 func get_next_state(state: State) -> int: if stats.health==0: return StateMachine.KEEP_CURRENT if state == State.DYING else State.DYING if pending_damage: return State.HURT # 判断是否可跳跃 var can_jump := is_on_floor() or coyote_timer.time_left > 0 var should_jump := can_jump and jump_request_timer.time_left > 0 if should_jump: return State.JUMP if state in GROUND_STATES and not is_on_floor(): return State.FALL var direction := Input.get_axis("move_left", "move_right") var is_still := is_zero_approx(direction) and is_zero_approx(velocity.x) match state: State.IDLE: if Input.is_action_just_pressed("attack"): return State.ATTACK_1 if not is_still: return State.RUNNING State.RUNNING: if Input.is_action_just_pressed("attack"): return State.ATTACK_1 if is_still: return State.IDLE State.JUMP: if velocity.y >= 0: return State.FALL State.FALL: if is_on_floor(): return State.LANDING if is_still else State.RUNNING # 移除外层 if is_still 判断 if can_wall_slide(): return State.WALL_SLIDING State.WALL_SLIDING: if jump_request_timer.time_left > 0: return State.WALL_JUMP if is_on_floor(): return State.IDLE if not is_on_wall(): return State.FALL State.LANDING: if not is_still: return State.RUNNING if not animation_player.is_playing(): return State.IDLE State.WALL_JUMP: if can_wall_slide() and not is_first_tick: return State.WALL_SLIDING if velocity.y >= 0: return State.FALL State.ATTACK_1: if not animation_player.is_playing(): return State.ATTACK_2 if is_combo_requested else State.IDLE State.ATTACK_2: if not animation_player.is_playing(): return State.ATTACK_3 if is_combo_requested else State.IDLE State.ATTACK_3: if not animation_player.is_playing(): return State.IDLE State.HURT,State.DYING: if not animation_player.is_playing(): return State.IDLE #if state in [State.JUMP, State.FALL]: #if can_wall_slide(): #return State.WALL_SLIDING # return StateMachine.KEEP_CURRENT # 状态过渡逻辑:切换状态时执行动画参数调整 #var physics_frame_count: int = 0 func transition_state(from: State, to: State) -> void: #is_first_tick = true # #if to == State.WALL_JUMP: #var wall_normal = get_wall_normal() #velocity.x = wall_normal.x * WALL_JUMP_VELOCITY.x #velocity.y = WALL_JUMP_VELOCITY.y if from not in GROUND_STATES and to in GROUND_STATES: coyote_timer.stop() match to: State.IDLE: animation_player.play("idle") State.RUNNING: animation_player.play("running") State.LANDING: animation_player.play("landing") State.JUMP: animation_player.play("jump") velocity.y = JUMP_VELOCITY coyote_timer.stop() jump_request_timer.stop() State.WALL_SLIDING: animation_player.play("wall_sliding") update_wall_slide_facing() velocity.y = 0 # 进入滑墙状态时立即更新朝向 State.FALL: animation_player.play("fall") if from in GROUND_STATES: coyote_timer.start() State.WALL_JUMP: animation_player.play("jump") velocity = WALL_JUMP_VELOCITY velocity.x *= get_wall_normal().x jump_request_timer.stop() State.ATTACK_1: animation_player.play("attack_1") is_combo_requested = false State.ATTACK_2: animation_player.play("attack_2") is_combo_requested = false State.ATTACK_3: animation_player.play("attack_3") is_combo_requested = false State.HURT: animation_player.play("die") # 从角色当前生命值中减去待处理的伤害量,实现生命值扣减 stats.health -= pending_damage.amount # 计算伤害源指向自身的方向向量(用于确定击退方向) var dir:= pending_damage.source.global_position.direction_to(global_position) # 根据方向向量击退力度常量计算角色的击退速度 velocity = dir * KNOCKBACK_AMOUNT pending_damage = null invincible_timer.start() State.DYING: animation_player.play("hurt") invincible_timer.stop() is_first_tick=true func _on_hurtbox_hurt(hitbox: Hitbox) -> void: if invincible_timer.time_left > 0: return pending_damage = Damage.new() pending_damage.amount=1 pending_damage.source=hitbox.owner class_name StateMachine extends Node const KEEP_CURRENT := -1 # 全局常量:表示“保持当前状态” # 当前状态(与业务枚举强绑定,如 Player.State) var current_state: int = -1: set(v): owner.transition_state(current_state, v) # 触发状态过渡逻辑 current_state = v state_time = 0 # 重置状态持续时间 var state_time: float# 记录当前状态持续的物理时间 func _ready() -> void: await owner.ready # 等待宿主节点(如 Player)初始化完成 current_state = 0 # 从业务枚举中获取初始状态 func _physics_process(delta: float) -> void: # 步骤1:循环计算状态,直到稳定 while true: var next := owner.get_next_state(current_state) as int # 调用宿主的状态计算逻辑 if next == KEEP_CURRENT: break # 状态不变或保持当前,退出循环 current_state = next# 状态变化时更新 # 步骤2:状态稳定后,执行物理逻辑 owner.tick_physics(current_state, delta) state_time += delta # 累加当前状态的持续时间 优化我的player代码使其完全适配状态
最新发布
11-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值