Что нового

[Script] Игра по мотивам "C Robots"

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
AutoIt: 3.3.6.1

Версия: 1.0

Категория: Математика, Сеть, Элементы GUI, Разное

Описание:
Во время моей молодости промелькнула такая игрушка "C Robots", основная идея которой в том, что ты пишешь программу для робота (сами понимаете, на С), а потом этот робот сражается с другими роботами-программами. Сражаются роботы, естественно, без вмешательства игроков. Идея мне понравилась, а вот реализация не очень. Автор явно был слабоват в физике...
Вашему вниманию предлагается игра, основа которой отдалённо напоминает C Robots.
Есть поле боя (500x500). В нём сражаются роботы. Роботы с помощью сканера могут искать других роботов и стрелять по ним из пушки (дальность пушки 350, перезарядка 3 секунды). Чем ближе к роботу ляжет снаряд, тем больше повреждения. Роботы двигаются по полю, используя реактивный двигатель (вспоминаем физику и математику). Трения нет - безвоздушное пространство. Ударившись о стенку робот тоже получает повреждения. Последний выживший - победитель.

Как играть.

1. Вы, как игрок, пишете программу для робота. Как ни удивительно, программу пишете на AutoIt, используя библиотеку RobotsWar.au3
Код:
Global $RobotWarSessionSocket

TCPStartup()

;==============================================
; Connect_to_Server($sIPadress, $sPort, $ConnectingMessage = "")
; подключение к серверу
; $sIPadress - ip-адрес сервера
; $sPort - порт сервера
; $ConnectingMessage - сообщение, которое будет отпралено ев сервер при подключении
;
Func Connect_to_Server($sIPadress, $sPort, $ConnectingMessage = "")
	$RobotWarSessionSocket = -1
	$RobotWarSessionSocket = TCPConnect($sIPadress, $sPort)
    If @error Then
		Return -1
    Else
		TCPSend($RobotWarSessionSocket, $ConnectingMessage)
		Return $RobotWarSessionSocket
	EndIf
EndFunc

;==============================================
; Wait_for_Start()
; ожидание от сервера сигнала о начале игры
; возвращает 1, когда получено сообщение о старте игры
;
Func Wait_for_Start()
	Local $inMsg = ""
	Do
		$inMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then Return 0
	Until $inMsg == "start"
	Return 1
EndFunc

;==============================================
; Scan($degree, $resolution)
; Сканер
; $degree - направление сканирования в градусах
; $resolution - Допустимое отклонение в градусах
; Сканируется сектор $degree +/- $resolution)
; возвращает расстояние до ближайшей цели в этом секторе
; если в секторе цели не найдены, то возвращает 0
;
Func Scan($degree, $resolution = 10)
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "scan/"&$degree&"/"&$resolution)
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; Cannon($degree, $range)
; Выстрел
; $degree - направление выстрела в градусах
; $range - дальность выстрела
; возвращает True, если выстрел произведён
; возвращает False, если выстрел не произведён
;
Func Cannon($degree, $range)
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "cannon/"&$degree&"/"&$range)
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	If $cMsg == "cannonfired" Then Return True
	Return False
EndFunc

;==============================================
; Drive($degree, $acceleration)
; устанавливает режим работы двигателья
; $degree - направление тяги в градусах
; $acceleration - мощность работы двигателя: от 0% до 100%
; $acceleration = 0  - двигатель не работает
;
Func Drive($degree, $acceleration)
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "drive/"&$degree&"/"&$acceleration)
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; Kurs()
; возвращает текущее напраление движения в градусах
;
Func Kurs()
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "kurs")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; Speed()
; возвращает текущую скорость
;
Func Speed()
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "speed")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; Health()
; возвращает текущие хитпоинты в процентах
; 0 - убит
; 100 - полностью исправен
;
Func Health()
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "health")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; loc_x()
; возвращает текущую координату по оси X
;
Func loc_x()
	Local $cMsg = "", $x
	TCPSend($RobotWarSessionSocket, "loc_x")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	$x = Number($cMsg)
	If $x >= 0 And $x <= 499 Then Return $x
	Return 0
EndFunc

;==============================================
; loc_y()
; возвращает текущую координату по оси Y
;
Func loc_y()
	Local $cMsg = "", $y
	TCPSend($RobotWarSessionSocket, "loc_y")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	$y = Number($cMsg)
	If $y >= 0 And $y <= 499 Then Return $y
	Return 0
EndFunc

Func EmergencyEXIT()
	MsgBox(0,"ошибка","Потеряна связь с сервером")
	Exit
EndFunc
(описание функций есть в библиотеке)

2. Компилируете роботов в exe-шники. Компилируете сервер в exe-шник.

3. Запускате серевер. Запускаете роботов.

4. Нажимаете старт и наблюдаете за боем.

Сервер:
Код:
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <Math.au3>
#include <Timers.au3>
#Include <Array.au3>

;==============================================
;					SERVER
;==============================================

Global $PlayerNumber = 4
Global $PlayerColor[$PlayerNumber] = [0x008000, 0x5050FF, 0x8000FF, 0x7F4000]

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891,$MainSocket
Global $PlayersConnected[$PlayerNumber],$PlayersIP[$PlayerNumber],$PlayerPorts[$PlayerNumber]
Local $msg, $recv

; создаём GUI
$ServerGUI = GUICreate("Server", 300, $PlayerNumber*50+20)
Global $PlayerNames[$PlayerNumber],$PlayerStats[$PlayerNumber]
Global $Button1 = GUICtrlCreateButton("Start", 60, 20, 75, 25)
Global $Button2 = GUICtrlCreateButton("Reset", 160, 20, 75, 25)
For $i = 0 To $PlayerNumber-1
	$PlayerNames[$i] = GUICtrlCreateLabel("пусто", 30, 70 + $i*30, 75, 25, 1)
	$PlayerStats[$i] = GUICtrlCreateLabel("", 110, 70 + $i*30, 160, 25, 1)
	$PlayersConnected[$i] = -1
Next
GUISetState(@SW_SHOW)
; завершение созания GUI

TCPStartup()

$MainSocket = TCPListen($ServerIPADDRESS, $ServerPort)	; начинаем слушать порт
If $MainSocket = -1 Then Exit				; если порт уже занят, то на выход

While 1
	$msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE
			ExitLoop
		Case $Button1
			_BATTLE()
			RESET_Players()
			GUISwitch ($ServerGUI)
		Case $Button2
			RESET_Players()
		Case Else
			For $i = 0 To $PlayerNumber-1
				If $PlayersConnected[$i] = -1 Then
					$PlayersConnected[$i] = TCPAccept($MainSocket) ; если i-тый игрок не подключенн, то пробуем подключить
					;ExitLoop	; <- если включить ExitLoop
								; то игроки будут подключаться по порядку начиная с 1-го сокета
								; но при обрыве игрока его слот будет уже недоступен
				Else
					If $PlayersIP[$i] == "" Then	; если по игроку ещё нет статистики, то получаем её
						$PlayersIP[$i] = SocketToIP($PlayersConnected[$i])
						GUICtrlSetData($PlayerStats[$i],$PlayersIP[$i])
					EndIf
					$recv = TCPRecv($PlayersConnected[$i], 1024)	; получаем данные от подключившегося игрока
					If @error Then
						$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем слот
						GUICtrlSetData($PlayerNames[$i],"пусто")
						GUICtrlSetData($PlayerStats[$i],"")
					EndIf
						If $recv <> "" Then GUICtrlSetData($PlayerNames[$i],$recv)
				EndIf
			Next
	EndSwitch

WEnd

TCPShutdown()

; Function to return IP Address from a connected socket.
; один в один взял из справки
Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")
    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
            "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf
    $sockaddr = 0
    Return $aRet
EndFunc   ;==>SocketToIP


Func RESET_Players() ; отключаем всех игроков и обнуляем информацию о них
	For $i = 0 To $PlayerNumber-1
		GUICtrlSetData($PlayerNames[$i],"пусто")
		GUICtrlSetData($PlayerStats[$i],"")
		TCPCloseSocket($PlayersConnected[$i])
		$PlayersConnected[$i] = -1
	Next
