728x90
반응형
SMALL

enumerate

 - 순회 가능한(iterable) 객체(예: 리스트, 튜플, 문자열)를 입력으로 받아 인덱스와 해당 요소를 순회할 수 있는 이터레이터(iterator)를 반환

 - 반복문에서 현재 요소의 인덱스를 함께 사용하고자 할 때 유용함

 

enumerate 예제

 

animals = ['cat', 'dog', 'rabbit']

for index, animal in enumerate(animals):
    print("Index:", index, "Animal:", animal)

 

출력 결과

 

Index: 0, Animal: cat
Index: 1, Animal: dog
Index: 2, Animal: rabbit

 

위의 예제에서 enumerate() 함수는 리스트 animals의 각 요소와 해당 인덱스를 함께 반환합니다.

728x90
반응형
LIST

'IT > 파이썬 문법' 카테고리의 다른 글

파이썬 sort, sorted 함수에 key, lambda 사용  (0) 2024.05.08
파이썬 sort, sorted 함수 차이  (0) 2024.05.08
파이썬 zip 함수 사용하기  (0) 2024.05.08
파이썬 map 함수  (0) 2024.05.08
변수  (0) 2022.03.26
728x90
반응형
SMALL
import speech_recognition as sr
import pyttsx3
import openai

openai.api_key = "openai key"

# Initialize the recognizer
r = sr.Recognizer()

# Initialize the voice engine
voice_engine = pyttsx3.init()

#스피치 목소리 타입 0: K, 1: female, 2: male
voices = voice_engine.getProperty('voices') 
voice_engine.setProperty('voice', voices[0].id)
voice_engine.setProperty('rate', 170)
		

# Function to convert text to speech
def SpeakText(user_text,command):
	
	#음성 파일 저장
	voice_engine.save_to_file(command, '/answer.mp3')

	#TTS 실행
	voice_engine.say(command)

	voice_engine.runAndWait()
	
	

def main():

	# 무한 
	with sr.Microphone() as source:
		r.adjust_for_ambient_noise(source, duration=0.2)

		while True:
	
			try:
				print('listen...')

				#listens for the user's input
				user_audio = r.listen(source)
				
				# Using google to recognize audio
				user_text = r.recognize_google(user_audio)
				user_text = user_text.lower()

				print("Did you say: ",user_text)
			
				completion = openai.ChatCompletion.create(
					model="gpt-3.5-turbo",
					messages=[
					{"role": "user", "content": user_text}
					]
				)

				#chatgpt 결과 출력
				print(completion.choices[0].message.content)

				SpeakText(user_text,completion.choices[0].message.content)

			
			except sr.RequestError as e:
				print("Could not request results; {0}".format(e))
		
			except sr.UnknownValueError:
				print("unknown error occurred")

if __name__ == "__main__":
    main()
728x90
반응형
LIST
728x90
반응형
SMALL

클라이언트 코드 입니다.

 

from tkinter import * # tkinter에서 모든 정의를 임포트한다.
import time
import pygame
import random
import time

import socket
import ast
import json
import threading

