개발로그

socket.io를 이용한 빙고 게임 구현 본문

IT

socket.io를 이용한 빙고 게임 구현

clohoon 2023. 10. 17. 23:22
채팅 앱에 이어 빙고 게임도 socket.io를 이용해 구현해보자!

 

 

완성된 빙고 게임

 

 

📌 빙고 게임 기능

1. 유저 이름 입력받기

2. 접속 중인 유저 이름 출력

3. 한 명이 게임을 시작하려 하면 막기, 알림 출력 (두 명 이상)

4. 게임 진행을 위해 턴 넘기기

5. 자기 턴이 아닐 경우 진행 불가능, 알림 출력

6. 숫자가 선택되면 상대방에게 알림 출력

7. 선택된 숫자에 글자 효과 주기

8. 게임이 진행 중일 때 상대방이 떠난 경우, 게임을 종료시키고 알림 출력하기

 

 

server.js

var express = require('express');
var app = express();
var http = require('http').Server(app); 
var io = require('socket.io')(http);    
var path = require('path');


// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));


app.get('/', (req, res) => {  
	res.render('main', { title: '온라인 빙고 게임', username: req.query.username });
});

var users = {};
var user_count = 0;
var turn_count = 0;


io.on('connection', function(socket){ 
	
	console.log('user connected : ', socket.id);
	
	socket.on('join', function (data) {
		var username = data.username;
		socket.username = username;
		
		users[user_count] = {};
		users[user_count].id = socket.id;
		users[user_count].name = username;
		users[user_count].turn = false;
		user_count++;
		
		io.emit('update_users', users, user_count);
	});
	
	socket.on('game_start', function (data) {
		socket.broadcast.emit("game_started", data);
		users[turn_count].turn = true;
		
		io.emit('update_users', users);
	});
	
	socket.on('select', function (data) {
		socket.broadcast.emit("check_number", data);
		
		users[turn_count].turn = false;
		turn_count++;
		
		if(turn_count >= user_count) {
			turn_count = 0;
		}
		users[turn_count].turn = true;
		
		io.sockets.emit('update_users', users);
	});
	
	socket.on('disconnect', function() {
		console.log('user disconnected : ', socket.id, socket.username);
		for(var i=0; i<user_count; i++){
			if(users[i].id == socket.id)
				delete users[i];
		}	
		
		user_count--;
		io.emit('update_users', users, user_count);
		io.emit('user_gone');
	});
});

http.listen(3000, function(){ 
	console.log('server on!');
});

 

main.js