EndFunc

;============================================================================================
;											BATTLE
;============================================================================================
Func _BATTLE()

	Local Const $dig_to_rad = 3.14159265358979 / 180	; перевод градусов в радианы
	Local Const $reload_time_ms = 3000		; время перезарядки пушки роботов
	Local Const $drivePower = 0.002			; мощность двигателя робота
	Local Const $Bomb_Damage = 10			; базовый урон от снарядов
	Local Const $Max_Cannon_Range = 350			; максимальная дальность стрельбы орудий

	Local $Bombs_X[1] = [0], $Bombs_Y[1] = [0]
	Local $Players[$PlayerNumber]
	Local $PlayersHP[$PlayerNumber],$Player_X[$PlayerNumber],$Player_Y[$PlayerNumber], _
		  $Player_Speed_X[$PlayerNumber],$Player_Speed_Y[$PlayerNumber], _
		  $Players_Reload_Timer[$PlayerNumber], $Player_Direction[$PlayerNumber], $Player_Power[$PlayerNumber], _
		  $PlayersStatLabel[$PlayerNumber], $PlayerLabels[$PlayerNumber]
	; создаём GUI поля битвы
	Local $BattleGUI = GUICreate("Battle", 700, 505)
	GUISwitch ($BattleGUI)
	GUICtrlCreateLabel("", 0, 0, 499, 499, 1)
	GUICtrlSetBkColor(-1, 0xFFFFFF)
	Local $LivePlayers = 0
	For $i = 0 To $PlayerNumber-1
		$Players[$i] = GUICtrlRead($PlayerNames[$i])
		$PlayersStatLabel[$i] = GUICtrlCreateLabel($Players[$i], 530, 50 + $i*100, 160, 90, 1)
		GUICtrlSetColor(-1, $PlayerColor[$i])
		If $PlayersConnected[$i] <> -1 Then
			TCPSend($PlayersConnected[$i], "start")
			If @error Then
				$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем
				$PlayersHP[$i] = 0
			Else
				$LivePlayers += 1
				$PlayersHP[$i] = 100
				$Player_X[$i] = Random(0,499,1)
				$Player_Y[$i] = Random(0,499,1)
				$PlayerLabels[$i] = GUICtrlCreateLabel("", $Player_X[$i], $Player_Y[$i], 5, 5, 1)
				GUICtrlSetBkColor(-1, $PlayerColor[$i])
				$Player_Speed_X[$i] = 0
				$Player_Speed_Y[$i] = 0
				$Players_Reload_Timer[$i] = _Timer_Init()
			EndIf
		EndIf
	Next
	GUISetState(@SW_SHOW)
	; завершение созания GUI

	While $LivePlayers > 1
		$msg = GUIGetMsg()
		If $Msg = $GUI_EVENT_CLOSE Then	ExitLoop
		$LivePlayers = 0
		For $i = 0 To $PlayerNumber-1
			If $PlayersHP[$i] > 0 Then
				$LivePlayers += 1

				;----------------------------------------------------------------------
				;							обмен данными с игроками
				;----------------------------------------------------------------------
				$recv = TCPRecv($PlayersConnected[$i], 256)	; получаем запрос от игрока
				;ToolTip($recv, 0,0)
				If @error Then
					$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
					$PlayersHP[$i] = 0
					$LivePlayers -= 1
					ContinueLoop
				EndIf
				$zapros = StringSplit($recv,"/")
				Switch $zapros[1]
					Case "scan"
						$snd = 999999
						If $zapros[0] = 3 Then
							For $j = 0 To $PlayerNumber-1
								If $i=$j Then ContinueLoop
								If $PlayersHP[$j]=0 Then ContinueLoop
								$dX = $Player_X[$j] - $Player_X[$i]
								$dY = $Player_Y[$j] - $Player_Y[$i]
								Select
									Case $dX = 0
										If $dY < 0 Then
											$azimut = 90
										Else
											$azimut = 270
										EndIf
									Case $dX > 0
										$azimut = ATan($dY/$dX) / $dig_to_rad
										If $azimut < 0 Then $azimut += 360
									Case Else
										$azimut = 180 + ATan($dY/$dX) / $dig_to_rad
										If $azimut < 0 Then $azimut += 360
								EndSelect
								If $azimut >= ($zapros[2]-$zapros[3]) And $azimut <= ($zapros[2]+$zapros[3]) Then
									$snd = _Min($snd, Sqrt($dX*$dX + $dY*$dY))
								EndIf
							Next
						EndIf
						If $snd = 999999 Then $snd = 0
						TCPSend($PlayersConnected[$i], ""&$snd)	; без "" глючит чегойто
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "cannon"
						If $zapros[0] <> 3 Or _Timer_Diff($Players_Reload_Timer[$i]) < $reload_time_ms Then
							$snd = "reloading"
						Else
							$zapros[2] = Mod($zapros[2],360)
							If $zapros[3] < 0 Then $zapros[3] = 0
							If $zapros[3] > $Max_Cannon_Range Then $zapros[3] = $Max_Cannon_Range
							$aim_X = $Player_X[$i] + $zapros[3]*Cos($zapros[2]*$dig_to_rad)
							$aim_Y = $Player_Y[$i] + $zapros[3]*Sin($zapros[2]*$dig_to_rad)
							If $aim_X < 0 Then $aim_X = 0
							If $aim_X > 499 Then $aim_X = 499
							If $aim_Y < 0 Then $aim_Y = 0
							If $aim_Y > 499 Then $aim_Y = 499
							$Players_Reload_Timer[$i] = _Timer_Init()
							_ArrayAdd($Bombs_X, $aim_X)
							$Bombs_X[0] += 1
							_ArrayAdd($Bombs_Y, $aim_Y)
							$Bombs_Y[0] += 1
							$snd = "cannonfired"
						EndIf
						TCPSend($PlayersConnected[$i], $snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "drive"
						If $zapros[0] = 3 Then
							$Player_Direction[$i] = $zapros[2]
							$Player_Power[$i] = $zapros[3]
							If $Player_Power[$i] < 0 Then $Player_Power[$i] = 0
							If $Player_Power[$i] > 100 Then $Player_Power[$i] = 100
							TCPSend($PlayersConnected[$i], ""&$Player_Power[$i])
							If @error Then
								$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
								$PlayersHP[$i] = 0
								$LivePlayers -= 1
								ContinueLoop
							EndIf
						EndIf

					Case "kurs"
						If $Player_Speed_X[$i] = 0 Then
							If $Player_Speed_Y[$i] < 0 Then
								$snd = 90
							Else
								$snd = 270
							EndIf
						Else
							$snd = ATan($Player_Speed_Y[$i]/$Player_Speed_X[$i]) / $dig_to_rad
						EndIf
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "speed"
						$snd = Sqrt($Player_Speed_Y[$i]*$Player_Speed_Y[$i]+$Player_Speed_X[$i]*$Player_Speed_X[$i])
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "health"
						$snd = $PlayersHP[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "loc_x"
						$snd = $Player_X[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "loc_y"
						$snd = $Player_Y[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

				EndSwitch

				;----------------------------------------------------------------------
				;							рассчет перемещений
				;----------------------------------------------------------------------

				; по оси X
				$a = ($Player_Power[$i]/100)*$drivePower*Cos($Player_Direction[$i]*$dig_to_rad)
				$Player_X[$i] = $Player_X[$i] + $Player_Speed_X[$i] + $a/2
				$Player_Speed_X[$i] = $Player_Speed_X[$i] + $a
				If $Player_X[$i] < 0 Then 	; если ударился в стенку
					$Player_X[$i] = 0
					$Player_Speed_X[$i] = 0
					$PlayersHP[$i] -= 1
				EndIf
				If $Player_X[$i] > 499 Then		; если ударился в стенку
					$Player_X[$i] = 499
					$Player_Speed_X[$i] = 0
					$PlayersHP[$i] -= 1
				EndIf

				; по оси Y
				$a = -($Player_Power[$i]/100)*$drivePower*Sin($Player_Direction[$i]*$dig_to_rad)
				; минус потому что ось Y не совпадает с радианами
				$Player_Y[$i] = $Player_Y[$i] + $Player_Speed_Y[$i] + $Player_Power[$i]*$a/2
				$Player_Speed_Y[$i] = $Player_Speed_Y[$i] + $a
				If $Player_Y[$i] < 0 Then 	; если ударился в стенку
					$Player_Y[$i] = 0
					$Player_Speed_Y[$i] = 0
					$PlayersHP[$i] -= 1
				EndIf
				If $Player_Y[$i] > 499 Then		; если ударился в стенку
					$Player_Y[$i] = 499
					$Player_Speed_Y[$i] = 0
					$PlayersHP[$i] -= 1
				EndIf

				; прорисовка перемещений
				GUICtrlSetPos($PlayerLabels[$i],$Player_X[$i],$Player_Y[$i])
			EndIf

		Next

		;----------------------------------------------------------------------
		;						рассчет повреждений от взрывов
		;----------------------------------------------------------------------

		For $i=$Bombs_X[0] To 1 Step -1

			$boom = GUICtrlCreateLabel("",$Bombs_X[$i],$Bombs_Y[$i],2,2)
			GUICtrlSetBkColor($boom,0xFF0000)

			For $j = 0 To $PlayerNumber-1
				$dX = $Player_X[$j] - $Bombs_X[$i]
				$dY = $Player_Y[$j] - $Bombs_Y[$i]
				$range = sqrt($dX*$dX+$dY*$dY)
				$damage = $Bomb_Damage * Floor(50/(10+$range))/5
				;MsgBox(0,$j,$range2&"/"&$damage)
				$PlayersHP[$j] -= $damage
			Next

			_ArrayDelete($Bombs_X, $i)
			$Bombs_X[0] -= 1
			_ArrayDelete($Bombs_Y, $i)
			$Bombs_Y[0] -= 1

		Next

		;----------------------------------------------------------------------
		;						показ статистики
		;----------------------------------------------------------------------
		For $i = 0 To $PlayerNumber-1
			If $PlayersHP[$i] > 0 Then
				GUICtrlSetData($PlayersStatLabel[$i],$PlayerNames[$i]&@CR&"HP = "&$PlayersHP[$i]&@CR&"X = "&Round($Player_X[$i])&@CR&"Y = "&Round($Player_Y[$i]))
			Else
				GUICtrlSetData($PlayersStatLabel[$i],"убит")
			EndIf
		Next

	WEnd

	Do
		$msg = GUIGetMsg()
	Until $Msg = $GUI_EVENT_CLOSE
	GUIDelete($BattleGUI)
EndFunc

Пример робота 1
Код:
#include <RobotWar.au3>

;==============================================
;					CLIENT
;==============================================

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891
Local $playerName = "player"

$ServerSocket = Connect_to_Server($ServerIPADDRESS, $ServerPort, $playerName)
If Wait_for_Start() <> 1 Then EmergencyEXIT()

$i= 0

While Health() > 0
	$rrr = Scan($i,10)
	If $rrr > 0 Then
		Detect($i,10)
	Else
		$i += 10
		If $i > 360 then $i -= 360
	EndIf
WEnd

Func Detect($dir,$rang)
	Local $sc = Scan($dir,$rang)
	If $sc = 0 Then Return False
	If $rang <=1 Then
		Cannon($dir,$sc)
		Return True
	EndIf
	Local $tmpRang = $rang/2, $res = Detect($dir - $tmpRang, Ceiling($tmpRang))
	If Not $res Then $res = Detect($dir + $tmpRang, $tmpRang)
	Return $res
EndFunc

Пример робота 2
Код:
#include <RobotWar.au3>

;==============================================
;					CLIENT
;==============================================

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891
Local $playerName = "player"

$ServerSocket = Connect_to_Server($ServerIPADDRESS, $ServerPort, $playerName)
If Wait_for_Start() <> 1 Then EmergencyEXIT()

If loc_x() < 250 Then
	drive(0,50)
Else
	drive(180,50)
EndIf

$i=0
While Health() > 0
	$rrr = Scan($i,10)
	If $rrr > 0 Then $tmp = Cannon($i,$rrr)
	$i += 10
	If $i > 360 then $i -= 360
	If loc_x() < 200 Then drive(0,80)
	If loc_x() > 300 Then drive(180,80)
WEnd

А с GUI я как и раньше не очень дружу...
Да и не нужно в этой игре ничего эдакого.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Re: [Script] Игра по мотивам \\\"C Robots\\\"

Если роботы это разноцветные пиксели, то почему то они не двигаются. Просто перестреливаются. Так и должно быть?


Добавлено:
Сообщение автоматически объединено:

А, вот. Заработало. :smile:


Добавлено:
Сообщение автоматически объединено:

Если бы они еще стреляли своим цветом. 8)
 

DarWiM

Продвинутый
Сообщения
527
Репутация
90
OffTopic:
Кажись первый пример роботов не работает


Хорошо бы видеть еще и направления выстрелов)

Код:
If $snd = 999999 Then $snd = 0
TCPSend($PlayersConnected[$i], ""&$snd) ; без "" глючит чегойто
порадовало. наверное нужно использовать String()
 
Автор
C2H5OH

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Почему не двигаются? Потому что это примеры. ;D
Первый бот не двигается вообще. Выполняет поиск по рекурсивному бинарному алгоритму и стреляет поточнее.
Второй бот бегает вправо-влево и на ходу стреляет без точного прицеливания.

DarWiM,
всё что я выкладываю на форуме, я, в основном, пишу для того чтобы разобраться самому как это работает. На ходу наступаю на грабли и обхожу их первым пришедшим в голову способом. ;)
Вопрос не в том чтобы преобразовать в строку, а в том почему числа в чистом виде не проходят нормально.
Большой вопрос почему не работают функции взаимодействия, если сервер не отправляет ничего в ответ. Например, первоначальный однонаправленный вариант функции Drive приводил к зависанию клиента.
Сервер
Код:
Case "drive"
						If $zapros[0] = 3 Then
							$Player_Direction[$i] = $zapros[2]
							$Player_Power[$i] = $zapros[3]
							If $Player_Power[$i] < 0 Then $Player_Power[$i] = 0
							If $Player_Power[$i] > 100 Then $Player_Power[$i] = 100
						EndIf


Клиент
Код:
Func Drive($degree, $acceleration)
	Local $cMsg = ""
	TCPSend($ConnectedSocket, "drive/"&$degree&"/"&$acceleration)
	If @error Then EmergencyEXIT()
EndFunc

И вообще я код выложил не для того чтобы увлечь кого-то этой игрой, а в качестве примера.
Наверное, надо было по частям код выкладывать - сеть, математика...
:IL_AutoIt_1:
 

DarWiM

Продвинутый
Сообщения
527
Репутация
90
C2H5OH
В любом случае достаточно интересно :smile: Хочу узнать, как будет выглядеть финальная версия :smile:
 
Автор
C2H5OH

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Re: [Script] Игра по мотивам \"C Robots\"

Повторюсь. В процеесе написания для меня было более интересно разобраться как работать с несколькими клиентами.
На всякий случай выкладываю начальные скрипты.
Сервер
Код:
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
;#include <GDIP.au3>
#include <GDIPlus.au3>
#include <Math.au3>

;==============================================
;					SERVER
;==============================================

Global $PlayerNumber = 4

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891,$MainSocket
Global $PlayersConnected[$PlayerNumber],$PlayersIP[$PlayerNumber],$PlayerPorts[$PlayerNumber]
Local $msg, $recv

; создаём GUI
GUICreate("Server", 300, $PlayerNumber*50+20)
Global $PlayerNames[$PlayerNumber],$PlayerStats[$PlayerNumber]
Global $Button1 = GUICtrlCreateButton("Start", 60, 20, 75, 25)
Global $Button2 = GUICtrlCreateButton("Reset", 160, 20, 75, 25)
For $i = 0 To $PlayerNumber-1
	$PlayerNames[$i] = GUICtrlCreateLabel("пусто", 30, 70 + $i*30, 75, 25, 1)
	$PlayerStats[$i] = GUICtrlCreateLabel("", 110, 70 + $i*30, 160, 25, 1)
	$PlayersConnected[$i] = -1
Next
GUISetState(@SW_SHOW)
; завершение созания GUI

TCPStartup()

$MainSocket = TCPListen($ServerIPADDRESS, $ServerPort)	; начинаем слушать порт
If $MainSocket = -1 Then Exit				; если порт уже занят, то на выход

While 1
	$msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE
			ExitLoop
		Case $Button1
			;_BATTLE()
		Case $Button2
			RESET_Players()
		Case Else
			For $i = 0 To $PlayerNumber-1
				If $PlayersConnected[$i] = -1 Then
					$PlayersConnected[$i] = TCPAccept($MainSocket) ; если i-тый игрок не подключенн, то пробуем подключить
					;ExitLoop	; <- если включить ExitLoop
								; то игроки будут подключаться по порядку начиная с 1-го сокета
								; но при обрыве игрока его слот будет уже недоступен
				Else
					If $PlayersIP[$i] == "" Then	; если по игроку ещё нет статистики, то получаем её
						$PlayersIP[$i] = SocketToIP($PlayersConnected[$i])
						GUICtrlSetData($PlayerStats[$i],$PlayersIP[$i])
					EndIf
					$recv = TCPRecv($PlayersConnected[$i], 1024)	; получаем данные от подключившегося игрока
					If @error Then
						$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем слот
						GUICtrlSetData($PlayerNames[$i],"пусто")
						GUICtrlSetData($PlayerStats[$i],"")
					EndIf
						If $recv <> "" Then
							GUICtrlSetData($PlayerNames[$i],$recv)
							TCPSend($PlayersConnected[$i], "клиент № "&$i&" - "&$recv)
						EndIf
				EndIf
			Next
	EndSwitch

WEnd

TCPShutdown()

; Function to return IP Address from a connected socket.
; один в один взял из справки
Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")
    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
            "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf
    $sockaddr = 0
    Return $aRet
EndFunc   ;==>SocketToIP


Func RESET_Players() ; отключаем всех игроков и обнуляем информацию о них
	For $i = 0 To $PlayerNumber-1
		GUICtrlSetData($PlayerNames[$i],"пусто")
		GUICtrlSetData($PlayerStats[$i],"")
		TCPCloseSocket($PlayersConnected[$i])
		$PlayersConnected[$i] = -1
	Next
EndFunc


Клиент
Код:
;==============================================
;==============================================
;CLIENT! Start Me after starting the SERVER!!!!!!!!!!!!!!!
;==============================================
;==============================================

Example()

Func Example()

	Local $ConnectedSocket, $szData
	Local $szIPADDRESS = @IPAddress1
	Local $nPORT = 33891

	; Start The TCP Services
	;==============================================
	TCPStartup()

	; Initialize a variable to represent a connection
	;==============================================
	$ConnectedSocket = -1

	;Attempt to connect to SERVER at its IP and PORT 33891
	;=======================================================
	$ConnectedSocket = TCPConnect($szIPADDRESS, $nPORT)

	; If there is an error... show it
	$recv = ""
		;Loop forever asking for data to send to the SERVER
		While 1
			; InputBox for data to transmit
			$szData = InputBox($recv, @LF & @LF & "Enter data to transmit to the SERVER:")

			; If they cancel the InputBox or leave it blank we exit our forever loop
			If @error Or $szData = "" Then ExitLoop

			; We should have data in $szData... lets attempt to send it through our connected socket.
			TCPSend($ConnectedSocket, $szData)

			; If the send failed with @error then the socket has disconnected
			;----------------------------------------------------------------
			If @error Then ExitLoop

			$recv = ""
			While $recv == ""
				$recv = TCPRecv($ConnectedSocket, 256)
			WEnd

		WEnd

EndFunc   ;==>Example
Я запускал сервер, несколько клиентов exe-шников и смотрел как работает)

