diff --git a/DungeonShooting_Godot/DungeonShooting.csproj b/DungeonShooting_Godot/DungeonShooting.csproj
index 4e093b1..f88bca0 100644
--- a/DungeonShooting_Godot/DungeonShooting.csproj
+++ b/DungeonShooting_Godot/DungeonShooting.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Godot.NET.Sdk/4.1.0-beta.1">
+<Project Sdk="Godot.NET.Sdk/4.1.0-beta.2">
   <PropertyGroup>
     <TargetFramework>net6.0</TargetFramework>
     <EnableDynamicLoading>true</EnableDynamicLoading>
diff --git a/DungeonShooting_Godot/DungeonShooting.csproj.old.1 b/DungeonShooting_Godot/DungeonShooting.csproj.old.1
new file mode 100644
index 0000000..4e093b1
--- /dev/null
+++ b/DungeonShooting_Godot/DungeonShooting.csproj.old.1
@@ -0,0 +1,11 @@
+<Project Sdk="Godot.NET.Sdk/4.1.0-beta.1">
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <EnableDynamicLoading>true</EnableDynamicLoading>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+  </PropertyGroup>
+  <ItemGroup>
+    <Folder Include="src\game\ui\editorTools" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs
index e5d7a93..5b3c546 100644
--- a/DungeonShooting_Godot/src/framework/common/Utils.cs
+++ b/DungeonShooting_Godot/src/framework/common/Utils.cs
@@ -169,6 +169,21 @@
             }
         }
     }
+    
+    /// <summary>
+    /// 将一个任意角度转为0到360度
+    /// </summary>
+    public static float ConvertAngle(float angle)
+    {
+        angle %= 360; // 取余
+
+        if (angle < 0) // 如果角度为负数,转为正数
+        {
+            angle += 360;
+        }
+
+        return angle;
+    }
 
     /// <summary>
     /// 字符串首字母小写