class GameClient:
	def __init__(self,user,host,port):
		#사용자 아이디에서 공백 제거
		user = user.replace(" " , "")

		#네트워크 초기화 및 서버 연결
		#		
		self.port = port		# 연결 포트설정
		self.host = host		#서버 IP		
		self.user = user		#사용자 아이디 설정

		self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.client_socket.connect((self.host, self.port))

		#서버 연결 확인을 위한 패킷 송수신
		self.client_socket.sendall(self.user.encode())#서버에 사용자 아이디 전송
		data = self.client_socket.recv(1024)#서버응답 받기
		data = data.decode()#서버에서 받은 데이터를 문자열로 변환

		#서버 접속 확인: 접속 실패시 프로그램 종료
		if "Success" in data: print("서버에 접속하였습니다.")
		elif "Fail" in data:
			print(self.user, "동일한 사용자가 존재합니다. 사용자를 변경하기 바랍니다.")
			exit()
		else:
			print("서버에 접속에 실패하였습니다.","프로그램을 종료합니다.")
			exit()
		
		#서버에서 전송된 사용자 데이터를 저장하는 변수
		self.user_data={}
		
		#
		self.receive_thread = threading.Thread(target=self.handle_receive)
		self.receive_thread.daemon = True
		self.receive_thread.start()


		#게임윈도우 만들기 시작...
		print("게임윈도우를 생성합니다.")

		window = Tk() # 윈도우 생성
		window.title("네트워크게임예제") # 제목을 설정
		window.geometry("1440x960") # 윈도우 크기 설정
		window.resizable(0,0) # 윈도우 크기 조절 X
		
		self.lightingTimer = time.time() # 일정 주기로 lighting effect 효과를 위한 타임 변수

		
		self.keys=set() # 중복된 사용자 입력 키 값을 쉽게 제거하기 위해 set 타입으로 선언
		self.canvas = Canvas(window, bg = "white")
		self.canvas.pack(expand=True,fill=BOTH)

		window.bind("<KeyPress>",self.keyPressHandler)
		window.bind("<KeyRelease>",self.keyReleaseHandler)
		
		
		self.img_dragon = [PhotoImage(file='image/dragon-animated-gif.gif',format = 'gif -index %i' %(i)).subsample(3) for i in range(40)]
		self.img_light_effect = PhotoImage(file="image/lightning-effect-png2.png")
		self.img_fire = PhotoImage(file = "image/fire_type2.png")
		self.img_bg = PhotoImage(file="image/bgimage2.png")		
		self.img_enemy = PhotoImage(file='image/spaceship.png').subsample(6)

		#배경 그리기.
		self.canvas.create_image(0,0, image = self.img_bg,anchor = NW,tags="bg")

		self.isDebugMode = False

		#캔버스에 그려질 미사일에 대한 100 개의 더미 생성, 안보이게 설정
		self.fire_obj_list = []
		self.fire_obj_debug_list = []
		for i in range(100):
			self.fire_obj_list.append(self.canvas.create_image(0,0, image = self.img_fire,state='hidden', tags="fire"))
			self.fire_obj_debug_list.append(self.canvas.create_rectangle(0,0,5,5, fill='white',state='hidden', tags="fire"))
			

		#캔버스에 그려질 적에 대한 100 개의 더미 생성, 안보이게 설정
		self.enemy_obj_list = []
		self.enemy_obj_debug_list = []
		for i in range(100):
			self.enemy_obj_list.append(self.canvas.create_image(0,0, image = self.img_enemy,state='hidden', tags="enemy"))
			self.enemy_obj_debug_list.append(self.canvas.create_rectangle(0,0,140,65,state='hidden', tags="enemy"))
								
        #배경사운드
		pygame.init()
		pygame.mixer.music.load("sound/bgm.wav") #Loading File Into Mixer
		pygame.mixer.music.play(-1) #Playing It In The Whole Device

		#충돌 이펙트 사운드
		self.sounds = pygame.mixer
		self.sounds.init()
		self.s_effect1 = self.sounds.Sound("sound/destruction.mp3")

		self.canvas.create_text(150,60,fill="white",font="Times 15 italic bold",text="입력키: ↑ , ↓ , ← , → , space")
		self.canvas.create_text(720,810,fill="white",font="Times 20 italic bold",text="Network Game Example")
		self.canvas.create_text(720,850,fill="white",font="Times 20 italic bold",text="Major of computer software, Gyeongsang National Universityty")

		#
		user_list_in = set()

		while True:

			#사용자 입력이 있을 경우 서버로 데이터 전송
			if(len(self.keys)>0):#각 키값을 ',' 구분된 아스키 코드 값으로 전송
				self.client_socket.sendall(','.join(str(e) for e in self.keys).encode())

			fire_obj_idx = 0
			
			user_list_from_server = set()

			for key, value in self.user_data.items():
				if key != 'enemy':
					try:
						obj = self.canvas.find_withtag(key)
					except:
						print('프로그램을 종료합니다.')
						exit()
					
					img_dragon_idx = value[0]%len(self.img_dragon)

					if len(obj)==0:
						if self.user != key:
							print(key,' 사용자가 입장하였습니다.')
						self.canvas.create_image(value[1],value[2], image = self.img_dragon[img_dragon_idx],tags=key)
						self.canvas.create_text(value[1]+self.img_dragon[img_dragon_idx].width()/2,value[2]+self.img_dragon[img_dragon_idx].height()/2+20, font="Times 20 italic bold",fill='#ff00ff',text=key+' '+str(value[4]),tag=key)
						user_list_in.add(key)
						user_list_from_server.add(key)
					else:
						self.canvas.itemconfig(obj[0], image = self.img_dragon[img_dragon_idx])
						self.canvas.moveto(obj[0],value[1],value[2])

						#itemcget(item_id,속성): canvas item 들의 속성 값 가져오기
						pre_text = self.canvas.itemcget(obj[1],'text')
						post_text = key+' '+str(value[4])

						#값이 다르면 text 속성 업데이트, 충돌 사운드 재생
						if pre_text != post_text:
							self.canvas.itemconfig(obj[1], text=post_text)
							self.s_effect1.play()

						self.canvas.moveto(obj[1],value[1]+self.img_dragon[img_dragon_idx].width()/2,value[2]+self.img_dragon[img_dragon_idx].height()/2+20)
						user_list_from_server.add(key)

					for i in range(len(value[3])):
						if(fire_obj_idx < len(self.fire_obj_list)):
							self.canvas.itemconfig(self.fire_obj_list[fire_obj_idx],state='normal')
							self.canvas.moveto(self.fire_obj_list[fire_obj_idx],value[3][i][0],value[3][i][1])
							
							if self.isDebugMode:
								self.canvas.itemconfig(self.fire_obj_debug_list[fire_obj_idx],state='normal')
							else:
								self.canvas.itemconfig(self.fire_obj_debug_list[fire_obj_idx],state='hidden')

							self.canvas.moveto(self.fire_obj_debug_list[fire_obj_idx],value[3][i][0]+50,value[3][i][1])

							fire_obj_idx += 1
						else:#만약 보여되는 미사일 수가 더미로 미사일 수보다 많으면 추가로 만들기
							self.fire_obj_list.append(self.canvas.create_image(value[3][i][0],value[3][i][1], image = self.img_fire, tags="fire"))

							if self.isDebugMode:
								self.fire_obj_debug_list.append(self.canvas.create_rectangle(value[3][i][0],value[3][i][1],value[3][i][0]+5,value[3][i][1]+5, fill='white', tags="fire"))
							else:
								self.fire_obj_debug_list.append(self.canvas.create_rectangle(value[3][i][0],value[3][i][1],value[3][i][0]+5,value[3][i][1]+5, state='hidden', fill='white', tags="fire"))


			#서버에 접속이 끊긴 사용자들 제거
			user_list_exit = user_list_in - user_list_from_server			
			for u in list(user_list_exit):
				print(u,' 사용자가 퇴장하였습니다.')
				user_list_in.remove(u)
				objs = self.canvas.find_withtag(u)
				for o in objs:
					self.canvas.delete(o)
					
			#사용되지 않은 미사일 이미지들은 안보이게 설정
			for i in range(fire_obj_idx,len(self.fire_obj_list)):
				self.canvas.itemconfig(self.fire_obj_list[i],state='hidden')
				self.canvas.itemconfig(self.fire_obj_debug_list[i],state='hidden')

			enemy_obj_idx = 0
			#
			for p in self.user_data['enemy']:
				if(enemy_obj_idx < len(self.enemy_obj_list)):
					self.canvas.itemconfig(self.enemy_obj_list[enemy_obj_idx],state='normal')
					self.canvas.moveto(self.enemy_obj_list[enemy_obj_idx],p[0],p[1])

					if self.isDebugMode:
						self.canvas.itemconfig(self.enemy_obj_debug_list[enemy_obj_idx],state='normal')
					else:
						self.canvas.itemconfig(self.enemy_obj_debug_list[enemy_obj_idx],state='hidden')

					self.canvas.moveto(self.enemy_obj_debug_list[enemy_obj_idx],p[0],p[1])

					enemy_obj_idx += 1
				else:#만약 보여되는 적 수가 더미 적 수보다 많으면 추가로 만들기
					self.enemy_obj_list.append(self.canvas.create_image(p[0],p[1], image = self.img_enemy, tags="enemy"))

					if self.isDebugMode:
						self.enemy_obj_debug_list.append(self.canvas.create_rectangle(p[0],p[1],p[0]+5,p[1]+5, fill='red',  tags="enemy"))
					else:
						self.enemy_obj_debug_list.append(self.canvas.create_rectangle(p[0],p[1],p[0]+5,p[1]+5, state='hidden', fill='red',  tags="enemy"))

			#사용되지 않은 적 이미지들은 안보이게 설정
			for i in range(enemy_obj_idx,len(self.enemy_obj_list)):
				self.canvas.itemconfig(self.enemy_obj_list[i],state='hidden')
				self.canvas.itemconfig(self.enemy_obj_debug_list[i],state='hidden')

			self.display_lighting_effect()
			window.after(33)
			window.update()

		#
		self.client_socket.close()
		self.receive_thread.join()
		

	def keyReleaseHandler(self, event):
		if event.keycode==68:
			self.isDebugMode = not self.isDebugMode


		key = str(event.keycode)
		if key in self.keys:
		    self.keys.remove(key)

	def lighting_effect(self):
		for i in range(0,random.randint(5,15)):
		    self.canvas.create_image(random.randint(0,self.canvas.winfo_width()),random.randint(0,self.canvas.winfo_height()), image = self.img_light_effect,anchor = NW,tags="lighting")
		
	def display_lighting_effect(self):		

		if(self.lightingTimer == -1):
			self.lightingTimer = time.time()
			self.lighting_effect()
		else:
			now = time.time()
			if(now - self.lightingTimer > 4.0):
			    self.lightingTimer = -1
			elif(now - self.lightingTimer > 2.0):
			    lightings = self.canvas.find_withtag("lighting")
			    for light in lightings:
			        self.canvas.delete(light)


	def keyPressHandler(self, event):
		key = str(event.keycode)
		self.keys.add(key)
	
	def handle_receive(self):
		while True:
			try:
				data = self.client_socket.recv(1024)#데이터가 수신될 때까지 대기함
			except:
				print("서버 연결 끊김")
				break			
			#byte를 문자열로 디코딩
			data = data.decode()
			#디코딩된 문자열은 json 형식으로 되어 있음
			#네트워크 딜레이로 인해 누적된 패킷중 마지막 패킷만 추출하기
			data = data[:data.rfind('}')+1]
			data = data[data.rfind('{'):]
			#패킷의 형식 오류 확인
			if len(data) > 0 and data[0] =='{' and data[-1] == '}':
				#json 형식을 딕셔너리 타입으로 변환 후 저장
				self.user_data = json.loads(data)
			else:
				pass#print('패킷오류')

			
