Selfmade-Website
Disclaimer: Der gezeigte Aimbot dient nur der Erklärung und Bildungszwecken. Ich rate ausdrücklich davon ab, ihn in einem Spiel gegen andere Spieler einzusetzen. Bei Verwendung muss man mit einem Ausschluss aus dem Spiel rechnen (permanenter Ban).
In diesem Artikel zeige ich euch, wie ein Aimbot in einem Panzerspiel funktionieren könnte. Der Artikel dient der Veranschaulichung, um ein Verständnis für die Mechanik von Aimbots zu bekommen.
Die Formel und Idee für den Aimbot gab mir folgender Artikel in der Steam-Community: Perfect accuracy with CALCULATIONS
(Der folgende Code ist in Python geschrieben und alles kann nacheinander in ein Script kopiert werden)
Für den Bot brauchen wir die folgenden Bibliotheken:from PIL import ImageGrab
import cv2
import numpy as np
import win32gui
import time
import math
PIL und win32gui brauchen wir, um das Spielfeld zu bekommen. Dies geschieht durch einen einfachen Screenshot. Numpy und Math brauchen wir zur Berechnung. Time ist für einen kleinen Delay zuständig, da sonst Screenshot Probleme auftreten können.
Als erstes müssen wir das Spielfeld unserem Bot zeigen. Hierfür schreiben wir die Funktion get_window():def get_window():
hwnd = win32gui.FindWindow(None, GAMENAME) #select Game
win32gui.SetForegroundWindow(hwnd) #push it to foreground
time.sleep(0.1) #wait for it to be in foreground
rect = (0,50,1920,950) #image has to be in the upper left corner: 1920x1080
image = np.array(ImageGrab.grab(rect)) #gescreenshot
return image
Wenn man eine andere Spielauflösung als 1920x1080 benötigt, muss man bei der Formel die Pixelanzahl umrechnen. Weitere Angaben dazu im Steam-Artikel.
Nun müssen wir die gegnerischen Panzer und unseren Panzer mit der Funktion detector(image,color) ausfindig machen:def detector(image,color):
img = image
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
if color == "red":
# color range in hsv for red
lower = np.array([160, 100, 100])
upper = np.array([180, 255, 255])
elif color == "green":
# color range in hsv for green
lower = np.array([50, 150, 150])
upper = np.array([70, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
#cv2.imshow("mask", mask)
#cv2.waitKey(0)
points = cv2.findNonZero(mask) #get points of the color
res_points = points.reshape(len(points), -1) #reshape
sorted_p = res_points[res_points[:, 0].argsort()] #sort by first column value
#detect groups of red pixels to find enemies (works for single target too)
enemies = [] #array for the groups
while True:
sorted_p_l = len(sorted_p) #get started length of points
for i in range(sorted_p_l):
if i < sorted_p_l-1: #for out of range error
#proof if point as a meaningfull distance to next one
current_point = sorted_p[i]
next_point = sorted_p[i+1]
difference = next_point[0] - current_point[0]
if difference > 50: #proof if the difference is bigger than min distance
enemies.append([sorted_p[:i+1]]) #append this range
sorted_p = sorted_p[i+1:] #cut appended range of
break
if sorted_p_l == len(sorted_p): #proof if method found (deleted) something
enemies.append([sorted_p]) #append last group cause you cant find a distance cause there is only one left
break
enemies_pos = []
for enemy in enemies:
if len(enemy[0]) < 250: #if they have less than 300 points it isnt an enemy like the red arrow over your tank
pass
else:
#get min and max xs and ys
min = np.min(enemy[0], axis=0).flatten()
max = np.max(enemy[0], axis=0).flatten()
# filter to get middle pixel of tank
median_max = int(np.median([min[0], max[0]])) # convert to int to cut .5 of
x = median_max
y = min[1]+20 #+20 so i get the middle and not the top
enemies_pos.append((x,y)) #append
return enemies_pos
Dieser langer Codeblock macht Folgendes:
1. Wir suchen uns alle Pixel der ausgewählten Farbe (Grün oder Rot).
2. Nun gruppieren wir die Pixel zu Clustern und machen daran die Panzer ausfindig. Hierbei muss eine gewisse Anzahl an Pixeln erreicht sein.
3. Jetzt flatten wir den Array und suchen uns das Minimum und Maximum. So können wir die Position des Clusters bestimmen und bekommen X- und Y-Werte jedes Gegners zurück.
Nachdem wir dann per Input in der Main-Methode, die wir am Ende begutachten, den Gegner ausgewählt haben, berechnen wir mithilfe der Formeln aus dem Steam-Artikel die Kraft mit der Methode calc_power(x,y,angle). Hierbei sind X und Y relativ:def calc_power(x,y,angle):
g = (-379.106)
q = 0.0518718
angle = math.radians(angle)
velocity = math.sqrt(((-1*g)*(x**2))/(2*(math.cos(angle)**2)*(math.tan(angle)*x-y)))
power = (-2/(g*q)) * velocity
return power
Nun vereinen wir die einzelnen Methoden in der Main-Methode run_live():def run_live():
img = get_window()
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #cv2 reads in BGR and we want RGB
me = detector(img, "green")[0]
enemies = detector(img, "red")
#draw and save image
drawed = cv2.circle(img, me, radius=5, color=(255, 0, 255), thickness=2)
for enemy in enemies:
drawed = cv2.circle(drawed, enemy, radius=5, color=(0, 255, 255), thickness=2)
cv2.imwrite("drawed.png", drawed)
print("Enemies detected: ",len(enemies))
enemy = int(input("Enemy: "))-1 #so we start counting by 1 and not zero
#get distance of enemy
x = me[0] - enemies[enemy][0]
y = me[1] - enemies[enemy][1]
if x < 0:
x = x * -1
#insert angle
angle = int(input("angle: "))
print("Power: ",calc_power(x,y,angle))
Hier müssen wir wie erwähnt den Gegner per Zahl auswählen (es wird von links nach rechts gezählt) und den Winkel angeben in dem wir schießen möchten, da z.B. Berge im Weg sein könnten und das Script das nicht erkennt. Auch wird ein Bild namens drawed.png erstellt, auf dem man die Erkennung der Gegner und sich selbst nachvollziehen kann (Gegner: Gelber Kreis, Spieler: Lila Kreis):
Zum Schluss muss man nur noch die Funktion aufrufen:run_live()
Mögliche Probleme:
In vielen Spielen gibt es noch andere Dinge, die die gleiche bzw. ähnliche Farbe wie die gegnerischen Panzer haben. Da der Bot nur eindimensional scannt, können dadurch Fehler entstehen. Auch wenn Panzer übereinander sind, entstehen Fehler.
Eine weitere Besonderheit ist, dass wenn zwei Panzer sehr nah nebeneinander stehen, werden sie als ein Panzer erkannt. Dies ist nicht weiter schlimm, da wenn man diesen auswählt, in die Mitte der beiden Panzer trifft und optimalen Schaden anrichtet.
Selfmade-Website