#include "pingpong_paddle.h" #include #include #include #include #include #include #include using namespace godot; // ═══════════════════════════════════════════════════════ // 视觉颜色常量 — 以后替换素材时删除本段 // ═══════════════════════════════════════════════════════ static const Color PADDLE_PLAYER_COLOR = Color(0.2f, 0.7f, 1.0f); static const Color PADDLE_AI_COLOR = Color(1.0f, 0.35f, 0.25f); void PingPongPaddle::_bind_methods() { ClassDB::bind_method(D_METHOD("get_speed"), &PingPongPaddle::get_speed); ClassDB::bind_method(D_METHOD("set_speed", "value"), &PingPongPaddle::set_speed); ClassDB::add_property("PingPongPaddle", PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed"); ClassDB::bind_method(D_METHOD("get_is_player"), &PingPongPaddle::get_is_player); ClassDB::bind_method(D_METHOD("set_is_player", "value"), &PingPongPaddle::set_is_player); ClassDB::add_property("PingPongPaddle", PropertyInfo(Variant::BOOL, "is_player"), "set_is_player", "get_is_player"); ClassDB::bind_method(D_METHOD("get_ball_path"), &PingPongPaddle::get_ball_path); ClassDB::bind_method(D_METHOD("set_ball_path", "value"), &PingPongPaddle::set_ball_path); ClassDB::add_property("PingPongPaddle", PropertyInfo(Variant::NODE_PATH, "ball_path"), "set_ball_path", "get_ball_path"); } PingPongPaddle::PingPongPaddle() { speed = 350.0f; is_player = true; ai_reaction_counter = 0.0f; ai_target_y = 0.0f; } PingPongPaddle::~PingPongPaddle() { } // ═══════════════════════════════════════════════════════ // 视觉层 — 圆角球拍(几何体占位) // 替换方法:删除本方法 → 添加 Sprite2D 子节点 // ═══════════════════════════════════════════════════════ void PingPongPaddle::_draw() { Color color = is_player ? PADDLE_PLAYER_COLOR : PADDLE_AI_COLOR; float hw = PADDLE_WIDTH / 2.0f; float hh = PADDLE_HEIGHT / 2.0f; float cr = PADDLE_CORNER_RADIUS; // 主体矩形 draw_rect(Rect2(Vector2(-hw, -hh + cr), Vector2(PADDLE_WIDTH, PADDLE_HEIGHT - cr * 2.0f)), color); // 上下两端矩形 draw_rect(Rect2(Vector2(-hw + cr, -hh), Vector2(PADDLE_WIDTH - cr * 2.0f, cr)), color); draw_rect(Rect2(Vector2(-hw + cr, hh - cr), Vector2(PADDLE_WIDTH - cr * 2.0f, cr)), color); // 四角圆形 draw_circle(Vector2(-hw + cr, -hh + cr), cr, color); draw_circle(Vector2(hw - cr, -hh + cr), cr, color); draw_circle(Vector2(-hw + cr, hh - cr), cr, color); draw_circle(Vector2(hw - cr, hh - cr), cr, color); } void PingPongPaddle::_physics_process(double delta) { queue_redraw(); float move_amount = 0.0f; if (is_player) { // ── 玩家控制 ── Input *input = Input::get_singleton(); if (input->is_action_pressed("ui_up")) { move_amount = -1.0f; } else if (input->is_action_pressed("ui_down")) { move_amount = 1.0f; } } else { // ── AI 控制(有延迟和不精确性)── if (!ball_path.is_empty()) { Node *node = get_node_or_null(ball_path); if (node) { Node2D *ball = Object::cast_to(node); if (ball) { float ball_y = ball->get_global_position().y; // 反应延迟计数器 ai_reaction_counter -= (float)delta; if (ai_reaction_counter <= 0.0f) { // 更新目标位置(加入随机偏移) float noise = (UtilityFunctions::randf() - 0.5f) * 2.0f * AI_TRACKING_NOISE; ai_target_y = ball_y + noise; // 随机重置延迟 ai_reaction_counter = AI_REACTION_DELAY_MIN + UtilityFunctions::randf() * (AI_REACTION_DELAY_MAX - AI_REACTION_DELAY_MIN); } float paddle_y = get_global_position().y; if (ai_target_y < paddle_y - 15.0f) { move_amount = -1.0f; } else if (ai_target_y > paddle_y + 15.0f) { move_amount = 1.0f; } } } } } // 移动(AI 速度略慢) float effective_speed = is_player ? speed : speed * AI_SPEED_FACTOR; Vector2 velocity = Vector2(0.0f, move_amount * effective_speed * (float)delta); move_and_collide(velocity); // 限制移动范围 Viewport *viewport = get_viewport(); if (viewport) { Vector2 screen_size = viewport->get_visible_rect().size; Vector2 pos = get_global_position(); if (pos.y < half_height) { set_global_position(Vector2(pos.x, half_height)); } else if (pos.y > screen_size.y - half_height) { set_global_position(Vector2(pos.x, screen_size.y - half_height)); } } } void PingPongPaddle::set_speed(float p_speed) { speed = p_speed; } float PingPongPaddle::get_speed() const { return speed; } void PingPongPaddle::set_is_player(bool p_is_player) { is_player = p_is_player; } bool PingPongPaddle::get_is_player() const { return is_player; } void PingPongPaddle::set_ball_path(const NodePath &p_path) { ball_path = p_path; } NodePath PingPongPaddle::get_ball_path() const { return ball_path; }