# PhysicsPush —— CLIENT-GAP §3.7:受击击退,逐行移植 GameLib/PhysicsObject.cpp `CPhysicsObject` # + GameLib/MapUtil.cpp `CEaseOutInterpolation`。单位 = Metin2 cm(平面 x / y)。 # __PushCircle -> set_direction(normalize(victim - attacker)) # IncreaseExternalForce(base, fExternalForce) -> increase_external_force(force[, collides]) # PhysicsProcess:update(dt) 后 AddMovement(get_movement()) extends RefCounted const FRAME_TIME := 0.02 # c_fFrameTime const EPSILON := 0.001 const LOOP_VALUE := 100 const FLT_EPSILON := 1.192092896e-07 class EaseOut: var remaining := 0.0 var value := 0.0 var speed := 0.0 var acceleration := 0.0 var start_value := 0.0 var last_value := 0.0 func initialize() -> void: remaining = 0.0 value = 0.0 speed = 0.0 acceleration = 0.0 start_value = 0.0 last_value = 0.0 func setup(f_start: float, f_end: float, f_time: float) -> void: if absf(f_time) < FLT_EPSILON: f_time = 0.01 value = f_start start_value = f_start last_value = f_start speed = (2.0 * (f_end - f_start)) / f_time acceleration = 2.0 * (f_end - f_start) / (f_time * f_time) - 2.0 * speed / f_time remaining = f_time func interpolate(dt: float) -> void: last_value = value remaining -= dt speed += acceleration * dt value += speed * dt if not is_playing(): value = 0.0 last_value = 0.0 func is_playing() -> bool: return remaining > 0.0 func changing_value() -> float: return value - last_value var mass := 1.0 var friction := 0.3 var direction := Vector3.ZERO var acceleration := Vector3.ZERO var velocity := Vector3.ZERO var last_position := Vector3.ZERO var _x := EaseOut.new() var _y := EaseOut.new() func initialize() -> void: mass = 1.0 friction = 0.3 direction = Vector3.ZERO acceleration = Vector3.ZERO velocity = Vector3.ZERO last_position = Vector3.ZERO _x.initialize() _y.initialize() func set_direction(dir: Vector2) -> void: direction = Vector3(dir.x, dir.y, 0.0) func update(dt: float) -> void: if _x.is_playing(): _x.interpolate(dt) if _y.is_playing(): _y.interpolate(dt) func _accumulate(pos: Vector3) -> Vector3: var force := 0.0 if absf(velocity.x) < EPSILON or absf(velocity.y) < EPSILON or absf(velocity.z) < EPSILON: force -= mass * friction acceleration = direction * (force / mass) velocity += acceleration if velocity.x * direction.x < EPSILON: velocity.x = 0.0 direction.x = 0.0 if velocity.y * direction.y < EPSILON: velocity.y = 0.0 direction.y = 0.0 if velocity.z * direction.z < EPSILON: velocity.z = 0.0 direction.z = 0.0 return pos + velocity # collides(movement: Vector2) -> bool 对应 IPhysicsWorld::isPhysicalCollision(base + movement); # 空 Callable = 没有物理世界(参考端 pWorld == NULL 分支)。 func increase_external_force(force: float, collides := Callable()) -> void: acceleration = direction * (force / mass) velocity = acceleration var movement := Vector3.ZERO for i in LOOP_VALUE: movement = _accumulate(movement) if collides.is_valid() and bool(collides.call(Vector2(movement.x, movement.y))): initialize() return if absf(velocity.x) < EPSILON and absf(velocity.y) < EPSILON and absf(velocity.z) < EPSILON: break set_last_position(Vector2(movement.x, movement.y), float(LOOP_VALUE) * FRAME_TIME) func set_last_position(p: Vector2, blending_time: float) -> void: last_position = Vector3(p.x, p.y, 0.0) _x.setup(0.0, p.x, blending_time) _y.setup(0.0, p.y, blending_time) func get_last_position() -> Vector2: return Vector2(last_position.x, last_position.y) # GetXMovement / GetYMovement:本帧 ease-out 增量。 func get_movement() -> Vector2: return Vector2(_x.changing_value(), _y.changing_value()) func is_blending() -> bool: if velocity.length() != 0.0: return true return _x.is_playing() or _y.is_playing()