149 行
5.9 KiB
C++
149 行
5.9 KiB
C++
#include "pingpong_paddle.h"
|
|
|
|
#include <godot_cpp/core/class_db.hpp>
|
|
#include <godot_cpp/variant/utility_functions.hpp>
|
|
#include <godot_cpp/classes/input.hpp>
|
|
#include <godot_cpp/classes/engine.hpp>
|
|
#include <godot_cpp/classes/node.hpp>
|
|
#include <godot_cpp/classes/scene_tree.hpp>
|
|
#include <godot_cpp/classes/viewport.hpp>
|
|
|
|
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<Node2D>(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;
|
|
}
|