diff --git a/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs b/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs
new file mode 100644
index 0000000..3470adb
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/map/image/ImageCanvas.cs
@@ -0,0 +1,106 @@
+
+using Godot;
+
+public partial class ImageCanvas : Sprite2D
+{
+    public int Width { get; }
+    public int Height { get; }
+
+    private Image _canvas;
+    private ImageTexture _texture;
+
+    public ImageCanvas(int width, int height)
+    {
+        Width = width;
+        Height = height;
+        
+        _canvas = Image.Create(width, height, false, Image.Format.Rgba8);
+    }
+
+    public override void _Ready()
+    {
+        var imageTexture = ImageTexture.CreateFromImage(_canvas);
+        Texture = imageTexture;
+    }
+    
+    public void DrawImageInCanvas(Texture2D texture, int x, int y, float angle, int centerX, int centerY, bool flipY)
+    {
+        var image = texture.GetImage();
+        var newAngle = Mathf.RoundToInt(Utils.ConvertAngle(angle));
+
+        if (newAngle == 0) //原图, 直接画上去
+        {
+            //_canvas.BlitRectMask();
+        }
+        else if (newAngle == 90) //旋转90度
+        {
+            
+        }
+        else if (newAngle == 180) //旋转180度
+        {
+            
+        }
+        else if (newAngle == 270) //旋转270度
+        {
+            
+        }
+        else
+        {
+            
+        }
+    }
+    
+    private void DrawRotateImage(Image origin, Image canvas, int x, int y, int angle, int centerX, int centerY)
+    {
+        var rotation = Mathf.DegToRad(angle);
+        var width = origin.GetWidth();
+        var height = origin.GetHeight();
+
+        var cosAngle = Mathf.Cos(rotation);
+        var sinAngle = Mathf.Sin(rotation);
+
+        var newWidth = width * Mathf.Abs(cosAngle) + height * sinAngle;
+        var newHeight = width * sinAngle + height * Mathf.Abs(cosAngle);
+
+        var num1 = -0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width;
+        var num2 = 0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height;
+
+        var offsetX =
+            (int)((centerX / sinAngle +
+                   (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
+                   cosAngle -
+                   (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
+                   sinAngle - centerY / cosAngle) /
+                  (cosAngle / sinAngle + sinAngle / cosAngle));
+
+        var offsetY =
+            (int)((centerX / cosAngle -
+                      (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
+                      cosAngle -
+                      (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
+                      sinAngle + centerY / sinAngle) /
+                  (sinAngle / cosAngle + cosAngle / sinAngle));
+
+
+        for (int x2 = 0; x2 < newWidth; x2++)
+        {
+            for (int y2 = 0; y2 < newHeight; y2++)
+            {
+                //如果(x1,y1)不在原图宽高所表示范围内,则(x2,y2)处的像素值设置为0或255
+                var x1 = x2 * cosAngle + y2 * sinAngle + num1;
+                var y1 = -x2 * sinAngle + y2 * cosAngle + num2;
+
+                if (x1 < 0 || x1 >= width || y1 < 0 || y1 >= height)
+                {
+                    //image.SetPixel(x, y, new Color(0, 0, 0, 0));
+                    //在图片外
+                    continue;
+                }
+
+                //如果(x1,y1)在原图宽高所表示范围内,使用最近邻插值或双线性插值,求出(x2,y2)处的像素值
+                canvas.SetPixel(x2 + x - offsetX, y2 + y - offsetY,
+                    origin.GetPixel(Mathf.FloorToInt(x1), Mathf.FloorToInt(y1)));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs b/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs
index ea1ca3e..6097932 100644
--- a/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs
+++ b/DungeonShooting_Godot/src/test/TestOptimizeSprite.cs
@@ -6,7 +6,7 @@
 
     public override void _Ready()
     {
-        var canvas = Image.Create(150, 150, true, Image.Format.Rgba8);
+        var canvas = Image.Create(150, 150, false, Image.Format.Rgba8);
 
         for (int x = 0; x < 150; x++)
         {
@@ -17,7 +17,8 @@
         }
 
         var image = Texture2D.GetImage();
-        RotateImage(image, canvas, 50, 50, 120, image.GetWidth(), image.GetHeight());
+        
+        RotateImage(image, canvas, 50, 50, 0, image.GetWidth(), image.GetHeight());
 
         //RotateImage(imgData, image, 0);
 
@@ -53,22 +54,22 @@
         var newWidth = width * Mathf.Abs(cosAngle) + height * sinAngle;
         var newHeight = width * sinAngle + height * Mathf.Abs(cosAngle);
 
-        var num1 = -0.5 * newWidth * cosAngle - 0.5 * newHeight * sinAngle + 0.5 * width;
-        var num2 = 0.5 * newWidth * sinAngle - 0.5 * newHeight * cosAngle + 0.5 * height;
+        var num1 = -0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width;
+        var num2 = 0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height;
 
         var offsetX =
             (int)((centerX / sinAngle +
-                   (0.5 * newWidth * sinAngle - 0.5 * newHeight * cosAngle + 0.5 * height) /
+                   (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
                    cosAngle -
-                   (-0.5 * newWidth * cosAngle - 0.5 * newHeight * sinAngle + 0.5 * width) /
+                   (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
                    sinAngle - centerY / cosAngle) /
                   (cosAngle / sinAngle + sinAngle / cosAngle));
 
         var offsetY =
             (int)((centerX / cosAngle -
-                      (-0.5 * newWidth * cosAngle - 0.5 * newHeight * sinAngle + 0.5 * width) /
+                      (-0.5f * newWidth * cosAngle - 0.5f * newHeight * sinAngle + 0.5f * width) /
                       cosAngle -
-                      (0.5 * newWidth * sinAngle - 0.5 * newHeight * cosAngle + 0.5 * height) /
+                      (0.5f * newWidth * sinAngle - 0.5f * newHeight * cosAngle + 0.5f * height) /
                       sinAngle + centerY / sinAngle) /
                   (sinAngle / cosAngle + cosAngle / sinAngle));