if __name__ == '__main__':
	#사용자 아이디, 서버 IP, 연결포트 설정
	GameClient('CKang','127.0.0.1',4000) # GameClient 생성한다.

 

서버 코드입니다.

import socket
import argparse
import threading
import time
import random
import json

user_data = {'enemy':[]}
user_socket = {}

user_image_size = [280,249]
user_missile_size = [50,10]
user_enemy_size = [140, 65]
user_wnd_size = [1440,960]

#frame, 위치 x, 위치 y, 미사일, 점수
user_ini_data = [0,100,480-user_image_size[1]/2,[],0]


def handle_sendToUsers():
    while 1:

          #모든 미사일의 위치값 업데이트
        for key in user_data.keys():
            if key != 'enemy':
                for i in range(len(user_data[key][3])):
                    user_data[key][3][i][0] += 9
                    
                    #미사일, 적 충돌 체크
                    isChecked = False
                    for e in user_data['enemy']:
                        if e[0] < user_data[key][3][i][0]+user_missile_size[0] and user_data[key][3][i][0]+user_missile_size[0] < e[0] + user_enemy_size[0] and e[1] < user_data[key][3][i][1] and user_data[key][3][i][1] < e[1] + user_enemy_size[1]:
                            e[0] = -1440 #충돌된 적은 화면을 벗어나게 하기
                            user_data[key][4] += 1#사용자 점수 증가
                            #print(key,'명중:',user_data[key][4])
                            isChecked=True

                    if isChecked:
                        user_data[key][3][i][0] = 2880#충돌된 미사일은 화면을 벗어나게 하기


                #화면을 벗어난 미사일 데이터 제거
                user_data[key][3] = [e for e in user_data[key][3] if e[0]<user_wnd_size[0]]


        #각 사용자의 프레임 번호 업데이트
        for key in user_data.keys():
            if key != 'enemy':
                user_data[key][0] += 1
        #적 생성
        if (random.randint(0,100) == 0 and len(user_data.keys())>1):		
            user_data['enemy'].append([user_wnd_size[0],random.randint(10, user_wnd_size[1]-10)])

        # 적 이동
        for e in user_data['enemy']:
            e[0] -= 4

        # 화면 밖으로 벗어난 적 데이터 제거
        user_data['enemy'] = [e for e in user_data['enemy'] if e[0]>-user_enemy_size[0]]        


        #각 서버에 저장된 사용자 데이터를 모든 클라이언트에 전송
        for con in user_socket.values():  
            #딕셔너리 타입을 json 포맷 변환후 바이트형으로 인코딩
            user_encode_data = json.dumps(user_data).encode()
            #사용자에게 전송함
            try:
                con.sendall(user_encode_data)
            except:
                pass
      
        time.sleep(0.03)
            

