设置对象相对于其他对象的位置

Set object position relative to other object

所以我尝试学习游戏开发,我想让我的角色可以移动它的肘部。 the elbow looks like this,它由2个精灵组成,arm1和arm2。 Arm1 可以以其原点为基础旋转,arm2 应位于 arm1 的尖端(距 arm1 原点约 60 px)。但我不知道如何将 arm2 放在正确的位置,就像在 img 中一样。我尝试使用极坐标,因为我知道角度和臂距

        lines[0].position=Vector2f(arm1.getPosition().x,arm1.getPosition().y);
        lines[0].color=Color::Blue;

        armPos.x=arm1.getPosition().x+(d*cos(AngleToRad(arm1.getRotation()-toleransi) ));
        armPos.y=arm1.getPosition().y+(d*sin(AngleToRad(arm1.getRotation()-toleransi)));
        lines[1].position=armPos;
        lines[1].color=Color::Blue;
        

        cir.setPosition(armPos);
        arm1.setPosition(mc.getPosition().x+10,mc.getPosition().y-50);
        arm2.setPosition(arm1.getPosition().x,mc.getPosition().y-10);

,但这不起作用。我使用圆和线只是为了调试。 完整代码如下所示:

#include <SFML/Graphics.hpp>
#include <math.h>
#include <iostream>
#include <vector>
#include "Player.h"
#include "Particle.h"

using namespace sf;
float AngleToRad(float a)
{
    return (a/360.0f)*3.14159265359;
}
int main()
{
    RenderWindow window(VideoMode(1000,640), "Small Life");

//////////////Setup////////////
    
    //mc//
    Texture idle_texture;
    idle_texture.loadFromFile("image/idle.png");
    IntRect player_rect(264,0,264,264);
    Sprite mc(idle_texture,player_rect);
    mc.setOrigin(132,264);
    Player player(&idle_texture, Vector2u(4,1),0.3f);
    mc.setPosition(0,300);
    mc.setScale(0.7,0.7);
    //arm//
    Texture arm1_texture;
    arm1_texture.loadFromFile("image/arm1.png");
    Sprite arm1(arm1_texture);
    Texture arm2_texture;
    arm2_texture.loadFromFile("image/arm2.png");
    Sprite arm2(arm2_texture);

    arm1.setOrigin(70,158);
    arm2.setOrigin(79,158);
    arm1.setScale(0.5,0.5);
    arm2.setScale(0.7,0.7);
    //blood//
    Texture blood_texture;
    blood_texture.loadFromFile("image/blood.png");
    

    
    CircleShape cir(10);
    cir.setOrigin(5,5);
    VertexArray lines(LinesStrip,2);
    
    
    cir.setFillColor(Color::Red);


    float deltaTime=0.0f;

    Clock clock;
    Clock particle_time;
    
    float speed=0.2f;
   
    
    std::vector<Sprite>bloodVec;
    std::cout<<sin(1.5708)<<" "<<cos(AngleToRad(180))<<" "<< AngleToRad(180)<<" "<<" "<<asin(1)<<" "<<acos(1)<<std::endl;
    while (window.isOpen())
    {
        Event event;
        deltaTime=clock.restart().asSeconds();
        while (window.pollEvent(event))
        {
            if (event.type == Event::Closed)
                window.close();
        }
        
        if(Keyboard::isKeyPressed(Keyboard::W)) mc.move(0,-speed);
        if(Keyboard::isKeyPressed(Keyboard::S)) mc.move(0,speed);
        if(Keyboard::isKeyPressed(Keyboard::A)) mc.move(-speed,0);
        if(Keyboard::isKeyPressed(Keyboard::D)) mc.move(speed,0);


        //blood particle//
        if(particle_time.getElapsedTime().asSeconds()>1.5f)
        {
            
            IntRect blRect(0,0,200,200);
            Sprite b_blood(blood_texture,blRect);
            ParticleConstDrop(b_blood,mc.getPosition());
            
            bloodVec.push_back(b_blood);
            particle_time.restart();
            
        }
        int bloodCount=bloodVec.size();
        for(int i=0;i<bloodCount;i++)
        {
            
            window.draw(bloodVec[i]);
        
        }
        Vector2f armPos(arm1.getPosition());
        float d=30.0f;
        float toleransi=90;
        
        lines[0].position=Vector2f(arm1.getPosition().x,arm1.getPosition().y);
        lines[0].color=Color::Blue;

        armPos.x=arm1.getPosition().x+(d*cos(AngleToRad(arm1.getRotation()-toleransi) ));
        armPos.y=arm1.getPosition().y+(d*sin(AngleToRad(arm1.getRotation()-toleransi)));
        lines[1].position=armPos;
        lines[1].color=Color::Blue;
        

        cir.setPosition(armPos);
        arm1.setPosition(mc.getPosition().x+10,mc.getPosition().y-50);
        arm2.setPosition(arm1.getPosition().x,mc.getPosition().y-10);
        
        arm1.setRotation(110);//arm1.getRotation()+0.1
       
      
        

        
        player.Update(0,deltaTime);
        mc.setTextureRect(player.plRect);
        window.draw(arm1);
        //window.draw(arm2);
        window.draw(mc);
        window.draw(cir);
        window.draw(lines);
        
        window.display();
        window.clear(Color(255,255,255));
    }

    return 0;
}

任何人都可以告诉我我的代码有什么问题,或者有其他实现方法吗?

相对位置是通过变换合成(矩阵乘法)实现的。您可以尝试手动执行,但 SFML 已经实现了它,甚至更好:它在 sf::Sprite::draw.

后面使用它

那么让我们看看:arm2 必须有一个相对于 arm1 的位置,那么我们该怎么做呢?

  1. arm2本地坐标arm2中设置arm2原点,其中肘关节
  2. arm1局部坐标中设置arm2位置,其中肘关节
  3. 每次绘制 arm2 时,将 arm1 转换传递给 sf::RenderStates。下面会进行变换乘法
// Do this once
arm2.setOrigin(elbow_x_in_arm2, elbow_y_in_arm2);
arm2.setPosition(elbow_x_in_arm1, elbow_y_in_arm1);

// But this, each time you draw them
window.draw(arm1);
window.draw(arm2, sf::RenderStates(arm1.getTransform()));

结果: 每当您移动、旋转或缩放 arm1 时,arm2 将保持附加状态。另外,如果你旋转arm2,它会绕着肘部旋转。


重要! arm2 的变换将表示 局部变换 ,因此即使它绘制在正确的位置,数据也不包含全局 position/rotation/scale。例如,如果你想检查 arm2 中的碰撞,你应该考虑到这一点:

// don't use this to get the bounding box
sf::FloatRect boundingBoxBad = arm2.getGlobalBounds(); // WRONG: now they are not global
// use this:
sf::Transform tr1 = arm1.getTransform();
sf::Transform tr2 = arm2.getTransform();
sf::FloatRect boundingbBoxGood = tr2.transformRect(tr1.transformRect(arm2.getLocalBounds()));