package sprite import ( "image" "math" ) type Sprite struct { Name string Position image.Point Images []image.Image Delay []int delayIncreased []int CurrentFrame int Index int } func (s *Sprite) SetImage(img *image.RGBA) { if len(s.Images) == 0 { s.Images = []image.Image{img} s.CurrentFrame = 0 } else { s.Images[s.CurrentFrame] = img } } func (s *Sprite) Rotate(angle float64) { // 创建旋转矩阵 sin, cos := math.Sin(angle), math.Cos(angle) // 获取原始图像的边界 bounds := s.Images[s.CurrentFrame].Bounds() width, height := bounds.Dx(), bounds.Dy() centerX, centerY := width/2, height/2 // 计算旋转后图像的边界 corners := [4][2]int{ {0 - centerX, 0 - centerY}, {width - centerX, 0 - centerY}, {0 - centerX, height - centerY}, {width - centerX, height - centerY}, } // 计算旋转后的四个角点位置 minX, minY, maxX, maxY := 0, 0, 0, 0 for i, p := range corners { // 应用旋转 rotX := int(cos*float64(p[0]) - sin*float64(p[1])) rotY := int(sin*float64(p[0]) + cos*float64(p[1])) // 更新边界 if i == 0 || rotX < minX { minX = rotX } if i == 0 || rotY < minY { minY = rotY } if i == 0 || rotX > maxX { maxX = rotX } if i == 0 || rotY > maxY { maxY = rotY } } // 创建新图像 newWidth, newHeight := maxX-minX+1, maxY-minY+1 newImage := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) newCenterX, newCenterY := newWidth/2, newHeight/2 // 预计算矩阵常量 invSin, invCos := math.Sin(-angle), math.Cos(-angle) // 使用查找表存储sin/cos值,避免重复计算 srcXOrigin := make([]int, newWidth) srcYOrigin := make([]int, newHeight) // 预计算X坐标的变换 for x := 0; x < newWidth; x++ { srcXOrigin[x] = centerX } // 预计算Y坐标的变换 for y := 0; y < newHeight; y++ { srcYOrigin[y] = centerY } // 批量处理像素 for y := 0; y < newHeight; y++ { srcY := y - newCenterY for x := 0; x < newWidth; x++ { srcX := x - newCenterX // 应用逆向旋转矩阵 origX := int(invCos*float64(srcX)-invSin*float64(srcY)) + centerX origY := int(invSin*float64(srcX)+invCos*float64(srcY)) + centerY // 检查是否在原图范围内 if origX >= 0 && origX < width && origY >= 0 && origY < height { newImage.Set(x, y, s.Images[s.CurrentFrame].At(origX, origY)) } } } s.Images[s.CurrentFrame] = newImage } func (s *Sprite) Move(x, y int) { s.Position.X += x s.Position.Y += y } func (s *Sprite) Project(projectMatrix *ProjectMatrix) { bounds := s.Images[s.CurrentFrame].Bounds() // 计算四个角点投影后的位置 minX, minY, maxX, maxY := 0, 0, 0, 0 // 预先计算所有角点的投影,一次性确定边界 corners := [4]image.Point{ {bounds.Min.X, bounds.Min.Y}, {bounds.Max.X, bounds.Min.Y}, {bounds.Min.X, bounds.Max.Y}, {bounds.Max.X, bounds.Max.Y}, } for i, corner := range corners { projected := projectMatrix.ProjectPoint(corner) if i == 0 { minX, minY = projected.X, projected.Y maxX, maxY = projected.X, projected.Y } else { if projected.X < minX { minX = projected.X } if projected.Y < minY { minY = projected.Y } if projected.X > maxX { maxX = projected.X } if projected.Y > maxY { maxY = projected.Y } } } // 创建新图像 newWidth, newHeight := maxX-minX+1, maxY-minY+1 newImage := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) // 计算逆矩阵 det := projectMatrix.Matrix[0][0]*projectMatrix.Matrix[1][1] - projectMatrix.Matrix[0][1]*projectMatrix.Matrix[1][0] if math.Abs(det) < 1e-6 { // 矩阵接近不可逆 return } invDet := 1.0 / det invMatrix := [2][2]float64{ {projectMatrix.Matrix[1][1] * invDet, -projectMatrix.Matrix[0][1] * invDet}, {-projectMatrix.Matrix[1][0] * invDet, projectMatrix.Matrix[0][0] * invDet}, } // 预计算变换常量 m00, m01 := invMatrix[0][0], invMatrix[0][1] m10, m11 := invMatrix[1][0], invMatrix[1][1] // 使用直接内存访问优化像素设置 dstRGBA := newImage.Pix srcImg, srcRGBA, _ := getImageBytes(s.Images[s.CurrentFrame]) // 批量处理像素 for y := 0; y < newHeight; y++ { srcY := float64(y + minY) for x := 0; x < newWidth; x++ { srcX := float64(x + minX) // 使用逆矩阵计算 origX := int(m00*srcX + m01*srcY) origY := int(m10*srcX + m11*srcY) // 检查边界 if origX >= bounds.Min.X && origX < bounds.Max.X && origY >= bounds.Min.Y && origY < bounds.Max.Y { // 设置像素 - 直接使用indexing会更快 if srcRGBA != nil { // 如果源图像是RGBA格式,直接复制像素 dstIdx := (y*newImage.Stride + x*4) srcIdx := ((origY-bounds.Min.Y)*srcImg.Stride + (origX-bounds.Min.X)*4) dstRGBA[dstIdx] = srcRGBA[srcIdx] // R dstRGBA[dstIdx+1] = srcRGBA[srcIdx+1] // G dstRGBA[dstIdx+2] = srcRGBA[srcIdx+2] // B dstRGBA[dstIdx+3] = srcRGBA[srcIdx+3] // A } else { // 否则使用通用方法 newImage.Set(x, y, s.Images[s.CurrentFrame].At(origX, origY)) } } } } s.Images[s.CurrentFrame] = newImage } func (s *Sprite) DrawLine(line *Line) { // 使用Line.ToSprite方法在当前精灵上绘制线条 line.AddToSprite(s) } // getImageBytes 尝试提取图像的原始字节数据以加速访问 func getImageBytes(img image.Image) (*image.RGBA, []uint8, bool) { if rgba, ok := img.(*image.RGBA); ok { return rgba, rgba.Pix, true } return nil, nil, false } // AddFrame 添加一个新的图像帧 func (s *Sprite) AddFrame(img image.Image) { s.Images = append(s.Images, img) } // SetFrames 设置所有图像帧 func (s *Sprite) SetFrames(images []image.Image) { s.Images = images s.CurrentFrame = 0 } // NextFrame 切换到下一帧 func (s *Sprite) NextFrame() { if len(s.Images) > 1 { s.CurrentFrame = (s.CurrentFrame + 1) % len(s.Images) } } // SetFrame 设置当前帧 func (s *Sprite) SetFrame(frame int) { if len(s.Images) > 0 && frame >= 0 && frame < len(s.Images) { s.CurrentFrame = frame } } // GetCurrentImage 获取当前帧图像 func (s *Sprite) GetCurrentImage() image.Image { if len(s.Images) == 0 { return nil } return s.Images[s.CurrentFrame] } func (s *Sprite) GetFrame(index int) image.Image { if index < 0 { return s.Images[0] } else if index >= len(s.Images) { return s.Images[len(s.Images)-1] } return s.Images[index] } func (s *Sprite) GetFrameOnDelay(delay int) (image.Image, int) { if s.delayIncreased == nil || len(s.delayIncreased) != len(s.Delay) { s.delayIncreased = make([]int, len(s.Delay)) for i := range s.Delay { if i == 0 { s.delayIncreased[i] = s.Delay[i] } else { s.delayIncreased[i] = s.Delay[i] + s.delayIncreased[i-1] } } } if delay < 0 { return s.Images[0], 0 } else if delay >= s.delayIncreased[len(s.delayIncreased)-1] { return s.Images[len(s.Images)-1], len(s.Images) - 1 } // 使用二分查找代替线性查找 left, right := 0, len(s.delayIncreased)-1 for left <= right { mid := left + (right-left)/2 if delay < s.delayIncreased[mid] { if mid == 0 || delay >= s.delayIncreased[mid-1] { return s.Images[mid], mid } right = mid - 1 } else { left = mid + 1 } } return s.Images[0], 0 } func (s *Sprite) GetTotalTime() int { if s.delayIncreased == nil || len(s.delayIncreased) != len(s.Delay) { s.delayIncreased = make([]int, len(s.Delay)) for i := range s.Delay { if i == 0 { s.delayIncreased[i] = s.Delay[i] } else { s.delayIncreased[i] = s.Delay[i] + s.delayIncreased[i-1] } } } return s.delayIncreased[len(s.delayIncreased)-1] } // FrameCount 返回图像帧数量 func (s *Sprite) FrameCount() int { return len(s.Images) }