Разбираясь со скриптами Dellrocа http://autoit-script.ru/index.php/topic,11445.msg75139/topicseen.html#new
понял почему не работает односторонняя передача - потому что у меня боты успевали накидать несколько запросов в сокет, а сервер выгребал буфер и обрабатывал его как один запрос. Поскольку запрос не требовал ответа, то сервер ничего и не посылал, а клиент в общей куче бросал запрос, на который требуется ответ и ждал его...


Добавлено:
Сообщение автоматически объединено:

Облегчил игру (думаю что любителей математики не так много...).
Теперь боты ходят по клеткам.
Вместо функций drive, speed, kurs теперь одна функция move.
Библиотека
Код:
Global $RobotWarSessionSocket

TCPStartup()

;==============================================
; Connect_to_Server($sIPadress, $sPort, $ConnectingMessage = "")
; подключение к серверу
; $sIPadress - ip-адрес сервера
; $sPort - порт сервера
; $ConnectingMessage - сообщение, которое будет отпралено ев сервер при подключении
;
Func Connect_to_Server($sIPadress, $sPort, $ConnectingMessage = "")
	$RobotWarSessionSocket = -1
	$RobotWarSessionSocket = TCPConnect($sIPadress, $sPort)
    If @error Then
		Return -1
    Else
		TCPSend($RobotWarSessionSocket, $ConnectingMessage)
		Return $RobotWarSessionSocket
	EndIf