var bingo = {
	is_my_turn: Boolean,
	socket: null,
		
	init: function(socket){
		var self = this;
		var user_cnt = 0;
		
		this.is_my_turn = false;
		
		socket = io();

		socket.on("check_number", function (data) {
			self.where_is_it(data.num);
			self.print_msg(data.username + "님이 '" + data.num + "'을 선택했습니다.");
		});
		
		socket.on("game_started", function(data){
			console.log("enter the game_started");
			self.print_msg(data.username + " 님이 게임을 시작했습니다.");
			$("#start_button").hide();
		});
		
		socket.on("update_users", function (data, user_count) {
			console.log(data);
			user_cnt = user_count;
			self.update_userlist(data, socket);
		});
		
		socket.on("user_gone", function(){
			self.print_msg("참가자 한 명이 게임을 종료했습니다.");
		});
		
		//join
		
		$("#un").click(function (){
			$("#un").hide();
			socket.emit("join", { username: $('#username').val() });
			$("#un").hide();
		});
		
		var numbers = [];
		for(var i=1; i<=25; i++){
			numbers.push(i);
		}
		
		numbers.sort(function (a,b) {
			var temp = parseInt(Math.random() * 10);
			var isOddOrEven = temp%2;
			var isPosOrNeg = temp > 5 ? 1 : -1;
			return (isOddOrEven*isPosOrNeg);
		});
		
		$("table.bingo-board td").each(function (i) {
			$(this).html(numbers[i]);
			
			$(this).click(function (){
				if(user_cnt == 1){
					self.print_msg("<알림> 최소 2명부터 게임이 가능합니다.");
				}
				else{
					self.select_num(this, socket);
				}
			});
		});
		
		$("#start_button").click(function () {
			if(user_cnt == 1){
			   self.print_msg("<알림> 최소 2명부터 게임이 가능합니다.");
			}
			else{
				socket.emit('game_start', { username: $('#username').val() });
				self.print_msg("<알림> 게임을 시작했습니다.");
				$("#start_button").hide();
			}
		});
		
	},
	
	// init 끝
	select_num: function (obj, socket) {
		if(this.is_my_turn && !$(obj).attr("checked")) {
			//send num to other players
			socket.emit("select", { username: $('#username').val(), num: $(obj).text() });		
			this.check_num(obj);
			
			this.is_my_turn = false;
		}
		else {
			this.print_msg("<알림> 차례가 아닙니다!");
		}
	},
	
	where_is_it: function (num) {
		var self = this;
		var obj = null;
		
		$("table.bingo-board td").each(function (i) {
			if ($(this).text() == num) {
				self.check_num(this);
			}
		});
	},
	
	check_num: function (obj) {
		$(obj).css("text-decoration", "line-through");
		$(obj).css("color", "lightgray");
		$(obj).attr("checked", true);
	},
	
	update_userlist: function (data, this_socket) {
		var self = this;
		$("#list").empty();
		console.log(data);
		
		$.each(data, function (key, value) {
			var turn = "(-) ";
			if(value.turn === true) {
				turn = "(*) ";
				
				if(value.id == this_socket.id ) {
					self.is_my_turn = true;
				}
			}
			if(value.id == this_socket.id){
				$("#list").append("<font color='DodgerBlue'>" + turn + value.name + "<br></font>");
			}
			else{
				$("#list").append("<font color='black'>" + turn + value.name + "<br></font>");
			}
		});
	},
	
	
	print_msg: function (msg) {
		$("#logs").append(msg + "<br />");
		$('#logs').scrollTop($('#logs')[0].scrollHeight);
	}
};

$(document).ready(function () {
	bingo.init();
});

 

main.pug

extends layout

block content
 h1= title
 p 
  font(color='DodgerBlue') #{username}
  input#username(type= 'text', value= username)
  input#un(type='button' value='참가')
  | 님 환영합니다.
 
 #game
  #bingo
   table.bingo-board
    tr
     td
     td
     td
     td
     td
    tr
     td
     td
     td
     td
     td
    tr
     td
     td
     td
     td
     td
    tr
     td
     td
     td
     td
     td
    tr
     td
     td
     td
     td
     td

   #user
    #list
    #logs
    input#start_button(type='button', value='Game Start!')

 

layout.pug

doctype html
html
	head
		title= title
		link(rel='stylesheet', href='/stylesheets/style.css')
		script(src='/socket.io/socket.io.js')
		script(src='//code.jquery.com/jquery.min.js')
		script(src='/javascripts/main.js')
	body
		center
			block content

 

style.css

body {
  padding: 50px;
  font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}

a {
  color: #00B7FF;
}

#game {
	width: 320px;
	height: 300px;
}

#bingo {
	float: center;
}

#user {
	float: center;
}

#list {
	border: 1px solid gray;
	width: 300px;
	height: 100px;
	overflow: auto;
	margin-bottom: 10px;
}

#logs {
	border: 1px solid gray;
	width: 300px;
	height: 100px;
	overflow: auto;
	margin-bottom: 10px;
}

.bingo-board {
	border-left: 1px solid gray;
	border-top: 1px solid gray;
	border-spacing: 0px;
	margin-bottom: 20px;
	text-align: center;
}

.bingo-board td {
	width: 35px;
	height: 35px;
	border-right: 1px solid gray;
	border-bottom: 1px solid gray;
}

'IT' 카테고리의 다른 글

Redis에 대해 알아보자!  (1) 2023.10.22
mongoose에 대해 알아보자!  (0) 2023.10.20
socket.io를 이용한 채팅 앱 구현  (0) 2023.10.09
Node.js에 대해 알아보자!  (0) 2023.09.30
객체지향 자바스크립트  (0) 2023.09.29