def handle_receive(client_socket, addr, user):   
    
    missile_time = time.time()
        
    while 1:
        try:
            #클라이언트로부터 데이터 올때까지 대기함
            data = client_socket.recv(1024)
            #클라이언트로부터 받은 데이터를 문자열 변환후 입력 키 값들을 분리한다.
            key_list = data.decode().split(',')
            for key in key_list:
                if key == '39' and user_data[user][1] < (user_wnd_size[0]-user_image_size[0]/2): # right direction key
                    user_data[user][1] = user_data[user][1] + 5
                elif key == '37' and -user_image_size[0]/2 < user_data[user][1]: # left direction key
                    user_data[user][1] = user_data[user][1] - 5
                elif key == '38' and -user_image_size[1]/2 < user_data[user][2]: # up direction key
                    user_data[user][2] = user_data[user][2] - 5
                elif key == '40' and user_data[user][2] < (user_wnd_size[1]-user_image_size[1]/2): # down direction key
                    user_data[user][2] = user_data[user][2] + 5
                elif key == '32':
                    now = time.time()
                    #미사일 연사속도 조절
                    if (now-missile_time) > 0.4:#0.4초
                        missile_time = now
                        #사용자의 현재 위치값을 이용하여 미사일 최초 위치 설정하고 미사일 위치 데이터 저장
                        user_data[user][3].append([user_data[user][1]+user_image_size[0]/2+95,user_data[user][2]+user_image_size[1]/2+12])
            
        except:
            print(user,': 연결 끊김')
            break

    del user_data[user]
    del user_socket[user]
    client_socket.close()

if __name__ == '__main__':

    host = "127.0.0.1"
    port = 4000
    

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    server_socket.bind((host, port))
    server_socket.listen(5)# 클라이언트 최대 접속 수
    
    
    send_thread = threading.Thread(target=handle_sendToUsers)
    send_thread.daemon = True
    send_thread.start()

    print('게임서버를 시작합니다.')

    
    
    while 1:
        try:            
            client_socket, addr = server_socket.accept()#클라이언트 접속 까지 대기
        except KeyboardInterrupt:            
            for user, con in user_socket:
                con.close()
            server_socket_tcp.close()
            print("Keyboard interrupt")
            break

        user = client_socket.recv(1024)        
        user = user.decode()
        
        if user in user_data:
            print(user,'와 동일한 접속자가 있습니다.(접속실패)')
            client_socket.sendall("Fail: 동일한 사용자가 존재합니다.".encode())
        else:
            print(user,'서버에 접속하였습니다.')
            client_socket.sendall("Success".encode())

            user_socket[user] = client_socket
            user_data[user] = list(user_ini_data)

            receive_thread = threading.Thread(target=handle_receive, args=(client_socket, addr,user))
            receive_thread.daemon = True
            receive_thread.start()

 

게임 사운드 코드

 

게임 사운드

from tkinter import * import pygame class GameSound: def __init__(self): window = Tk() # 윈도우 생성 window.title("게임사운드") # 제목을 설정 window.geometry("640x480") # 윈도우 크기 설정 window.resizable(0,0) self.canvas = Canvas(win

ckang.tistory.com

네트워크 채팅 코드

 

파이썬 네트워크 통신 채팅 프로그램 서버 클라이언트 예제

# 서버코드import socketimport argparseimport threadingimport timeuser_list = {}def handle_receive(client_socket, addr, user): while 1: data = client_socket.recv(1024) data = data.decode() if data == "/종료" or data == "/exit" : break print(user,data)

ckang.tistory.com

GUI 메뉴 만들기 코드

 

파이썬 tkinter canvas GUI 게임 메뉴 만들기 코드