EndFunc

;==============================================
; Wait_for_Start()
; ожидание от сервера сигнала о начале игры
; возвращает 1, когда получено сообщение о старте игры
;
Func Wait_for_Start()
	Local $inMsg = ""
	Do
		$inMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then Return 0
	Until $inMsg == "start"
	Return 1
EndFunc

;==============================================
; Scan($degree, $resolution)
; Сканер
; $degree - направление сканирования в градусах
; $resolution - Допустимое отклонение в градусах
; Сканируется сектор $degree +/- $resolution)
; возвращает расстояние до ближайшей цели в этом секторе
; если в секторе цели не найдены, то возвращает 0
;
Func Scan($degree, $resolution = 10)
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "scan/"&$degree&"/"&$resolution)
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; Cannon($degree, $range)
; Выстрел
; $degree - направление выстрела в градусах
; $range - дальность выстрела
; возвращает True, если выстрел произведён
; возвращает False, если выстрел не произведён
;
Func Cannon($degree, $range)
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "cannon/"&$degree&"/"&$range)
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	If $cMsg == "cannonfired" Then Return True
	Return False
EndFunc

;==============================================
; Move($direction)
; перемещение на одну клетку
; $direction - направление: 0-n,1-ne,2-e,3-se,4-s,5-sw,6-w,7-nw
;
Func Move($direction)
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "move/"&$direction)
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
EndFunc

;==============================================
; Health()
; возвращает текущие хитпоинты в процентах
; 0 - убит
; 100 - полностью исправен
;
Func Health()
	Local $cMsg = ""
	TCPSend($RobotWarSessionSocket, "health")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	Return Number($cMsg)
EndFunc

;==============================================
; loc_x()
; возвращает текущую координату по оси X
;
Func loc_x()
	Local $cMsg = "", $x
	TCPSend($RobotWarSessionSocket, "loc_x")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	$x = Number($cMsg)
	If $x >= 0 And $x <= 499 Then Return $x
	Return 0
EndFunc

;==============================================
; loc_y()
; возвращает текущую координату по оси Y
;
Func loc_y()
	Local $cMsg = "", $y
	TCPSend($RobotWarSessionSocket, "loc_y")
	If @error Then EmergencyEXIT()
	While $cMsg == ""
		$cMsg = TCPRecv($RobotWarSessionSocket, 256)
		If @error Then EmergencyEXIT()
	WEnd
	$y = Number($cMsg)
	If $y >= 0 And $y <= 499 Then Return $y
	Return 0
