XMWAI 0.4.6__tar.gz → 0.4.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of XMWAI might be problematic. Click here for more details.

Files changed (130) hide show
  1. {xmwai-0.4.6 → xmwai-0.4.7}/MANIFEST.in +1 -1
  2. {xmwai-0.4.6/XMWAI.egg-info → xmwai-0.4.7}/PKG-INFO +1 -1
  3. xmwai-0.4.7/XMWAI/snake_core.py +417 -0
  4. {xmwai-0.4.6 → xmwai-0.4.7/XMWAI.egg-info}/PKG-INFO +1 -1
  5. {xmwai-0.4.6 → xmwai-0.4.7}/setup.py +1 -1
  6. xmwai-0.4.6/XMWAI/snake_core.py +0 -595
  7. {xmwai-0.4.6 → xmwai-0.4.7}/LICENSE.txt +0 -0
  8. {xmwai-0.4.6 → xmwai-0.4.7}/README.md +0 -0
  9. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/__init__.py +0 -0
  10. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/1.png +0 -0
  11. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/g.png +0 -0
  12. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/h.png +0 -0
  13. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/l.png +0 -0
  14. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/m.png +0 -0
  15. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/s.png +0 -0
  16. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets/t.png +0 -0
  17. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/assets//345/276/256/350/275/257/351/233/205/351/273/221.ttf" +0 -0
  18. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/bomb_core.py +0 -0
  19. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/core.py +0 -0
  20. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/file/__init__.py +0 -0
  21. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/file/idiom.json +0 -0
  22. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/0.gif +0 -0
  23. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/1.gif +0 -0
  24. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/10.gif +0 -0
  25. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/11.gif +0 -0
  26. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/12.gif +0 -0
  27. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/13.gif +0 -0
  28. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/14.gif +0 -0
  29. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/15.gif +0 -0
  30. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/16.gif +0 -0
  31. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/17.gif +0 -0
  32. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/18.gif +0 -0
  33. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/19.gif +0 -0
  34. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/2.gif +0 -0
  35. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/20.gif +0 -0
  36. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/21.gif +0 -0
  37. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/22.gif +0 -0
  38. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/23.gif +0 -0
  39. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/24.gif +0 -0
  40. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/25.gif +0 -0
  41. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/26.gif +0 -0
  42. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/27.gif +0 -0
  43. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/28.gif +0 -0
  44. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/29.gif +0 -0
  45. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/3.gif +0 -0
  46. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/30.gif +0 -0
  47. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/31.gif +0 -0
  48. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/32.gif +0 -0
  49. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/33.gif +0 -0
  50. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/34.gif +0 -0
  51. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/35.gif +0 -0
  52. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/36.gif +0 -0
  53. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/37.gif +0 -0
  54. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/38.gif +0 -0
  55. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/39.gif +0 -0
  56. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/4.gif +0 -0
  57. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/40.gif +0 -0
  58. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/41.gif +0 -0
  59. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/42.gif +0 -0
  60. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/43.gif +0 -0
  61. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/44.gif +0 -0
  62. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/45.gif +0 -0
  63. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/46.gif +0 -0
  64. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/47.gif +0 -0
  65. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/48.gif +0 -0
  66. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/49.gif +0 -0
  67. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/5.gif +0 -0
  68. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/50.gif +0 -0
  69. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/51.gif +0 -0
  70. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/52.gif +0 -0
  71. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/53.gif +0 -0
  72. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/54.gif +0 -0
  73. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/55.gif +0 -0
  74. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/56.gif +0 -0
  75. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/57.gif +0 -0
  76. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/58.gif +0 -0
  77. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/59.gif +0 -0
  78. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/6.gif +0 -0
  79. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/60.gif +0 -0
  80. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/61.gif +0 -0
  81. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/62.gif +0 -0
  82. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/63.gif +0 -0
  83. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/64.gif +0 -0
  84. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/65.gif +0 -0
  85. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/66.gif +0 -0
  86. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/67.gif +0 -0
  87. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/68.gif +0 -0
  88. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/69.gif +0 -0
  89. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/7.gif +0 -0
  90. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/70.gif +0 -0
  91. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/71.gif +0 -0
  92. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/72.gif +0 -0
  93. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/73.gif +0 -0
  94. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/74.gif +0 -0
  95. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/75.gif +0 -0
  96. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/76.gif +0 -0
  97. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/77.gif +0 -0
  98. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/78.gif +0 -0
  99. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/79.gif +0 -0
  100. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/8.gif +0 -0
  101. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/80.gif +0 -0
  102. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/81.gif +0 -0
  103. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/82.gif +0 -0
  104. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/83.gif +0 -0
  105. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/84.gif +0 -0
  106. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/85.gif +0 -0
  107. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/9.gif +0 -0
  108. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/gif/__init__.py +0 -0
  109. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/idiom_core.py +0 -0
  110. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/magic_core.py +0 -0
  111. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/burger.js +0 -0
  112. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/BottomBun.png +0 -0
  113. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/TopBun.png +0 -0
  114. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/beef.png +0 -0
  115. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/bg.jpeg +0 -0
  116. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/bg.png +0 -0
  117. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/cheese.png +0 -0
  118. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/lettuce.png +0 -0
  119. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/sauce.png +0 -0
  120. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/static/images/tomato.png +0 -0
  121. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/templates/burger.html +0 -0
  122. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/templates/nutrition_pie.html +0 -0
  123. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/templates//345/210/233/346/204/217/350/217/234/350/260/261.html" +0 -0
  124. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/trial_class.py +0 -0
  125. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI/web_core.py +0 -0
  126. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI.egg-info/SOURCES.txt +0 -0
  127. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI.egg-info/dependency_links.txt +0 -0
  128. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI.egg-info/requires.txt +0 -0
  129. {xmwai-0.4.6 → xmwai-0.4.7}/XMWAI.egg-info/top_level.txt +0 -0
  130. {xmwai-0.4.6 → xmwai-0.4.7}/setup.cfg +0 -0
