본문 바로가기
Blockchain/Testnet

AO 테스트넷 가이드 4편

by GrayChoi 2024. 3. 5.
반응형

AO Testnet Guide 4편

Bots and Games

 

이전글 : AO 테스트넷 가이드 3편

 

 

 


 

 

1. Let's Play A Game

AO-EFFECT 게임이란

실시간으로 전 세계의 친구들이나 다른 플레이어와 경쟁 할 수 있는 게임이다.

 

규칙

- 각 플레이어의 체력은 100으로 시작하며 에너지는 0으로 시작한다.

- 40x40의 맵에서 시작한다.

- 에너지는 시간이 지남에 따라 100까지 보충된다.

- 맵을 탐색하고, 다른 플레이어를 찾아 공격해서 이겨야한다.

- 범위 내에 있을 때만 에너지를 사용하여 공격할 수 있다.

- 한 명의 플레이어만 남거나 할당된 시간이 만료되면 게임이 끝이난다.

 

2. 게임 Process ID 설정

// 게임 ID의 주소도 기존 9pe-GCPGdQ-WlCKBj1E7079s0Sl75DDOVgZwhA2RJYY에서 변경되었다.
aos> Game = "3HSmhQ-lHaCQlOKtq5GDgbVQXQ6mWIp40uUASAG13Xk"

 

3. 게임 토큰 요청 및 게임 서버 등록

// 게임 서버 등록
aos> Send({ Target = Game, Action = "Register" })
// 토큰 요청
aos> Send({ Target = Game, Action = "RequestTokens" })

 

 

게임에 참가하려면 토큰이 필요한데 위 명령어를 통해 토큰을 요청할 수 있다.

 

4. 게임참가

aos> Send({ Target = Game, Action = "Transfer", Recipient = Game, Quantity = "1000" })

토큰을 받은후 입장료를 지불하여 게임에 참가한다.

몇 초만 기다리면 플레이어 결제 상태에 대한 실시간 업데이트가 화면에 표시된다.

2명이상의 플레이어가 참가한 후, 2분 후에 게임이 시작된다.

 

5. 게임 플레이

// 예시
aos> Send({ Target = Game, Action = "PlayerMove", Player = ao.id, Direction = "DownRight"})
// 방향종류, 위의 예시에서 Direction = "DownRight" 부분을 아래 원하는 종류로 변경하면된다.
Up = {x = 0, y = -1},
Down = {x = 0, y = 1},
Left = {x = -1, y = 0},
Right = {x = 1, y = 0},
UpRight = {x = 1, y = -1},
UpLeft = {x = -1, y = -1},
DownRight = {x = 1, y = 1},
DownLeft = {x = -1, y = 1}

맵의 밖으로 이동하면 그 반대편으로 이동한다.

 

6. 공격

aos> Send({ Target = Game, Action = "PlayerAttack", Player = ao.id, AttackEnergy = "energy_integer"})

3x3 범위 내의 다른 플레이어를 공격하는데 축적된 에너지를 사용한다.

 

여기서부터 대충 한번 보고 바로 11번으로 넘어가도된다.

7. Announcement 전달 봇 만들기

// Ctrl + c 를 눌러 aos 밖으로 나온다
nano bot.lua
// 생성 후 아래 코드 복사 붙여넣기
Handlers.add(
"PrintAnnouncements",
Handlers.utils.hasMatchingTag("Action", "Announcement"),
function (msg)
print(msg.Event .. ": " .. msg.Data)
end
)

Ctrl x, Y, 엔터

핸들러의 이름은 "PrintAnnouncements"

내장된 특수 유틸리티로 hasMatchingTags를 사용하며

announcement의 메세지를 받을 때

변환하여 보여준다.

 

8. 리로드 및 테스트

.load bot.lua

 

9. 게임의 진행상태를 체크 봇 만들기

// Ctrl + c 입력 후 aos 밖으로 나온다.
nano bot.lua
// HandleAnnouncements 핸들러 코드를 아래의 코드로 대체한다.
Handlers.add(
"HandleAnnouncements",
Handlers.utils.hasMatchingTag("Action", "Announcement"),
function (msg)
ao.send({Target = Game, Action = "GetGameState"})
print(msg.Event .. ": " .. msg.Data)
end
)

Ctrl x, Y, 엔터

 

aos
.load bot.lua

 

10. 전체적으로 수정하기

nano bot.lua
//아래 코드로 전부 대체한다.
LatestGameState = LatestGameState or nil
Handlers.add(
"HandleAnnouncements",
Handlers.utils.hasMatchingTag("Action", "Announcement"),
function (msg)
ao.send({Target = Game, Action = "GetGameState"})
print(msg.Event .. ": " .. msg.Data)
end
)
Handlers.add(
"UpdateGameState",
Handlers.utils.hasMatchingTag("Action", "GameState"),
function (msg)
local json = require("json")
LatestGameState = json.decode(msg.Data)
ao.send({Target = ao.id, Action = "UpdatedGameState"})
print("Game state updated. Print \'LatestGameState\' for detailed view.")
end
)