EndFunc

Func EmergencyEXIT()
	MsgBox(0,"ошибка","Потеряна связь с сервером")
	Exit
EndFunc

Теперь роботы стреляют своим цветом (линии нарисовать то я могу, но не представляю как их убирать после выстрела)
Сервер
Код:
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <Math.au3>
#include <Timers.au3>
;#Include <Array.au3>

;==============================================
;					SERVER
;==============================================

Global $PlayerNumber = 4
Global $PlayerColor[$PlayerNumber] = [0x008000, 0x5050FF, 0x8000FF, 0x7F4000]

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891,$MainSocket
Global $PlayersConnected[$PlayerNumber],$PlayersIP[$PlayerNumber],$PlayerPorts[$PlayerNumber]
Local $msg, $recv

; создаём GUI
$ServerGUI = GUICreate("Server", 300, $PlayerNumber*50+20)
Global $PlayerNames[$PlayerNumber],$PlayerStats[$PlayerNumber]
Global $Button1 = GUICtrlCreateButton("Start", 60, 20, 75, 25)
Global $Button2 = GUICtrlCreateButton("Reset", 160, 20, 75, 25)
For $i = 0 To $PlayerNumber-1
	$PlayerNames[$i] = GUICtrlCreateLabel("пусто", 30, 70 + $i*30, 75, 25, 1)
	$PlayerStats[$i] = GUICtrlCreateLabel("", 110, 70 + $i*30, 160, 25, 1)
	$PlayersConnected[$i] = -1
Next
GUISetState(@SW_SHOW)
; завершение созания GUI

TCPStartup()

$MainSocket = TCPListen($ServerIPADDRESS, $ServerPort)	; начинаем слушать порт
If $MainSocket = -1 Then Exit				; если порт уже занят, то на выход

While 1
	$msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE
			ExitLoop
		Case $Button1
			_BATTLE()
			RESET_Players()
			GUISwitch ($ServerGUI)
		Case $Button2
			RESET_Players()
		Case Else
			For $i = 0 To $PlayerNumber-1
				If $PlayersConnected[$i] = -1 Then
					$PlayersConnected[$i] = TCPAccept($MainSocket) ; если i-тый игрок не подключенн, то пробуем подключить
					;ExitLoop	; <- если включить ExitLoop
								; то игроки будут подключаться по порядку начиная с 1-го сокета
								; но при обрыве игрока его слот будет уже недоступен
				Else
					If $PlayersIP[$i] == "" Then	; если по игроку ещё нет статистики, то получаем её
						$PlayersIP[$i] = SocketToIP($PlayersConnected[$i])
						GUICtrlSetData($PlayerStats[$i],$PlayersIP[$i])
					EndIf
					$recv = TCPRecv($PlayersConnected[$i], 1024)	; получаем данные от подключившегося игрока
					If @error Then
						$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем слот
						GUICtrlSetData($PlayerNames[$i],"пусто")
						GUICtrlSetData($PlayerStats[$i],"")
					EndIf
						If $recv <> "" Then GUICtrlSetData($PlayerNames[$i],$recv)
				EndIf
			Next
	EndSwitch

WEnd

TCPShutdown()

; Function to return IP Address from a connected socket.
; один в один взял из справки
Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")
    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
            "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf
    $sockaddr = 0
    Return $aRet
EndFunc   ;==>SocketToIP


Func RESET_Players() ; отключаем всех игроков и обнуляем информацию о них
	For $i = 0 To $PlayerNumber-1
		GUICtrlSetData($PlayerNames[$i],"пусто")
		GUICtrlSetData($PlayerStats[$i],"")
		TCPCloseSocket($PlayersConnected[$i])
		$PlayersConnected[$i] = -1
	Next
EndFunc

