added server communication between client and server

This commit is contained in:
steev 2024-01-07 19:26:41 +01:00
parent fab79061ea
commit 6adea1730e
31 changed files with 173 additions and 129 deletions

View File

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 612 B

View File

@ -1,7 +1,7 @@
{
"id": 1,
"name": "Test Monster",
"image": "Assets/Cards/testmonstercard/cards.png",
"image": "Assets/Cards/1/cards.png",
"description": "can attack other monsters",
"costs": 30,
"defense": 40,

View File

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,6 +1,6 @@
{
"name": "testspell",
"image":"Assets/Cards/testspelltcard/artwork.png",
"image":"Assets/Cards/2/artwork.png",
"costs": 30,
"description":"this is a test spell card"
}

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,6 @@
{
"name": "testtrap",
"image":"Assets/Cards/3/artwork.png",
"costs": 30,
"description":"this is a test trap card"
}

View File

@ -1,6 +0,0 @@
{
"name": "testtrap",
"image":"Assets/Cards/testtrapcard/artwork.png",
"costs": 30,
"description":"this is a test tryp card"
}

View File

@ -1,14 +0,0 @@
import json
import pygame
class Card(pygame.sprite.Sprite):
def __init__(self, pos:tuple, assetDir:str):
if assetDir == "":
return ValueError.add_note("Card: imagePath cannot be empty")

View File

@ -1,9 +1,8 @@
import json
from typing import Any
import pygame
from Classes.System.Components.InputHandler import InputHandler
from Classes.Game.Player import Player
class MonsterCard(pygame.sprite.Sprite):
__name:str
@ -15,16 +14,18 @@ class MonsterCard(pygame.sprite.Sprite):
__dragging:bool = False
__offset:pygame.Vector2 = pygame.Vector2(0,0)
__inputHandler: InputHandler
__owner:Player
image:pygame.image
rect:pygame.rect
def __init__(self, pos:pygame.Vector2, assetDir:str, inputHandler:InputHandler):
def __init__(self, pos:pygame.Vector2, assetDir:str, inputHandler:InputHandler, owner:Player):
if assetDir == "":
return ValueError.add_note("Card: imagePath cannot be empty")
pygame.sprite.Sprite.__init__(self)
data = json.load(open(assetDir + "/card.json"))
self.__owner = owner
self.__id = int(data["id"])
self.__pos = pos
self.__name = data["name"]
@ -42,7 +43,7 @@ class MonsterCard(pygame.sprite.Sprite):
self.__attacks.append(attack)
def update(self):
if self.getDragging():
if self.__dragging:
mouse_pos = self.__inputHandler.getMousePos()
self.__pos = mouse_pos
self.rect.center = self.__pos
@ -74,6 +75,9 @@ class MonsterCard(pygame.sprite.Sprite):
def getID(self) -> int:
return self.__id
def getOwner(self) -> Player:
return self.__owner
def setDragging(self, dragging:bool):
self.__dragging = dragging

View File

@ -0,0 +1,7 @@
from Classes.Game.World import World
# send from the server to tell the player the game starts
# gives the client its and the opponents stats (not cards!!)
def GameStart(world: World):
pass

View File

@ -1,42 +1,9 @@
import pygame
from Classes.Game.World import World
from Classes.System.Network.NetworkManager import NetworkManager
from Classes.Game.Cards.MonsterCard import MonsterCard
from Game_Client.Classes.Game.Cards.SpellCard import SpellCard
from Game_Client.Classes.Game.Cards.TrapCard import TrapCard
# the event the client sends to the server when it places a card
def PlaceMonsterCard(networkManager: NetworkManager, card:MonsterCard):
# todo: send card information to the server
# todo: required info is:
# - position
# - field type (used for validating what field the card is played in will be compared on server side)
# - card id (server will do the rest to fetch card info)
payload = {
"event":"placecard",
"card": card.getID(),
"pos": card.getPos(),
}
networkManager.udp.send(payload)
# the event the client sends to the server when it places a card
def PlaceSpellCard(networkManager: NetworkManager, card:SpellCard):
# todo: send card information to the server.
# todo: required info is:
# - position
# - field type (used for validating what field the card is played in will be compared on server side)
# - card id (server will do the rest to fetch card info)
payload = {
"event":"placecard",
"card": card.getID(),
"pos": card.getPos(),
}
networkManager.udp.send(payload)
# the event the client sends to the server when it places a card
def PlaceTrapCard(networkManager: NetworkManager, card:TrapCard):
def PlaceCard(networkManager: NetworkManager, card):
# todo: send card information to the server
# todo: required info is:
# - position
@ -51,5 +18,6 @@ def PlaceTrapCard(networkManager: NetworkManager, card:TrapCard):
networkManager.udp.send(payload)
# the event send from the server to display a card on the field
def CardPlaced(world:World):
def CardPlaced(world:World, card:int, pos:pygame.Vector2):
pass

View File

@ -3,11 +3,13 @@ import pygame
class Player:
__id:int
__hp:int
__mana:int
__name:str
__handCards:pygame.Sprite.Group
__handCards:pygame.sprite.Group
def __init__(self, hp:int, name:str):
def __init__(self, hp:int, mana:int, name:str):
self.__hp = hp
self.__mana = mana
self.__name = name
def setID(self, id:int):
@ -22,16 +24,20 @@ class Player:
def getHP(self) -> int:
return self.__hp
def getMana(self) -> int:
return self.__mana
def adjustHP(self, hp:int) -> int:
self.__hp = self.__hp + hp
def getHand(self) -> pygame.Sprite.Group:
def getHand(self) -> pygame.sprite.Group:
return self.__handCards
def AddToHand(self, card) -> pygame.Sprite.Group:
def AddToHand(self, card) -> pygame.sprite.Group:
self.__handCards.add(card)
return self.__handCards
def removeFromHand(self, pos:int) -> pygame.Sprite.Group:
def removeFromHand(self, pos:int) -> pygame.sprite.Group:
self.__handCards.remove(pos)
return self.__handCards

View File

@ -2,12 +2,18 @@ import pygame
from Classes.Game.BoardField import BoardField
from Classes.System.Components.Label import Label
from Classes.Game.Cards.MonsterCard import MonsterCard
from Classes.Game.Cards.SpellCard import SpellCard
from Classes.Game.Cards.TrapCard import TrapCard
from Classes.System.Components.InputHandler import InputHandler
from Classes.Game.Player import Player
class World():
__boardFields:list
__player:Player
__enemy:Player
__labels:list
__cards:pygame.sprite.Group()
__PlayerHandCards:pygame.sprite.Group()
__screen:pygame.surface
__cardWidth:int = 150
__cardHeight:int = 200
@ -16,11 +22,14 @@ class World():
def __init__(self, screen:pygame.surface, cardWidth:int=200, cardHeight:int=250, cardOffset:int=400):
self.__boardFields = []
self.__labels = []
self.__cards = []
self.__cards = pygame.sprite.Group()
self.__PlayerHandCards = pygame.sprite.Group()
self.__screen = screen
self.__cardWidth = cardWidth
self.__cardHeight = cardHeight
self.__cardOffset = cardOffset
self.__player = None
self.__enemy = None
self.buildGameWorld()
def buildGameWorld(self):
@ -42,17 +51,19 @@ class World():
pDeckPos = pygame.Vector2((self.__cardOffset + (((self.__cardWidth + 10) - 30 ) * 5)), pRow2Height)
pNamePos = pygame.Vector2(20, pRow2Height + 195)
pHPPos = pygame.Vector2(20, pRow2Height + 225)
pManaPos = pygame.Vector2(20, pRow2Height + 255)
# labeling
self.__labels.append(Label("PlayerHP", self.__screen, "1000 / 1000", pHPPos))
self.__labels.append(Label("PlayerName", self.__screen, "Player", pNamePos))
self.__labels.append(Label("PlayerName", self.__screen, "0", pManaPos))
self.__labels.append(Label("EnemyHP", self.__screen, "1000 / 1000", eHPPos))
self.__labels.append(Label("EnemyName", self.__screen, "Enemy", eNamePos))
self.__boardFields.append(BoardField("EnemyDeck", "Enemy", "Deck", eDeckPos, "Assets/Cards/Arena/field.png"))
self.__boardFields.append(BoardField("EnemyGraveyard", "Enemy", "Grave", eGravePos, "Assets/Cards/Arena/field.png"))
self.__boardFields.append(BoardField("PlayerDeck", "Player", "Deck", pDeckPos, "Assets/Cards/Arena/field.png"))
self.__boardFields.append(BoardField("PlayerGraveyard", "Player", "Grave", pGravePos, "Assets/Cards/Arena/field.png"))
self.__boardFields.append(BoardField("EnemyDeck", "Enemy", "Deck", eDeckPos, "Assets/Cards/0/field.png", "e-deck"))
self.__boardFields.append(BoardField("EnemyGraveyard", "Enemy", "Grave", eGravePos, "Assets/Cards/0/field.png", "e-grave"))
self.__boardFields.append(BoardField("PlayerDeck", "Player", "Deck", pDeckPos, "Assets/Cards/0/field.png", "P-deck"))
self.__boardFields.append(BoardField("PlayerGraveyard", "Player", "Grave", pGravePos, "Assets/Cards/0/field.png", "p-grave"))
# handle field creation
for i in range(5):
@ -61,10 +72,10 @@ class World():
eMonsterPos = pygame.Vector2((self.__cardOffset + (((self.__cardWidth + 10) - 30) * (i+1)), eRow1Height))
eEffectPos = pygame.Vector2((self.__cardOffset + (((self.__cardWidth + 10) - 30) * (i+1))), eRow2Height)
self.__boardFields.append(BoardField("PlayerMonsterField-"+str(i), "Player", "MonsterField", pMonsterPos, "Assets/Cards/Arena/field.png", "pm"+str(id)))
self.__boardFields.append(BoardField("PlayerEffectField-"+str(i), "Player", "EffectField", pEffectPos, "Assets/Cards/Arena/field.png", "pe"+str(id)))
self.__boardFields.append(BoardField("EnemyMonsterField-"+str(i), "Enemy", "MonsterField", eMonsterPos, "Assets/Cards/Arena/field.png", "em"+str(id)))
self.__boardFields.append(BoardField("EnemySpellTrapField-"+str(i), "Enemy", "EffectField", eEffectPos, "Assets/Cards/Arena/field.png", "ee"+str(id)))
self.__boardFields.append(BoardField("PlayerMonsterField-"+str(i), "Player", "MonsterField", pMonsterPos, "Assets/Cards/0/field.png", "pm"+str(id)))
self.__boardFields.append(BoardField("PlayerEffectField-"+str(i), "Player", "EffectField", pEffectPos, "Assets/Cards/0/field.png", "pe"+str(id)))
self.__boardFields.append(BoardField("EnemyMonsterField-"+str(i), "Enemy", "MonsterField", eMonsterPos, "Assets/Cards/0/field.png", "em"+str(id)))
self.__boardFields.append(BoardField("EnemySpellTrapField-"+str(i), "Enemy", "EffectField", eEffectPos, "Assets/Cards/0/field.png", "ee"+str(id)))
def getBoardFields(self) -> list:
return self.__boardFields
@ -81,9 +92,45 @@ class World():
def getCards(self) -> pygame.sprite.Group:
return self.__cards
def spawnCard(self, asset:str, pos:pygame.Vector2, inputHandler:InputHandler) -> MonsterCard:
self.__cards.add(MonsterCard(pos, asset, inputHandler))
def getHandCards(self) -> pygame.sprite.Group:
return self.__PlayerHandCards
def getPlayer(self) -> Player:
return self.__player
def getEnemy(self) -> Player:
return self.__enemy
def setPlayer(self, player:Player):
for label in self.__labels:
if label.getName() == "PlayerName":
label.setText(player.getName())
self.__player = player
def setEnemy(self, player:Player):
for label in self.__labels:
if label.getName() == "EnemyName":
label.setText(player.getName())
self.__enemy = player
def spawnMonsterCard(self, asset:str, pos:pygame.Vector2, inputHandler:InputHandler, owner:Player) -> MonsterCard:
card = MonsterCard(pos, asset, inputHandler, owner)
self.__cards.add(card)
return card
def spawnSpellCard(self, asset:str, pos:pygame.Vector2, inputHandler:InputHandler, owner:Player) -> SpellCard:
card = SpellCard(pos, asset, inputHandler, owner)
self.__cards.add(card)
return card
def spawnTrapCard(self, asset:str, pos:pygame.Vector2, inputHandler:InputHandler, owner:Player) -> TrapCard:
card = TrapCard(pos, asset, inputHandler, owner)
self.__cards.add(card)
return card
def spawnCards(self, cards:pygame.sprite.Group):
for card in cards:
self.__cards.append(card)
self.__cards.add(card)
def AddToPlayerHand(self, Card):
self.__PlayerHandCards.add(Card)

View File

@ -7,6 +7,8 @@ from Classes.System.Components.InputHandler import InputHandler
from Classes.Game.World import World
from Classes.System.Network.NetworkManager import NetworkManager
from Classes.Game.Events.Login import Login
from Classes.Game.Events.PlaceCard import PlaceCard
from Classes.Game.Player import Player
class App:
@ -24,8 +26,14 @@ class App:
self.__myFont = pygame.font.SysFont('Comic Sans MS', 30)
self.__window = Window(width=width, height=height, title=title)
self.__inputHandler = InputHandler()
self.__networkManager("127.0.0.1", "54322", "54323")
Login(self.__networkManager) # will login to the server
try:
self.__networkManager = NetworkManager("127.0.0.1", "54322", "54323")
Login(self.__networkManager) # will login to the server
except Exception as e:
print(f"failed to login due to error {e}")
print("server connection failed or got refused")
pass
# game word
self.__world = World(self.__window.getScreen())
@ -38,12 +46,12 @@ class App:
# create sprite groups
# todo: remove these and let server handle card creation instead
# blocker: server - client communication [WIP]
self.__world.spawnCard("Assets/Cards/MonsterCards/testmonstercard/", (pygame.Vector2(500, 1050), self.__inputHandler))
self.__world.spawnCard("Assets/Cards/MonsterCards/testmonstercard/", (pygame.Vector2(600, 1050), self.__inputHandler))
self.__world.spawnCard("Assets/Cards/MonsterCards/testmonstercard/", (pygame.Vector2(700, 1050), self.__inputHandler))
self.__world.spawnCard("Assets/Cards/MonsterCards/testmonstercard/", (pygame.Vector2(800, 1050), self.__inputHandler))
self.__world.spawnCard("Assets/Cards/MonsterCards/testmonstercard/", (pygame.Vector2(900, 1050), self.__inputHandler))
self.__world.spawnCard("Assets/Cards/MonsterCards/testmonstercard/", (pygame.Vector2(1000, 1050), self.__inputHandler))
self.__world.spawnMonsterCard("Assets/Cards/1/", pygame.Vector2(500, 1050), self.__inputHandler, Player(1000, 0, "test"))
self.__world.spawnMonsterCard("Assets/Cards/1/", pygame.Vector2(600, 1050), self.__inputHandler, Player(1000, 0, "test"))
self.__world.spawnMonsterCard("Assets/Cards/1/", pygame.Vector2(700, 1050), self.__inputHandler, Player(1000, 0, "test"))
self.__world.spawnMonsterCard("Assets/Cards/1/", pygame.Vector2(800, 1050), self.__inputHandler, Player(1000, 0, "test"))
self.__world.spawnMonsterCard("Assets/Cards/1/", pygame.Vector2(900, 1050), self.__inputHandler, Player(1000, 0, "test"))
self.__world.spawnMonsterCard("Assets/Cards/1/", pygame.Vector2(1000, 1050), self.__inputHandler, Player(1000, 0, "test"))
while self.__running:
self.__clock.tick(self.__FPS)
@ -57,7 +65,8 @@ class App:
self.__world.getCards().update()
# draw groups
self.__window.drawSpriteGroup(self.cards)
self.__window.drawSpriteGroup(self.__world.getCards())
self.__window.drawSpriteGroup(self.__world.getHandCards())
# event handler
self.handleEvent(pygame.event.get())
@ -95,7 +104,9 @@ class App:
card.rect.center = field.rect.center
field.image = card.image.copy()
card.setDragging(False)
elif self.__inputHandler.getPressed()[pygame.K_SPACE]:
print("card spawned")
self.__world.spawnMonsterCard("Assets/Cards/MonsterCards/testmonstercard/", self.__inputHandler.getMousePos(), self.__inputHandler)
elif event.type == pygame.MOUSEBUTTONUP:
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_pos = pygame.Vector2(mouse_x, mouse_y)
@ -104,6 +115,7 @@ class App:
card.setDragging(False)
# TODO: send place card event to server
# resets the currently selected card in order to prevent it getting moved
PlaceCard(self.__networkManager, card) # tells the server that the player placed this card
if not card == None:
card = None

View File

@ -1,17 +1,18 @@
import pygame
from Classes.Objects.World import World
from Classes.Objects.BoardField import BoardField
from Classes.Game.BoardField import BoardField
class InputHandler:
# returns pressed key
@staticmethod
def getPressed():
return pygame.key.get_pressed()
# takes in movement inputs and maps them to x and y axis
@staticmethod
def getInputAxis() -> tuple:
xvel:int = 0
yvel:int = 0
xvel = 0
yvel = 0
# construct x and y velocity input axis
if InputHandler.getPressed()[pygame.K_a] or InputHandler.getPressed()[pygame.K_LEFT]:
@ -25,20 +26,21 @@ class InputHandler:
return tuple((xvel, yvel))
def getMousePos(self) -> pygame.Vector2:
@staticmethod
def getMousePos() -> pygame.Vector2:
return pygame.Vector2(pygame.mouse.get_pos())
# get field under mousbutton
def getMouseHover(self, world:World) -> BoardField:
mouse_pos = self.getMousePos()
x_pos = mouse_pos.x / world.getCardWidth()
y_pos = mouse_pos.y / world.getCardHeight()
@staticmethod
def getMouseHover(mouse_pos: pygame.Vector2, world_card_width: int, world_card_height: int, board_fields: list) -> BoardField:
x_pos = mouse_pos.x / world_card_width
y_pos = mouse_pos.y / world_card_height
for field in world.getBoardFields():
for field in board_fields:
field_x = field.getPos().x
field_y = field.getPos().y
field_width = world.getCardWidth() # Annahme: Jedes Feld hat eine Breite von 1 Einheit
field_height = world.getCardHeight() # Annahme: Jedes Feld hat eine Höhe von 1 Einheit
field_width = world_card_width # Annahme: Jedes Feld hat eine Breite von 1 Einheit
field_height = world_card_height # Annahme: Jedes Feld hat eine Höhe von 1 Einheit
if field_x <= x_pos < field_x + field_width and field_y <= y_pos < field_y + field_height:
return field

View File

@ -1,8 +1,8 @@
import pygame
from pygame.locals import *
from Classes.Objects.BoardField import BoardField
from Classes.Objects.World import World
from Classes.Game.BoardField import BoardField
from Classes.Game.World import World
class Window:
__width:int = 800

View File

@ -2,7 +2,7 @@ import json
import socket
import threading
from Game_Client.Classes.System.Network.EventHandler import TCPEventHandler, UDPEventHandler
from Classes.System.Network.EventHandler import TCPEventHandler, UDPEventHandler
class NetworkManager:
class UDP:
@ -12,18 +12,21 @@ class NetworkManager:
self.udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.eventHandler = UDPEventHandler(self.udpSocket)
try:
self.udpSocket.bind((self.addr, self.port))
except Exception as e:
print(f"Error binding UDP socket: {e}")
# start listener thread
self.listen()
def send(self, message: dict):
self.udpSocket.sendto(json.dumps(message).encode(), (self.addr, self.port))
try:
self.udpSocket.sendto(json.dumps(message).encode(), (self.addr, self.port))
except Exception as e:
print(f"Error sending UDP data: {e}")
# starts a listener thread for udp data
def listen(self):
udpThread = threading.Thread(target=self.receive)
udpThread.daemon = True
udpThread.start()
def receive(self):
while True:
try:
@ -35,6 +38,11 @@ class NetworkManager:
print(f"Error receiving UDP data: {e}")
break
def listen(self):
udpThread = threading.Thread(target=self.receive)
udpThread.daemon = True
udpThread.start()
class TCP:
def __init__(self, addr: str, port: str):
self.addr = addr
@ -42,20 +50,19 @@ class NetworkManager:
self.tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.eventHandler = TCPEventHandler(self.tcpSocket)
# start listener thread
try:
self.tcpSocket.connect((self.addr, self.port))
except Exception as e:
print(f"Error connecting TCP socket: {e}")
# Starten des Listener-Threads
self.listen()
def connect(self):
self.tcpSocket.connect((self.addr, self.port))
def send(self, message: dict):
self.tcpSocket.sendall(json.dumps(message).encode())
# starts a listener thread for tcp data
def listen(self):
tcp_thread = threading.Thread(target=self.receive)
tcp_thread.daemon = True
tcp_thread.start()
try:
self.tcpSocket.sendall(json.dumps(message).encode())
except Exception as e:
print(f"Error sending TCP data: {e}")
def receive(self):
while True:
@ -68,6 +75,11 @@ class NetworkManager:
print(f"Error receiving TCP data: {e}")
break
def __init__(self, addr: str, port: str):
self.tcp = self.TCP(addr, port)
self.udp = self.UDP(addr, port)
def listen(self):
tcpThread = threading.Thread(target=self.receive)
tcpThread.daemon = True
tcpThread.start()
def __init__(self, addr: str, tcpport: str, udpport: str):
self.tcp = self.TCP(addr, tcpport)
self.udp = self.UDP(addr, udpport)