【问题标题】:get name of file used as texture获取用作纹理的文件名
【发布时间】:2023-12-25 22:45:01
【问题描述】:

我正在尝试获取用作材质纹理的 jpg 的名称。但不知道如何将其作为字符串取回。

我有这个注意:CreateCube[1] 是一个数组中的 TCube 组件

CreateCube[1].Material.Texture.CreateFromFile(gamedir+'\pics\'+blocktype);

blocktype 的位置

grass.jpg
dirt.jpg
snow.jpg
stone.jpg

等.. 但是一旦它被分配,如何获得类型?目前我在记录cube中有一个字符串texture

cube.texture := createCube[i].Material.Texture.?????

什么属性会将名称作为字符串给出?

【问题讨论】:

  • 我认为它不会存储在某个地方。就像您将文件中的图像加载到TBitmap 中一样。没有人关心它来自哪里,每个人都想要那个位图的数据。我宁愿考虑将多维数据集的类型存储在您的记录中。类似于Kind 类型为TCubeKind 的字段,其中该类型将是类似(ckGrass, ckDirt, ckSnow, ckStone) 的枚举。将立方体类型存储在字段中可以立即指示您在其中加载了哪个纹理。
  • @Tlama 抱歉应该添加这个,但 createCube[i] 是组件 TCube。立方体是记录。所以我需要将属性 cubeKind 添加到 tcube ,从而制作一个新的组件?或者我可以将一个属性添加到一个已经创建好的组件,一个带有 firemonkey 的组件?
  • 是的,我是,是的,我需要知道.. 但希望 TCube 能在某处保留 jpg 的名称.. 它是回合制游戏,所以时间并不重要。但似乎不太考虑向 TCube 添加属性,并等待看看是否有办法从 tcube 中提取 jpg 的名称。
  • 为什么不记得传递给对象的文件名?
  • 正如其他人指出的那样,具有图像数据的对象不是“源感知”的,它们只关心图像数据和属性本身(例如宽度、高度等属性)。由于性能原因,位图数据被直接推送到 VRAM,无法存储位置/来源等数据。唯一真正的解决方案是将源存储在变量中(如果需要,然后将其保存到文件中)。替代解决方案包括编写您自己的TCube 导数(例如下面“J...”的答案)并将纹理预设存储在属性中,并在运行时读取该信息。

标签: delphi delphi-xe2 firemonkey


【解决方案1】:

继续 cmets 中的讨论,这里有一个示例说明您可以如何执行此操作 - 创建一个新组件并将其添加到您的项目中。这里我称之为TextureCube(右键单击包 -> 安装。要更改,请右键单击 -> 卸载,进行更改,然后右键单击 -> 再次安装):

unit TextureCube;

interface

uses
  System.SysUtils, System.Classes, FMX.Types, FMX.Types3D, FMX.Objects3D,
  Generics.Collections;

type
  TCubeTexture = (ctGrass, ctDirt, ctSnow, ctStone);

  TTextureSource = Class(TComponent)
    private
      FSelectedTexture : TCubeTexture;
      FTextures : TDictionary<TCubeTexture, TBitmap>;
      function GetTexture : TBitmap;
      procedure SetTexture(setTex : TBitmap);
    public
      constructor Create(AOwner : TComponent); override;
      destructor Destroy; override;
      property Textures : TDictionary<TCubeTexture, TBitmap> read FTextures;
    published
      property SelectedTexture : TCubeTexture read FSelectedTexture write FSelectedTexture;
      property Texture : TBitmap read GetTexture write SetTexture;

  End;

  TTextureCube = class(TCube)
  private
    FType : TCubeTexture;
    FTextureSource : TTextureSource;
    procedure SetCubeTexture(cubeTex : TCubeTexture);
    procedure SetTextureSource(texSource : TTextureSource);
  published
    property CubeType : TCubeTexture read FType write SetCubeTexture;
    property TextureSource : TTextureSource read FTextureSource write SetTextureSource;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TTextureCube]);
  RegisterComponents('Samples', [TTextureSource]);
end;

constructor TTextureSource.Create(AOwner : TComponent);
begin
  inherited;
  FTextures := TDictionary<TCubeTexture, TBitmap>.Create();
end;

destructor TTextureSource.Destroy;
begin
  FTextures.Free;
  inherited;
end;

