目前只操控方向键
算法为每局速度增加奖励增加,每把用时比上把少奖励增加
后续会增加氮气键,漂移键。优化每把操作,如果上次操作导致速度降低,立马反打方向
代码如下:
#利用了openai的gym库
import gym
from gym import spaces
import numpy as np
import pyautogui
import cv2
import time
import pytesseract
class Asphalt9Env(gym.Env):
def __init__(self):
super(AsphaltUNITEEnv, self).__init__()
self.action_space = spaces.Discrete(3)
self.observation_space = spaces.Box(low=np.array([0]), high=np.array([1]), dtype=np.float32)
self.game_over_image = cv2.imread('8.png', cv2.IMREAD_GRAYSCALE)
self.game_start_image = cv2.imread('9.png', cv2.IMREAD_GRAYSCALE)
self.start_click_image = cv2.imread('10.png', cv2.IMREAD_GRAYSCALE) # 载入 10.png
self.start_time = None
self.last_speed = 0
self.best_time = None
def reset(self):
"""重置环境,执行初始点击操作并等待游戏开始,返回初始状态"""
# 在执行初始点击序列前检查截图是否与10.png相符
if self.is_start_condition_met():
self.perform_initial_clicks()
# 等待新一局游戏开始
self.wait_for_new_game()
# 初始化状态
self.start_time = time.time()
self.state = np.array([1], dtype=np.float32)
self.last_speed = self.state[0]
return self.state
def is_start_condition_met(self):
"""检查截图是否与10.png相符"""
screenshot = self.capture_screen()
result = cv2.matchTemplate(screenshot, self.start_click_image, cv2.TM_CCOEFF_NORMED)
_, max_val, _, _ = cv2.minMaxLoc(result)
threshold = 0.8
return max_val >= threshold
def perform_initial_clicks(self):
"""在初始状态时点击指定的点"""
click_sequence = [
(878, 779), # 点击开始第一个点
(1483, 878), # 点击开始第二个点
(443, 470), # 点击开始第三个点
(1583, 889) # 点击开始第四个点
]
wait_times = [2, 2, 2, 2 ] # 每次点击后的等待时间
for (x, y), wait_time in zip(click_sequence, wait_times):
pyautogui.click(x, y)
time.sleep(wait_time)
def step(self, action):
"""执行一个动作并返回新状态、奖励和是否结束"""
if action == 0: # 左转
pyautogui.mouseDown(134, 853) # 按下左键
time.sleep(0.2) # 长按0.5秒
pyautogui.mouseUp(134, 853) # 释放左键
elif action == 1: # 右转
pyautogui.mouseDown(1793, 898) # 按下右键
time.sleep(0.2) # 长按2秒
pyautogui.mouseUp(1793, 898) # 释放右键
elif action == 2: # 不按键
pass
current_speed = self.get_current_speed()
self.state = np.array([current_speed], dtype=np.float32)
reward = self.calculate_reward(current_speed)
done = self.check_done()
if done:
# 捕获并保存截图
screenshot = self.capture_screen(region=(679, 190, 866, 234))
screenshot_path = 'screenshot.png'
cv2.imwrite(screenshot_path, screenshot)
print(f"Screenshot saved to {screenshot_path}")
time_text = self.extract_time_from_image(screenshot)
print(f"Detected time text: {time_text}")
if time_text: # 确保 time_text 不为空
current_time = self.parse_time_to_seconds(time_text)
print(f"Parsed current time in seconds: {current_time}") # 打印 current_time
reward += self.get_time_reward(current_time)
print(f"Updated reward: {reward}") # 打印更新后的 reward
self.perform_end_sequence()
return self.state, reward, done, {}
def perform_end_sequence(self):
"""在每局结束时执行一系列点击操作"""
click_sequence = [
(1513, 917), # 点击结束第一个点
(1533, 917), # 点击结束第二个点
]
wait_times = [3, 3]
for (x, y), wait_time in zip(click_sequence, wait_times):
pyautogui.click(x, y)
time.sleep(wait_time)
def wait_for_new_game(self):
"""等待新的一局游戏开始"""
while True:
screenshot = self.capture_screen()
if self.is_game_start(screenshot):
break
time.sleep(1)
def calculate_reward(self, current_speed):
"""计算奖励"""
reward = current_speed
return reward
def get_time_reward(self, current_time):
"""计算时间奖励"""
if self.best_time is None or current_time < self.best_time:
self.best_time = current_time
return 1 # 奖励1
return 0
def get_current_speed(self):
"""模拟获取当前速度"""
x1, y1, x2, y2 = 1533, 94, 1716, 177
screenshot = self.capture_screen(region=(x1, y1, x2 - x1, y2 - y1))
speed_text = pytesseract.image_to_string(screenshot, config='--psm 7')
print(f"Detected speed text: {speed_text}")
try:
speed = float(speed_text.strip())
except ValueError:
speed = 0.0
speed = min(max(speed / 300, 0), 1) # 归一化速度
return speed
def check_done(self):
"""检查游戏是否结束"""
screenshot = self.capture_screen()
return self.is_game_over(screenshot)
def capture_screen(self, region=None):
"""截取屏幕"""
screenshot = pyautogui.screenshot(region=region)
screenshot_np = np.array(screenshot)
screenshot_gray = cv2.cvtColor(screenshot_np, cv2.COLOR_RGB2GRAY)
return screenshot_gray
def is_game_over(self, screenshot):
"""判断截图中是否显示了游戏结束提示"""
result = cv2.matchTemplate(screenshot, self.game_over_image, cv2.TM_CCOEFF_NORMED)
_, max_val, _, _ = cv2.minMaxLoc(result)
threshold = 0.8
if max_val >= threshold:
print("find 8.png") # 检测到 8.png 时打印文字
return True
return False
def is_game_start(self, screenshot):
"""判断截图中是否显示了新一局游戏开始提示"""
result = cv2.matchTemplate(screenshot, self.game_start_image, cv2.TM_CCOEFF_NORMED)
_, max_val, _, _ = cv2.minMaxLoc(result)
threshold = 0.8
if max_val >= threshold:
print("find 9.png") # 检测到 9.png 时打印文字
return True
return False
def extract_time_from_image(self, image):
"""从图像中提取时间"""
time_text = pytesseract.image_to_string(image, config='--psm 7 -c tessedit_char_whitelist=:0123456789')
print(f"Detected time text: {time_text.strip()}")
return time_text.strip()
def parse_time_to_seconds(self, time_text):
"""将时间文本解析为秒数"""
# 去掉非数字和冒号以外的字符
cleaned_text = ''.join(c for c in time_text if c.isdigit() or c == ':')
# 去掉开头的0和空格
cleaned_text = cleaned_text.lstrip('0').strip()
if not cleaned_text or ':' not in cleaned_text:
return 0 # 如果时间文本格式不正确,则返回0秒
# 确保时间文本有正确的格式(如 'MM:SS.mmm')
try:
parts = cleaned_text.split(':')
if len(parts) == 2:
minutes = int(parts[0]) if parts[0] else 0
seconds = float(parts[1]) if parts[1] else 0
return minutes * 60 + seconds
except ValueError:
pass
return 0 # 如果解析失败,则返回0秒
if __name__ == "__main__":
env = Asphalt9Env()
while True:
state = env.reset() # 重置环境并开始新的一局
done = False
while not done:
action = env.action_space.sample()
state, reward, done, _ = env.step(action)
print(f"Action: {action}, State: {state}, Reward: {reward}, Done: {done}")
time.sleep(1)
print("Game over. Resetting environment...")