@@ -2,4 +2,4 @@ recursive-include XMWAI/gif *
2
2
  recursive-include XMWAI/file *.json
3
3
  recursive-include XMWAI/templates *.html
4
4
  recursive-include XMWAI/static *.js *.css *.png *.jpg *.gif *.jpeg
5
- recursive-include XMWAI/assets *
5
+ recursive-include XMWAI/assets *.png *.ttf
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: XMWAI
3
- Version: 0.4.6
3
+ Version: 0.4.7
4
4
  Summary: Small code King AI related library
5
5
  Home-page: https://github.com/Tonykai88/XMWAI.git
6
6
  Author: pydevelopment
@@ -0,0 +1,417 @@
1
+ import cv2
2
+ import math
3
+ import random
4
+ import cvzone
5
+ import numpy as np
6
+ from cvzone.HandTrackingModule import HandDetector
7
+ from PIL import ImageFont, ImageDraw, Image
8
+ import time
9
+ from importlib.resources import files
10
+ from pathlib import Path
11
+ import os
12
+
13
+
14
+ def get_resource_path(filename: str) -> str:
15
+ """返回 snake_core 模块内资源的绝对路径"""
16
+ return str(files("XMWAI.assets").joinpath(filename))
17
+
18
+
19
+ class SnakeGame:
20
+ def __init__(self, width=720, height=720, snakeInitLength=150, snakeGrowth=50,
21
+ snakeLineWidth=10, snakeHeadSize=15, foodPaths=None, foodNames=None, foodScores=None,
22
+ obstaclePaths=None, fontPath=None):
23
+
24
+ self.resolution = (width, height)
25
+ self.snakeInitLength = snakeInitLength
26
+ self._snakeGrowth = snakeGrowth
27
+ self._snakeHeadSize = snakeHeadSize
28
+ self._foodScores = foodScores if foodScores is not None else [3, 2, 1]
29
+ self.snakeLineWidth = snakeLineWidth
30
+ self.fontPath = fontPath or get_resource_path("微软雅黑.ttf")
31
+
32
+ if foodPaths is None:
33
+ foodPaths = [get_resource_path(f)
34
+ for f in ["h.png", "s.png", "t.png"]]
35
+ if foodNames is None:
36
+ foodNames = ["汉堡", "薯条", "甜甜圈"]
37
+ if obstaclePaths is None:
38
+ obstaclePaths = [get_resource_path(f)
39
+ for f in ["g.png", "l.png", "m.png"]]
40
+
41
+ self.foodPaths = foodPaths
42
+ self.foodNames = foodNames
43
+ self.obstaclePaths = obstaclePaths
44
+
45
+ self.cap = None
46
+ self.detector = None
47
+ self.snake = None
48
+ self.foodManager = None
49
+ self.obstacleManager = None
50
+ self.img = None
51
+ self.overlayTexts = []
52
+
53
+ self.timer = 30
54
+ self.start_time = None
55
+
56
+ self._init_game_objects()
57
+ self.open_window()
58
+
59
+ # ---------------- 属性自动同步 ----------------
60
+ @property
61
+ def snakeHeadSize(self):
62
+ return self._snakeHeadSize
63
+
64
+ @snakeHeadSize.setter
65
+ def snakeHeadSize(self, value):
66
+ self._snakeHeadSize = value
67
+ if self.snake:
68
+ self.snake.headSize = value
69
+
70
+ @property
71
+ def foodScores(self):
72
+ return self._foodScores
73
+
74
+ @foodScores.setter
75
+ def foodScores(self, scores):
76
+ self._foodScores = scores
77
+ if self.foodManager:
78
+ self.foodManager.foodScores = scores
79
+
80
+ @property
81
+ def snakeGrowth(self):
82
+ return self._snakeGrowth
83
+
84
+ @snakeGrowth.setter
85
+ def snakeGrowth(self, value):
86
+ self._snakeGrowth = value
87
+
88
+ # ---------------- 工具函数 ----------------
89
+ def _putChineseText(self, img, text, pos, fontSize=40, color=(0, 0, 255)):
90
+ img_pil = Image.fromarray(img)
91
+ draw = ImageDraw.Draw(img_pil)
92
+ try:
93
+ font = ImageFont.truetype(self.fontPath, fontSize)
94
+ except OSError:
95
+ font = ImageFont.load_default()
96
+ draw.text(pos, text, font=font, fill=color)
97
+ return np.array(img_pil)
98
+
99
+ def _init_game_objects(self):
100
+ self.snake = self.Snake(color=(0, 0, 255), initLength=self.snakeInitLength,
101
+ lineWidth=self.snakeLineWidth, headSize=self._snakeHeadSize)
102
+ self.foodManager = self.FoodManager(
103
+ self.foodPaths, self.foodNames, self._foodScores)
104
+ self.obstacleManager = self.ObstacleManager(self.obstaclePaths)
105
+ self.obstacleManager.randomObstacles()
106
+
107
+ def _render_frame(self, show_food=True, show_obstacle=True):
108
+ if self.cap is None:
109
+ return
110
+ success, self.img = self.cap.read()
111
+ if not success:
112
+ return
113
+ self.img = cv2.flip(self.img, 1)
114
+ hands, self.img = self.detector.findHands(self.img, flipType=False)
115
+ player_head = tuple(hands[0]['lmList'][8][0:2]) if hands else None
116
+
117
+ if not self.snake.gameOver and player_head:
118
+ self.snake.update(self.img, player_head, self.obstacleManager)
119
+
120
+ if not self.snake.gameOver and player_head and show_food:
121
+ cx, cy = player_head
122
+ rx, ry = self.foodManager.foodPoint
123
+ w, h = self.foodManager.wFood, self.foodManager.hFood
124
+ if rx - w//2 <= cx <= rx + w//2 and ry - h//2 <= cy <= ry + h//2:
125
+ self.snake.score += self.foodManager.foodScores[self.foodManager.foodIndex]
126
+ self.snake.allowedLength += self._snakeGrowth
127
+ self.foodManager.randomFoodLocation(self.obstacleManager)
128
+
129
+ if show_obstacle:
130
+ self.img = self.obstacleManager.draw(self.img)
131
+ self.obstacleManager.moveObstacles(*self.resolution)
132
+
133
+ if show_food:
134
+ self.img = self.foodManager.draw(self.img)
135
+
136
+ # ---------------- 对外接口 ----------------
137
+ def open_window(self):
138
+ self.cap = cv2.VideoCapture(0)
139
+ self.cap.set(3, self.resolution[0])
140
+ self.cap.set(4, self.resolution[1])
141
+ self.detector = HandDetector(detectionCon=0.7, maxHands=1)
142
+ success, self.img = self.cap.read()
143
+ if not success:
144
+ print("摄像头打开失败")
145
+ return
146
+ self.img = cv2.flip(self.img, 1)
147
+ cv2.imshow("AI Snake", self.img)
148
+ cv2.waitKey(1)
149
+
150
+ def hand(self):
151
+ if self.cap is None:
152
+ print("请先调用 open_window()")
153
+ return
154
+ if self.detector is None:
155
+ self.detector = HandDetector(detectionCon=0.8, maxHands=1)
156
+ while True:
157
+ success, self.img = self.cap.read()
158
+ if not success:
159
+ break
160
+ self.img = cv2.flip(self.img, 1)
161
+ hands, self.img = self.detector.findHands(self.img, flipType=False)
162
+ cv2.imshow("AI Snake", self.img)
163
+ key = cv2.waitKey(1) & 0xFF
164
+ if hands or key == ord('q'):
165
+ break
166
+
167
+ def display(self):
168
+ if self.img is None:
169
+ self._render_frame(show_food=False)
170
+ self.foodManager.randomFoodLocation(self.obstacleManager)
171
+ self._render_frame(show_food=True)
172
+ self.overlayTexts = [
173
+ (f'玩家分数:{self.snake.score}', (50, 50), 30, (255, 0, 255)),
174
+ (f'倒计时:{self.timer} 秒', (50, 120), 30, (255, 0, 255))
175
+ ]
176
+ img_copy = self.img.copy()
177
+ for txt, pos, size, color in self.overlayTexts:
178
+ img_copy = self._putChineseText(img_copy, txt, pos, size, color)
179
+ cv2.imshow("AI Snake", img_copy)
180
+ cv2.waitKey(1)
181
+
182
+ # ---------------- 重置游戏 ----------------
183
+ def reset_game(self):
184
+ self.snake.reset()
185
+ self.snake.headSize = self._snakeHeadSize
186
+ self.obstacleManager.randomObstacles()
187
+ self.foodManager.foodScores = self._foodScores
188
+ self.foodManager.randomFoodLocation(self.obstacleManager)
189
+ self.start_time = time.time()
190
+ self.timer = 30
191
+ if self.cap is None or not self.cap.isOpened():
192
+ self.open_window()
193
+
194
+ # ---------------- 游戏结束 ----------------
195
+ def gameover(self, path=None, size=(100, 100)):
196
+ if path is None:
197
+ path = get_resource_path("1.png")
198
+
199
+ if os.path.exists(path):
200
+ gameover_img = cv2.imread(path)
201
+ gameover_img = cv2.resize(gameover_img, self.resolution)
202
+ else:
203
+ gameover_img = np.zeros(
204
+ (self.resolution[1], self.resolution[0], 3), np.uint8)
205
+ cv2.putText(gameover_img, "Game Over Image Missing!", (50, 100),
206
+ cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 3)
207
+
208
+ gameover_img = self._putChineseText(
209
+ gameover_img, f"最终分数:{self.snake.score}", size, 40, (68, 84, 106))
210
+
211
+ while True:
212
+ cv2.imshow("AI Snake", gameover_img)
213
+ key = cv2.waitKey(0) & 0xFF
214
+ if key == ord('r'): # 重启游戏
215
+ self.reset_game()
216
+ self.start()
217
+ break
218
+ elif key == ord('q'): # 退出游戏
219
+ if self.cap is not None:
220
+ self.cap.release()
221
+ cv2.destroyAllWindows()
222
+ break
223
+
224
+ # ---------------- 游戏主循环 ----------------
225
+ def start(self):
226
+ if self.cap is None or not self.cap.isOpened():
227
+ self.open_window()
228
+ self.start_time = time.time()
229
+ self.timer = 30
230
+
231
+ while True:
232
+ if self.snake.gameOver or self.timer == 0:
233
+ self.gameover()
234
+ break
235
+
236
+ self._render_frame(show_food=True, show_obstacle=True)
237
+ elapsed = int(time.time() - self.start_time)
238
+ self.timer = max(0, 30 - elapsed)
239
+
240
+ self.overlayTexts = [
241
+ (f'玩家分数:{self.snake.score}', (50, 50), 30, (255, 0, 255)),
242
+ (f'倒计时:{self.timer} 秒', (50, 120), 30, (255, 0, 255))
243
+ ]
244
+
245
+ if self.img is not None:
246
+ img_copy = self.img.copy()
247
+ for txt, pos, size, color in self.overlayTexts:
248
+ img_copy = self._putChineseText(
249
+ img_copy, txt, pos, size, color)
250
+ cv2.imshow("AI Snake", img_copy)
251
+
252
+ key = cv2.waitKey(1)
253
+ if key == ord('r'): # 游戏中途重置
254
+ self.reset_game()
255
+ elif key == ord('q'):
256
+ if self.cap is not None:
257
+ self.cap.release()
258
+ cv2.destroyAllWindows()
259
+ break
260
+
261
+ # ---------------- 内部类 ----------------
262
+ class Snake:
263
+ def __init__(self, color, initLength=150, lineWidth=10, headSize=15):
264
+ self.points = []
265
+ self.currentLength = 0
266
+ self.allowedLength = initLength
267
+ self.previousHead = None
268
+ self.score = 0
269
+ self.color = color
270
+ self.gameOver = False
271
+ self.lineWidth = lineWidth
272
+ self.headSize = headSize
273
+
274
+ def reset(self):
275
+ self.points = []
276
+ self.currentLength = 0
277
+ self.allowedLength = 150
278
+ self.previousHead = None
279
+ self.score = 0
280
+ self.gameOver = False
281
+
282
+ def update(self, imgMain, currentHead, obstacleManager=None):
283
+ if self.gameOver:
284
+ return
285
+ cx, cy = currentHead
286
+ if cx is None or cy is None:
287
+ return
288
+ if self.previousHead is None:
289
+ self.previousHead = (cx, cy)
290
+ px, py = self.previousHead
291
+
292
+ alpha = 0.7
293
+ cx = int(px * (1 - alpha) + cx * alpha)
294
+ cy = int(py * (1 - alpha) + cy * alpha)
295
+
296
+ maxStep = 50
297
+ dx = cx - px
298
+ dy = cy - py
299
+ distance = math.hypot(dx, dy)
300
+ if distance > maxStep:
301
+ steps = int(distance / maxStep)
302
+ for i in range(1, steps + 1):
303
+ ix = int(px + dx * i / steps)
304
+ iy = int(py + dy * i / steps)
305
+ self.points.append((ix, iy))
306
+ self.currentLength += maxStep
307
+ else:
308
+ self.points.append((cx, cy))
309
+ self.currentLength += distance
310
+
311
+ self.previousHead = (cx, cy)
312
+
313
+ while self.currentLength > self.allowedLength:
314
+ if len(self.points) > 1:
315
+ removed_dx = self.points[1][0] - self.points[0][0]
316
+ removed_dy = self.points[1][1] - self.points[0][1]
317
+ removed_dist = math.hypot(removed_dx, removed_dy)
318
+ self.currentLength -= removed_dist
319
+ self.points.pop(0)
320
+
321
+ for i in range(1, len(self.points)):
322
+ cv2.line(
323
+ imgMain, self.points[i-1], self.points[i], self.color, self.lineWidth)
324
+
325
+ snakeHeadColor = (random.randint(0, 255), random.randint(
326
+ 0, 255), random.randint(0, 255))
327
+ cv2.circle(imgMain, (cx, cy), self.headSize,
328
+ snakeHeadColor, cv2.FILLED)
329
+
330
+ h, w, _ = imgMain.shape
331
+ margin = 5
332
+ if cx <= margin or cx >= w - margin or cy <= margin or cy >= h - margin:
333
+ self.gameOver = True
334
+
335
+ if obstacleManager:
336
+ for ox, oy, ow, oh, *_ in obstacleManager.obstacles:
337
+ if ox <= cx <= ox + ow and oy <= cy <= oy + oh:
338
+ self.gameOver = True
339
+
340
+ # ---------------- 内部类 ----------------
341
+ class FoodManager:
342
+ def __init__(self, foodPaths, foodNames, foodScores):
343
+ self.foodImages = []
344
+ for path in foodPaths:
345
+ if os.path.exists(path):
346
+ self.foodImages.append(
347
+ cv2.imread(path, cv2.IMREAD_UNCHANGED))
348
+ else:
349
+ self.foodImages.append(np.zeros((50, 50, 4), np.uint8))
350
+ self.foodNames = foodNames
351
+ self.foodScores = foodScores
352
+ self.foodIndex = 0
353
+ self.hFood, self.wFood = 0, 0
354
+ self.foodPoint = 0, 0
355
+ self.randomFoodLocation()
356
+
357
+ def randomFoodLocation(self, obstacleManager=None):
358
+ max_attempts = 100
359
+ for _ in range(max_attempts):
360
+ self.foodPoint = random.randint(
361
+ 50, 670), random.randint(50, 670)
362
+ self.foodIndex = random.randint(0, len(self.foodImages)-1)
363
+ self.hFood, self.wFood, _ = self.foodImages[self.foodIndex].shape
364
+ if obstacleManager:
365
+ overlap = False
366
+ for ox, oy, ow, oh, *_ in obstacleManager.obstacles:
367
+ if ox < self.foodPoint[0] < ox + ow and oy < self.foodPoint[1] < oy + oh:
368
+ overlap = True
369
+ break
370
+ if not overlap:
371
+ return
372
+ return
373
+
374
+ def draw(self, imgMain):
375
+ rx, ry = self.foodPoint
376
+ imgMain = cvzone.overlayPNG(imgMain, self.foodImages[self.foodIndex],
377
+ (rx - self.wFood//2, ry - self.hFood//2))
378
+ return imgMain
379
+
380
+ # ---------------- 内部类 ----------------
381
+ class ObstacleManager:
382
+ def __init__(self, obstaclePaths):
383
+ self.obstacleImages = []
384
+ for path in obstaclePaths:
385
+ if os.path.exists(path):
386
+ self.obstacleImages.append(
387
+ cv2.imread(path, cv2.IMREAD_UNCHANGED))
388
+ else:
389
+ self.obstacleImages.append(np.zeros((50, 50, 4), np.uint8))
390
+ self.obstacles = []
391
+
392
+ def randomObstacles(self):
393
+ self.obstacles.clear()
394
+ for img in self.obstacleImages:
395
+ h, w, _ = img.shape
396
+ x = random.randint(150, 570)
397
+ y = random.randint(50, 570)
398
+ dx = random.choice([-5, 5])
399
+ dy = random.choice([-5, 5])
400
+ self.obstacles.append([x, y, w, h, dx, dy, img])
401
+
402
+ def moveObstacles(self, wMax, hMax):
403
+ for obs in self.obstacles:
404
+ x, y, ow, oh, dx, dy, img = obs
405
+ x += dx
406
+ y += dy
407
+ if x <= 0 or x + ow >= wMax:
408
+ dx *= -1
409
+ if y <= 0 or y + oh >= hMax:
410
+ dy *= -1
411
+ obs[0], obs[1], obs[4], obs[5] = x, y, dx, dy
412
+
413
+ def draw(self, imgMain):
414
+ for obs in self.obstacles:
415
+ x, y, w, h, dx, dy, img = obs
416
+ imgMain = cvzone.overlayPNG(imgMain, img, (int(x), int(y)))
417
+ return imgMain
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: XMWAI
3
- Version: 0.4.6
3
+ Version: 0.4.7
4
4
  Summary: Small code King AI related library
5
5
  Home-page: https://github.com/Tonykai88/XMWAI.git
6
6
  Author: pydevelopment
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name="XMWAI", # 包名(pip install XMWAI)
6
- version="0.4.6", # 每次上传记得升级版本号
6
+ version="0.4.7", # 每次上传记得升级版本号
7
7
  author="pydevelopment", # 作者
8
8
  author_email="hekai@xiaoma.cn", # 邮箱
9
9
  description="Small code King AI related library", # 简短描述