diff --git a/gdrust/src/player.rs b/gdrust/src/player.rs index a108ea2..b8b9896 100644 --- a/gdrust/src/player.rs +++ b/gdrust/src/player.rs @@ -1,6 +1,8 @@ -use godot::engine::{Area2D, CharacterBody2D, ICharacterBody2D}; +use core::panic; +use godot::engine::{CharacterBody2D, GpuParticles2D, ICharacterBody2D, Timer}; use godot::obj::WithBaseField; use godot::prelude::*; +use std::time::{Duration, Instant}; #[derive(GodotClass)] #[class(base = CharacterBody2D)] @@ -8,8 +10,38 @@ pub struct Player { #[var] health: i32, base: Base, + status: Movement, + /// 上一次点击克盾冲刺键的时间,记录来判断双击 + click_time: Instant, + /// 上一次的类型 + click_type: Click, } +/// 描述按键点击状态 +#[derive(PartialEq, Eq, Debug)] +enum Click { + Right, + Left, + Up, + Down, + None, +} + +/// 控制玩家状态 +#[derive(PartialEq, Eq, Debug)] +enum Movement { + /// 克盾冲刺 + Rush, + // 普通移动 + Move, +} + +const MOVE_RIGHT: &str = "move_right"; +const MOVE_LEFT: &str = "move_left"; +const MOVE_UP: &str = "move_up"; +const MOVE_DOWN: &str = "move_down"; +const SLOW_DOWN: &str = "slow_down"; + #[godot_api()] impl ICharacterBody2D for Player { fn init(base: Base) -> Player { @@ -17,30 +49,79 @@ impl ICharacterBody2D for Player { Self { base, health: Self::MAX_HEALTH, + status: Movement::Move, + click_time: Instant::now(), + click_type: Click::None, } } fn ready(&mut self) {} fn physics_process(&mut self, delta: f64) { - let mut vel = Vector2::ZERO; let input_obj = Input::singleton(); - if input_obj.is_action_pressed("move_left".into()) { + let mut speed = Self::SPEED; + if input_obj.is_action_pressed(SLOW_DOWN.into()) { + speed /= 2; + } + if self.status == Movement::Rush { + godot_print!("rush inside!"); + let vel = Vector2::new( + match self.click_type { + Click::Left => -Self::RUSH_SPEED as f32, + Click::Right => Self::RUSH_SPEED as f32, + _ => { + let msg = format!("wrong movement {:?} when rush", self.click_type); + godot_error!("{}", &msg); + panic!("{}", &msg); + } + }, + 0.0, + ); + self.base_mut() + .move_and_collide(vel * delta as f32 * speed as f32); + return; + } + let mut vel = Vector2::ZERO; + if input_obj.is_action_pressed(MOVE_LEFT.into()) { vel.x -= 1.0; } - if input_obj.is_action_pressed("move_right".into()) { + if input_obj.is_action_pressed(MOVE_RIGHT.into()) { vel.x += 1.0; } - if input_obj.is_action_pressed("move_up".into()) { + // 触发克盾 + if input_obj.is_action_just_pressed(MOVE_LEFT.into()) + && self.click_type == Click::Left + && self.click_time.elapsed() < Duration::new(0, 100 * 1000) + { + self.start_rush(); + } + if input_obj.is_action_just_pressed(MOVE_LEFT.into()) + && self.click_type == Click::Left + && self.click_time.elapsed() < Duration::new(0, 100 * 1000) + { + self.start_rush(); + } + // 记录克盾第一次按按钮 + if input_obj.is_action_just_released(MOVE_RIGHT.into()) { + self.click_time = Instant::now(); + self.click_type = Click::Right; + } + if input_obj.is_action_just_released(MOVE_LEFT.into()) { + self.click_time = Instant::now(); + self.click_type = Click::Left; + } + if input_obj.is_action_just_released(MOVE_DOWN.into()) { + self.click_type = Click::Down; + } + if input_obj.is_action_just_released(MOVE_UP.into()) { + self.click_type = Click::Up; + } + if input_obj.is_action_pressed(MOVE_UP.into()) { vel.y -= 1.0; } - if input_obj.is_action_pressed("move_down".into()) { + if input_obj.is_action_pressed(MOVE_DOWN.into()) { vel.y += 1.0; } - let mut speed = Self::SPEED; - if input_obj.is_action_pressed("slow_down".into()) { - speed /= 2; - } let res = self .base_mut() .move_and_collide(vel.normalized() * speed as f32 * delta as f32); @@ -52,6 +133,8 @@ impl Player { #[constant] const SPEED: i32 = 500; #[constant] + const RUSH_SPEED: i32 = 700; + #[constant] const MAX_HEALTH: i32 = 100; #[signal] fn hit_sig(attack: i32); @@ -62,4 +145,28 @@ impl Player { self.base_mut() .emit_signal("hit_sig".into(), &[attack.to_variant()]); } + + fn start_rush(&mut self) { + godot_print!("rush inside!"); + self.status = Movement::Rush; + // 冲刺结束计时器 + let mut timer = self.base().get_node_as::("Cthulhu"); + timer.start(); + // 启动拖尾粒子 + let mut particle = self.get_virtual_particle(); + particle.set_emitting(true); + } + + fn get_virtual_particle(&self) -> Gd { + self.base().get_node_as::("virtual") + } + + #[func] + fn stop_rush(&mut self) { + godot_print!("rush!"); + let mut particle = self.get_virtual_particle(); + particle.set_emitting(false); + self.status = Movement::Move; + self.click_type = Click::None; + } } diff --git a/resources/images/PlayerHeart/Default/000.png b/resources/images/PlayerHeart/Default/000.png index 5601e41..e90acf4 100644 Binary files a/resources/images/PlayerHeart/Default/000.png and b/resources/images/PlayerHeart/Default/000.png differ diff --git a/scenes/fight.tscn b/scenes/fight.tscn index 5469b02..8263285 100644 --- a/scenes/fight.tscn +++ b/scenes/fight.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=17 format=3 uid="uid://cibwxaqnuodid"] +[gd_scene load_steps=22 format=3 uid="uid://cibwxaqnuodid"] [ext_resource type="Texture2D" uid="uid://cqp3l8q7xbxrt" path="res://resources/images/weapons/Zenith.webp" id="3_2spkb"] [ext_resource type="PackedScene" uid="uid://dn2ixin15jtt3" path="res://scenes/weapons/star_wrath.tscn" id="4_8ipx5"] @@ -16,6 +16,28 @@ [ext_resource type="Texture2D" uid="uid://do5eitiicfjge" path="res://resources/images/shields/Shield_of_Cthulhu.webp" id="14_gkc4x"] [ext_resource type="Texture2D" uid="uid://drljhif31i83o" path="res://resources/images/UI/CategoryPanel.png" id="14_miw1s"] +[sub_resource type="Gradient" id="Gradient_w6p7b"] +offsets = PackedFloat32Array(0.315, 0.435, 1) +colors = PackedColorArray(0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_0mtog"] +gradient = SubResource("Gradient_w6p7b") + +[sub_resource type="Curve" id="Curve_k6gjo"] +_data = [Vector2(0, 0.494505), 0.0, 0.0, 0, 0, Vector2(1, 0.274725), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_yl2ko"] +curve = SubResource("Curve_k6gjo") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_adfmi"] +gravity = Vector3(0, 0, 0) +scale_min = 4.5 +scale_max = 5.0 +scale_curve = SubResource("CurveTexture_yl2ko") +color = Color(1, 0, 0, 1) +color_ramp = SubResource("GradientTexture1D_0mtog") + [sub_resource type="CircleShape2D" id="CircleShape2D_yfrnq"] radius = 52.67 @@ -48,9 +70,17 @@ texture = ExtResource("3_2spkb") [node name="Player" type="Player" parent="."] position = Vector2(570, 414) -rotation = 1.5708 scale = Vector2(0.2, 0.2) +[node name="virtual" type="GPUParticles2D" parent="Player"] +emitting = false +amount = 4 +process_material = SubResource("ParticleProcessMaterial_adfmi") +texture = ExtResource("5_3ufqu") +lifetime = 0.2 +speed_scale = 2.0 +trail_lifetime = 0.5 + [node name="HitPoint" type="CollisionShape2D" parent="Player"] shape = SubResource("CircleShape2D_yfrnq") debug_color = Color(1, 1, 1, 1) @@ -67,6 +97,9 @@ scale = Vector2(0.2, 0.2) shape = SubResource("CircleShape2D_yfrnq") debug_color = Color(1, 1, 1, 1) +[node name="Cthulhu" type="Timer" parent="Player"] +wait_time = 0.1 + [node name="BlockDrawer" type="BlockDrawer" parent="."] light_mask = 3 visibility_layer = 3 @@ -161,3 +194,4 @@ position = Vector2(0, -1) texture = ExtResource("14_gkc4x") [connection signal="hit_sig" from="Player" to="HealthBar" method="attack"] +[connection signal="timeout" from="Player/Cthulhu" to="Player" method="stop_rush"]