1+ import { Key } from "../../entities/Key" ;
2+ import { EntityRenderer } from "./EntityRenderer" ;
3+
4+ export class KeyRenderer implements EntityRenderer < Key > {
5+ private frameCount : number = 0 ;
6+
7+ render ( ctx : CanvasRenderingContext2D , key : Key ) : void {
8+ const position = key . getPosition ( ) ;
9+ const size = key . getSize ( ) ;
10+
11+ // 帧计数器,用于动画效果
12+ this . frameCount = ( this . frameCount + 1 ) % 60 ;
13+
14+ this . renderKey ( ctx , position . x , position . y , size ) ;
15+ }
16+
17+ private renderKey (
18+ ctx : CanvasRenderingContext2D ,
19+ x : number ,
20+ y : number ,
21+ size : number
22+ ) : void {
23+ const centerX = x + size / 2 ;
24+ const centerY = y + size / 2 ;
25+
26+ // 旋转动画效果
27+ const rotation = Math . sin ( this . frameCount * 0.05 ) * 0.2 ;
28+
29+ ctx . save ( ) ;
30+ ctx . translate ( centerX , centerY ) ;
31+ ctx . rotate ( rotation ) ;
32+
33+ // 钥匙主体颜色 (金色)
34+ ctx . fillStyle = "#FFD700" ;
35+
36+ // 钥匙柄 (圆形部分)
37+ const handleRadius = size / 4 ;
38+ const handleCenterX = - size / 4 ;
39+ const handleCenterY = 0 ;
40+
41+ // 绘制圆形钥匙柄 (像素风格)
42+ this . drawPixelCircle ( ctx , handleCenterX , handleCenterY , handleRadius ) ;
43+
44+ // 钥匙柄中心的孔
45+ ctx . fillStyle = "#000000" ;
46+ this . drawPixelCircle ( ctx , handleCenterX , handleCenterY , 2 ) ;
47+
48+ // 钥匙杆
49+ ctx . fillStyle = "#FFD700" ;
50+ const shaftWidth = 2 ;
51+ const shaftLength = size / 2 ;
52+ ctx . fillRect ( - shaftWidth / 2 , - shaftWidth / 2 , shaftLength , shaftWidth ) ;
53+
54+ // 钥匙齿 (像素风格)
55+ ctx . fillStyle = "#FFD700" ;
56+ const toothX = shaftLength / 2 ;
57+
58+ // 第一个齿
59+ ctx . fillRect ( toothX - 2 , shaftWidth / 2 , 2 , 3 ) ;
60+ // 第二个齿
61+ ctx . fillRect ( toothX , shaftWidth / 2 , 2 , 2 ) ;
62+
63+ // 钥匙高光
64+ ctx . fillStyle = "#FFFF99" ;
65+ ctx . fillRect ( handleCenterX - 1 , handleCenterY - 2 , 2 , 1 ) ;
66+ ctx . fillRect ( - 1 , - 1 , shaftLength / 2 , 1 ) ;
67+
68+ // 钥匙阴影/边框
69+ ctx . strokeStyle = "#DAA520" ;
70+ ctx . lineWidth = 1 ;
71+
72+ // 描边钥匙柄
73+ this . strokePixelCircle ( ctx , handleCenterX , handleCenterY , handleRadius ) ;
74+
75+ // 描边钥匙杆
76+ ctx . strokeRect ( - shaftWidth / 2 , - shaftWidth / 2 , shaftLength , shaftWidth ) ;
77+
78+ ctx . restore ( ) ;
79+
80+ // 发光效果
81+ const glowAlpha = 0.2 + Math . sin ( this . frameCount * 0.1 ) * 0.1 ;
82+ ctx . fillStyle = `rgba(255, 215, 0, ${ glowAlpha } )` ;
83+
84+ // 在钥匙周围绘制发光像素点
85+ const sparkleOffsets = [
86+ { x : - 3 , y : - 3 } , { x : 3 , y : - 3 } ,
87+ { x : - 3 , y : 3 } , { x : 3 , y : 3 } ,
88+ { x : 0 , y : - 4 } , { x : 0 , y : 4 } ,
89+ { x : - 4 , y : 0 } , { x : 4 , y : 0 }
90+ ] ;
91+
92+ sparkleOffsets . forEach ( ( offset , index ) => {
93+ if ( this . frameCount % 15 === index * 2 ) {
94+ ctx . fillRect ( centerX + offset . x , centerY + offset . y , 1 , 1 ) ;
95+ }
96+ } ) ;
97+ }
98+
99+ private drawPixelCircle ( ctx : CanvasRenderingContext2D , centerX : number , centerY : number , radius : number ) : void {
100+ // 绘制像素风格的圆形
101+ const pixelSize = 1 ;
102+
103+ for ( let x = - radius ; x <= radius ; x += pixelSize ) {
104+ for ( let y = - radius ; y <= radius ; y += pixelSize ) {
105+ const distance = Math . sqrt ( x * x + y * y ) ;
106+ if ( distance <= radius && distance > radius - 2 ) {
107+ ctx . fillRect ( centerX + x , centerY + y , pixelSize , pixelSize ) ;
108+ }
109+ }
110+ }
111+
112+ // 填充内部
113+ for ( let x = - radius + 2 ; x <= radius - 2 ; x += pixelSize ) {
114+ for ( let y = - radius + 2 ; y <= radius - 2 ; y += pixelSize ) {
115+ const distance = Math . sqrt ( x * x + y * y ) ;
116+ if ( distance <= radius - 2 ) {
117+ ctx . fillRect ( centerX + x , centerY + y , pixelSize , pixelSize ) ;
118+ }
119+ }
120+ }
121+ }
122+
123+ private strokePixelCircle ( ctx : CanvasRenderingContext2D , centerX : number , centerY : number , radius : number ) : void {
124+ // 绘制像素风格圆形的描边
125+ const pixelSize = 1 ;
126+
127+ for ( let x = - radius ; x <= radius ; x += pixelSize ) {
128+ for ( let y = - radius ; y <= radius ; y += pixelSize ) {
129+ const distance = Math . sqrt ( x * x + y * y ) ;
130+ if ( distance <= radius && distance > radius - 1 ) {
131+ ctx . strokeRect ( centerX + x , centerY + y , pixelSize , pixelSize ) ;
132+ }
133+ }
134+ }
135+ }
136+ }
0 commit comments