You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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无法正确计算实际位置。

修正步骤

  1. 移除自定义的m_transform成员
    Player已经继承sf::Transformable,基类内部已维护变换矩阵,无需额外声明m_transform。直接使用基类的translate()、getTransform()等方法即可。

  2. 修改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; 
        }
    }
    
  3. 修正draw方法,使用基类变换

    void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // 合并基类的变换到渲染状态
        states.transform *= getTransform();
        target.draw(square, states);
    }
    
  4. 清理create方法
    删除m_transform = getTransform();这一行,因为不再使用自定义变换矩阵。

最终效果

修改后,getVertexPos方法会正确返回顶点的世界坐标(屏幕实际位置),调用该方法即可获取用于SAT碰撞检测的顶点实际位置。


内容的提问来源于stack exchange,提问作者Davide Venturini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:55:03