Ctrl x, Y, 엔터

 

aos
.load bot.lua

 

11. Strategic Decisions and 자동 응답

// Ctrl + c로 aos 밖으로 나온 후
nano bot.lua
//아래 코드 전체로 대체
LatestGameState = LatestGameState or nil
InAction = InAction or false
Logs = Logs or {}
colors = {
red = "\27[31m",
green = "\27[32m",
blue = "\27[34m",
reset = "\27[0m",
gray = "\27[90m"
}
function addLog(msg, text)
Logs[msg] = Logs[msg] or {}
table.insert(Logs[msg], text)
end
function inRange(x1, y1, x2, y2, range)
return math.abs(x1 - x2) <= range and math.abs(y1 - y2) <= range
end
function decideNextAction()
local player = LatestGameState.Players[ao.id]
local targetInRange = false
for target, state in pairs(LatestGameState.Players) do
if target ~= ao.id and inRange(player.x, player.y, state.x, state.y, 1) then
targetInRange = true
break
end
end
if player.energy > 5 and targetInRange then
print(colors.red .. "Player in range. Attacking." .. colors.reset)
ao.send({Target = Game, Action = "PlayerAttack", Player = ao.id, AttackEnergy = tostring(player.energy)})
else
print(colors.red .. "No player in range or insufficient energy. Moving randomly." .. colors.reset)
local directionMap = {"Up", "Down", "Left", "Right", "UpRight", "UpLeft", "DownRight", "DownLeft"}
local randomIndex = math.random(#directionMap)
ao.send({Target = Game, Action = "PlayerMove", Player = ao.id, Direction = directionMap[randomIndex]})
end
InAction = false
end
Handlers.add(
"PrintAnnouncements",
Handlers.utils.hasMatchingTag("Action", "Announcement"),
function (msg)
if msg.Event == "Started-Waiting-Period" then
ao.send({Target = ao.id, Action = "AutoPay"})
elseif (msg.Event == "Tick" or msg.Event == "Started-Game") and not InAction then
InAction = true
ao.send({Target = Game, Action = "GetGameState"})
elseif InAction then
print("Previous action still in progress. Skipping.")
end
print(colors.green .. msg.Event .. ": " .. msg.Data .. colors.reset)
end
)
Handlers.add(
"GetGameStateOnTick",
Handlers.utils.hasMatchingTag("Action", "Tick"),
function ()
if not InAction then
InAction = true
print(colors.gray .. "Getting game state..." .. colors.reset)
ao.send({Target = Game, Action = "GetGameState"})
else
print("Previous action still in progress. Skipping.")
end
end
)
Handlers.add(
"AutoPay",
Handlers.utils.hasMatchingTag("Action", "AutoPay"),
function (msg)
print("Auto-paying confirmation fees.")
ao.send({ Target = Game, Action = "Transfer", Recipient = Game, Quantity = "1000"})
end
)
Handlers.add(
"UpdateGameState",
Handlers.utils.hasMatchingTag("Action", "GameState"),
function (msg)
local json = require("json")
LatestGameState = json.decode(msg.Data)
ao.send({Target = ao.id, Action = "UpdatedGameState"})
print("Game state updated. Print \'LatestGameState\' for detailed view.")
end
)
Handlers.add(
"decideNextAction",
Handlers.utils.hasMatchingTag("Action", "UpdatedGameState"),
function ()
if LatestGameState.GameMode ~= "Playing" then
InAction = false
return
end
print("Deciding next action.")
decideNextAction()
ao.send({Target = ao.id, Action = "Tick"})
end
)
Handlers.add(
"ReturnAttack",
Handlers.utils.hasMatchingTag("Action", "Hit"),
function (msg)
if not InAction then
InAction = true
local playerEnergy = LatestGameState.Players[ao.id].energy
if playerEnergy == undefined then
print(colors.red .. "Unable to read energy." .. colors.reset)
ao.send({Target = Game, Action = "Attack-Failed", Reason = "Unable to read energy."})
elseif playerEnergy == 0 then
print(colors.red .. "Player has insufficient energy." .. colors.reset)
ao.send({Target = Game, Action = "Attack-Failed", Reason = "Player has no energy."})
else
print(colors.red .. "Returning attack." .. colors.reset)
ao.send({Target = Game, Action = "PlayerAttack", Player = ao.id, AttackEnergy = tostring(playerEnergy)})
end
InAction = false
ao.send({Target = ao.id, Action = "Tick"})
else
print("Previous action still in progress. Skipping.")
end
end
)

Ctrl + x, Y, 엔터

 

aos
.load bot.lua

 

12.Expanding the Arena

// Ctrl + c 입력 후 밖으로 나온다.
nano ao-effect.lua
// 아래 전체 복사 후 붙여넣기
Width = 40
Height = 40
Range = 1
MaxEnergy = 100
EnergyPerSec = 1
AverageMaxStrengthHitsToKill = 3
function playerInitState()
return {
x = math.random(0, Width),
y = math.random(0, Height),
health = 100,
energy = 0
}
end
function onTick()
if GameMode ~= "Playing" then return end
if LastTick == undefined then LastTick = Now end
local Elapsed = Now - LastTick
if Elapsed >= 1000 then
for player, state in pairs(Players) do
local newEnergy = math.floor(math.min(MaxEnergy, state.energy + (Elapsed * EnergyPerSec // 2000)))
state.energy = newEnergy
end
LastTick = Now
end
end
function move(msg)
local playerToMove = msg.From
local direction = msg.Tags.Direction
local directionMap = {
Up = {x = 0, y = -1}, Down = {x = 0, y = 1},
Left = {x = -1, y = 0}, Right = {x = 1, y = 0},
UpRight = {x = 1, y = -1}, UpLeft = {x = -1, y = -1},
DownRight = {x = 1, y = 1}, DownLeft = {x = -1, y = 1}
}
if directionMap[direction] then
local newX = Players[playerToMove].x + directionMap[direction].x
local newY = Players[playerToMove].y + directionMap[direction].y
Players[playerToMove].x = (newX - 1) % Width + 1
Players[playerToMove].y = (newY - 1) % Height + 1
announce("Player-Moved", playerToMove .. " moved to " .. Players[playerToMove].x .. "," .. Players[playerToMove].y .. ".")
else
ao.send({Target = playerToMove, Action = "Move-Failed", Reason = "Invalid direction."})
end
onTick()
end
function attack(msg)
local player = msg.From
local attackEnergy = tonumber(msg.Tags.AttackEnergy)
local x = Players[player].x
local y = Players[player].y
if Players[player].energy < attackEnergy then
ao.send({Target = player, Action = "Attack-Failed", Reason = "Not enough energy."})
return
end
Players[player].energy = Players[player].energy - attackEnergy
local damage = math.floor((math.random() * 2 * attackEnergy) * (1/AverageMaxStrengthHitsToKill))
announce("Attack", player .. " has launched a " .. damage .. " damage attack from " .. x .. "," .. y .. "!")
for target, state in pairs(Players) do
if target ~= player and inRange(x, y, state.x, state.y, Range) then
local newHealth = state.health - damage
if newHealth <= 0 then
eliminatePlayer(target, player)
else
Players[target].health = newHealth
ao.send({Target = target, Action = "Hit", Damage = tostring(damage), Health = tostring(newHealth)})
ao.send({Target = player, Action = "Successful-Hit", Recipient = target, Damage = tostring(damage), Health = tostring(newHealth)})
end
end
end
end
function inRange(x1, y1, x2, y2, range)
return x2 >= (x1 - range) and x2 <= (x1 + range) and y2 >= (y1 - range) and y2 <= (y1 + range)
end
Handlers.add("PlayerMove", Handlers.utils.hasMatchingTag("Action", "PlayerMove"), move)
Handlers.add("PlayerAttack", Handlers.utils.hasMatchingTag("Action", "PlayerAttack"), attack)

 

Ctrl + x, Y, 엔터

 

aos
.load ao-effect.lua

 

귀찮지만 잘 따라와서 고생많았다.

 

여기까지 기본적인 Tutorial이 끝났으며

다음편에는 퀘스트를 진행하여 CRED를 얻을 것 이다.

 

다음글 : AO 테스트넷 퀘스트 가이드


 

스팸 댓글이 많아서 본 게시글의 댓글 확인을 안합니다.

궁금하신 점이 있다면 아래 채팅방으로 문의 부탁드립니다.

 

퍼가실 땐 출처 명시 부탁드립니다.

 


 

 

노드 대행 및 기타 문의

graychoi0920@gmail.com


 

노드그레이 텔레그램 공지방

 

노드그레이

그레이의 50가지 노드 그림자

t.me

 

노드그레이 텔레그램 채팅방

 

노드그레이 채팅방

공지방 : https://t.me/nodegray

t.me

 

반응형

'Blockchain > Testnet' 카테고리의 다른 글

Polymer 테스트넷 가이드 1편  (58) 2024.03.12
AO 테스트넷 퀘스트 가이드  (0) 2024.03.05
AO 테스트넷 가이드 3편  (0) 2024.03.05
AO 테스트넷 가이드 2편  (0) 2024.03.05
AO 테스트넷 가이드 1편  (0) 2024.03.04

댓글