;============================================================================================
;											BATTLE
;============================================================================================
Func _BATTLE()

	Local Const $dig_to_rad = 3.14159265358979 / 180	; перевод градусов в радианы
	Local Const $reload_time_ms = 3000		; время перезарядки пушки роботов
	Local Const $drivePower = 0.002			; мощность двигателя робота
	Local Const $Bomb_Damage = 10			; базовый урон от снарядов
	Local Const $Max_Cannon_Range = 350			; максимальная дальность стрельбы орудий

	Local $Players[$PlayerNumber], $Bombs[$PlayerNumber][3]
	Local $PlayersHP[$PlayerNumber],$Player_X[$PlayerNumber],$Player_Y[$PlayerNumber], _
		$Players_Reload_Timer[$PlayerNumber], $PlayersStatLabel[$PlayerNumber], $PlayerLabels[$PlayerNumber]
	; создаём GUI поля битвы
	Local $BattleGUI = GUICreate("Battle", 700, 505)
	GUISwitch ($BattleGUI)
	GUICtrlCreateLabel("", 0, 0, 499, 499, 1)
	GUICtrlSetBkColor(-1, 0xFFFFFF)
	Local $LivePlayers = 0
	For $i = 0 To $PlayerNumber-1
		$Players[$i] = GUICtrlRead($PlayerNames[$i])
		$PlayersStatLabel[$i] = GUICtrlCreateLabel($Players[$i], 530, 50 + $i*100, 160, 90, 1)
		GUICtrlSetColor(-1, $PlayerColor[$i])
		$Bombs[$i][0] = False
		If $PlayersConnected[$i] <> -1 Then
			TCPSend($PlayersConnected[$i], "start")
			If @error Then
				$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем
				$PlayersHP[$i] = 0
			Else
				$LivePlayers += 1
				$PlayersHP[$i] = 100
				$Player_X[$i] = Random(0,499,1)
				$Player_Y[$i] = Random(0,499,1)
				$PlayerLabels[$i] = GUICtrlCreateLabel("", $Player_X[$i], $Player_Y[$i], 5, 5, 1)
				GUICtrlSetBkColor(-1, $PlayerColor[$i])
				$Players_Reload_Timer[$i] = _Timer_Init()
			EndIf
		EndIf
	Next
	GUISetState(@SW_SHOW)
	; завершение созания GUI

	While $LivePlayers > 1
		$msg = GUIGetMsg()
		If $Msg = $GUI_EVENT_CLOSE Then	ExitLoop
		$LivePlayers = 0
		For $i = 0 To $PlayerNumber-1
			If $PlayersHP[$i] > 0 Then
				$LivePlayers += 1

				;----------------------------------------------------------------------
				;							обмен данными с игроками
				;----------------------------------------------------------------------
				$recv = TCPRecv($PlayersConnected[$i], 256)	; получаем запрос от игрока
				;ToolTip($recv, 0,0)
				If @error Then
					$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
					$PlayersHP[$i] = 0
					$LivePlayers -= 1
					ContinueLoop
				EndIf
				$zapros = StringSplit($recv,"/")
				Switch $zapros[1]
					Case "scan"
						$snd = 999999
						If $zapros[0] = 3 Then
							For $j = 0 To $PlayerNumber-1
								If $i=$j Then ContinueLoop
								If $PlayersHP[$j]=0 Then ContinueLoop
								$dX = $Player_X[$j] - $Player_X[$i]
								$dY = $Player_Y[$j] - $Player_Y[$i]
								Select
									Case $dX = 0
										If $dY < 0 Then
											$azimut = 90
										Else
											$azimut = 270
										EndIf
									Case $dX > 0
										$azimut = ATan($dY/$dX) / $dig_to_rad
										If $azimut < 0 Then $azimut += 360
									Case Else
										$azimut = 180 + ATan($dY/$dX) / $dig_to_rad
										If $azimut < 0 Then $azimut += 360
								EndSelect
								If $azimut >= ($zapros[2]-$zapros[3]) And $azimut <= ($zapros[2]+$zapros[3]) Then
									$snd = _Min($snd, Sqrt($dX*$dX + $dY*$dY))
								EndIf
							Next
						EndIf
						If $snd = 999999 Then $snd = 0
						TCPSend($PlayersConnected[$i], ""&$snd)	; без "" глючит чегойто
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "cannon"
						If $zapros[0] <> 3 Or _Timer_Diff($Players_Reload_Timer[$i]) < $reload_time_ms Then
							$snd = "reloading"
						Else
							$zapros[2] = Mod($zapros[2],360)
							If $zapros[3] < 0 Then $zapros[3] = 0
							If $zapros[3] > $Max_Cannon_Range Then $zapros[3] = $Max_Cannon_Range
							$aim_X = $Player_X[$i] + $zapros[3]*Cos($zapros[2]*$dig_to_rad)
							$aim_Y = $Player_Y[$i] + $zapros[3]*Sin($zapros[2]*$dig_to_rad)
							If $aim_X < 0 Then $aim_X = 0
							If $aim_X > 499 Then $aim_X = 499
							If $aim_Y < 0 Then $aim_Y = 0
							If $aim_Y > 499 Then $aim_Y = 499
							$Players_Reload_Timer[$i] = _Timer_Init()
							$Bombs[$i][0] = True
							$Bombs[$i][1] = $aim_X
							$Bombs[$i][2] = $aim_Y
							$snd = "cannonfired"
						EndIf
						TCPSend($PlayersConnected[$i], $snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "move"
						If $zapros[0] = 2 Then
							Switch $zapros[2]
								Case "0"
									$Player_Y[$i] -= 1
								Case "1"
									$Player_X[$i] += 1
									$Player_Y[$i] -= 1
								Case "2"
									$Player_X[$i] += 1
								Case "3"
									$Player_X[$i] += 1
									$Player_Y[$i] += 1
								Case "4"
									$Player_Y[$i] += 1
								Case "5"
									$Player_X[$i] -= 1
									$Player_Y[$i] += 1
								Case "6"
									$Player_X[$i] -= 1
								Case "7"
									$Player_X[$i] -= 1
									$Player_Y[$i] -= 1
							EndSwitch
						EndIf
						If $Player_X[$i] < 0 Then 	; если ударился в стенку
							$Player_X[$i] = 0
							$PlayersHP[$i] -= 1
						EndIf
						If $Player_X[$i] > 499 Then		; если ударился в стенку
							$Player_X[$i] = 499
							$PlayersHP[$i] -= 1
						EndIf
						If $Player_Y[$i] < 0 Then 	; если ударился в стенку
							$Player_Y[$i] = 0
							$PlayersHP[$i] -= 1
						EndIf
						If $Player_Y[$i] > 499 Then		; если ударился в стенку
							$Player_Y[$i] = 499
							$PlayersHP[$i] -= 1
						EndIf
						TCPSend($PlayersConnected[$i], "moved")
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "health"
						$snd = $PlayersHP[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "loc_x"
						$snd = $Player_X[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "loc_y"
						$snd = $Player_Y[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

				EndSwitch

				; прорисовка перемещений
				GUICtrlSetPos($PlayerLabels[$i],$Player_X[$i],$Player_Y[$i])
			EndIf

		Next

		;----------------------------------------------------------------------
		;						рассчет повреждений от взрывов
		;----------------------------------------------------------------------

		For $i=0 To $PlayerNumber-1
			If $Bombs[$i][0] Then
				$boom = GUICtrlCreateLabel("",$Bombs[$i][1],$Bombs[$i][2],2,2)
				GUICtrlSetBkColor($boom,$PlayerColor[$i])
				For $j = 0 To $PlayerNumber-1
					$dX = $Player_X[$j] - $Bombs[$i][1]
					$dY = $Player_Y[$j] - $Bombs[$i][2]
					$range = sqrt($dX*$dX+$dY*$dY)
					$damage = $Bomb_Damage * Floor(50/(10+$range))/5
					$PlayersHP[$j] -= $damage
				Next
			EndIf
			$Bombs[$i][0] = False
		Next

		;----------------------------------------------------------------------
		;							прорисовка перемещений
		;----------------------------------------------------------------------

		For $i=0 To $PlayerNumber-1
			GUICtrlSetPos($PlayerLabels[$i],$Player_X[$i],$Player_Y[$i])
		Next

		;----------------------------------------------------------------------
		;						показ статистики
		;----------------------------------------------------------------------
		For $i = 0 To $PlayerNumber-1
			If $PlayersHP[$i] > 0 Then
				GUICtrlSetData($PlayersStatLabel[$i],$PlayerNames[$i]&@CR&"HP = "&$PlayersHP[$i]&@CR&"X = "&Round($Player_X[$i])&@CR&"Y = "&Round($Player_Y[$i]))
			Else
				GUICtrlSetData($PlayersStatLabel[$i],"убит")
			EndIf
		Next

	WEnd

	Do
		$msg = GUIGetMsg()
	Until $Msg = $GUI_EVENT_CLOSE
	GUIDelete($BattleGUI)
EndFunc

Примеры роботов
Код:
#include <RobotsWarLight.au3>

;==============================================
;					CLIENT
;==============================================

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891
Local $playerName = "binary"

$ServerSocket = Connect_to_Server($ServerIPADDRESS, $ServerPort, $playerName)
If Wait_for_Start() <> 1 Then EmergencyEXIT()

Local $Hp = Health(), $i = 0

While $Hp > 0
	$rrr = Scan($i,10)
	If $rrr > 0 Then
		Detect($i,10)
	Else
		$i += 10
		If $i > 360 then $i -= 360
	EndIf
	$hhh  = Health()
	If $hhh = 0 Then ExitLoop
	If $hhh < $Hp Then
		$Hp = $hhh
		$ddd = Random(0,7,1)
		Move($ddd)
		Move($ddd)
		Move($ddd)
		$Hp	= Health()
	EndIf
WEnd

Func Detect($dir,$rang)
	Local $sc = Scan($dir,$rang)
	If $sc = 0 Then Return False
	If $rang <=1 Then
		Cannon($dir,$sc)
		Return True
	EndIf
	Local $tmpRang = $rang/2, $res = Detect($dir - $tmpRang, Ceiling($tmpRang))
	If Not $res Then $res = Detect($dir + $tmpRang, $tmpRang)
	Return $res
EndFunc
Код:
#include <RobotsWarLight.au3>

;==============================================
;					CLIENT
;==============================================

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891
Local $playerName = "movingX"

$ServerSocket = Connect_to_Server($ServerIPADDRESS, $ServerPort, $playerName)
If Wait_for_Start() <> 1 Then EmergencyEXIT()

Local $kurs = 2, $i=0

While Health() > 0
	$rrr = Scan($i,10)
	If $rrr > 0 Then $tmp = Cannon($i,$rrr)
	$i += 10
	If $i > 360 then $i -= 360

	If loc_x() < 10 Then $kurs = 2
	If loc_x() > 490 Then $kurs = 6
	Move($kurs)
WEnd
Код:
#include <RobotsWarLight.au3>

;==============================================
;					CLIENT
;==============================================

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891
Local $playerName = "sqr"

$ServerSocket = Connect_to_Server($ServerIPADDRESS, $ServerPort, $playerName)
If Wait_for_Start() <> 1 Then EmergencyEXIT()

Local $kurs = 2, $i=0
If loc_x() > 490 Then $kurs = 6

While Health() > 0
	$rrr = Scan($i,10)
	If $rrr > 0 Then $tmp = Cannon($i,$rrr)
	$i += 10
	If $i > 360 then $i -= 360

	If loc_x() = 490 Then
		If loc_y() < 490 Then
			$kurs = 4
		Else
			$kurs = 6
		EndIf
	EndIf
	If loc_x() = 10 Then
		If loc_y() > 10 Then
			$kurs = 0
		Else
			$kurs = 2
		EndIf
	EndIf
	Move($kurs)
WEnd
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
370
C2H5OH [?]
линии нарисовать то я могу, но не представляю как их убирать после выстрела
Была такая тема с рисованием отрезка и стиранием его, но все на GDIPlus. В кратце смысл такой: рисуем отрезок любого цвета, а для его стирания рисуем по верх него (по этим же координатам) другой, но цвета заднего фона ;)
 
Автор
C2H5OH

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Ну что ж, обратимся к начальной концепции "C Robots".
Роботы теперь стреляют не снарядами, а ракетами. Ракеты попадают в цель не мгновенно, а имеют собственную скорость, превышающую скорость роботов. Ракеты летят по несколько кривой траектории (в связи с округлением координат), но всегда прилетают в ту точку, куда были посланы.

Кроме того.
Заметил такую неприятную вещь - когда водишь мышкой над GUI битвы, то весь процесс ускоряется со страшной силой. Чтобы устранить это, избавился от GUIGetMsg() в основном цикле битвы. Заодно и мерцание ушло. :smile:
Код:
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <Math.au3>
#include <Timers.au3>
#Include <Array.au3>

;==============================================
;					SERVER
;==============================================

Global $continue_battle = True	; переменная-флаг для функции BATTLE

Global $PlayerNumber = 4
Global $PlayerColor[$PlayerNumber] = [0x008000, 0x5050FF, 0x8000FF, 0x7F4000]

Global $ServerIPADDRESS = @IPAddress1, $ServerPort = 33891,$MainSocket
Global $PlayersConnected[$PlayerNumber],$PlayersIP[$PlayerNumber],$PlayerPorts[$PlayerNumber]
Local $msg, $recv

; создаём GUI
$ServerGUI = GUICreate("Server", 300, $PlayerNumber*50+20)
Global $PlayerNames[$PlayerNumber],$PlayerStats[$PlayerNumber]
Global $Button1 = GUICtrlCreateButton("Start", 60, 20, 75, 25)
Global $Button2 = GUICtrlCreateButton("Reset", 160, 20, 75, 25)
For $i = 0 To $PlayerNumber-1
	$PlayerNames[$i] = GUICtrlCreateLabel("пусто", 30, 70 + $i*30, 75, 25, 1)
	$PlayerStats[$i] = GUICtrlCreateLabel("", 110, 70 + $i*30, 160, 25, 1)
	$PlayersConnected[$i] = -1
Next
GUISetState(@SW_SHOW)
; завершение созания GUI

TCPStartup()

$MainSocket = TCPListen($ServerIPADDRESS, $ServerPort)	; начинаем слушать порт
If $MainSocket = -1 Then Exit				; если порт уже занят, то на выход

While 1
	$msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE
			ExitLoop
		Case $Button1
			_BATTLE()
			RESET_Players()
			GUISwitch ($ServerGUI)
		Case $Button2
			RESET_Players()
		Case Else
			For $i = 0 To $PlayerNumber-1
				If $PlayersConnected[$i] = -1 Then
					$PlayersConnected[$i] = TCPAccept($MainSocket) ; если i-тый игрок не подключенн, то пробуем подключить
					;ExitLoop	; <- если включить ExitLoop
								; то игроки будут подключаться по порядку начиная с 1-го сокета
								; но при обрыве игрока его слот будет уже недоступен
				Else
					If $PlayersIP[$i] == "" Then	; если по игроку ещё нет статистики, то получаем её
						$PlayersIP[$i] = SocketToIP($PlayersConnected[$i])
						GUICtrlSetData($PlayerStats[$i],$PlayersIP[$i])
					EndIf
					$recv = TCPRecv($PlayersConnected[$i], 1024)	; получаем данные от подключившегося игрока
					If @error Then
						$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем слот
						GUICtrlSetData($PlayerNames[$i],"пусто")
						GUICtrlSetData($PlayerStats[$i],"")
					EndIf
						If $recv <> "" Then GUICtrlSetData($PlayerNames[$i],$recv)
				EndIf
			Next
	EndSwitch

WEnd

TCPShutdown()

; Function to return IP Address from a connected socket.
; один в один взял из справки
Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")
    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
            "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf
    $sockaddr = 0
    Return $aRet
EndFunc   ;==>SocketToIP


Func RESET_Players() ; отключаем всех игроков и обнуляем информацию о них
	For $i = 0 To $PlayerNumber-1
		GUICtrlSetData($PlayerNames[$i],"пусто")
		GUICtrlSetData($PlayerStats[$i],"")
		TCPCloseSocket($PlayersConnected[$i])
		$PlayersConnected[$i] = -1
	Next
EndFunc

;============================================================================================
;											BATTLE
;============================================================================================

Func stop_Battle()
	$continue_battle = False
EndFunc

Func _BATTLE()

	HotKeySet("{F10}", "stop_Battle")

	Local Const $dig_to_rad = 3.14159265358979 / 180	; перевод градусов в радианы
	Local Const $reload_time_ms = 3000		; время перезарядки пушки роботов
	Local Const $drivePower = 0.002			; мощность двигателя робота
	Local Const $Bomb_Damage = 10			; базовый урон от снарядов
	Local Const $Max_Cannon_Range = 350		; максимальная дальность стрельбы орудий
	Local Const $rocket_speed = 2			; сколко пролетает снаряд за такт

	Local $Players[$PlayerNumber], $Bombs[1]=[0], $TagetX[1]=[0], $TagetY[1]=[0], $Explode[1]=[0]
	Local $PlayersHP[$PlayerNumber],$Player_X[$PlayerNumber],$Player_Y[$PlayerNumber], _
		$Players_Reload_Timer[$PlayerNumber], $PlayersStatLabel[$PlayerNumber], $PlayerLabels[$PlayerNumber]

	; создаём GUI поля битвы
	Local $BattleGUI = GUICreate("Battle", 700, 505)
	GUISwitch ($BattleGUI)
	GUICtrlCreateLabel("", 0, 0, 499, 499, 1)
	GUICtrlSetBkColor(-1, 0xFFFFFF)
	Local $LivePlayers = 0
	For $i = 0 To $PlayerNumber-1
		$Players[$i] = GUICtrlRead($PlayerNames[$i])
		$PlayersStatLabel[$i] = GUICtrlCreateLabel($Players[$i], 530, 50 + $i*100, 160, 90, 1)
		GUICtrlSetColor(-1, $PlayerColor[$i])
		If $PlayersConnected[$i] <> -1 Then
			TCPSend($PlayersConnected[$i], "start")
			If @error Then
				$PlayersConnected[$i] = -1			; если игрок оторвался, то обнуляем
				$PlayersHP[$i] = 0
			Else
				$LivePlayers += 1
				$PlayersHP[$i] = 100
				$Player_X[$i] = Random(0,499,1)
				$Player_Y[$i] = Random(0,499,1)
				$PlayerLabels[$i] = GUICtrlCreateLabel("", $Player_X[$i], $Player_Y[$i], 5, 5, 1)
				GUICtrlSetBkColor(-1, $PlayerColor[$i])
				$Players_Reload_Timer[$i] = _Timer_Init()
			EndIf
		EndIf
	Next
	GUICtrlCreateLabel(" F10 - Stop", 570, 450, 70, 20, 1)
	GUISetState(@SW_SHOW)
	; завершение созания GUI

	While $continue_battle And $LivePlayers > 1
		$LivePlayers = 0
		For $i = 0 To $PlayerNumber-1
			If $PlayersHP[$i] > 0 Then
				$LivePlayers += 1

				;----------------------------------------------------------------------
				;							обмен данными с игроками
				;----------------------------------------------------------------------
				$recv = TCPRecv($PlayersConnected[$i], 256)	; получаем запрос от игрока
				If @error Then
					$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
					$PlayersHP[$i] = 0
					$LivePlayers -= 1
					ContinueLoop
				EndIf
				$zapros = StringSplit($recv,"/")
				Switch $zapros[1]
					Case "scan"
						$snd = 999999
						If $zapros[0] = 3 Then
							For $j = 0 To $PlayerNumber-1
								If $i=$j Then ContinueLoop
								If $PlayersHP[$j]=0 Then ContinueLoop
								$dX = $Player_X[$j] - $Player_X[$i]
								$dY = $Player_Y[$j] - $Player_Y[$i]
								Select
									Case $dX = 0
										If $dY < 0 Then
											$azimut = 90
										Else
											$azimut = 270
										EndIf
									Case $dX > 0
										$azimut = ATan($dY/$dX) / $dig_to_rad
										If $azimut < 0 Then $azimut += 360
									Case Else
										$azimut = 180 + ATan($dY/$dX) / $dig_to_rad
										If $azimut < 0 Then $azimut += 360
								EndSelect
								If $azimut >= ($zapros[2]-$zapros[3]) And $azimut <= ($zapros[2]+$zapros[3]) Then
									$snd = _Min($snd, Sqrt($dX*$dX + $dY*$dY))
								EndIf
							Next
						EndIf
						If $snd = 999999 Then $snd = 0
						TCPSend($PlayersConnected[$i], ""&$snd)	; без "" глючит чегойто
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "cannon"
						If $zapros[0] <> 3 Or _Timer_Diff($Players_Reload_Timer[$i]) < $reload_time_ms Then
							$snd = "reloading"
						Else
							$zapros[2] = Mod($zapros[2],360)
							If $zapros[3] < 0 Then $zapros[3] = 0
							If $zapros[3] > $Max_Cannon_Range Then $zapros[3] = $Max_Cannon_Range
							$aim_X = $Player_X[$i] + $zapros[3]*Cos($zapros[2]*$dig_to_rad)
							$aim_Y = $Player_Y[$i] + $zapros[3]*Sin($zapros[2]*$dig_to_rad)
							If $aim_X < 0 Then $aim_X = 0
							If $aim_X > 499 Then $aim_X = 499
							If $aim_Y < 0 Then $aim_Y = 0
							If $aim_Y > 499 Then $aim_Y = 499
							$Players_Reload_Timer[$i] = _Timer_Init()
							_ArrayAdd($TagetX,$aim_X)
							_ArrayAdd($TagetY,$aim_Y)
							$rocket = GUICtrlCreateLabel("",$Player_X[$i],$Player_Y[$i],2,2)
							GUICtrlSetBkColor($rocket,$PlayerColor[$i])
							_ArrayAdd($Bombs,$rocket)
							$snd = "cannonfired"
						EndIf
						TCPSend($PlayersConnected[$i], $snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "move"
						If $zapros[0] = 2 Then
							Switch $zapros[2]
								Case "0"
									$Player_Y[$i] -= 1
								Case "1"
									$Player_X[$i] += 1
									$Player_Y[$i] -= 1
								Case "2"
									$Player_X[$i] += 1
								Case "3"
									$Player_X[$i] += 1
									$Player_Y[$i] += 1
								Case "4"
									$Player_Y[$i] += 1
								Case "5"
									$Player_X[$i] -= 1
									$Player_Y[$i] += 1
								Case "6"
									$Player_X[$i] -= 1
								Case "7"
									$Player_X[$i] -= 1
									$Player_Y[$i] -= 1
							EndSwitch
						EndIf
						If $Player_X[$i] < 0 Then 	; если ударился в стенку
							$Player_X[$i] = 0
							$PlayersHP[$i] -= 1
						EndIf
						If $Player_X[$i] > 499 Then		; если ударился в стенку
							$Player_X[$i] = 499
							$PlayersHP[$i] -= 1
						EndIf
						If $Player_Y[$i] < 0 Then 	; если ударился в стенку
							$Player_Y[$i] = 0
							$PlayersHP[$i] -= 1
						EndIf
						If $Player_Y[$i] > 499 Then		; если ударился в стенку
							$Player_Y[$i] = 499
							$PlayersHP[$i] -= 1
						EndIf
						If $PlayersHP[$i]<0 Then $PlayersHP[$i]=0
						TCPSend($PlayersConnected[$i], "moved")
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "health"
						$snd = $PlayersHP[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "loc_x"
						$snd = $Player_X[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

					Case "loc_y"
						$snd = $Player_Y[$i]
						TCPSend($PlayersConnected[$i], ""&$snd)
						If @error Then
							$PlayersConnected[$i] = -1		; если игрок оторвался, то обнуляем
							$PlayersHP[$i] = 0
							$LivePlayers -= 1
							ContinueLoop
						EndIf

				EndSwitch

			EndIf

		Next

		;----------------------------------------------------------------------
		;							полёт снарядов
		;----------------------------------------------------------------------

		For $i=UBound($Bombs)-1 To 1 Step -1
			$tmpPOS = ControlGetPos($BattleGUI,"",$Bombs[$i])
			;MsgBox(0,"bomb","x="&$tmpPOS[0]&" y="&$tmpPOS[1])
			$dX = $TagetX[$i] - $tmpPOS[0]
			$dY = $TagetY[$i] - $tmpPOS[1]
			$range = sqrt($dX*$dX+$dY*$dY)
			If $range > $rocket_speed Then
				GUICtrlSetPos($Bombs[$i],Round($tmpPOS[0]+$dX*$rocket_speed/$range),Round($tmpPOS[1]+$dY*$rocket_speed/$range))
			Else
				GUICtrlSetPos($Bombs[$i],$TagetX[$i],$TagetY[$i],5,5)
				GUICtrlSetBkColor($Bombs[$i],0xFF0000)
				GUICtrlSetColor($Bombs[$i],0xFF0000)
				GUICtrlSetData($Bombs[$i],3)
				_ArrayAdd($Explode,$Bombs[$i])
				_ArrayDelete($Bombs, $i)
				_ArrayDelete($TagetX,$i)
				_ArrayDelete($TagetY,$i)
			EndIf
		Next

		;----------------------------------------------------------------------
		;						рассчет повреждений от взрывов
		;----------------------------------------------------------------------

		For $i=UBound($Explode)-1 To 1 Step -1
			$tmpCLR = GUICtrlRead($Explode[$i])
			Switch $tmpCLR
				Case 0
					GUICtrlDelete($Explode[$i])
					_ArrayDelete($Explode,$i)
					ContinueLoop
				Case 3
					$tmpPOS = ControlGetPos($BattleGUI,"",$Explode[$i])
					For $j = 0 To $PlayerNumber-1
						If $PlayersHP[$j]=0 Then ContinueLoop
						$dX = $Player_X[$j] - $tmpPOS[0]
						$dY = $Player_Y[$j] - $tmpPOS[1]
						$range = sqrt($dX*$dX+$dY*$dY)
						$damage = $Bomb_Damage * Floor(50/(10+$range))/5
						$PlayersHP[$j] -= $damage
						If $PlayersHP[$j]<0 Then $PlayersHP[$j]=0
					Next
					GUICtrlSetData($Explode[$i],$tmpCLR-1)
				Case Else
					GUICtrlSetData($Explode[$i],$tmpCLR-1)
			EndSwitch
		Next

		;----------------------------------------------------------------------
		;							прорисовка перемещений
		;----------------------------------------------------------------------

		For $i=0 To $PlayerNumber-1
			GUICtrlSetPos($PlayerLabels[$i],$Player_X[$i],$Player_Y[$i])
		Next

		;----------------------------------------------------------------------
		;						показ статистики
		;----------------------------------------------------------------------
		For $i = 0 To $PlayerNumber-1
			If $PlayersHP[$i] > 0 Then
				GUICtrlSetData($PlayersStatLabel[$i],$Players[$i]&@CR&"HP = "&$PlayersHP[$i]&@CR&"X = "&Round($Player_X[$i])&@CR&"Y = "&Round($Player_Y[$i]))
			Else
				GUICtrlSetData($PlayersStatLabel[$i],$Players[$i]&@CR&"убит")
			EndIf
		Next

		Sleep(10)
	WEnd

	HotKeySet("{F10}")

	Do
		$msg = GUIGetMsg()
	Until $Msg = $GUI_EVENT_CLOSE
	GUIDelete($BattleGUI)
EndFunc

Вот теперь думаю, перезарядку оставить на _Timer_Diff или привязать к количеству тактов битвы. На таймерах вроде бы нормально, но, если подумать, то получается что на компьютерах с разной производительностью роботы между выстрелами успевают выполнить разное количество операций. Результат получается потенциально зависим от производительности сервера.
 
Верх