Hi all!
I use Cocos Creator version 3.8.6.
I have my own IconView component in my project, it is located in the following path:
assets/scripts/coreView/IconView.ts
I don’t know exactly under what conditions, but sometimes the link to this component becomes invalid. I just start the game and get an error that I’m trying to call a function on an object that is not assigned.
This doesn’t happen often, but it’s still unpleasant. For example, I’m working with some part of the UI, placing completely different things, assigning links, saving the prefab (usually I then close the prefab), launching the scene and getting an error (although I didn’t touch the IconView links manually). As far as I understand, this only happens if I open the prefab. I don’t think I’ve ever had links get messed up like that in prefabs that I haven’t opened recently. Afterwards, I have to open the prefab and assign the links again (in the inspector it shows as if I didn’t set anything, and not a missing object).
To be honest, I’m already tired of this. I noticed this since version 3.8.3.
I have many components in my project, but I only got this error with three of my components. Two of them are gone - only IconView remains.
What’s wrong with him?
import { Color, Component, Enum, Size, Sprite, SpriteFrame, UITransform, _decorator } from "cc";
const { ccclass, property } = _decorator;
export enum IconFillingMethod {
filling, // May go out of area
fitting // Will be included in the area
}
Enum(IconFillingMethod);
@ccclass('IconView')
export class IconView extends Component {
@property({ type: UITransform })
private areaUITransform: UITransform;
@property({ type: UITransform })
private iconUITransform: UITransform;
@property({ type: Sprite })
private icon: Sprite;
@property({ type: IconFillingMethod })
private fillingMethod: IconFillingMethod = IconFillingMethod.fitting;
public SetIcon(sprite: SpriteFrame): void {
this.icon.spriteFrame = sprite;
this.UpdateSize();
}
public SetIconWithOriginalSize(sprite: SpriteFrame, scale: number = 1): void {
this.areaUITransform.setContentSize(sprite.rect.width * scale, sprite.rect.height * scale);
this.icon.spriteFrame = sprite;
this.UpdateSize();
}
public GetIcon(): SpriteFrame {
return this.icon.spriteFrame;
}
public GetIconSize(): Readonly<Size> {
return this.iconUITransform.contentSize;
}
public SetIconColor(color: Readonly<Color>): void {
this.icon.color = color;
}
public GetIconColor(): Readonly<Color> {
return this.icon.color;
}
public SetGrayscale(isGrayscale: boolean): void {
this.icon.grayscale = isGrayscale;
}
private UpdateSize(): void {
let areaWidth = this.areaUITransform.contentSize.width;
let areaHeight = this.areaUITransform.contentSize.height;
let originalSpriteWidth = this.icon.spriteFrame.rect.width;
let originalSpriteHeight = this.icon.spriteFrame.rect.height;
switch(this.fillingMethod) {
case IconFillingMethod.filling:
this.CalcProportionalRectFillingSize(areaWidth, areaHeight, originalSpriteWidth, originalSpriteHeight);
break;
case IconFillingMethod.fitting:
this.CalcProportionalRectFittingSize(areaWidth, areaHeight, originalSpriteWidth, originalSpriteHeight);
break;
}
}
private CalcProportionalRectFillingSize(fillableWidth: number, fillableHeight: number, spriteWidth: number, spriteHeight: number): void {
let width = 0;
let height = 0;
let aspectRatio = spriteWidth / spriteHeight;
width = fillableWidth;
height = width / aspectRatio;
if (height < fillableHeight) {
height = fillableHeight;
width = height * aspectRatio;
}
this.iconUITransform.setContentSize(width, height);
}
private CalcProportionalRectFittingSize(fillableWidth: number, fillableHeight: number, spriteWidth: number, spriteHeight: number): void {
let width = 0;
let height = 0;
let aspectRatio = spriteWidth / spriteHeight;
width = fillableWidth;
height = width / aspectRatio;
if (height > fillableHeight) {
height = fillableHeight;
width = height * aspectRatio;
}
this.iconUITransform.setContentSize(width, height);
}
}