Trying to access an object that has been destroyed


#1

Hi,

I’m doing some test to create a third person controller but I have some problems.

So, I have the TPWalker file (copy of FPSWalker), I added a animationClip when I press “goingForward2”, the build is ok, but when I press the button (so the animation would play), the game crash with this message (I have log but I can’t put it in this message, don’t know how) :

A fatal error occurred and the program has to terminate!
  - Error: InternalErrorException
  - Description: Trying to access an object that has been destroyed.
  - In function: void __cdecl bs::GameObjectHandleBase::throwIfDestroyed(void) const
  - In file: c:\users\none\desktop\bsf\source\foundation\bsfcore\scene\bsgameobjecthandle.cpp:51

Here is the TPWalker.cpp file and the Assets.cpp :

https://pastebin.com/1LGnrhRH <= TPWalker.cpp (line 59)

https://pastebin.com/FeB9anbk <= Assets.cpp

(maybe you want the header files too)

https://pastebin.com/hamFjMR7 <= Assets.h

https://pastebin.com/5GsS2EyW <= TPWalker.h

Can you help me please ? What do I do wrong ?


#2

It doesn’t look like you are populating the assets1 struct anywhere, so at that line you are attempting to access a handle that hasn’t been assigned to anything.


#3

assets1 is a call for the struct Asset in Assets.h so I guess it’s already populated (populated = filled ?), I would want to use the animationClip from the Assets.h .cpp so I called the Assets struct in TPWalker.cpp, this is not the good way ?


#4

They are two separate objects, that’s not how it works.


#5

See if it helps you. maybe it will help you because I’ve cloned the project examples and had to make some changes like this.

#pragma once

#include “BsPrerequisites.h”
#include “Reflection/BsRTTIType.h”
#include “Resources/BsResources.h”
#include “Resources/BsResourceManifest.h”
#include “Mesh/BsMesh.h”
#include “Importer/BsImporter.h”
#include “Importer/BsMeshImportOptions.h”
#include “Importer/BsTextureImportOptions.h”
#include “BsExampleConfig.h”
#include “Text/BsFontImportOptions.h”
#include “FileSystem/BsFileSystem.h”
#include “Input/BsVirtualInput.h”

namespace bs
{
/** A list of mesh assets provided with the example projects. */
enum class ExampleMesh
{
Pistol,
Cerberus
};

/** A list of texture assets provided with the example projects. */
enum class ExampleTexture
{
	PistolAlbedo,
	PistolNormal,
	PistolRoughness,
	PistolMetalness,
	EnvironmentPaperMill,
	GUIBansheeIcon,
	GUIExampleButtonNormal,
	GUIExampleButtonHover,
	GUIExampleButtonActive,
	DroneAlbedo,
	DroneNormal,
	DroneRoughness,
	DroneMetalness,
	GridPattern,
	GridPattern2,
	EnvironmentDaytime,
	EnvironmentRathaus,
	CerberusAlbedo,
	CerberusNormal,
	CerberusRoughness,
	CerberusMetalness
};

/** A list of shader assets provided with the example projects. */
enum class ExampleShader
{
	CustomVertex,
	CustomDeferredSurface,
	CustomDeferredLighting,
	CustomForward
};

/** A list of font assets provided with the example projects. */
enum class ExampleFont
{
	SegoeUILight,
	SegoeUISemiBold
};

/** Various helper functionality used throught the examples. */
class ExampleFramework
{
public:
	/** Loads a manifest of all resources that were previously saved using this class. */
	static void loadResourceManifest()
	{
		const Path dataPath = EXAMPLE_DATA_PATH;
		const Path manifestPath = "../Data/ResourceManifest.asset";
		if (FileSystem::exists(manifestPath))
			manifest = ResourceManifest::load(manifestPath, dataPath);
		else
			manifest = ResourceManifest::create("ExampleAssets");

		gResources().registerResourceManifest(manifest);
	}

