SFML中Vertex Array的Transform未修改顶点?如何获取实际顶点位置
问题:SFML中获取应用Transform后的顶点实际位置
在使用SFML开发游戏实现SAT碰撞检测时,发现Player类的Vertex Array顶点原始位置始终不变,尽管Transform已经让玩家在屏幕上正常移动。需要获取这些顶点的实际渲染位置用于碰撞检测。
Player.h
#include <SFML/Graphics.hpp> #ifndef PLAYER_H #define PLAYER_H class Player : public sf::Drawable, public sf::Transformable { private: sf::VertexArray square; sf::Vector2f velocity; float speed = 10.f; sf::Vector2f position; sf::Transform m_transform; virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; public: Player() = default; Player(int screen_width, int screen_height); void create(int screen_width, int screen_height); void move(bool w, bool a, bool s, bool d); void setVertexColor(sf::Color color, int vertex); int getVertexCount(); sf::Vector2f getVertexPos(int n); }; #endif
Player.cpp
#include <SFML/Graphics.hpp> #include "Player.h" #include <cmath> #include<iostream> Player::Player( int screen_width, int screen_height) { create(screen_width, screen_height); } void Player::create( int screen_width, int screen_height) { float size = 60.f; square.setPrimitiveType(sf::Triangles); square.resize(6); square[0].position = sf::Vector2f(0.f, 0.f); //top left square[1].position = sf::Vector2f(0.f, size); //bottom left square[2].position = sf::Vector2f(size, 0.f); //top right square[3].position = sf::Vector2f(0.f, size); //bottom left square[4].position = sf::Vector2f(size, 0.f); //top right square[5].position = sf::Vector2f(size, size); // bottom left square[0].color = sf::Color(200,200,200); square[1].color = sf::Color::White; square[2].color = sf::Color(100,100,100); square[3].color = sf::Color::White; square[4].color = sf::Color(100,100,100); square[5].color = sf::Color(200,200,200); m_transform = getTransform(); } void Player::move(bool w, bool a, bool s, bool d) { float mod_velocity; sf::Vector2f t; sf::Vector2f pos; velocity = sf::Vector2f(0.f, 0.f); if (w) { velocity.y -= 1; } if (a) { velocity.x -= 1; } if (s) { velocity.y += 1; } if (d) { velocity.x += 1; } if ((velocity.x != 0.f) || (velocity.y != 0.f)) { mod_velocity = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y)); t = velocity/mod_velocity; velocity = t * speed; } m_transform.translate(velocity); for (int i = 0; i < 6; i++) { std::cout << "square[" << i << "].position: " << square[i].position.x <<" " <<square[i].position.y <<std::endl; } } void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const { states.transform *= m_transform; // draw the vertex array target.draw(square, states); } int Player::getVertexCount() { return square.getVertexCount(); } sf::Vector2f Player::getVertexPos(int n) { sf::Vertex vertex = square[n]; return getTransform().transformPoint( vertex.position ); } void Player::setVertexColor(sf::Color color, int vertex) { square[vertex].color = color; }
解决方案
问题根源
你当前代码中,square的顶点存储的是局部坐标(相对于Player自身原点的位置),而m_transform是独立维护的变换矩阵,并未修改原始顶点坐标。SFML通过将变换矩阵应用到局部坐标得到屏幕实际位置,所以原始顶点坐标自然不会改变。同时你自定义的m_transform和继承的Transformable基类变换矩阵脱节,导致getVertexPos无法正确计算实际位置。
修正步骤
移除自定义的
m_transform成员
Player已经继承sf::Transformable,基类内部已维护变换矩阵,无需额外声明m_transform。直接使用基类的translate()、getTransform()等方法即可。修改
move方法,使用基类变换
将原本操作m_transform的逻辑改为调用基类translate(),确保变换矩阵统一维护:void Player::move(bool w, bool a, bool s, bool d) { float mod_velocity; sf::Vector2f t; velocity = sf::Vector2f(0.f, 0.f); if (w) velocity.y -= 1; if (a) velocity.x -= 1; if (s) velocity.y += 1; if (d) velocity.x += 1; if ((velocity.x != 0.f) || (velocity.y != 0.f)) { mod_velocity = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y)); t = velocity/mod_velocity; velocity = t * speed; } // 使用Transformable基类的translate方法更新变换 translate(velocity); // 输出变换后的实际位置 for (int i = 0; i < 6; i++) { sf::Vector2f worldPos = getTransform().transformPoint(square[i].position); std::cout << "square[" << i << "] world position: " << worldPos.x << " " << worldPos.y << std::endl; } }修正
draw方法,使用基类变换void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const { // 合并基类的变换到渲染状态 states.transform *= getTransform(); target.draw(square, states); }清理
create方法
删除m_transform = getTransform();这一行,因为不再使用自定义变换矩阵。
最终效果
修改后,getVertexPos方法会正确返回顶点的世界坐标(屏幕实际位置),调用该方法即可获取用于SAT碰撞检测的顶点实际位置。
内容的提问来源于stack exchange,提问作者Davide Venturini
相关产品推荐
相关产品推荐

