mirror of
				https://gitee.com/ruanwujing/green-pack-cocos
				synced 2025-10-31 03:16:40 +00:00 
			
		
		
		
	拼图
This commit is contained in:
		
							
								
								
									
										138
									
								
								assets/resources/effects/puzzle.effect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								assets/resources/effects/puzzle.effect
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | |||||||
|  | // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. | ||||||
|  | CCEffect %{ | ||||||
|  |   techniques: | ||||||
|  |   - passes: | ||||||
|  |     - vert: sprite-vs:vert | ||||||
|  |       frag: sprite-fs:frag | ||||||
|  |       depthStencilState: | ||||||
|  |         depthTest: false | ||||||
|  |         depthWrite: false | ||||||
|  |       blendState: | ||||||
|  |         targets: | ||||||
|  |         - blend: true | ||||||
|  |           blendSrc: src_alpha | ||||||
|  |           blendDst: one_minus_src_alpha | ||||||
|  |           blendDstAlpha: one_minus_src_alpha | ||||||
|  |       rasterizerState: | ||||||
|  |         cullMode: none | ||||||
|  |       properties: | ||||||
|  |         rows: {value: 4} | ||||||
|  |         columns: {value: 8} | ||||||
|  |         sizeExpand: {value: 0.6} | ||||||
|  |         radius: {value: 0.15} | ||||||
|  | }% | ||||||
|  |  | ||||||
|  | CCProgram sprite-vs %{ | ||||||
|  |   precision highp float; | ||||||
|  |   #include <builtin/uniforms/cc-global> | ||||||
|  |   #if USE_LOCAL | ||||||
|  |     #include <builtin/uniforms/cc-local> | ||||||
|  |   #endif | ||||||
|  |   #if SAMPLE_FROM_RT | ||||||
|  |     #include <common/common-define> | ||||||
|  |   #endif | ||||||
|  |   in vec3 a_position; | ||||||
|  |   in vec2 a_texCoord; | ||||||
|  |   in vec4 a_color; | ||||||
|  |  | ||||||
|  |   out vec4 color; | ||||||
|  |   out vec2 uv0; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   vec4 vert () { | ||||||
|  |     vec4 pos = vec4(a_position, 1); | ||||||
|  |  | ||||||
|  |     #if USE_LOCAL | ||||||
|  |       pos = cc_matWorld * pos; | ||||||
|  |     #endif | ||||||
|  |  | ||||||
|  |     #if USE_PIXEL_ALIGNMENT | ||||||
|  |       pos = cc_matView * pos; | ||||||
|  |       pos.xyz = floor(pos.xyz); | ||||||
|  |       pos = cc_matProj * pos; | ||||||
|  |     #else | ||||||
|  |       pos = cc_matViewProj * pos; | ||||||
|  |     #endif | ||||||
|  |  | ||||||
|  |     uv0 = a_texCoord; | ||||||
|  |     #if SAMPLE_FROM_RT | ||||||
|  |       CC_HANDLE_RT_SAMPLE_FLIP(uv0); | ||||||
|  |     #endif | ||||||
|  |     color = a_color; | ||||||
|  |  | ||||||
|  |     return pos; | ||||||
|  |   } | ||||||
|  | }% | ||||||
|  |  | ||||||
|  | CCProgram sprite-fs %{ | ||||||
|  |   precision highp float; | ||||||
|  |   #include <builtin/internal/embedded-alpha> | ||||||
|  |   #include "../chunks/sdf2d" | ||||||
|  |   uniform Const { | ||||||
|  |     float rows; | ||||||
|  |     float columns; | ||||||
|  |     float sizeExpand; | ||||||
|  |     float radius; | ||||||
|  |   }; | ||||||
|  |   in vec4 color; | ||||||
|  |   in vec2 uv0; | ||||||
|  |    | ||||||
|  |   float smin(float a,float b,float k){ | ||||||
|  |       float h = clamp(0.5+0.5*(a-b)/k,0.0,1.0); | ||||||
|  |       return mix(a,b,h)-k*h*(1.0-h); | ||||||
|  |   } | ||||||
|  |   float smax(float a,float b,float k){ | ||||||
|  |       return -smin(-a,-b,k); | ||||||
|  |   } | ||||||
|  |   float isOdd(float x) { | ||||||
|  |     return fract(x/2.0) * 2.0; | ||||||
|  |   } | ||||||
|  |   #pragma builtin(local) | ||||||
|  |   layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   vec4 frag () { | ||||||
|  |     vec4 o = vec4(1, 1, 1, 1);       | ||||||
|  |  | ||||||
|  |     vec2 id = floor(uv0 * vec2(columns, rows)); | ||||||
|  |     vec2 uv_center = (id + 0.5) / vec2(columns, rows); | ||||||
|  |  | ||||||
|  |     float exp = sizeExpand + 1.0; | ||||||
|  |     vec2 uv = (uv0 - uv_center) * vec2(columns, rows) * exp; | ||||||
|  |     o *= CCSampleWithAlphaSeparated(cc_spriteTexture, (uv0 - uv_center) * exp + uv_center); | ||||||
|  |     float d = sdBox(uv, vec2(0.5, 0.5)); | ||||||
|  |  | ||||||
|  |     float rad = radius; | ||||||
|  |     float dd = 0.1; | ||||||
|  |     float odd = isOdd(id.x + id.y); | ||||||
|  |     float s = sign(odd - 0.5); | ||||||
|  |  | ||||||
|  |     float dc_top = sdCircle(uv + vec2(0, 0.5 - dd * s), rad); | ||||||
|  |     float dc_bottom = sdCircle(uv + vec2(0, -0.5 + dd * s), rad); | ||||||
|  |     float dc_left = sdCircle(uv + vec2(0.5 + dd * s, 0), rad); | ||||||
|  |     float dc_right = sdCircle(uv + vec2(-0.5 - dd * s, 0), rad); | ||||||
|  |  | ||||||
|  |     float k = 0.02; | ||||||
|  |     float nOdd = 1.0 - odd; | ||||||
|  |  | ||||||
|  |     float dt = smax(d, -dc_top, k) * odd + smin(d, dc_top , k) * nOdd; | ||||||
|  |     float edge = step(id.y, 0.5); | ||||||
|  |     d = dt * (1.0 - edge) + d * edge; | ||||||
|  |  | ||||||
|  |     float db = smax(d, -dc_bottom, k) * odd + smin(d, dc_bottom, k) * nOdd; | ||||||
|  |     edge = step(rows - 1.5, id.y); | ||||||
|  |     d = db * (1.0 - edge) + d * edge; | ||||||
|  |  | ||||||
|  |     float dl = smin(d, dc_left, k) * odd + smax(d, -dc_left, k) * nOdd; | ||||||
|  |     edge = step(id.x, 0.5); | ||||||
|  |     d = dl * (1.0 - edge) + d * edge; | ||||||
|  |  | ||||||
|  |     float dr = smin(d, dc_right, k) * odd + smax(d, -dc_right, k) * nOdd; | ||||||
|  |     edge = step(columns - 1.5, id.x); | ||||||
|  |     d = dr * (1.0 - edge) + d * edge; | ||||||
|  |  | ||||||
|  |     float c = smoothstep(0.01, -0.01, d); | ||||||
|  |     o *= c; | ||||||
|  |     return o; | ||||||
|  |   } | ||||||
|  | }% | ||||||
							
								
								
									
										11
									
								
								assets/resources/effects/puzzle.effect.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								assets/resources/effects/puzzle.effect.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.7.1", | ||||||
