#include "pingpong_ball.h" #include #include #include #include #include #include #include #include using namespace godot; // ═══════════════════════════════════════════════════════ // 视觉颜色常量 — 以后替换素材时删除本段 // ═══════════════════════════════════════════════════════ static const Color BALL_COLOR = Color(1.0f, 1.0f, 1.0f); void PingPongBall::_bind_methods() { // 属性 ClassDB::bind_method(D_METHOD("get_speed"), &PingPongBall::get_speed); ClassDB::bind_method(D_METHOD("set_speed", "value"), &PingPongBall::set_speed); ClassDB::add_property("PingPongBall", PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed"); ClassDB::bind_method(D_METHOD("get_initial_speed"), &PingPongBall::get_initial_speed); ClassDB::bind_method(D_METHOD("set_initial_speed", "value"), &PingPongBall::set_initial_speed); ClassDB::add_property("PingPongBall", PropertyInfo(Variant::FLOAT, "initial_speed"), "set_initial_speed", "get_initial_speed"); ClassDB::bind_method(D_METHOD("get_active"), &PingPongBall::get_active); ClassDB::bind_method(D_METHOD("set_active", "value"), &PingPongBall::set_active); // 方法 ClassDB::bind_method(D_METHOD("reset"), &PingPongBall::reset); // 信号 ADD_SIGNAL(MethodInfo("scored", PropertyInfo(Variant::INT, "which"))); } PingPongBall::PingPongBall() { speed = 350.0f; initial_speed = 350.0f; is_active = false; } PingPongBall::~PingPongBall() { } void PingPongBall::_ready() { reset(); } // ═══════════════════════════════════════════════════════ // 视觉层 — 球体 + 拖尾(几何体占位) // 替换方法:删除本方法 → 添加 Sprite2D 子节点 // ═══════════════════════════════════════════════════════ void PingPongBall::_draw() { // 拖尾:从旧到新画渐隐圆 int trail_count = (int)trail_positions.size(); for (int i = 0; i < trail_count; i++) { float alpha = (float)(i + 1) / (float)BALL_TRAIL_LENGTH * 0.3f; float radius = BALL_RADIUS * (0.5f + 0.5f * (float)(i + 1) / (float)BALL_TRAIL_LENGTH); draw_circle(trail_positions[i], radius, Color(1.0f, 1.0f, 1.0f, alpha)); } // 球本体 draw_circle(Vector2(0.0f, 0.0f), BALL_RADIUS, BALL_COLOR); } void PingPongBall::_physics_process(double delta) { queue_redraw(); if (!is_active) { return; } // 更新拖尾 trail_positions.push_back(get_position()); if ((int)trail_positions.size() > BALL_TRAIL_LENGTH) { trail_positions.erase(trail_positions.begin()); } Vector2 velocity = direction * speed * (float)delta; Ref collision = move_and_collide(velocity); if (collision.is_valid()) { Vector2 normal = collision->get_normal(); direction = direction.bounce(normal); Object *collider = collision->get_collider(); if (collider) { Node *collider_node = Object::cast_to(collider); if (collider_node) { StringName node_name = collider_node->get_name(); // 碰到球拍 if (node_name.find("Paddle") != -1) { Node2D *collider_2d = Object::cast_to(collider_node); if (collider_2d) { // 根据击中位置微调角度 float hit_offset = (get_global_position().y - collider_2d->get_global_position().y) / 60.0f; hit_offset = CLAMP(hit_offset, -1.0f, 1.0f); direction.y += hit_offset * 0.5f; direction = direction.normalized(); // 速度递增 speed *= BALL_SPEED_INCREMENT; if (speed > BALL_MAX_SPEED) { speed = BALL_MAX_SPEED; } } } } } direction = direction.normalized(); } // 得分判定 Viewport *viewport = get_viewport(); if (viewport) { Vector2 screen_size = viewport->get_visible_rect().size; Vector2 pos = get_global_position(); if (pos.x < -50.0f) { emit_signal("scored", 1); reset(); } else if (pos.x > screen_size.x + 50.0f) { emit_signal("scored", 0); reset(); } // Y 边界限制 if (pos.y < BALL_RADIUS) { set_global_position(Vector2(pos.x, BALL_RADIUS)); direction.y = std::abs(direction.y); } else if (pos.y > screen_size.y - BALL_RADIUS) { set_global_position(Vector2(pos.x, screen_size.y - BALL_RADIUS)); direction.y = -std::abs(direction.y); } } } void PingPongBall::reset() { Viewport *viewport = get_viewport(); if (viewport) { Vector2 screen_size = viewport->get_visible_rect().size; set_global_position(screen_size / 2.0f); } else { set_global_position(Vector2(640.0f, 360.0f)); } // 重置速度 speed = initial_speed; // 清空拖尾 trail_positions.clear(); // 随机方向 float angle = (UtilityFunctions::randf() - 0.5f) * Math_PI / 2.0f; int side = (UtilityFunctions::randf() > 0.5f) ? 1 : -1; direction = Vector2((float)side * std::cos(angle), std::sin(angle)).normalized(); // 确保水平分量足够 if (std::abs(direction.x) < 0.3f) { direction.x = (direction.x > 0 ? 1.0f : -1.0f) * 0.3f; direction = direction.normalized(); } } void PingPongBall::set_active(bool p_active) { is_active = p_active; } bool PingPongBall::get_active() const { return is_active; } void PingPongBall::set_speed(float p_speed) { speed = p_speed; } float PingPongBall::get_speed() const { return speed; } void PingPongBall::set_initial_speed(float p_speed) { initial_speed = p_speed; } float PingPongBall::get_initial_speed() const { return initial_speed; }