	/** Saves the current resource manifest. */
	static void saveResourceManifest()
	{
		const Path dataPath = EXAMPLE_DATA_PATH;
		const Path manifestPath = "../Data/ResourceManifest.asset";

		if(manifest)
			ResourceManifest::save(manifest, manifestPath, dataPath);
	}

	/** Registers a common set of keys/buttons that are used for controlling the examples. */
	static void setupInputConfig()
	{
		// Register input configuration
		// bsf allows you to use VirtualInput system which will map input device buttons and axes to arbitrary names,
		// which allows you to change input buttons without affecting the code that uses it, since the code is only
		// aware of the virtual names.  If you want more direct input, see Input class.
		auto inputConfig = gVirtualInput().getConfiguration();

		// Camera controls for buttons (digital 0-1 input, e.g. keyboard or gamepad button)
		inputConfig->registerButton("Forward", BC_W);
		inputConfig->registerButton("Back", BC_S);
		inputConfig->registerButton("Left", BC_A);
		inputConfig->registerButton("Right", BC_D);
		inputConfig->registerButton("Forward", BC_UP);
		inputConfig->registerButton("Back", BC_DOWN);
		inputConfig->registerButton("Left", BC_LEFT);
		inputConfig->registerButton("Right", BC_RIGHT);
		inputConfig->registerButton("FastMove", BC_LSHIFT);
		inputConfig->registerButton("RotateObj", BC_MOUSE_LEFT);
		inputConfig->registerButton("RotateCam", BC_MOUSE_RIGHT);

		// Camera controls for axes (analog input, e.g. mouse or gamepad thumbstick)
		// These return values in [-1.0, 1.0] range.
		inputConfig->registerAxis("Horizontal", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseX));
		inputConfig->registerAxis("Vertical", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseY));
	}

	/** 
	 * Loads one of the builtin mesh assets. If the asset doesn't exist, the mesh will be re-imported from the source
	 * file, and then saved so it can be loaded on the next call to this method. 
	 * 
	 * Use the 'scale' parameter to control the size of the mesh. Note this option is only relevant when a mesh is
	 * being imported (i.e. when the asset file is missing).
	 */
	static HMesh loadMesh(ExampleMesh type, float scale = 1.0f)
	{
		// Map from the enum to the actual file path
		static Path assetPaths[] =
		{
			Path( "../Data/Pistol/Pistol01.fbx"),
			Path("../Data/Cerberus/Cerberus.FBX"),
		};

		const Path& srcAssetPath = assetPaths[(UINT32)type];

		// Attempt to load the previously processed asset
		Path assetPath = srcAssetPath;
		assetPath.setExtension(srcAssetPath.getExtension() + ".asset");

		HMesh model = gResources().load<Mesh>(assetPath);
		if (model == nullptr) // Mesh file doesn't exist, import from the source file.
		{
			// When importing you may specify optional import options that control how is the asset imported.
			SPtr<ImportOptions> meshImportOptions = Importer::instance().createImportOptions(srcAssetPath);

			// rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a
			// non-mesh resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
			if (rtti_is_of_type<MeshImportOptions>(meshImportOptions))
			{
				MeshImportOptions* importOptions = static_cast<MeshImportOptions*>(meshImportOptions.get());

				importOptions->setImportScale(scale);
			}

			model = gImporter().import<Mesh>(srcAssetPath, meshImportOptions);

			// Save for later use, so we don't have to import on the next run.
			gResources().save(model, assetPath, true);

			// Register with manifest, if one is present. Manifest allows the engine to find the resource even after
			// the application was restarted, which is important if resource was referenced in some serialized object.
			if(manifest)
				manifest->registerResource(model.getUUID(), assetPath);
		}

		return model;
	}

	/**
	 * Loads one of the builtin texture assets. If the asset doesn't exist, the texture will be re-imported from the 
	 * source file, and then saved so it can be loaded on the next call to this method. 
	 * 
	 * Textures not in sRGB space (e.g. normal maps) need to be specially marked by setting 'isSRGB' to false. Also 
	 * allows for conversion of texture to cubemap by setting the 'isCubemap' parameter. If the data should be imported
	 * in a floating point format, specify 'isHDR' to true. Note these options are only relevant when a texture is
	 * being imported (i.e. when asset file is missing). If 'mips' is true, mip-map levels will be generated.
	 */
	static HTexture loadTexture(ExampleTexture type, bool isSRGB = true, bool isCubemap = false, bool isHDR = false, 
		bool mips = true)
	{
		// Map from the enum to the actual file path
		static Path assetPaths[] =
		{
			Path("../Data/Pistol/Pistol_DFS.png"),
			Path("../Data/Pistol/Pistol_NM.png"),
			Path("../Data/Pistol/Pistol_RGH.png"),
			Path("../Data/Pistol/Pistol_MTL.png"),
			Path("../Data/Environments/PaperMill_E_3k.hdr"),
			Path("../Data/GUI/BansheeIcon.png"),
			Path("../Data/GUI/ExampleButtonNormal.png"),
			Path("../Data/GUI/ExampleButtonHover.png"),
			Path("../Data/GUI/ExampleButtonActive.png"),
			Path("../Data/MechDrone/Drone_diff.jpg"),
			Path("../Data/MechDrone/Drone_normal.jpg"),
			Path("../Data/MechDrone/Drone_rough.jpg"),
			Path("../Data/MechDrone/Drone_metal.jpg"),
			Path("../Data/Grid/GridPattern.png"),
			Path("../Data/Grid/GridPattern2.png"),
			Path("../Data/Environments/daytime.hdr"),
			Path("../Data/Environments/rathaus.hdr"),
			Path("../Data/Cerberus/Cerberus_A.tga"),
			Path("../Data/Cerberus/Cerberus_N.tga"),
			Path("../Data/Cerberus/Cerberus_R.tga"),
			Path("../Data/Cerberus/Cerberus_M.tga"),
		};

		const Path& srcAssetPath = assetPaths[(UINT32)type];

		// Attempt to load the previously processed asset
		Path assetPath = srcAssetPath;
		assetPath.setExtension(srcAssetPath.getExtension() + ".asset");

		HTexture texture = gResources().load<Texture>(assetPath);
		if (texture == nullptr) // Texture file doesn't exist, import from the source file.
		{
			// When importing you may specify optional import options that control how is the asset imported.
			SPtr<ImportOptions> textureImportOptions = Importer::instance().createImportOptions(srcAssetPath);

			// rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a 
			// non-texture resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
			if (rtti_is_of_type<TextureImportOptions>(textureImportOptions))
			{
				TextureImportOptions* importOptions = static_cast<TextureImportOptions*>(textureImportOptions.get());

				// We want maximum number of mipmaps to be generated
				importOptions->setGenerateMipmaps(mips);

				// If the texture is in sRGB space the system needs to know about it
				importOptions->setSRGB(isSRGB);

				// Ensures we can save the texture contents
				importOptions->setCPUCached(true);

				// Import as cubemap if needed
				importOptions->setIsCubemap(isCubemap);

				// If importing as cubemap, assume source is a panorama
				importOptions->setCubemapSourceType(CubemapSourceType::Cylindrical);

				// Importing using a HDR format if requested
				if (isHDR)
					importOptions->setFormat(PF_RG11B10F);
			}

			// Import texture with specified import options
			texture = gImporter().import<Texture>(srcAssetPath, textureImportOptions);

			// Save for later use, so we don't have to import on the next run.
			gResources().save(texture, assetPath, true);

			// Register with manifest, if one is present. Manifest allows the engine to find the resource even after
			// the application was restarted, which is important if resource was referenced in some serialized object.
			if(manifest)
				manifest->registerResource(texture.getUUID(), assetPath);
		}

		return texture;
	}

	/** 
	 * Loads one of the builtin shader assets. If the asset doesn't exist, the shader will be re-imported from the 
	 * source file, and then saved so it can be loaded on the next call to this method. 
	 */
	static HShader loadShader(ExampleShader type)
	{
		// Map from the enum to the actual file path
		static Path assetPaths[] =
		{
			Path("../Data/Shaders/CustomVertex.bsl"),
			Path("../Data/Shaders/CustomDeferredSurface.bsl"),
			Path("../Data/Shaders/CustomDeferredLighting.bsl"),
			Path("../Data/Shaders/CustomForward.bsl"),
		};

		const Path& srcAssetPath = assetPaths[(UINT32)type];

		// Attempt to load the previously processed asset
		Path assetPath = srcAssetPath;
		assetPath.setExtension(srcAssetPath.getExtension() + ".asset");

		HShader shader = gResources().load<Shader>(assetPath);
		if (shader == nullptr) // Shader file doesn't exist, import from the source file.
		{
			shader = gImporter().import<Shader>(srcAssetPath);

			// Save for later use, so we don't have to import on the next run.
			gResources().save(shader, assetPath, true);

			// Register with manifest, if one is present. Manifest allows the engine to find the resource even after
			// the application was restarted, which is important if resource was referenced in some serialized object.
			if(manifest)
				manifest->registerResource(shader.getUUID(), assetPath);
		}

		return shader;
	}

	/** 
	 * Loads one of the builtin font assets. If the asset doesn't exist, the font will be re-imported from the 
	 * source file, and then saved so it can be loaded on the next call to this method. 
	 *
	 * Use the 'fontSizes' parameter to determine which sizes of this font should be imported. Note this option is only
	 * relevant when a font is being imported (i.e. when the asset file is missing).
	 */
	static HFont loadFont(ExampleFont type, Vector<UINT32> fontSizes)
	{
		// Map from the enum to the actual file path
		static Path assetPaths[] =
		{
			Path("../Data/GUI/segoeuil.ttf"),
			Path("../Data/GUI/seguisb.ttf"),
		};

		const Path& srcAssetPath = assetPaths[(UINT32)type];

		// Attempt to load the previously processed asset
		Path assetPath = srcAssetPath;
		assetPath.setExtension(srcAssetPath.getExtension() + ".asset");

		HFont font = gResources().load<Font>(assetPath);
		if (font == nullptr) // Font file doesn't exist, import from the source file.
		{
			// When importing you may specify optional import options that control how is the asset imported.
			SPtr<FontImportOptions> fontImportOptions = FontImportOptions::create();
			fontImportOptions->setFontSizes(fontSizes);

			font = gImporter().import<Font>(srcAssetPath, fontImportOptions);

			// Save for later use, so we don't have to import on the next run.
			gResources().save(font, assetPath, true);

			// Register with manifest, if one is present. Manifest allows the engine to find the resource even after
			// the application was restarted, which is important if resource was referenced in some serialized object.
			if(manifest)
			{
				manifest->registerResource(font.getUUID(), assetPath);

				// Font has child resources, which also need to be registered
				for (auto& size : fontSizes)
				{
					SPtr<const FontBitmap> fontData = font->getBitmap(size);

					Path texPageOutputPath = Path( "../Data/GUI/");
					UINT32 pageIdx = 0;
					for (const auto& tex : fontData->texturePages)
					{
						String fontName = srcAssetPath.getFilename(false);
						texPageOutputPath.setFilename(fontName + "_" + toString(size) + "_texpage_" +
							toString(pageIdx) + ".asset");

						gResources().save(tex, texPageOutputPath, true);
						manifest->registerResource(tex.getUUID(), texPageOutputPath);

						pageIdx++;
					}
				}
			}
		}

		return font;
	}

private:
	static SPtr<ResourceManifest> manifest;
};

SPtr<ResourceManifest> ExampleFramework::manifest;

}


#6

Thank you but didn’t help, I searched in the doc and I’ve tried hundred of way to get the animations working but nothing. Don’t know what to do, will try others things.


#7

ajuda a render wireframe do wiresphere.
Can anyone tell me how I can render a wiresphere. please a little help was not coming