|  |   "importer": "effect", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "8db6f7be-b91e-44ba-be47-5857f763dcc2", | ||||||
|  |   "files": [ | ||||||
|  |     ".json" | ||||||
|  |   ], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								assets/resources/materials/puzzle.mtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								assets/resources/materials/puzzle.mtl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | { | ||||||
|  |   "__type__": "cc.Material", | ||||||
|  |   "_name": "", | ||||||
|  |   "_objFlags": 0, | ||||||
|  |   "__editorExtras__": {}, | ||||||
|  |   "_native": "", | ||||||
|  |   "_effectAsset": { | ||||||
|  |     "__uuid__": "8db6f7be-b91e-44ba-be47-5857f763dcc2", | ||||||
|  |     "__expectedType__": "cc.EffectAsset" | ||||||
|  |   }, | ||||||
|  |   "_techIdx": 0, | ||||||
|  |   "_defines": [ | ||||||
|  |     {} | ||||||
|  |   ], | ||||||
|  |   "_states": [ | ||||||
|  |     { | ||||||
|  |       "rasterizerState": {}, | ||||||
|  |       "depthStencilState": {}, | ||||||
|  |       "blendState": { | ||||||
|  |         "targets": [ | ||||||
|  |           {} | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "_props": [ | ||||||
|  |     { | ||||||
|  |       "rows": 6, | ||||||
|  |       "columns": 10 | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								assets/resources/materials/puzzle.mtl.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								assets/resources/materials/puzzle.mtl.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.0.21", | ||||||
|  |   "importer": "material", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "0080e1e8-609b-41f2-ad39-2a1c3fb9b4dc", | ||||||
|  |   "files": [ | ||||||
|  |     ".json" | ||||||
|  |   ], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
							
								
								
									
										1196
									
								
								assets/resources/scenes/puzzle.scene
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1196
									
								
								assets/resources/scenes/puzzle.scene
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										11
									
								
								assets/resources/scenes/puzzle.scene.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								assets/resources/scenes/puzzle.scene.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.50", | ||||||
|  |   "importer": "scene", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "946213b2-dc04-4756-8c82-e9df6ac4d571", | ||||||
|  |   "files": [ | ||||||
|  |     ".json" | ||||||
|  |   ], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								assets/resources/ui/images.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								assets/resources/ui/images.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.2.0", | ||||||
|  |   "importer": "directory", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "7a473951-f04b-4028-8ec6-741d8319818f", | ||||||
|  |   "files": [], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/resources/ui/images/cyberpunk.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/resources/ui/images/cyberpunk.jpeg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 294 KiB | 
							
								
								
									
										134
									
								
								assets/resources/ui/images/cyberpunk.jpeg.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								assets/resources/ui/images/cyberpunk.jpeg.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.0.26", | ||||||
|  |   "importer": "image", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "10336bef-42f1-4bfd-a795-1f29554ccdd8", | ||||||
|  |   "files": [ | ||||||
|  |     ".jpeg", | ||||||
|  |     ".json" | ||||||
|  |   ], | ||||||
|  |   "subMetas": { | ||||||
|  |     "6c48a": { | ||||||
|  |       "importer": "texture", | ||||||
|  |       "uuid": "10336bef-42f1-4bfd-a795-1f29554ccdd8@6c48a", | ||||||
|  |       "displayName": "cyberpunk", | ||||||
|  |       "id": "6c48a", | ||||||
|  |       "name": "texture", | ||||||
|  |       "userData": { | ||||||
|  |         "wrapModeS": "clamp-to-edge", | ||||||
|  |         "wrapModeT": "clamp-to-edge", | ||||||
|  |         "minfilter": "linear", | ||||||
|  |         "magfilter": "linear", | ||||||
|  |         "mipfilter": "none", | ||||||
|  |         "anisotropy": 0, | ||||||
|  |         "isUuid": true, | ||||||
|  |         "imageUuidOrDatabaseUri": "10336bef-42f1-4bfd-a795-1f29554ccdd8", | ||||||
|  |         "visible": false | ||||||
|  |       }, | ||||||
|  |       "ver": "1.0.22", | ||||||
|  |       "imported": true, | ||||||
|  |       "files": [ | ||||||
|  |         ".json" | ||||||
|  |       ], | ||||||
|  |       "subMetas": {} | ||||||
|  |     }, | ||||||
|  |     "f9941": { | ||||||
|  |       "importer": "sprite-frame", | ||||||
|  |       "uuid": "10336bef-42f1-4bfd-a795-1f29554ccdd8@f9941", | ||||||
|  |       "displayName": "cyberpunk", | ||||||
|  |       "id": "f9941", | ||||||
|  |       "name": "spriteFrame", | ||||||
|  |       "userData": { | ||||||
|  |         "trimType": "auto", | ||||||
|  |         "trimThreshold": 1, | ||||||
|  |         "rotated": false, | ||||||
|  |         "offsetX": 0, | ||||||
|  |         "offsetY": 0, | ||||||
|  |         "trimX": 0, | ||||||
|  |         "trimY": 0, | ||||||
|  |         "width": 800, | ||||||
|  |         "height": 480, | ||||||
|  |         "rawWidth": 800, | ||||||
|  |         "rawHeight": 480, | ||||||
|  |         "borderTop": 0, | ||||||
|  |         "borderBottom": 0, | ||||||
|  |         "borderLeft": 0, | ||||||
|  |         "borderRight": 0, | ||||||
|  |         "packable": false, | ||||||
|  |         "pixelsToUnit": 100, | ||||||
|  |         "pivotX": 0.5, | ||||||
|  |         "pivotY": 0.5, | ||||||
|  |         "meshType": 0, | ||||||
|  |         "vertices": { | ||||||
|  |           "rawPosition": [ | ||||||
|  |             -400, | ||||||
|  |             -240, | ||||||
|  |             0, | ||||||
|  |             400, | ||||||
|  |             -240, | ||||||
|  |             0, | ||||||
|  |             -400, | ||||||
|  |             240, | ||||||
|  |             0, | ||||||
|  |             400, | ||||||
|  |             240, | ||||||
|  |             0 | ||||||
|  |           ], | ||||||
|  |           "indexes": [ | ||||||
|  |             0, | ||||||
|  |             1, | ||||||
|  |             2, | ||||||
|  |             2, | ||||||
|  |             1, | ||||||
|  |             3 | ||||||
|  |           ], | ||||||
|  |           "uv": [ | ||||||
|  |             0, | ||||||
|  |             480, | ||||||
|  |             800, | ||||||
|  |             480, | ||||||
|  |             0, | ||||||
|  |             0, | ||||||
|  |             800, | ||||||
|  |             0 | ||||||
|  |           ], | ||||||
|  |           "nuv": [ | ||||||
|  |             0, | ||||||
|  |             0, | ||||||
|  |             1, | ||||||
|  |             0, | ||||||
|  |             0, | ||||||
|  |             1, | ||||||
|  |             1, | ||||||
|  |             1 | ||||||
|  |           ], | ||||||
|  |           "minPos": [ | ||||||
|  |             -400, | ||||||
|  |             -240, | ||||||
|  |             0 | ||||||
|  |           ], | ||||||
|  |           "maxPos": [ | ||||||
|  |             400, | ||||||
|  |             240, | ||||||
|  |             0 | ||||||
|  |           ] | ||||||
|  |         }, | ||||||
|  |         "isUuid": true, | ||||||
|  |         "imageUuidOrDatabaseUri": "10336bef-42f1-4bfd-a795-1f29554ccdd8@6c48a", | ||||||
|  |         "atlasUuid": "" | ||||||
|  |       }, | ||||||
|  |       "ver": "1.0.12", | ||||||
|  |       "imported": true, | ||||||
|  |       "files": [ | ||||||
|  |         ".json" | ||||||
|  |       ], | ||||||
|  |       "subMetas": {} | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "userData": { | ||||||
|  |     "hasAlpha": false, | ||||||
|  |     "type": "sprite-frame", | ||||||
|  |     "fixAlphaTransparencyArtifacts": false, | ||||||
|  |     "redirect": "10336bef-42f1-4bfd-a795-1f29554ccdd8@f9941" | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -59,11 +59,11 @@ export const ColorSDFAssembler: IAssembler = { | |||||||
|  |  | ||||||
|         const renderData = sprite.renderData!; |         const renderData = sprite.renderData!; | ||||||
|         const chunk = renderData.chunk; |         const chunk = renderData.chunk; | ||||||
|         if (sprite["_flagChangedVersion"] !== sprite.node["_flagChangedVersion"] || renderData.vertDirty) { |         if (sprite["_flagChangedVersion"] !== sprite.node["flagChangedVersion"] || renderData.vertDirty) { | ||||||
|             // const vb = chunk.vertexAccessor.getVertexBuffer(chunk.bufferId); |             // const vb = chunk.vertexAccessor.getVertexBuffer(chunk.bufferId); | ||||||
|             this.updateWorldVerts(sprite, chunk); |             this.updateWorldVerts(sprite, chunk); | ||||||
|             renderData.vertDirty = false; |             renderData.vertDirty = false; | ||||||
|             sprite["_flagChangedVersion"] = sprite.node["_flagChangedVersion"]; |             sprite["_flagChangedVersion"] = sprite.node["flagChangedVersion"]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // quick version |         // quick version | ||||||
| @@ -158,6 +158,8 @@ export const ColorSDFAssembler: IAssembler = { | |||||||
|     updateColor (sprite: GPSpriteSDF) { |     updateColor (sprite: GPSpriteSDF) { | ||||||
|         const renderData = sprite.renderData!; |         const renderData = sprite.renderData!; | ||||||
|         const vData = renderData.chunk.vb; |         const vData = renderData.chunk.vb; | ||||||
|  |         if (!sprite.spriteFrame) | ||||||
|  |             return | ||||||
|         const uv = sprite.spriteFrame.uv; |         const uv = sprite.spriteFrame.uv; | ||||||
|  |  | ||||||
|         let colorOffset = 5; |         let colorOffset = 5; | ||||||
|   | |||||||
| @@ -107,6 +107,13 @@ export const GPRoundBoxAssembler: IAssembler = { | |||||||
|             this.updateWorldVerts(sprite, chunk); |             this.updateWorldVerts(sprite, chunk); | ||||||
|             renderData.vertDirty = false; |             renderData.vertDirty = false; | ||||||
|         } |         } | ||||||
|  |         if (sprite["_flagChangedVersion"] !== sprite.node["flagChangedVersion"] || renderData.vertDirty) { | ||||||
|  |             // const vb = chunk.vertexAccessor.getVertexBuffer(chunk.bufferId); | ||||||
|  |             this.updateWorldVerts(sprite, chunk); | ||||||
|  |             renderData.vertDirty = false; | ||||||
|  |             sprite["_flagChangedVersion"] = sprite.node["flagChangedVersion"]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         // quick version |         // quick version | ||||||
|         const bid = chunk.bufferId; |         const bid = chunk.bufferId; | ||||||
|   | |||||||
							
								
								
									
										174
									
								
								assets/scripts/puzzle/PuzzleAssembler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								assets/scripts/puzzle/PuzzleAssembler.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | |||||||
|  | import { Color, IAssembler, IRenderData, RenderData, dynamicAtlasManager } from "cc"; | ||||||
|  | import { PuzzleSprite } from "./PuzzleSprite"; | ||||||
|  | const QUAD_INDICES = Uint16Array.from([0, 1, 2, 1, 3, 2]); | ||||||
|  |  | ||||||
|  | export const PuzzleAssembler: IAssembler = { | ||||||
|  |     createData (sprite: PuzzleSprite) { | ||||||
|  |         const renderData = sprite.requestRenderData(); | ||||||
|  |         renderData.dataLength = 4; | ||||||
|  |         renderData.resize(4, 6); | ||||||
|  |         renderData.chunk.setIndexBuffer(QUAD_INDICES); | ||||||
|  |         return renderData; | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     updateRenderData (sprite: PuzzleSprite) { | ||||||
|  |         const frame = sprite.spriteFrame; | ||||||
|  |  | ||||||
|  |         dynamicAtlasManager.packToDynamicAtlas(sprite, frame); | ||||||
|  |         this.updateUVs(sprite);// dirty need | ||||||
|  |         //this.updateColor(sprite);// dirty need | ||||||
|  |  | ||||||
|  |         const renderData = sprite.renderData; | ||||||
|  |         if (renderData && frame) { | ||||||
|  |             if (renderData.vertDirty) { | ||||||
|  |                 this.updateVertexData(sprite); | ||||||
|  |             } | ||||||
|  |             renderData.updateRenderData(sprite, frame); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     updateWorldVerts (sprite: PuzzleSprite, chunk: { vb: any; }) { | ||||||
|  |         const renderData = sprite.renderData!; | ||||||
|  |         const vData = chunk.vb; | ||||||
|  |  | ||||||
|  |         const dataList: IRenderData[] = renderData.data; | ||||||
|  |         const node = sprite.node; | ||||||
|  |         const m = node.worldMatrix; | ||||||
|  |  | ||||||
|  |         const stride = renderData.floatStride; | ||||||
|  |         let offset = 0; | ||||||
|  |         const length = dataList.length; | ||||||
|  |         for (let i = 0; i < length; i++) { | ||||||
|  |             const curData = dataList[i]; | ||||||
|  |             const x = curData.x; | ||||||
|  |             const y = curData.y; | ||||||
|  |             let rhw = m.m03 * x + m.m07 * y + m.m15; | ||||||
|  |             rhw = rhw ? 1 / rhw : 1; | ||||||
|  |  | ||||||
|  |             offset = i * stride; | ||||||
|  |             vData[offset + 0] = (m.m00 * x + m.m04 * y + m.m12) * rhw; | ||||||
|  |             vData[offset + 1] = (m.m01 * x + m.m05 * y + m.m13) * rhw; | ||||||
|  |             vData[offset + 2] = (m.m02 * x + m.m06 * y + m.m14) * rhw; | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     fillBuffers (sprite: PuzzleSprite) { | ||||||
|  |         if (sprite === null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const renderData = sprite.renderData!; | ||||||
|  |         const chunk = renderData.chunk; | ||||||
|  |  | ||||||
|  |         if (sprite["_flagChangedVersion"] !== sprite.node["flagChangedVersion"] || renderData.vertDirty) { | ||||||
|  |             // const vb = chunk.vertexAccessor.getVertexBuffer(chunk.bufferId); | ||||||
|  |             this.updateWorldVerts(sprite, chunk); | ||||||
|  |             renderData.vertDirty = false; | ||||||
|  |             sprite["_flagChangedVersion"] = sprite.node["flagChangedVersion"]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // quick version | ||||||
|  |         const vidOrigin = chunk.vertexOffset; | ||||||
|  |         const meshBuffer = chunk.meshBuffer; | ||||||
|  |         const ib = chunk.meshBuffer.iData; | ||||||
|  |         let indexOffset = meshBuffer.indexOffset; | ||||||
|  |  | ||||||
|  |         const vid = vidOrigin; | ||||||
|  |  | ||||||
|  |         // left bottom | ||||||
|  |         ib[indexOffset++] = vid; | ||||||
|  |         // right bottom | ||||||
|  |         ib[indexOffset++] = vid + 1; | ||||||
|  |         // left top | ||||||
|  |         ib[indexOffset++] = vid + 2; | ||||||
|  |  | ||||||
|  |         // right bottom | ||||||
|  |         ib[indexOffset++] = vid + 1; | ||||||
|  |         // right top | ||||||
|  |         ib[indexOffset++] = vid + 3; | ||||||
|  |         // left top | ||||||
|  |         ib[indexOffset++] = vid + 2; | ||||||
|  |  | ||||||
|  |         // IndexOffset should add 6 when vertices of a rect are visited. | ||||||
|  |         meshBuffer.indexOffset += 6; | ||||||
|  |         // slow version | ||||||
|  |         // renderer.switchBufferAccessor().appendIndices(chunk); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     updateVertexData (sprite: PuzzleSprite) { | ||||||
|  |         const renderData: RenderData | null = sprite.renderData; | ||||||
|  |         if (!renderData) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const uiTrans = sprite.node._uiProps.uiTransformComp!; | ||||||
|  |         const dataList: IRenderData[] = renderData.data; | ||||||
|  |         const cw = uiTrans.width; | ||||||
|  |         const ch = uiTrans.height; | ||||||
|  |         const appX = uiTrans.anchorX * cw; | ||||||
|  |         const appY = uiTrans.anchorY * ch; | ||||||
|  |         let l = 0; | ||||||
|  |         let b = 0; | ||||||
|  |         let r = 0; | ||||||
|  |         let t = 0; | ||||||
|  |  | ||||||
|  |         const frame = sprite.spriteFrame!; | ||||||
|  |         const originSize = frame.originalSize; | ||||||
|  |         const ow = originSize.width; | ||||||
|  |         const oh = originSize.height; | ||||||
|  |         const scaleX = cw / ow; | ||||||
|  |         const scaleY = ch / oh; | ||||||
|  |         const trimmedBorder = frame.trimmedBorder; | ||||||
|  |         l = trimmedBorder.x * scaleX - appX; | ||||||
|  |         b = trimmedBorder.z * scaleY - appY; | ||||||
|  |         r = cw + trimmedBorder.y * scaleX - appX; | ||||||
|  |         t = ch + trimmedBorder.w * scaleY - appY; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         dataList[0].x = l; | ||||||
|  |         dataList[0].y = b; | ||||||
|  |  | ||||||
|  |         dataList[1].x = r; | ||||||
|  |         dataList[1].y = b; | ||||||
|  |  | ||||||
|  |         dataList[2].x = l; | ||||||
|  |         dataList[2].y = t; | ||||||
|  |  | ||||||
|  |         dataList[3].x = r; | ||||||
|  |         dataList[3].y = t; | ||||||
|  |  | ||||||
|  |         renderData.vertDirty = true; | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     updateUVs (sprite: PuzzleSprite) { | ||||||
|  |         const renderData = sprite.renderData!; | ||||||
|  |         const vData = renderData.chunk.vb; | ||||||
|  |         const uv = sprite.uv; | ||||||
|  |         // 01 11 00 10 | ||||||
|  |         vData[3] = uv[0]; | ||||||
|  |         vData[4] = uv[1]; | ||||||
|  |         vData[12] = uv[2]; | ||||||
|  |         vData[13] = uv[3]; | ||||||
|  |         vData[21] = uv[4]; | ||||||
|  |         vData[22] = uv[5]; | ||||||
|  |         vData[30] = uv[6]; | ||||||
|  |         vData[31] = uv[7]; | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     updateColor (sprite: PuzzleSprite) { | ||||||
|  |         const renderData = sprite.renderData!; | ||||||
|  |         const vData = renderData.chunk.vb; | ||||||
|  |         let colorOffset = 5; | ||||||
|  |         const color = sprite.color; | ||||||
|  |         const colorR = color.r / 255; | ||||||
|  |         const colorG = color.g / 255; | ||||||
|  |         const colorB = color.b / 255; | ||||||
|  |         const colorA = color.a / 255; | ||||||
|  |         for (let i = 0; i < renderData.dataLength; i++, colorOffset += renderData.floatStride) { | ||||||
|  |             vData[colorOffset] = colorR; | ||||||
|  |             vData[colorOffset + 1] = colorG; | ||||||
|  |             vData[colorOffset + 2] = colorB; | ||||||
|  |             vData[colorOffset + 3] = colorA; | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  | }; | ||||||
							
								
								
									
										9
									
								
								assets/scripts/puzzle/PuzzleAssembler.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								assets/scripts/puzzle/PuzzleAssembler.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | { | ||||||
|  |   "ver": "4.0.23", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "a02a1645-241e-4702-988b-34876ae0ae10", | ||||||
|  |   "files": [], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
							
								
								
									
										310
									
								
								assets/scripts/puzzle/PuzzleSprite.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								assets/scripts/puzzle/PuzzleSprite.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,310 @@ | |||||||
|  | import { _decorator, CCInteger, cclegacy, Color, Component, InstanceMaterialType, Material, Node, NodeEventType, RenderTexture, Sprite, SpriteAtlas, SpriteFrame, UIRenderer } from 'cc'; | ||||||
|  | import { BUILD, EDITOR } from 'cc/env'; | ||||||
|  | import { PuzzleAssembler } from './PuzzleAssembler'; | ||||||
|  | const { ccclass, property ,type, executionOrder} = _decorator; | ||||||
|  | enum EventType { | ||||||
|  |     SPRITE_FRAME_CHANGED = 'spriteframe-changed', | ||||||
|  | } | ||||||
|  | @ccclass('PuzzleSprite') | ||||||
|  | export class PuzzleSprite extends UIRenderer { | ||||||
|  |     // 尺寸模式,可以看枚举原本定义的地方有注释说明 | ||||||
|  |     @property({serializable:true}) | ||||||
|  |     protected _sizeMode = Sprite.SizeMode.TRIMMED; | ||||||
|  |     @type(Sprite.SizeMode) | ||||||
|  |     get sizeMode () { | ||||||
|  |         return this._sizeMode; | ||||||
|  |     } | ||||||
|  |     set sizeMode (value) { | ||||||
|  |         if (this._sizeMode === value) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._sizeMode = value; | ||||||
|  |         if (value !== Sprite.SizeMode.CUSTOM) { | ||||||
|  |             this._applySpriteSize(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // 图集 | ||||||
|  |     @property({serializable:true}) | ||||||
|  |     protected _atlas: SpriteAtlas | null = null; | ||||||
|  |     @type(SpriteAtlas) | ||||||
|  |     get spriteAtlas () { | ||||||
|  |         return this._atlas; | ||||||
|  |     } | ||||||
|  |     set spriteAtlas (value) { | ||||||
|  |         if (this._atlas === value) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this._atlas = value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @property({serializable:true}) | ||||||
|  |     protected _spriteFrame: SpriteFrame | null = null; | ||||||
|  |     @type(SpriteFrame) | ||||||
|  |     get spriteFrame () { | ||||||
|  |         return this._spriteFrame; | ||||||
|  |     } | ||||||
|  |     set spriteFrame (value) { | ||||||
|  |         if (this._spriteFrame === value) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const lastSprite = this._spriteFrame; | ||||||
|  |         this._spriteFrame = value; | ||||||
|  |         this.markForUpdateRenderData(); | ||||||
|  |         this._applySpriteFrame(lastSprite); | ||||||
|  |         if (EDITOR) { | ||||||
|  |             this.node.emit(EventType.SPRITE_FRAME_CHANGED, this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _row =1 | ||||||
|  |     @property({type:CCInteger, step:1, min:1}) | ||||||
|  |     public get row(){return this._row} | ||||||
|  |     public set row(v){this._row = v;  | ||||||
|  |         this._updateUVs() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _column = 1 | ||||||
|  |     @property({type:CCInteger, step:1, min:1}) | ||||||
|  |     public get column(){return this._column} | ||||||
|  |     public set column(v){this._column = v;  | ||||||
|  |         this._updateUVs() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _rowMax = 4 | ||||||
|  |     @property({type:CCInteger, step:1, min:1}) | ||||||
|  |     public get rowMax(){return this._rowMax} | ||||||
|  |     public set rowMax(v){this._rowMax = v;  | ||||||
|  |         this._updateUVs() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _columnMax = 4 | ||||||
|  |     @property({type:CCInteger, step:1, min:1}) | ||||||
|  |     public get columnMax(){return this._columnMax} | ||||||
|  |     public set columnMax(v){this._columnMax = v;  | ||||||
|  |         this._updateUVs() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public uv= [0,1, 1,1, 0,0, 1,0] | ||||||
|  |  | ||||||
|  |     onLoad(): void { | ||||||
|  |         this._flushAssembler(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public __preload () { | ||||||
|  |         this.changeMaterialForDefine(); | ||||||
|  |         super.__preload(); | ||||||
|  |  | ||||||
|  |         if (EDITOR) { | ||||||
|  |             this._resized(); | ||||||
|  |             this.node.on(NodeEventType.SIZE_CHANGED, this._resized, this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public onEnable () { | ||||||
|  |         console.log("onEnable") | ||||||
|  |         super.onEnable(); | ||||||
|  |  | ||||||
|  |         // Force update uv, material define, active material, etc | ||||||
|  |         this._activateMaterial(); | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |         if (this.spriteFrame) | ||||||
|  |             this._updateUVs(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public onDestroy () { | ||||||
|  |         if (EDITOR) { | ||||||
|  |             this.node.off(NodeEventType.SIZE_CHANGED, this._resized, this); | ||||||
|  |         } | ||||||
|  |         super.onDestroy(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @en | ||||||
|  |      * Quickly switch to other sprite frame in the sprite atlas. | ||||||
|  |      * If there is no atlas, the switch fails. | ||||||
|  |      * | ||||||
|  |      * @zh | ||||||
|  |      * 选取使用精灵图集中的其他精灵。 | ||||||
|  |      * @param name @en Name of the spriteFrame to switch. @zh 要切换的 spriteFrame 名字。 | ||||||
|  |      */ | ||||||
|  |     public changeSpriteFrameFromAtlas (name: string) { | ||||||
|  |         if (!this._atlas) { | ||||||
|  |             console.warn('SpriteAtlas is null.'); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         const sprite = this._atlas.getSpriteFrame(name); | ||||||
|  |         this.spriteFrame = sprite; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @deprecated Since v3.7.0, this is an engine private interface that will be removed in the future. | ||||||
|  |      */ | ||||||
|  |     public changeMaterialForDefine () { | ||||||
|  |         let texture; | ||||||
|  |         const lastInstanceMaterialType = this._instanceMaterialType; | ||||||
|  |         if (this._spriteFrame) { | ||||||
|  |             texture = this._spriteFrame.texture; | ||||||
|  |         } | ||||||
|  |         let value = false; | ||||||
|  |         if (texture instanceof cclegacy.TextureBase) { | ||||||
|  |             const format = texture.getPixelFormat(); | ||||||
|  |             value = (format === cclegacy.TextureBase.PixelFormat.RGBA_ETC1 || format === cclegacy.TextureBase.PixelFormat.RGB_A_PVRTC_4BPPV1 || format === cclegacy.TextureBase.PixelFormat.RGB_A_PVRTC_2BPPV1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (value) { | ||||||
|  |             this._instanceMaterialType = InstanceMaterialType.USE_ALPHA_SEPARATED; | ||||||
|  |         } else { | ||||||
|  |             this._instanceMaterialType = InstanceMaterialType.ADD_COLOR_AND_TEXTURE; | ||||||
|  |         } | ||||||
|  |         if (lastInstanceMaterialType !== this._instanceMaterialType) { | ||||||
|  |             // this.updateMaterial(); | ||||||
|  |             // d.ts里没有注上这个函数,直接调用会表红。 | ||||||
|  |             this["updateMaterial"](); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _updateBuiltinMaterial () { | ||||||
|  |         let mat = super._updateBuiltinMaterial(); | ||||||
|  |         if (this.spriteFrame && this.spriteFrame.texture instanceof RenderTexture) { | ||||||
|  |             const defines = { SAMPLE_FROM_RT: true, ...mat.passes[0].defines }; | ||||||
|  |             const renderMat = new Material(); | ||||||
|  |             renderMat.initialize({ | ||||||
|  |                 effectAsset: mat.effectAsset, | ||||||
|  |                 defines, | ||||||
|  |             }); | ||||||
|  |             mat = renderMat; | ||||||
|  |         } | ||||||
|  |         return mat; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _render (render) { | ||||||
|  |         render.commitComp(this, this.renderData, this._spriteFrame, this._assembler, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _canRender () { | ||||||
|  |         if (!super._canRender()) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |         if (!spriteFrame || !spriteFrame.texture) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected resetAssembler() { | ||||||
|  |         this._assembler = null; | ||||||
|  |         this._flushAssembler(); | ||||||
|  |     } | ||||||
|  |     protected _flushAssembler () { | ||||||
|  |         const assembler = PuzzleAssembler; | ||||||
|  |  | ||||||
|  |         if (this._assembler !== assembler) { | ||||||
|  |             this.destroyRenderData(); | ||||||
|  |             this._assembler = assembler; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if (!this._renderData) { | ||||||
|  |             if (this._assembler && this._assembler.createData) { | ||||||
|  |                 this._renderData = this._assembler.createData(this); | ||||||
|  |                 this._renderData!.material = this.getRenderMaterial(0); | ||||||
|  |                 this.markForUpdateRenderData(); | ||||||
|  |                 if (this.spriteFrame) { | ||||||
|  |                     this._assembler.updateRenderData(this); | ||||||
|  |                 } | ||||||
|  |                 this._updateColor(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _applySpriteSize () { | ||||||
|  |         if (this._spriteFrame) { | ||||||
|  |             if (BUILD || !this._spriteFrame.isDefault) { | ||||||
|  |                 if (Sprite.SizeMode.RAW === this._sizeMode) { | ||||||
|  |                     const size = this._spriteFrame.originalSize; | ||||||
|  |                     this.node._uiProps.uiTransformComp!.setContentSize(size); | ||||||
|  |                 } else if (Sprite.SizeMode.TRIMMED === this._sizeMode) { | ||||||
|  |                     const rect = this._spriteFrame.rect; | ||||||
|  |                     this.node._uiProps.uiTransformComp!.setContentSize(rect.width, rect.height); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             this.markForUpdateRenderData(true) | ||||||
|  |             this._assembler.updateRenderData(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _resized () { | ||||||
|  |         if (!EDITOR) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._spriteFrame) { | ||||||
|  |             const actualSize = this.node._uiProps.uiTransformComp!.contentSize; | ||||||
|  |             let expectedW = actualSize.width; | ||||||
|  |             let expectedH = actualSize.height; | ||||||
|  |             if (this._sizeMode === Sprite.SizeMode.RAW) { | ||||||
|  |                 const size = this._spriteFrame.originalSize; | ||||||
|  |                 expectedW = size.width; | ||||||
|  |                 expectedH = size.height; | ||||||
|  |             } else if (this._sizeMode === Sprite.SizeMode.TRIMMED) { | ||||||
|  |                 const rect = this._spriteFrame.rect; | ||||||
|  |                 expectedW = rect.width; | ||||||
|  |                 expectedH = rect.height; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (expectedW !== actualSize.width || expectedH !== actualSize.height) { | ||||||
|  |                 this._sizeMode = Sprite.SizeMode.CUSTOM; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _activateMaterial () { | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |         const material = this.getRenderMaterial(0); | ||||||
|  |         if (spriteFrame) { | ||||||
|  |             if (material) { | ||||||
|  |                 this.markForUpdateRenderData(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.renderData) { | ||||||
|  |             this.renderData.material = material; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _updateUVs () { | ||||||
|  |         const _uv= [0,1, 1,1, 0,0, 1,0] | ||||||
|  |         const blockWidth = 1 / this.columnMax | ||||||
|  |         const blockHeight = 1 / this.rowMax | ||||||
|  |         for (let i = 0; i < 4; i++) { | ||||||
|  |             this.uv[i * 2] = (this.column - 1) * blockWidth + _uv[i * 2] * blockWidth; | ||||||
|  |             this.uv[i * 2 + 1] = (this.row - 1) * blockHeight + _uv[i * 2 + 1] * blockHeight; | ||||||
|  |         } | ||||||
|  |         if (this._assembler) { | ||||||
|  |             this._assembler.updateUVs(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _applySpriteFrame (oldFrame: SpriteFrame | null) { | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |  | ||||||
|  |         let textureChanged = false; | ||||||
|  |         if (spriteFrame) { | ||||||
|  |             if (!oldFrame || oldFrame.texture !== spriteFrame.texture) { | ||||||
|  |                 textureChanged = true; | ||||||
|  |             } | ||||||
|  |             if (textureChanged) { | ||||||
|  |                 if (this.renderData) this.renderData.textureDirty = true; | ||||||
|  |                 this.changeMaterialForDefine(); | ||||||
|  |             } | ||||||
|  |             this._applySpriteSize(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								assets/scripts/puzzle/PuzzleSprite.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								assets/scripts/puzzle/PuzzleSprite.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | { | ||||||
|  |   "ver": "4.0.23", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "f238c61b-614b-4131-9d46-b431ae863374", | ||||||
|  |   "files": [], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
							
								
								
									
										274
									
								
								assets/scripts/puzzle/PuzzleSpriteTest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								assets/scripts/puzzle/PuzzleSpriteTest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,274 @@ | |||||||
|  | import { _decorator, cclegacy, Component, InstanceMaterialType, Material, Node, NodeEventType, RenderTexture, Sprite, SpriteAtlas, SpriteFrame, UIRenderer } from 'cc'; | ||||||
|  | import { BUILD, EDITOR } from 'cc/env'; | ||||||
|  | import { PuzzleAssembler } from './PuzzleAssembler'; | ||||||
|  | import { ColorSDFAssembler } from '../components/ColorSDFAssembler'; | ||||||
|  | const { ccclass, property ,type} = _decorator; | ||||||
|  | enum EventType { | ||||||
|  |     SPRITE_FRAME_CHANGED = 'spriteframe-changed', | ||||||
|  | } | ||||||
|  | @ccclass('PuzzleSpriteTest') | ||||||
|  | export class PuzzleSpriteTest extends UIRenderer { | ||||||
|  |     // 尺寸模式,可以看枚举原本定义的地方有注释说明 | ||||||
|  |     @property({serializable:true}) | ||||||
|  |     protected _sizeMode = Sprite.SizeMode.TRIMMED; | ||||||
|  |     @type(Sprite.SizeMode) | ||||||
|  |     get sizeMode () { | ||||||
|  |         return this._sizeMode; | ||||||
|  |     } | ||||||
|  |     set sizeMode (value) { | ||||||
|  |         if (this._sizeMode === value) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._sizeMode = value; | ||||||
|  |         if (value !== Sprite.SizeMode.CUSTOM) { | ||||||
|  |             this._applySpriteSize(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // 图集 | ||||||
|  |     @property({serializable:true}) | ||||||
|  |     protected _atlas: SpriteAtlas | null = null; | ||||||
|  |     @type(SpriteAtlas) | ||||||
|  |     get spriteAtlas () { | ||||||
|  |         return this._atlas; | ||||||
|  |     } | ||||||
|  |     set spriteAtlas (value) { | ||||||
|  |         if (this._atlas === value) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this._atlas = value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @property({serializable:true}) | ||||||
|  |     protected _spriteFrame: SpriteFrame | null = null; | ||||||
|  |     @type(SpriteFrame) | ||||||
|  |     get spriteFrame () { | ||||||
|  |         return this._spriteFrame; | ||||||
|  |     } | ||||||
|  |     set spriteFrame (value) { | ||||||
|  |         if (this._spriteFrame === value) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const lastSprite = this._spriteFrame; | ||||||
|  |         this._spriteFrame = value; | ||||||
|  |         this.markForUpdateRenderData(); | ||||||
|  |         this._applySpriteFrame(lastSprite); | ||||||
|  |         if (EDITOR) { | ||||||
|  |             this.node.emit(EventType.SPRITE_FRAME_CHANGED, this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onLoad(): void { | ||||||
|  |         this._flushAssembler(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public __preload () { | ||||||
|  |         this.changeMaterialForDefine(); | ||||||
|  |         super.__preload(); | ||||||
|  |  | ||||||
|  |         if (EDITOR) { | ||||||
|  |             this._resized(); | ||||||
|  |             this.node.on(NodeEventType.SIZE_CHANGED, this._resized, this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public onEnable () { | ||||||
|  |         super.onEnable(); | ||||||
|  |  | ||||||
|  |         // Force update uv, material define, active material, etc | ||||||
|  |         this._activateMaterial(); | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |         if (spriteFrame) { | ||||||
|  |             this._updateUVs(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public onDestroy () { | ||||||
|  |         if (EDITOR) { | ||||||
|  |             this.node.off(NodeEventType.SIZE_CHANGED, this._resized, this); | ||||||
|  |         } | ||||||
|  |         super.onDestroy(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @en | ||||||
|  |      * Quickly switch to other sprite frame in the sprite atlas. | ||||||
|  |      * If there is no atlas, the switch fails. | ||||||
|  |      * | ||||||
|  |      * @zh | ||||||
|  |      * 选取使用精灵图集中的其他精灵。 | ||||||
|  |      * @param name @en Name of the spriteFrame to switch. @zh 要切换的 spriteFrame 名字。 | ||||||
|  |      */ | ||||||
|  |     public changeSpriteFrameFromAtlas (name: string) { | ||||||
|  |         if (!this._atlas) { | ||||||
|  |             console.warn('SpriteAtlas is null.'); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         const sprite = this._atlas.getSpriteFrame(name); | ||||||
|  |         this.spriteFrame = sprite; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @deprecated Since v3.7.0, this is an engine private interface that will be removed in the future. | ||||||
|  |      */ | ||||||
|  |     public changeMaterialForDefine () { | ||||||
|  |         let texture; | ||||||
|  |         const lastInstanceMaterialType = this._instanceMaterialType; | ||||||
|  |         if (this._spriteFrame) { | ||||||
|  |             texture = this._spriteFrame.texture; | ||||||
|  |         } | ||||||
|  |         let value = false; | ||||||
|  |         if (texture instanceof cclegacy.TextureBase) { | ||||||
|  |             const format = texture.getPixelFormat(); | ||||||
|  |             value = (format === cclegacy.TextureBase.PixelFormat.RGBA_ETC1 || format === cclegacy.TextureBase.PixelFormat.RGB_A_PVRTC_4BPPV1 || format === cclegacy.TextureBase.PixelFormat.RGB_A_PVRTC_2BPPV1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (value) { | ||||||
|  |             this._instanceMaterialType = InstanceMaterialType.USE_ALPHA_SEPARATED; | ||||||
|  |         } else { | ||||||
|  |             this._instanceMaterialType = InstanceMaterialType.ADD_COLOR_AND_TEXTURE; | ||||||
|  |         } | ||||||
|  |         if (lastInstanceMaterialType !== this._instanceMaterialType) { | ||||||
|  |             // this.updateMaterial(); | ||||||
|  |             // d.ts里没有注上这个函数,直接调用会表红。 | ||||||
|  |             this["updateMaterial"](); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _updateBuiltinMaterial () { | ||||||
|  |         let mat = super._updateBuiltinMaterial(); | ||||||
|  |         if (this.spriteFrame && this.spriteFrame.texture instanceof RenderTexture) { | ||||||
|  |             const defines = { SAMPLE_FROM_RT: true, ...mat.passes[0].defines }; | ||||||
|  |             const renderMat = new Material(); | ||||||
|  |             renderMat.initialize({ | ||||||
|  |                 effectAsset: mat.effectAsset, | ||||||
|  |                 defines, | ||||||
|  |             }); | ||||||
|  |             mat = renderMat; | ||||||
|  |         } | ||||||
|  |         return mat; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _render (render) { | ||||||
|  |         render.commitComp(this, this.renderData, this._spriteFrame, this._assembler, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _canRender () { | ||||||
|  |         if (!super._canRender()) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |         if (!spriteFrame || !spriteFrame.texture) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected resetAssembler() { | ||||||
|  |         this._assembler = null; | ||||||
|  |         this._flushAssembler(); | ||||||
|  |     } | ||||||
|  |     protected _flushAssembler () { | ||||||
|  |         const assembler = ColorSDFAssembler; | ||||||
|  |  | ||||||
|  |         if (this._assembler !== assembler) { | ||||||
|  |             this.destroyRenderData(); | ||||||
|  |             this._assembler = assembler; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if (!this._renderData) { | ||||||
|  |             if (this._assembler && this._assembler.createData) { | ||||||
|  |                 this._renderData = this._assembler.createData(this); | ||||||
|  |                 this._renderData!.material = this.getRenderMaterial(0); | ||||||
|  |                 this.markForUpdateRenderData(); | ||||||
|  |                 if (this.spriteFrame) { | ||||||
|  |                     this._assembler.updateRenderData(this); | ||||||
|  |                 } | ||||||
|  |                 this._updateColor(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _applySpriteSize () { | ||||||
|  |         if (this._spriteFrame) { | ||||||
|  |             if (BUILD || !this._spriteFrame.isDefault) { | ||||||
|  |                 if (Sprite.SizeMode.RAW === this._sizeMode) { | ||||||
|  |                     const size = this._spriteFrame.originalSize; | ||||||
|  |                     this.node._uiProps.uiTransformComp!.setContentSize(size); | ||||||
|  |                 } else if (Sprite.SizeMode.TRIMMED === this._sizeMode) { | ||||||
|  |                     const rect = this._spriteFrame.rect; | ||||||
|  |                     this.node._uiProps.uiTransformComp!.setContentSize(rect.width, rect.height); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             this.markForUpdateRenderData(true) | ||||||
|  |             this._assembler.updateRenderData(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _resized () { | ||||||
|  |         if (!EDITOR) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._spriteFrame) { | ||||||
|  |             const actualSize = this.node._uiProps.uiTransformComp!.contentSize; | ||||||
|  |             let expectedW = actualSize.width; | ||||||
|  |             let expectedH = actualSize.height; | ||||||
|  |             if (this._sizeMode === Sprite.SizeMode.RAW) { | ||||||
|  |                 const size = this._spriteFrame.originalSize; | ||||||
|  |                 expectedW = size.width; | ||||||
|  |                 expectedH = size.height; | ||||||
|  |             } else if (this._sizeMode === Sprite.SizeMode.TRIMMED) { | ||||||
|  |                 const rect = this._spriteFrame.rect; | ||||||
|  |                 expectedW = rect.width; | ||||||
|  |                 expectedH = rect.height; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (expectedW !== actualSize.width || expectedH !== actualSize.height) { | ||||||
|  |                 this._sizeMode = Sprite.SizeMode.CUSTOM; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _activateMaterial () { | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |         const material = this.getRenderMaterial(0); | ||||||
|  |         if (spriteFrame) { | ||||||
|  |             if (material) { | ||||||
|  |                 this.markForUpdateRenderData(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.renderData) { | ||||||
|  |             this.renderData.material = material; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _updateUVs () { | ||||||
|  |         if (this._assembler) { | ||||||
|  |             this._assembler.updateUVs(this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _applySpriteFrame (oldFrame: SpriteFrame | null) { | ||||||
|  |         const spriteFrame = this._spriteFrame; | ||||||
|  |  | ||||||
|  |         let textureChanged = false; | ||||||
|  |         if (spriteFrame) { | ||||||
|  |             if (!oldFrame || oldFrame.texture !== spriteFrame.texture) { | ||||||
|  |                 textureChanged = true; | ||||||
|  |             } | ||||||
|  |             if (textureChanged) { | ||||||
|  |                 if (this.renderData) this.renderData.textureDirty = true; | ||||||
|  |                 this.changeMaterialForDefine(); | ||||||
|  |             } | ||||||
|  |             this._applySpriteSize(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								assets/scripts/puzzle/PuzzleSpriteTest.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								assets/scripts/puzzle/PuzzleSpriteTest.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | { | ||||||
|  |   "ver": "4.0.23", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "imported": true, | ||||||
|  |   "uuid": "bff05d5e-35b8-40ca-8ceb-939a046440e8", | ||||||
|  |   "files": [], | ||||||
|  |   "subMetas": {}, | ||||||
|  |   "userData": {} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user