function TTextureSource.GetTexture : TBitmap;
var tex : TBitmap;
begin
  if FTextures.TryGetValue(FSelectedTexture, tex) then
    result := tex
  else begin
    tex := TBitmap.Create(1,1);
    FTextures.AddOrSetValue(FSelectedTexture, tex);
    result := tex;
  end;
end;

procedure TTextureSource.SetTexture(setTex : TBitmap);
begin
  FTextures.AddOrSetValue(FSelectedTexture, setTex);
end;

procedure TTextureCube.SetCubeTexture(cubeTex: TCubeTexture);
var tex : TBitmap;    
begin
  FType := cubeTex;

  if Assigned(FTextureSource) and
     (FTextureSource.Textures.TryGetValue(cubeTex, tex)) then
    self.Material.Texture := tex
  else
    self.Material.Texture.Clear(0);
end;

procedure TTextureCube.SetTextureSource(texSource: TTextureSource);
begin
  FTextureSource := texSource;
  SetCubeTexture(FType);
end;   

end.

这提供了一个新的立方体类TTextureCube,它继承自TCube - 立方体添加了一个枚举类型,并且可以链接到为每种类型提供纹理的TTextureSource。在这里,我已将这些添加到组件工具栏中的Samples 部分,您可以将它们放在任何您想要的地方。将一个 TTextureSource 和一个 TTexture 立方体放到您的表单上,然后离开。这显然可以通过在表单上让TTextureCubes 与TTextureSources 自动关联来改善 - 现在只需关联多维数据集和源:

我没有费心在这里制作自定义编辑器/查看器 - 在TTextureSource 中,您可以选择任何类型并为该类型设置纹理。 TTextureSource 将保存与每种立方体类型相关的纹理库:

然后对于每个TTextureCube,您只需要更改立方体类型,它就会从TTextureSource 中获取相关的纹理:

作为一个完整的警告 - 我出于周日的无聊而很快写了这篇文章,作为一个如何开始的例子,也许如何融入一个稍微优雅的设计。显然,我可能遗漏了很多东西,可能没有正确清理等等。如果没有良好的一次性处理、一些添加的异常处理、错误检查和整洁,我不会在生产代码中使用它。

【讨论】:

  • @GlenMorse 不客气。当然,请注意,如果您想要一个可视化组件,您只需要走组件路线,您可以在 IDE 中的表单上插入并在设计时进行可视化设置。如果您乐于以编程方式完成所有操作,那么当然,您可以省略组件注册位,只在您自己的项目中包含该单元。
  • 这似乎有点过头了,对我来说可能毫无意义。没有什么可以阻止用户直接设置材质。此时纹理类型枚举值不同步。我不会考虑使用这个类。我只记得我使用的纹理文件的名称。
  • @DavidHeffernan 正如我所说,这是一个例子的骨架,它不是一个经过战斗强化的防弹类。就个人而言,我认为正如其他人所说,文件名无关紧要。当你只能加载一次纹理时,为什么还要从磁盘加载纹理两次、十次或一千次?尤其是在游戏的上下文中,看起来就是这样,我认为早点开始抽象比晚点开始更有意义。草 - 可以被驱赶,然后变成泥土,冬天把它变成雪。可以想象,一个块可以经常从一种类型更改为另一种类型。我不认为这是一个延伸。
  • 另外,谁知道这个块最终可能会承担什么其他功能 - 从如何自定义组件的教学示例的第一步开始,它显然可以增长以添加更多功能。我对 Glen 的游戏一无所知,但我对一般游戏的了解足以怀疑游戏中的方块最终会具有更多的功能、属性等,而不仅仅是描述其纹理类型的那些。
  • @DavidHeffernan 你的观点很好,我认为在很多情况下都是正确的。在这种情况下,我几乎不知道格伦对他的计划有什么想法。当然,在某些情况下,继承是正确的答案。我没有足够的信息来做出这个决定。我提供了这个作为如何开始将对象模型作为解决方案应用于问题的单个示例。它还提供了学习组件设计的机会 - 最终由 Glen 来决定在他的特定应用程序的上下文中什么最有意义。
【解决方案2】:

框架不跟踪纹理的来源。因此,无法按照您的要求进行操作,您需要自己在应用程序代码中跟踪纹理源。

【讨论】:

  • 不太确定否决票。答案似乎实际上是准确的。
最近更新 更多