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

even though  비록 ~ 이지만 : 사실이 아닌 가정을 나타냄

 - ex) Even though I passed the test, I didn't leave here

내가 그 시험을 통과 했지만, 여기를 떠나지 않았다.

 

even if  비록 ~ 일지라도 : 실제 사실을 나타냄

 - ex) Even if I pass the test, I won't leave here.

내가 그 시험을 통과할지라도, 나는 여기를 떠나지 않을 것이다.

 

728x90
반응형
LIST

'영어' 카테고리의 다른 글

get there 뜻 예제  (0) 2024.05.04
receive, get 차이  (0) 2023.09.02
It's been ~ 시간이 흘렀다. 는 표현  (0) 2022.06.28
work out , exercise 차이  (0) 2022.06.27
출근하다 영어 표현  (0) 2022.06.27
728x90
반응형
SMALL

It's (It has) been 시간 (since ~): (~이래로) 시간이 흐르다.

 

It's been 2 hours: 2시간이 흘렀다.

It's been over 10 years: 10년이 넘었다.

It's been a while: 시간이 꽤 흘렀네~!.

 

It's been over 10 years since we broke up.: 우리가 헤어진 후로 10년이 넘었어.

It's been already a year since we started studying English together: 우리가 함께 영어공부를 시작한지 벌써 1년이 되었어요.

 

 

 

 

728x90
반응형
LIST

'영어' 카테고리의 다른 글

get there 뜻 예제  (0) 2024.05.04
receive, get 차이  (0) 2023.09.02
even though 와 even if 차이  (1) 2023.08.22
work out , exercise 차이  (0) 2022.06.27
출근하다 영어 표현  (0) 2022.06.27
728x90
반응형
SMALL

work out 과 exercise 는 둘 다 '운동하다 ' 라는 뜻을 가짐.

 

차이점

work out : (헬스장에서) 운동하는 것을 의미함.

 

exercise: 일반적인 운동에 대한 표현에서 사용됨. 걷기, 조깅 등....

728x90
반응형
LIST

'영어' 카테고리의 다른 글

get there 뜻 예제  (0) 2024.05.04
receive, get 차이  (0) 2023.09.02
even though 와 even if 차이  (1) 2023.08.22
It's been ~ 시간이 흘렀다. 는 표현  (0) 2022.06.28
출근하다 영어 표현  (0) 2022.06.27
728x90
반응형
SMALL

나는 (교통수단)로 출근한다.

 

 

예제 문장

1. 나는 버스타고 출근한다.

- I take a bus to work.

- I go to work by bus.

 

2. 나는 걸어서 출근한다.

- I walk to work.

- I go to work on foot.

- I go to work by walking.

 

 

 

 

728x90
반응형
LIST

'영어' 카테고리의 다른 글

get there 뜻 예제  (0) 2024.05.04
receive, get 차이  (0) 2023.09.02
even though 와 even if 차이  (1) 2023.08.22
It's been ~ 시간이 흘렀다. 는 표현  (0) 2022.06.28
work out , exercise 차이  (0) 2022.06.27
728x90
반응형
SMALL

아래 이미지 파일을 다운로드 & 소스와 같은 폴더에 복사후 실행하기 바랍니다.

arrow.png
0.32MB

 

protocol() 함수는 이벤트와 함수를 연결하는 기능을 하며 아래 코드에는 위도우 창 닫기 이벤트(WM_DELETE_WINDOW)와 on_closing() 함수를 연결하여, 윈도우 창을 닫을 때 on_closing() 함수를 호출합니다.

 

from tkinter import *


class StageCanvas:
    def __init__(self,window):
        self.window = window
        self.canvas=Canvas(self.window, bg ="white") # game scene canvas
        self.canvas.create_text(320,300,font="Times 15 italic bold",text="Backspace 키 메뉴로 돌아가기")
        self.canvas.create_text(320,360,font="Times 15 italic bold",text="Stage Scene")
        

    def display(self):
        pass

    def pack(self):
        self.canvas.pack(expand=True, fill=BOTH)

    def unpack(self):
        self.canvas.pack_forget()

    def keyReleaseHandler(self, event):
        if event.keycode == 8:
            return 0
        else:
            return -1

    def destroy(self):
        self.canvas.destroy()


class MenuCanvas:
    def __init__(self,window):
        self.window = window
        self.menu_idx = 0

        self.canvas=Canvas(self.window, bg ="white")# menu canvas

        self.canvas.create_text(320,360,font="Times 15 italic bold",text="Scene Change")
                
        self.canvas.create_text(320,160,font="Times 15 italic bold",text="Start")
        self.canvas.create_text(320,200,font="Times 15 italic bold",text="Option")
        self.canvas.create_text(320,240,font="Times 15 italic bold",text="Exit")


        self.arrowimg = PhotoImage(file="arrow.png").subsample(20)
        self.arrow = self.canvas.create_image(250,160, image = self.arrowimg,tags="arrow")


    def display(self):
        pass
        

    def pack(self):
        self.canvas.pack(expand=True, fill=BOTH)

    def unpack(self):
        self.canvas.pack_forget()


    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)
            return -1
        elif 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)
            return -1
        elif event.keycode == 32:
            return self.menu_idx


    def destroy(self):
        self.canvas.destroy()




class SceneChange:
    def __init__(self):
        self.window = Tk()
        self.window.title("장면전환")
        self.window.geometry("640x480")

        self.window.protocol("WM_DELETE_WINDOW", self.on_closing)

        self.scene_idx = 0
        
        self.stage = StageCanvas(self.window)
        self.menu = MenuCanvas(self.window)
        self.menu.pack()


        self.canvas_list = []
        self.canvas_list.append(self.stage)
        self.canvas_list.append(self.stage)

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

        while True:
            #
            #
            for canvas in self.canvas_list:
                canvas.display()


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

    def on_closing(self):
        for canvas in self.canvas_list:
            canvas.destroy()

        self.window.destroy()

    def keyReleaseHandler(self, event):

        result = -1

        if self.scene_idx == 0:
            result = self.menu.keyReleaseHandler(event)

        elif self.scene_idx == 1:
            result = self.stage.keyReleaseHandler(event)

        if self.scene_idx == 0 and result==0:
            self.scene_idx = 1
            self.menu.unpack()
            self.stage.pack()

        elif self.scene_idx==1 and result==0:
            self.scene_idx = 0
            self.menu.pack()#메뉴 canvas 나타남
            self.stage.unpack()# Main 장면 canvas 사라짐
                
    def keyPressHandler(self,event):
        print(event.keycode)


SceneChange()
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

+ Recent posts