tkinter 를 이용하여 메뉴 만들기 코드 입니다.아래 이미지파일을 다운로드받고 소스코드와 같은 폴더에서 복사하여 주세요from tkinter import *class Menu: def __init__(self): window = Tk() window.title("키보드 이

ckang.tistory.com

 

728x90
반응형
LIST
728x90
반응형
SMALL

 

 

# 서버코드
import socket
import argparse
import threading
import time

user_list = {}

def handle_receive(client_socket, addr, user):
    while 1:
        data = client_socket.recv(1024)
        data = data.decode()

        if data == "/종료" or data == "/exit" : break        
        print(user,data)

        #받은 데이터를 모든 클라이언트에게 전송한다.
        for con in user_list.values():
            try:
                con.sendall(data.encode())
            except:
                print("클라이언트 소켓 에러")

    del user_list[user]
    client_socket.close()

if __name__ == '__main__':

    host = "host_ip" #127.0.0.1
    port = 4000

    #IPv4 체계, TCP 타입 소켓 객체를 생성
    # socket.AF_INET: 해당 소켓을 IP version 4 용으로 사용하겠다는 의미
    # socket.SOCK_STREAM: 해당 소켓에 TCP 패킷을 받겠다는 의미
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #포트를 사용 중 일때 에러를 해결하기 위한 구문
    #기본적으로 socket을 사용하고 나면 사용한 port는 close로 닫아주는게 맞다.
    #그래야 해당 port를 다른데서도 사용할 수 있으니깐.
    #근데 port를 닫았다고해도 일정시간 동안은 TIME_WAIT 상태로 대기한다고 한다.
    #그리고 이 상태에서는 즉각적으로 다시 바로 사용할 수 없다.
    #그래서 socket을 쓰고 close를 했는데도 already in use 에러가 발생하게된다.
    #이런 에러를 막기위해서 setsockopt을 사용한다. 사용법은 아래와 같다.
    #socket.SO_REUSEADDR: 방금 사용하고 close한 port를 즉시 다시 사용한다는 의미
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    #ip주소와 port번호를 함께 socket에 바인드 한다.
    #포트의 범위: 1~65535
    server_socket.bind((host, port))
    server_socket.listen(5)# 클라이언트 최대 접속 수

    print('채팅서버를 시작합니다.')
    while 1:
        try:
            #클라이언트 함수가 접속하면 새로운 소켓을 반환한다.
            client_socket, addr = server_socket.accept()#클라이언트 접속까지 대기함
        except:            
            #의도하지 않은 서버 종료에 대한 예외 처리
            #프로그램 중단시 모든 클라이언트 소켓들 닫기.
            for user, con in user_list:
                con.close()
            server_socket.close()            
            break

        user = client_socket.recv(1024)
        user = user.decode()
        print(user,'서버에 접속하였습니다.')
        user_list[user] = client_socket
                        
        #daemon 속성은 서브쓰레드가 데몬 쓰레드인지 아닌지를 지정하는 것인데,
        #데몬 쓰레드란 백그라운드에서 실행되는 쓰레드로 메인 쓰레드가 종료되면 즉시 종료되는 쓰레드이다.
        #반면 데몬 쓰레드가 아니면 해당 서브쓰레드는 메인 쓰레드가 종료할 지라도 자신의 작업이 끝날 때까지 계속 실행된다.
        receive_thread = threading.Thread(target=handle_receive, args=(client_socket, addr,user))
        receive_thread.daemon = True
        receive_thread.start()
import socket
import threading

def handle_receive(client_socket, user):
    while True:
        try:
            data = client_socket.recv(1024)#데이터가 수신될 때까지 대기함
        except:
            print("연결 끊김")
            break
        data = data.decode()#바이트 타입의 데이터를 decode()로 문자열로 변환
        if not user in data:#자신의 데이터를 제외한 나머지 데이터를 출력함
            print(data)

def handle_send(client_socket, user):
    while True:        
        data = input()#사용자로부터 문자열을 입력받는 함수
        #데이터는 encode()함수를 이용하여 바이트형으로 변환
        client_socket.sendall(data.encode())#소켓을 통해 서버로 데이터 보내기
        if data == "/종료" or data == "/exit": break
    client_socket.close()
    print('소켓 닫기')


if __name__ == '__main__':
    
    port = 4000 # 포트넘버
    host = 'server_ip' #서버 IP #127.0.0.1
    user = 'user_id'

    #IPv4 체계, TCP 타입 소켓 객체를 생성
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 지정한 host와 prot를 통해 서버에 접속합니다.
    client_socket.connect((host, port))

    # 문자열을 전송할 때 encode()을 이용한다. 파이썬 문자열의 encode() 메소드는 문자열을 byte로 변환해주는 메소드이기 때문이다.
    # 파이썬 내부에서 다뤄지는 문자열은 파이썬에서 생성된 객체이고, 이를 바로 트랜스포트에 그대로 싣는 것은 불가능합니다.
    # 그러므로 적절한 인코딩을 하여 보내야만 합니다.
    # 만약 encode()을 사용하지 않을 경우 에러가 발생 한다. 
    client_socket.sendall(user.encode())

    receive_thread = threading.Thread(target=handle_receive, args=(client_socket, user))
    receive_thread.daemon = True
    receive_thread.start()

    send_thread = threading.Thread(target=handle_send, args=(client_socket, user))
    send_thread.daemon = True
    send_thread.start()

    #join()은 부모쓰레드가 자식 쓰레드가 종료될 때까지 기다려준다.
    #즉 전체 프로그램의 실행이 하나의 쓰레드이고 부모쓰레드가 되며,
    #먼저 send_thread, receive_thread가 종료된후 프로그램이 종료하게 된다.
    send_thread.join()    
    receive_thread.join()
728x90
반응형
LIST
728x90
반응형
SMALL

tkinter 를 이용하여 메뉴 만들기 코드 입니다.

아래 이미지파일을 다운로드받고 소스코드와 같은 폴더에서 복사하여 주세요

arrow.png
0.32MB

from tkinter import *

class Menu:
    def __init__(self):
        window = Tk()
        window.title("키보드 이벤트")
        window.geometry("640x480")
        self.menu_idx = 0
        self.canvas=Canvas(window, bg ="white")
        self.canvas.pack(expand=True, fill=BOTH)
        window.bind("<KeyPress>",self.keyPressHandler)
        window.bind("<KeyRelease>",self.keyReleaseHandler)
        self.canvas.create_text(320,360,font="Times 15 italic bold",text="Menu Example")
                
        self.canvas.create_text(320,160,font="Times 15 italic bold",text="Menu 1")
        self.canvas.create_text(320,200,font="Times 15 italic bold",text="Menu 2")
        self.canvas.create_text(320,240,font="Times 15 italic bold",text="Menu 3")

        self.menustr = "Menu selection: "
        self.menu_id = self.canvas.create_text(320,320,font="Times 15 italic bold",text=self.menustr)    


        self.arrowimg = PhotoImage(file="arrow.png").subsample(20)
        self.arrow = self.canvas.create_image(250,160, image = self.arrowimg,tags="arrow")
        while True:
            #
            #
            window.after(33)
            window.update()

    def keyReleaseHandler(self, event):
        if event.keycode == 38 and self.menu_idx > 0: # up direction key
            self.menu_idx = self.menu_idx - 1
            self.canvas.move(self.arrow, 0, -40)
        if event.keycode == 40 and self.menu_idx < 2: # down direction key
            self.menu_idx = self.menu_idx + 1
            self.canvas.move(self.arrow, 0, 40)
        if event.keycode == 32:
            self.menustr = "Menu selection: " + str(self.menu_idx)
            self.canvas.itemconfigure(self.menu_id, text=self.menustr)#object 속성 수정

    def keyPressHandler(self,event):
        print(event.keycode)


Menu()

게임 사운드 코드

 

게임 사운드

from tkinter import * import pygame class GameSound: def __init__(self): window = Tk() # 윈도우 생성 window.title("게임사운드") # 제목을 설정 window.geometry("640x480") # 윈도우 크기 설정 window.resizable(0,0) self.canvas = Canvas(win

ckang.tistory.com

네트워크 채팅 코드

 

파이썬 네트워크 통신 채팅 프로그램 서버 클라이언트 예제

# 서버코드import socketimport argparseimport threadingimport timeuser_list = {}def handle_receive(client_socket, addr, user): while 1: data = client_socket.recv(1024) data = data.decode() if data == "/종료" or data == "/exit" : break print(user,data)

ckang.tistory.com

슈팅 게임 서버 클라인 언트 코드

 

파이썬 네트워크 게임 서버 클라이언트 (socket, ast, json, threading)

클라이언트 코드 입니다. from tkinter import * # tkinter에서 모든 정의를 임포트한다.import timeimport pygameimport randomimport timeimport socketimport astimport jsonimport threadingclass GameClient: def __init__(self,user,host,port):

ckang.tistory.com

 

728x90
반응형
LIST
728x90
반응형
SMALL

tkinter 를 이용한 마우스 이벤트는

window에 bind 함수를 이용하여 마우스 이벤트를 각각 연결시킨다.

 

이때 bind() 함수는 다음과 같이 두 개의 이자를 가져야 한다.

 - bind("이벤트명",연결함수) #이벤트 연결을 위한 가장 중요한 함수!!!!!

 

이벤트 종류는 다음과 같다.

<Button-1> : 마우스 왼쪽 버튼 클릭
<Button-2> : 마우스 중간 버튼 클릭
<Button-3> : 마우스 오른쪽 버튼 클릭
<Button-4> : 마우스 휠을 스크롤바에서 위로 올릴 때(scroll up event)
<Button-5> : 마우스 휠을 스크롤바에서 아래로 내릴 때(scroll down event)
<ButtonPress> : 아무 마우스 버튼이라도 눌리면 호출 된다. 휠까지도
<Double-Button-1> : 마우스 왼쪽 버튼 더블 클릭
<Double-Button-2> : 마우스 중간 버튼 더블 클릭
<Double-Button-3> : 마우스 오른쪽 버튼 더블 클릭
<Return> : 엔터가 눌러짐
<Key> : 키가 눌러짐
<Enter> : 마우스 포인터가 위젯에 들어올 때
<Leave> : 마우스 포인터가 위젯을 떠날때
<Configure> : 위젯 사이즈에 변화가 있을때

 

이중에서 마우스와 관련 된 이벤트를 적용한 코드 예제는 아래와 같다.

from tkinter import *

class MouseEvent:
    def __init__(self):
        window = Tk()
        window.title("마우스 이벤트")
        window.geometry("640x480")
        
        self.canvas=Canvas(window, bg ="white")
        self.canvas.pack(expand=True, fill=BOTH)
        window.bind("<Button-1>",self.MouseClickEvent)
        window.bind('<Double-1>', self.MouseDoubleClickEvent)
        window.bind('<B1-Motion>', self.MouseMotionEvent) 

        self.mousestr = "Mouse: "
        self.mouse_id = self.canvas.create_text(320,240,font="Times 15 italic bold",text=self.mousestr)    
        self.canvas.create_text(320,360,font="Times 15 italic bold",text="Mouse Event Example")
        
        while True:
            #
            self.canvas.itemconfigure(self.mouse_id, text=self.mousestr)
            #
            window.after(33)
            window.update()

    def MouseClickEvent(self, event):
        self.mousestr = "Mouse: " + str(event.x) + ", " + str(event.y) + "에서 마우스 클릭 이벤트 발생"
        

    def MouseDoubleClickEvent(self, event):
        self.mousestr = "Mouse: " + str(event.x) + ", " + str(event.y) + "에서 마우스 더블 클릭 이벤트 발생"

    def MouseMotionEvent(self, event):
        self.mousestr = "Mouse: " + str(event.x) + ", " + str(event.y) + "에서 마우스 모션 이벤트 발생"


MouseEvent()
728x90
반응형
LIST
728x90
반응형
SMALL

애니메이션 이미지는 여러개의 이미지가 겹쳐진 gif 포맷으로 되어 있다

그 이미지를 파이썬에 적용하기 위해서는 gif 가 몇장의 이미지로 구성되어 있는지 확인을 해야한다.

[gif png, jpg 이미지 추출 방법]

gif 읽기 방법은 gif 의 이미지들 모두 읽어서 각각 리스트에 저장하고

 

다음 이미지를 한장씩 보여주면서 애니메이션이 재생되는 방식이다.

 

그래서 리스트에 gif 에 포함된 모든 이미지를 저장하고 index를 증가시키면서 다음이미지를 보여준다.

 

for 문과 PhotoImage 함수를 이용하여 gif 파일 안에 이미지를 하나씩 읽어 올 수 있다. 이때 중요한 부분은 format 설정임(아래 코드 참조)

 

dragon-gif.gif
0.43MB

 

from tkinter import * # tkinter에서 모든 정의를 임포트한다.


class LoadGIFImage:
	def __init__(self):
		window = Tk() # 윈도우 생성
		window.title("GIF Image Example") # 제목을 설정
		window.geometry("640x480") # 윈도우 크기 설정
		window.resizable(0,0)        
		self.canvas = Canvas(window, bg = "white")
		self.canvas.pack(expand=True,fill=BOTH)	
		
		self.my_image_number = 0 
		#마지막 range(60) 에서 60 은 gif 이미지 수를 나타냄
		#gif 파일의 이미지를 한장씩 읽고 리스트에 저장함
		self.myimages = [PhotoImage(file='dragon-gif.gif',format = 'gif -index %i' %(i)) for i in range(60)]
		
		
		#아래 코드에서 subsample(2) 는 이미지 크기를 작게함. 인수 값에 따라 작아짐
		#self.myimages = [PhotoImage(file='dragon-gif.gif',format = 'gif -index %i' %(i)).subsample(1) for i in range(60)]

		#이미지를 canvas에 그리고 id 값을 생성후 self.dragon 변수에 저장
		self.dragon = self.canvas.create_image(300,240, image = self.myimages[0],tags="dragon")

		self.canvas.create_text(320,360,font="Times 15 italic bold",text="Load GIF Image")

		while True:

			#canvas에서 self.dragon 이미지를 읽어오고 gif의 다음 이미지로 교체함
			self.canvas.itemconfig(self.dragon, image = self.myimages[self.my_image_number%len(self.myimages)])    

			self.my_image_number += 1
			window.after(33)
			window.update()

		#window.mainloop() # 이벤트 루프를 생성한다.


LoadGIFImage() # GUI 생성한다.

 

728x90
반응형
LIST
728x90
반응형
SMALL

아래 이미지, 사운드(효과음) 파일을 다운로드 받고 소스코드 폴더에 함께 복사한 후 실행시키기 바랍니다.

tank.png
0.14MB
tankmove.MP3
0.29MB

from tkinter import *
import pygame

class ObjectControlByKeyEvent:
    def __init__(self):
        window = Tk()
        window.title("키보드를 이용한 이미지 컨트롤")
        window.geometry("640x480")
        self.keys = set()
        self.canvas=Canvas(window, bg ="white")
        self.canvas.pack(expand=True, fill=BOTH)
        window.bind("<KeyPress>",self.keyPressHandler)
        window.bind("<KeyRelease>",self.keyReleaseHandler)
        
        self.tankimg = PhotoImage(file="tank.png").subsample(8)
        self.tank = self.canvas.create_image(320,240, image = self.tankimg,tags="tank")

        #Effect sound
        self.sounds = pygame.mixer
        self.sounds.init()
        self.s_effect1 = self.sounds.Sound("tankmove.mp3")
        
        self.canvas.create_text(320,350,font="Times 15 italic bold",text="← 또는 → 키를 입력하시오")
        self.canvas.create_text(320,450,font="Times 15 italic bold",text="Object Control By KeyEvent")

        while True:
            #
            self.display()
            window.after(33)
            window.update()

    def display(self):
        for key in self.keys:
            if key == 39: # right direction key                
                #self.s_effect1.play()
                self.canvas.move(self.tank, 5, 0)
            if key == 37: # left direction key                
                #self.s_effect1.play()
                self.canvas.move(self.tank, -5, 0)

    def keyReleaseHandler(self, event):
        if event.keycode in self.keys:
            #self.s_effect1.stop()
            self.keys.remove(event.keycode)

    def keyPressHandler(self,event):        
        self.keys.add(event.keycode)
        
ObjectControlByKeyEvent()
728x90
반응형
LIST
728x90
반응형
SMALL

파이썬에서 모든 이벤트 처리는 bind를 통해서 이루어진다. bind는 "묶다" 라는 의미로서 이벤트가 발생할 때 어떠 함수가 호출 되도록 할 것인지를 연결하는 역할을 합니다. 다른 언어에도 bind 이외에 다른 용어 또는 키워드를 사용하지만 동일한 의미를 가지고 있습니다.
 
파이썬에서 이벤트와 함수와의 연결은 아래와 같은 형식으로 작성을 합니다.
 

widget.bind("이벤트 종류",함수명)
 

위젯은 윈도우, 버튼, 라벨 등 을 작성하고 bind() 함수를 이용하여 위젯에 발생한 이벤트를 두번째로 작성된 함수명으로 전달을 합니다.  아래 코드는 window 위젯에 키 이벤트처리를 위한 기본 예제 코드입니다.

from tkinter import *


def keyPressHandler(event):
	print("Press: ",event.keycode)

def keyReleaseHandler(event):
	print("Release: ",event.keycode)

window = Tk()
window.geometry("640x480")

window.bind("<KeyPress>",keyPressHandler)
window.bind("<KeyRelease>",keyReleaseHandler)

window.mainloop()

키를 눌렀을 때 KeyPressHandler 함수가 호출되고 호출된 함수안에 작성된 print() 함수를 실행합니다(Line 4, 5). 이때 계속 누르고 있으면 연속으로 계속 호출되는 것이 아닌 키를 누르는 시점에 한 번 호출됩니다. 반대로 키를 떼는 순간 keyReleaseHandler() 함수를 호출합니다.
이벤트에 의해 호출되는 함수를 정의할 때는 항상 매개변수 1개를 선언해야 합니다. 매개변수의 역할은 이벤트가 발생할 때 이벤트에 대한 정보를 함께 함수로 전달하는데 이때 전달된 정보가 매개변수에 저장됩니다. 위 예제의 키 이벤트의 경우 어떤 키가 눌러졌는지 키 정보가 event 변수에 저장됩니다. 그리고 event.keycode는 눌러진 키의 아스키코드 값을 알 수 있습니다.
키보드 이외에 마우스와 같은 많은 이벤트들이 있으며 필요에 따라 직접 찾아서 사용해보기 바랍니다.
 
이제 키보드 이벤트 기능을 게임 기본구조 코드에 적용하도록 하겠습니다.
일반적으로 게임에서는 키 입력에 따른 콘텐츠를 조작을 위해 키보드 이벤트를 사용한다. 이때 2가지 중요한 이슈가 있는데,
 
첫번째는 2개 이상의 키입력을 어떻게 처리 할 것인가?
두번째는 이벤트 처리 시점 입니다.
 
2개 이상의 키를 눌렀을 때 눌러진 상태를 알려주는 친절한 프로그래밍 언어는 없습니다.(라이브러리에서 지원해주는 경우는 있음) 가령, 대각선 위(북동 방향)로 계속 이동하도록 프로그래밍을 한다고 가정을 하였을 때, →, ↑ 방향 키를 동시에 누르고 있으면 두 키가 눌러진 시점에서 이벤트만 한번이 발생하고 끝입니다. 아래와 같이 프로그래밍을 한다면 누르는 시점 한번만 이동하고 더이상 움직임이 없다는 것입니다.

def keyPressHandler(event):
	if (event.keycode==38):#아스키코드 38 는 ↑ 키
    	# 콘텐츠 위로 이동 코드
	elif (event.keycode==39):#아스키코드 39 는 → 키
    	# 콘텐츠 앞으로 이동 코드

그래서
1. 키 이벤트 발생한 시점에서 콘텐츠(이미지)의 이동 코드를 작성하면 안되고, 콘텐츠의 이동 코드는 다른 코드영역(무한루프 영역)에서 작성해야 합니다.
2. KeyPress 이벤트 처리 함수에는 어떤 키가 눌러졌는지에 대한 키 정보를 저장하는 코드를 작성합니다. 그리고 KeyRelease 에는 저장된 키 정보에서 떼어진 키를 삭제하는 코드를 작성합니다.
 
 
앞에 내용들을 포함하여 작성한 코드는 아래와 같습니다.

from tkinter import *

keys = set()

def keyReleaseHandler(event):
    if event.keycode in keys:
        keys.remove(event.keycode)

def keyPressHandler(event):
    keys.add(event.keycode)
        
window = Tk()
window.geometry("640x480")

window.bind("<KeyPress>",keyPressHandler)
window.bind("<KeyRelease>",keyReleaseHandler)                

while True:
	#
	if (len(keys)>0):
		print("Key: ", keys)
	#
	window.after(33)
	window.update()

눌러진 키 정보를 저장할 때는 파이썬 자료구조 중 집합인 set() 을 이용하였습니다. set() 의 경우 유일한 값만 가지기 때문에 동일한 키값을 입력해도 자동으로 하나로 처리가 되는 장점이 있습니다.
 
위 코드를 게임 기본 코드 구조에 적용하면 아래와 같습니다. 이벤트 처리 함수의 경우, 클래스 멤버함수이기 때문에 매개변수가 하나 더 추가 되며 두번째 매개변수에 이벤트 정보가 저장됩니다.

from tkinter import *

class KeyboardEvent:
    def __init__(self):
        window = Tk()
        window.title("키보드 이벤트")
        window.geometry("640x480")
        
        self.keys = set()
        self.canvas=Canvas(window, bg ="white")
        self.canvas.pack(expand=True, fill=BOTH)
        
        window.bind("<KeyPress>",self.keyPressHandler)
        window.bind("<KeyRelease>",self.keyReleaseHandler)                
        
        self.canvas.create_text(320,400,font="Times 15 italic bold",text="Key Event Example")
        
        while True:
            #
            if(len(self.keys)>0):
            	print("Key: ", self.keys)            
            #
            window.after(33)
            window.update()

    def keyReleaseHandler(self, event):
        if event.keycode in self.keys:
            self.keys.remove(event.keycode)

    def keyPressHandler(self,event):
        self.keys.add(event.keycode)

KeyboardEvent()
728x90
반응형
LIST
728x90
반응형
SMALL
from tkinter import *
import pygame

class GameSound:
	def __init__(self):
		window = Tk() # 윈도우 생성
		window.title("게임사운드") # 제목을 설정
		window.geometry("640x480") # 윈도우 크기 설정
		window.resizable(0,0)        
		
		
		self.canvas = Canvas(window, bg = "white")
		self.canvas.pack(expand=True,fill=BOTH)
		window.bind("<KeyPress>",self.keyPressHandler)
		window.bind("<KeyRelease>",self.keyReleaseHandler)

		#pygame 에서 music vs sound
		# music: 배경음악 재생을 위해 사용
		# sound: 효과음을 위해 사용

        #BG sound.
		pygame.init()
		pygame.mixer.music.load("bgm.wav") #Loading File Into Mixer
		pygame.mixer.music.play(-1) #Playing It In The Whole Device
		self.canvas.create_text(320,400,font="Times 15 italic bold",text="Sound Example")

		#Effect sound
		self.sounds = pygame.mixer
		self.sounds.init()
		self.s_effect1 = self.sounds.Sound("gunsound.mp3")
				
		while True:
			#
			window.after(33)
			window.update()

	def keyReleaseHandler(self, event):
		if event.keycode in self.keys:
		    self.keys.remove(event.keycode)

	def keyPressHandler(self, event):		
		self.s_effect1.play()
		self.keys.add(event.keycode)

GameSound()

tkinter에서는 사운드와 관련된 클래스 및 함수를 제공하지 않습니다.  그래서 코드에서는 pygame 모듈을 이용하여 사운드 재생방법을 설명을 하도록 하겠습니다. (앞서 설명된 게임 기본 코드 구조 위에서 추가된 내용들만 설명)

 

사운드의 종류는 크게 기본적으로 배경사운드, 이펙트사운드로 구분될 수 있습니다. 배경사운드는 게임의 전체적인 분위기를 담당하고 이펙트 사운드는 그 순간의 효과 또는 느낌(타격감, 행위(점프, 스피드업, 아이템 획득), 죽음 등)을 담당하며, 사운드를 게임의 진행에 있어서 필수적인 요소입니다. 그래서 위 코드에서는 배경사운드와 이펙트사운드의 재생 방법에 대해서 설명하도록 하겠습니다.

 

pygame에서 사운드 재생 방법은 music와 sound 이렇게 2가지를 제공하고 있습니다.

차이점은 music의 경우 하나의 재생만 가능하고 만약 다른 파일을 load() 해서 재생하면 기존 재생은 멈추게 되며, 반대로 sound 는 여러 개가 동시 재생이 가능하고 같은 사운드의 중첩해서 재생도 가능합니다.

그리고 music의 경우 파일이 저장된 장치(ssd 또는 hard disk 등)에서 재생을 하지만 sound의 경우 파일 전체를 메모리에 가져온 후 재생하게 됩니다. 즉 music은 큰 용량을 가진 음악 파일 재생에 유리하며 sound의 경우 작은 용량과 짧은 사운드(이펙트)에 유리합니다.

그러므로 music의 경우 배경사운드에 이용되고 sound의 경우 이펙트사운드에 사용합니다.

 

위 소스에 대한 주요 코드 설명은 아래와 같습니다.

  • pygame 모듈을 사용하기 위해 pygame을 import 한다.(line 2)
  • pygame을 사용하기 위해서는 pygame.init()함수를 호출해야한다.(line 21)
  • 위 코드에서 music.load(), music.play() 함수를 이용하여 배경음악을 무한반복 재생한다.(line 22, 23)
  • effect sound를 위해 sounds 를 초기화 한다.(line 28)
  • 이펙트 사운드 'gunsound.mp3'  파일을 읽고 sound 객체를 반환한다. sound 객체는 이펙트 사운드는 게임중 재생 및 멈춤을 컨트롤할 수 있다.
  • line 41에서 이펙트 사운드를 재생한다.

위 코드만으로 간단히 게임에서 필요한 음악 재생은 가능하며 좀 더 다양한 기능을 구현하기 위해서는 아래의 링크를 참조하기 바랍니다.

 

 

https://www.pygame.org/docs/ref/music.html

 

pygame.mixer.music — pygame v2.1.1 documentation

Resets playback of the current music to the beginning. If pause() has previoulsy been used to pause the music, the music will remain paused. Note rewind() supports a limited number of file types and notably WAV files are NOT supported. For unsupported file

www.pygame.org

https://www.pygame.org/docs/ref/mixer.html

 

pygame.mixer — pygame v2.1.1 documentation

begin sound playback play(loops=0, maxtime=0, fade_ms=0) -> Channel Begin playback of the Sound (i.e., on the computer's speakers) on an available Channel. This will forcibly select a Channel, so playback may cut off a currently playing sound if necessary.

www.pygame.org

 

 

728x90
반응형
LIST

+ Recent posts