package model import ( "image" "math" ) type Sprite struct { Name string Position image.Point Image image.Image Index int } func (s *Sprite) SetImage(img *image.RGBA) { s.Image = img } func (s *Sprite) Rotate(angle float64) { // 创建旋转矩阵 sin, cos := math.Sin(angle), math.Cos(angle) // 获取原始图像的边界 bounds := s.Image.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.Image.At(origX, origY)) } } } s.Image = newImage } func (s *Sprite) Move(x, y int) { s.Position.X += x s.Position.Y += y } func (s *Sprite) Project(projectMatrix *ProjectMatrix) { bounds := s.Image.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.Image) // 批量处理像素 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.Image.At(origX, origY)) } } } } s.Image = newImage } // 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 }