얼마전 까지도 잘 되던게 갑자기 안된다. 이럴때 황당하지 … 처음부터 안되던것도 아니고 아무것도 만진게 없는데 갑자기 안된다. 음성으로 조명 켜기를 시켜 보면 구글 어시스턴트 자체가 꺼져 버린다. 에러는 아래와 같다.
tkk_expr = re.search(".*?(TKK=.*?;)W.*?", line).group(1)
AttributeError: 'NoneType' object has no attribute 'group'
끝에 저런 에러를 토해내고 중단되어 버린다. 어디서 발생되는 에러인지 찾아 보니 gTTS와 관련이 있는것 같다. 커스텀으로 음성제어 기능을 추가하면서 응답을 gTTS로 하도록 해 놨는데 이부분에서 에러가 나는듯 하다. 검색을 해보니 나만 그런게 아니다. gTTS 서비스에서 뭔가 바뀐게 있는 걸까?
일전에도 비슷한 에러를 만난것 같은데? 그때 찾아 보니 이 이슈는 패치가 되었다고 했었는데…? 음~ 알수가 없다.
/home/pi/env/lib/python3.5/site-packages/gtts_token/gtts_token.py 이 파일의 위 캡처 표시 라인이 문제라고 에러가 나온것이다.
PiP (Picture-in-Picture API)는 웹 페이지가 다른 창 상단에있는 작은 창에서 비디오를 재생할 수있게 해주는 새로운 실험용 웹 플랫폼 API이다. 이 기능은 사용자가 다른 일을하면서 비디오를 계속보고 싶어하는 비디오 사이트, 예를 들어 텍스트 자습서 비디오를 보면서 텍스트 편집기 등에서 코딩하는 비디오 사이트에 유용하다. 브라우저 버전이나 종류에 따라 지원하지 않을 경우가 있다. 크롬 최신 버전은 지원을 한다.
function runPip(){ if (!document.pictureInPictureElement) { video.requestPictureInPicture() .catch(error => { // Video failed to enter Picture-in-Picture mode. }); } else { document.exitPictureInPicture() .catch(error => { // Video failed to leave Picture-in-Picture mode. }); } }
아직은 영상을 별로 다루지 않아서 굳이 좋은 영상편집툴이 필요하지 무비메이커으로 충분하다. 그런데 좀더 나은 영상편집툴이 필요하다면 사용해 볼만한 영상편집툴이 있다. 어떤 프로그램인지 설치해서 사용해 보기로 하자. 다빈치 리졸브는 블랙매직디자인에서 만든 영상편집 및 색보정 툴이다. 윈도우, 맥, 리눅스를 지원한다. 스탠다드 버전은 무료로 사용이 가능하다. 이 무료버전 만으로도 일반적인 목적의 용도에는 충분하다고 한다. RAW파일을 편집할려면 유료버전을 구입해야 한다고 한다. 뭐 굳이… 일단 아래 사이트에서 다운로드 받아 설치 하자.
기본정보를 입력해 주고 다운로드 받으면 된다. 처음 설치후 기본 세팅하는 화면이 나오면 자신의 환경에 맞게 설정해 주면 된다.
다빈치 리졸브가 실행이 되었다. 오호 그럴싸 하다. 무비메이커에 비해 뭔가 전문가 스러운 화면이다. 음 이제 뭐 부터? 뭐 다를게 있겠어. 프로그램이라는게 다 비슷한 인터페이스를 가지고 있기 마련이다. 간단히 영상과 사진이미지를 가져와서 이어 붙이는 방식의 편집을 해 보기로 하자.
편집에 사용될 파일을 가져오는 것은 간단하다. 폴더에서 드래그 드라하면 된다. 당연히 메뉴를 통해서 가져 올 수 있다. 동영상 3개와 이미지 3개 배경음악 파일을 가져다 놓았다. 미리 사용할 파일들을 모아 놓고 사용한다고 생각하면 된다. 첫번째 영상을 선택하고 드래그 해서 타임라인 비디오 채널에 드래그 드랍하면 된다. 그러면 우측에 재생해서 볼 수 있는 상태가 된다.
영상 클립의 일부분만 사용하고 싶다면 타임라인에서 영상의 시작과 끝에 마우스를 가져가 보면 마우스 아이콘이 변견된다. 드래그 해서 원하는 만큼 시작과 끝을 지정해 주면 된다. 물론 중간에 영상을 칼로 잘라서 사용도 가능하다. 일단 이렇게 해서 원하는 부분을 지정해 주자. 다음 두번째 영상을 가져오자.
원하는 동영상과 이미지들을 순서대로 배치를 한다. 오디오가 포함된 비디오 클립인 경우 타임라인으로 가져 올때 키보드 shift를 누르면 오디오만 가져오고 alt키를 누르고 드래그 하면 비디오만 가져와 배치 할 수 있다. 이 예제에서는 영상에 포함된 오디오는 없애고 전체 배경음악을 넣을 것이기 때문에 영상에 포함된 오디오는 모두 제거 하였다. 이제 배경음악으로 사용할 오디오 파일을 드래그 해서 오디오 트랙에 배치하자.
이렇게 하면 비디오와 오디오를 모두 배치하여 편집이 끝이 났다. 이제 최종 결과물을 저장해 보자. 렌더링 한다고 한다.
렌더링 하기 위해서는 화면 맨 아래 로켓아이콘을 클릭하면 렌더링 화면으로 변경된다.
화면 좌측 상단에 보면 렌더링 설정을 변경할 수 있다. 주로 사용되는 포맷을 미리 제시된다. 유튜브를 선택하고 파일 이름과 저장위치, 비디오 오디오 포맷을 설정해 준다. 설정영역 아래에 있는 ‘Add to Render Queue’를 눌러서 렌더큐로 job을 등록한다. 이제 렌더링 하자. 렌더링 버튼은 화면 우측에 코딱지 만하게 잘 보이지도 않게 위치해 있다. 클릭하자. 렌더링이 끝이 나면 지정된 폴더에 최종 파일이 저장되게 된다.
일단 흐름은 이렇다. 제대로 할려면 영상 클립과 클립이 연결될때 전환효과 같은 것도 주고 자막도 넣고 시작할때 제목도 넣어 주고…해야 될것 같은데 다음에 알아 보기로 하자. 첫소감은 과분한 기능을 가지고 있는것 같다. 무비메이커는 비교가 안되네 … ^^; 앞으로 다양한 기능에 대해 알아가 보기로 하자.
jQuery를 이용하는 화려한 슬라이더 효과를 주는 라이브러리들이 많이 있다. 그런것 가져다가 사용하면 편할것 같지만 라이브러리 추가하고 설정을 해줘야 한다. 복잡하고 무겁다. 순수 자바스크립트(바닐라 자바스크립트)와 CSS만으로 간단한 슬라이더 효과를 만들어 보자. 세상.. 심플한것이 제일이다.
<script type="text/javascript"> const showing_class = "showing"; const firstSlide = document.querySelector(".slider_item:first-child"); function slide(){ const currentSlide = document.querySelector(`.${showing_class}`); // showing 클래스가 있는 엘리먼트를 찾는다. if(currentSlide){ // 지금 shwoing 클래스를 가진 엘리먼트 다음 엘리먼트에 클래스를 추가 한다. currentSlide.classList.remove(showing_class); const nextSlide = currentSlide.nextElementSibling; // 다음 엘리먼트가 있는지 없는지 체크 후 처리 if (nextSlide){ console.log(currentSlide); nextSlide.classList.add(showing_class); } else {//마지막이면(그다음 형제 엘리먼트가 없으니까) 첫 슬라이드에 추가 함. firstSlide.classList.add(showing_class); }
} else { // showing 클래스가 지정된 엘리먼트가 없으면 첫번째에 추가해 준다.(페이지 시작시) firstSlide.classList.add(showing_class); } }
이제 게임에 캐릭터를 등장 시켜서 몇가지 상황을 만들고 기본적인 동작을 하도록 수정해 주자. 게임패트 왼쪽 스틱으로 화면 아래쪽의 사각형을 x방향으로 만 왔다 갔다 움직이도록 하였다. 캐릭터가 아래로 빠져서 게임오버가 되지 않도록 위치를 잡아서 위로 튕켜 줘야 한다. 캐릭터는 자동으로 앞으로 점프를 하면서 이동하게 되어있다. 무기의 사용은 게임패드 우측의 A 버튼에 부여 하였다.
enemy들은 우측에서 무작위로 나오게 되어 있다. 이것들을 피하거나 제거해야 하는데 기능을 따로 주지 않았기 때문에 피할수는 없고 무기를 쐬서 제거를 해줘야 한다. 캐릭터도 스틱으로 움직히게 하면 되지만 예제는 예제니깐 간단히 하자.
-----------game.py--------------
import pygame
import random
import os
WIDTH = 800
HEIGHT = 480
FPS = 30
# Define colors
player1Color = (0, 180, 255)
player2Color = (180, 0, 180)
BGCOLOR = (255, 200, 0) #background color
WHITE = (255,255,255)
enemyColor = (0, 5, 255)
# set up assets folders
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "img")
# Player Class
class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(os.path.join(img_folder, "player1_1.png")).convert() # 이미지를 사용하는 경우 self.image.set_colorkey(WHITE) self.rect = self.image.get_rect() self.rect.center = (WIDTH/2 - 100, HEIGHT - 50) self.y_speed = 3
def update(self): self.rect.x += 3 self.rect.y += self.y_speed if self.rect.bottom > HEIGHT: self.rect.y = 0 if self.rect.top < 50: self.y_speed = 3 if self.rect.left > WIDTH: self.rect.right = 0
# 외곽를 지나면 처리 if self.rect.left > WIDTH: self.rect.right = 0 if self.rect.right < 0: self.rect.left = WIDTH
def shoot(self): bullet = Bullet(player1.rect.x+25, player1.rect.y+25) bullet_sprites.add(bullet) all_sprites.add(bullet)
# Class
class Box(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((60, 20)) # 도형을 사용하는 경우 self.image.fill(player2Color) self.rect = self.image.get_rect() self.rect.center = (WIDTH/2, HEIGHT - 45) self.x_speed = 0
def update(self): self.rect.x += self.x_speed # 스틱을 움직이면 if event.type == pygame.JOYAXISMOTION: self.x_speed += gamepads[-1].get_axis(0) *1 if self.x_speed > 10: self.x_speed = 10 # self.rect.y += gamepads[-1].get_axis(1) *4 if self.rect.left > WIDTH: self.rect.right = 0 if self.rect.right < 0: self.rect.left = WIDTH
# Enemy Class
class Enemy(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((30, 30)) # 도형을 사용하는 경우 self.image.fill(enemyColor) self.rect = self.image.get_rect() self.rect.center = (random.randrange(WIDTH, WIDTH *2), random.randrange(50, HEIGHT - 50)) self.x_speed = random.randrange(-5, -1)
def update(self): self.rect.x += self.x_speed if (self.rect.right < 0): self.rect.left = WIDTH self.rect.top = random.randrange(100, 300)
# bullets
class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((10, 3)) # 도형을 사용하는 경우 self.image.fill(player2Color) self.rect = self.image.get_rect() self.rect.center = (x,y) self.x_speed = 20
def update(self): self.rect.x += self.x_speed if self.rect.left > WIDTH: self.kill() # 오호 이거 편하네 .
# initialize
pygame.init()
pygame.mixer.init() #for sound
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Jumper')
clock = pygame.time.Clock()
width, height = pygame.display.get_surface().get_size()
lead_x = width/2 -100
lead_y = height - 100
lead2_x = width/2 + 100
lead2_y = height - 100
#연결된 모든 디바이스 배열에 추가
gamepads = []
for i in range(0, pygame.joystick.get_count()): gamepads.append(pygame.joystick.Joystick(i)) gamepads[-1].init()
# set up sprites
all_sprites = pygame.sprite.Group()
player_sprites = pygame.sprite.Group()
bullet_sprites = pygame.sprite.Group()
enemy_sprites = pygame.sprite.Group()
player1 = Player()
player_sprites.add(player1)
box_sprites = pygame.sprite.Group()
box = Box()
box_sprites.add(box)
# for문
for i in range(10): enemy = Enemy() enemy_sprites.add(enemy) all_sprites.add(enemy)
all_sprites.add(player1)
all_sprites.add(box)
# print(all_sprites)
#Game Loop
running = True
while running: clock.tick(FPS) # process input(events) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 버튼을 누르면 if event.type == pygame.JOYBUTTONDOWN : if event.button == 0: player1.shoot()
# update all_sprites.update()
hits = pygame.sprite.groupcollide(enemy_sprites, bullet_sprites, True, True) if hits: # 새로운 enemy를 추가해 줌 enemy = Enemy() enemy_sprites.add(enemy) all_sprites.add(enemy)
# 충돌감지 hit = pygame.sprite.spritecollide(player1, box_sprites, False) if hit: player1.y_speed *= -1
# draw / render screen.fill(BGCOLOR) all_sprites.draw(screen) pygame.display.update() # or flip()
pygame.quit()
quit()
-----------------
각각의 요소들은 클래스를 이용해서 생성하고 sprite 그룹에 등록해서 관리를 편하게 해준다. 충돌 감지등을 할때 편리하다. 각각의 스프라이트 클래스에 원하는대로 동작이나 모양을 지정해 주면 된다.
윈도우에서 파이썬으로 간단한 게임을 개발해 보기로 하자. 이전에 해 본것 같은데 복습이 될듯 하다. pygame을 사용하기 위해서 먼저 설치를 해줘야 한다. python -m pip install -U pygame –user
먼저 게임패드를 파이썬에서 어떻게 읽어 들릴까? 자바스크립트에서 끙끙대며 겨우 알아 냈었는데 파이썬도 마찬가지로 겨우 알아 냈다. 필요한 버튼만 찾아 내자. 나머지 버튼은 동일한 방식으로 활용하면 된다. 먼저 간단히 게임패드로 화면의 박스를 움직이는 예제를 만들어 보자. 좌, 우 스틱을 이용해서 박스를 움직이도록 했다. 전면의 L1과 R1에는 슈팅기능이나 기타 기능을 연결해 주면 될듯 하다. 예제에서는 색상이 변하도록 했다. 양손으로 오브젝트를 따로 따로 움직이는게 쉬운게 아니구나..ㅋ
유아틱한 색상 좋아. 파이썬 코드를 살펴 보자.
------------- game.py----------
import pygame
pygame.init()
playerColor1 = (0, 180, 255)
playerColor2 = (180, 0, 180)
bgColor = (255, 200, 0) #background color
gameDisplay = pygame.display.set_mode((640, 480))
pygame.display.set_caption('Control')
pygame.display.update()
gameExit = False
lead_x = 200
lead_y = 300
lead2_x = 400
lead2_y = 300
gamepads = []
clock = pygame.time.Clock()
사실 지금까지 해 왔던게 바로 이 게임패드를 연결해 보려고 했던것이었다. 게임패드 용도에 맞게 하나의 게임이 필요해서 P5.js로 만드는 게임을 지금 까지 해 봤던 것이다. 최신 웹 브라우저에서는 게임패드를 인식하고 사용할 수 있도록 기본으로 되어 있는데, 물론 브라우저마다 안되거나 약간 다른 용법을 사용한것 같기도 하다. 아직 지원하지 않기도 하는 모양이다. 여기서는 윈도우10에서 크롬브라우저를 기준으로 예제를 만들었다. 다른 환경에서 테스트는 해 보지 않았다. 제일 먼저 html 문서를 보자.
-------------------index.html-----------------
<!doctype html>
<html lang="ko">
<head>
<meta name="viewport" content="width=device-width, user-scalable=no">
<meta charset="UTF-8">
<meta name="Description" content="">
<title>P5.JS 연습</title>
<link href="https://fonts.googleapis.com/css?family=Orbitron" rel="stylesheet">
<style type="text/css">
body{
text-align: center;
margin: 0px;
padding: 0px;
}
p{
font-size: .8em;
}
#defaultCanvas0{
}
</style>
<!--공통-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.sound.min.js"></script>
<!--프로젝트 스크립트-->
<script src="sketch19-final.js"></script>
<script src="ship3.js"></script>
<script src="asteroid.js"></script>
<script src="laser.js"></script>
<script src="particle2.js"></script>
<script src="explode.js"></script>
<script src="firework.js"></script>
</head>
<body>
<h1>P5.js Example 19-final(Simple Game)</h1>
<audio autoplay controls preload="auto" loop id="myAudio">
<source src="http://soundimage.org/wp-content/uploads/2014/04/Game-Menu.mp3">
Your browser does not support the audio element.
</audio>
<p>게임패드 이동: 왼편 스틱, 슈팅: 오른쪽 R2, 재시작 : F5, BGM : Music by Eric Matyas www.soundimage.org</p>
</body>
</html>
---------------------------------------------
필요한 자바스크립들은 별도의 파일로 만들고 링크해서 사용하도록 하였다. 이문서는 간단하다.
-----------------sketch.js-----------------
var ship;
var asteroids = [];
var lasers = [];
var font, fontsize = 15;
var health = 100;
var shoot;
var bomb;
let particles = [];//var와 let의 차이를 모르겠음? let이 더 엄격하다 정도만.
var fireworks = [];
function preload(){
shoot = loadSound('sound/laser_shoot.mp3');
bomb = loadSound('sound/bom.wav');
}
function setup() {
createCanvas(800, 480);
//createCanvas(windowWidth,windowHeight);
font="Orbitron";
textFont(font);
textSize(fontsize);
//우주선 생성
ship = new Ship();
//소행성 생성
for(let i =0; i < 10; i++){
asteroids.push(new Asteroid());
}
}
function draw() {
background(0);
// Gamepad
pads = navigator.getGamepads();
pad0 = pads[0];
if(pad0){
// 오른쪽 R2 버튼(앞면 큰 버튼)
if (pad0.buttons[7].value > 0.6 && pad0.buttons[7].pressed == true){
lasers.push(new Laser(ship.pos, ship.heading));//너무 연속적으로 추가 되는 문제
shoot.play();
}
// 스틱
if(pad0.axes[0] >= .5 ){
ship.boosting(true);
} else if(pad0.axes[0] <= -.5) {
ship.boosting(true);
} else if (pad0.axes[1] < -.5){
ship.boosting(true);
} else if (pad0.axes[1] > .5){
ship.boosting(true);
}
}
ship.c = color(100, 255, 100, 255);
// Backgroud Particle
let p = new Particle();
particles.push(p);//draw()에 동작해서 계속해서 객체를 만들어 추가한다.
for(let i = particles.length-1; i >= 0; i--){
particles[i].update();
particles[i].show();
if(particles[i].finished()){
particles.splice(i, 1);
}
}
// Explosion
for(var i = 0; i < fireworks.length; i++){
fireworks[i].run();
if(fireworks.length>10){
fireworks.splice(0, 1);
}
}
//소행성
for (var i = 0; i < asteroids.length; i++){
//소행성과 우주선이 충돌하면
if(ship.hits(asteroids[i])){
//console.log("hit");
ship.c = color(255, 0, 0, 255);
health = health - asteroids[i].r * 0.05;
}
asteroids[i].update();
asteroids[i].render();
asteroids[i].edges();
}
// 레이저
for (var i = lasers.length -1; i >= 0; i--){
lasers[i].update();
lasers[i].render();
// 화면을 벗어나면 제거 해줌
if(lasers[i].offscreen()){
lasers.splice(i, 1);
} else {
// 충돌 감지
for(var j = asteroids.length-1; j >= 0; j--){
if(lasers[i].hits(asteroids[j])){
//console.log('hit');
health = health + asteroids[j].r * 0.1;
if(asteroids[j].r > 10) {
var newAsteroids = asteroids[j].breakup();// 충돌된 소행성을 쪼갠다.
asteroids = asteroids.concat(newAsteroids);
}
fireworks.push(new Firework(lasers[i].pos.x, lasers[i].pos.y));
asteroids.splice(j, 1); //j번째 1개를 제거한다.
lasers.splice(i, 1);
bomb.play();
break;
}
}
}
}
// 우주선
ship.render();
ship.turn();
ship.update();
ship.edges();
// Score
drawScore();
}
// Score and Health
function drawScore(){
fill(255);
if(health <= 0){
text("Game Over", 30, 30);
} else {
text(Math.ceil(health), 30, 30);
}
if (asteroids.length <= 0){
text("You Win", 30, 50);
}
}
----------------------------
메인 스케치 파일이다. 키보드 조작기능은 제거를 했다. 게임패드와 키보드 조작을 다 같이 사용하게 할려면 설정 코드가 더 필요한데 귀찮다. 원래 목적대로 게임패드만 사용하게 해 주자. 이 메인 스케치 이외에 우주선, 소행성, 레이저, 폭발효과를 위한 객체 클래스들이 필요하다. 이걸 다 일일히 여기 적기는 힘들고 자바스크립트 이니 소스가 다 보인다. 찾아서 참고 하면 될듯 하다. ^^;
기본 게임 만드는 유튜브로 만든 것에 필요한 기능 몇가지를 추가해 준것이다. 사운드 효과를 주면 더 게임 다워 진다.
게임패드의 왼쪽 조이스틱(맞나 용어가?)를 이용해서 우주선을 움직이게 하는데 이게 키보드 이동키로 단순히 회전하고 전진하고 하는 것과는 좀 다르게 해 줄 필요가 있었다. 상하좌우 아무곳으로나 이동이 가능하게 해주고 해당 방향으로 움직이면 그 방향으로 우주선 헤드가 돌아 가도록 해줘야 했다. 이것을 구현하는게 난감하게 생각되었는데 의외로 간단히 구현 할 수 있었다.
---------------ship.js-------------------
this.turn = function(){
//this.heading += this.rotation;
this.heading = this.vel.heading();
}
--------------------------------------------
vel 벡터의 heading() 을 적용하니 쉽게 구현이 되었다. 좋아~ 스틱의 움직임에 따라 우주선이 자유롭게 조정이 가능했다. 정밀하게 제어하기는 힘들지만 이정도면 충분해 보인다. 마지막 최종 결과는 아래 링크에서 확인해 보자. 물론 호환이 되는 기본형 게임패드가 있어야 게임이 가능하다. 없는 사람에게는 아무것도 해 볼 수 업다. ^^; 데모 영상은 차후 만들어서 추가해 볼 예정이다.
<script type="text/javascript"> var gamepadInfo = document.getElementById("gamepad-info"); var ball = document.getElementById("ball"); // pos var a = 0; var b = 0; var start; var text = "";
// webkitRequestAnimationFrame var rAF = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.requestAnimationFrame;
var rAFStop = window.mozCancelRequestAnimationFrame || window.webkitCancelRequestAnimationFrame || window.cancelRequestAnimationFrame;
// Check connection window.addEventListener("gamepadconnected", function(e) { var gp = navigator.getGamepads()[e.gamepad.index]; gamepadInfo.innerHTML = "Gamepad connected at index "+gp.index+": "+gp.id+", "+gp.buttons.length+" buttons, "+gp.axes.length+" axes";
배경에 파티클을 이용해서 저 멀리 별들도 그려 주자. 우주공간이 이잖아. 사운드 이펙트는 레이저빔 소리와 행성 쪼개지는 소리(이건 별로 마음에 안듬)를 넣어 주었다. 핼쓰(스코어) 수치도 넣어 주었다. 이제 더이상 할게 없다. ^^; 최종 결과는 아래 링크에서 확인 하자.
다수의 asteroid를 만들어 줘야 한다. 모양도 제각각이다. Asteroid 클스를 이용하여 원하는 갯수만큼 만들어 주면 된다. 여러가지 모양은 vertex를 이용해서 꼭지점의 위치에 무작위 변화를 주어 다른 모양으로 그려 준다. 기본적인 동작은 동일하다. 화면을 벗어 나면 반대편에서 다시 나오게 되어 있다.
P5.js를 이용하여 게임을 만드는 유튜브 동영상을 따라서 간단히(?) 게임을 하나 만들어 보자. 코드를 작성하는게 중요한게 아니고 코드의 의미를 이해하는 것이 더 중요하다. 제일 먼저 우주선 클래스를 만들고 플레이어가 될 우주선을 하나 만들어 키보드에 따라 움직이도록 하는 작업을 하자. 자세한 내용은 아래 링크이 동영상을 참조 하자. 게임의 목표는 떠 돌아 다니는 소행성을 모두 제거하면 된다.
파트1에 이어서 이번에는 좀 더 기능을 추가해 보기로 하자. 앞서 크롬 브라우저에서 음성을 인식하고 텍스트를 화면에 출력해 주는 것 까지 구현이 되었다. 여기다 한글 텍스트를 영문으로 번역하고 그 결과를 음성으로 읽어 주는 기능을 추가하자. 번역 API를 찾아 보니 몇가지 대안이 있는데 강력한 후보이 구글번역 API가 유료로 전환된듯 결제설정을 하라고 나온다. 이런…
구글 Translate API
Microsoft Azure Translate API
Yandex
구글은 유료(정확하지 않음)이고 마이크로소프트는 12개월 무료인데 그후엔 유료라고 한다. 결국 선택한것은 Yadex라는 API 서비스이다. 그런데 문제는 번역 품질이 시원찮다. 일단 흐름을 파악하기 위해서 이것을 이용해 보기로 하자.
뷰잉도 안드로이드TV박스이니 안드로이드 게임이 제한적으로 가능하다. 가끔 해볼려고 했더니 리모콘으로 제대로 하기는 힘들어 보인다. 그래서 게임패드(정확히 이름이 뭐지? 조정기?)를 저렴한것으로 하나 구입했다. 알리익스프레스에서 11.11 광군절에 쬐금 할일할때 구입했던게 이제 도착했다. 얼마였더라 $10 정도 였던것 같다.
부피 때문에 박스는 없고 에어비닐에 나름 안전하게 포장되어 도착했다. 우체부 아저씨가 편지함에 넣고 가는 배송으로 도착했다. 분실없이 잘 도착했다.
구성품은 조정기 본체랑 스마트폰 홀더, USB 리시버, 폰용 OTG 가 들어 있다. 각부 명칭.
안드로이드 TV인 뷰잉에 연결하기 위해서는 USB 리시버만 있으면 된다. 연결하자.
조정기 아래쪽에 AAA사이즈 건전지 두개로 전원을 공급한다.
리시버를 연결하면 자동으로 인식이 되니 특별히 설정할 것은 없다. 게임 하나 실행해 보니 정상적으로 작동이 되는것 같다. 버튼은 많은데 다 동작하는것은 아닌것 같다. 게임의 종류에 따라 작동되는 버튼이 따로 있는 모양이다. https://youtu.be/kGaB755YzeE
var message = document.querySelector("#message"); var button = document.querySelector("#speech"); var korea = document.querySelector("#korea"); var english = document.querySelector("#english"); var isRecognizing = false;
if ('SpeechRecognition' in window) { // Speech recognition support. Talk to your apps! console.log("음성인식을 지원하는 브라우저입니다.") }
try { var recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition)(); } catch(e){ console.error(e); }
function stop(){ recognition.stop(); message.innerHTML = "버튼을 누르고 아무말이나 하세요."; button.disabled = false; button.innerHTML = "Start STT"; isRecognizing = false; }
// Text to speech function text_to_speech(txt){ // Web Speech API - speech synthesis if ('speechSynthesis' in window) { // Synthesis support. Make your web apps talk! console.log("음성합성을 지원하는 브라우저입니다."); } var msg = new SpeechSynthesisUtterance(); var voices = window.speechSynthesis.getVoices(); //msg.voice = voices[10]; // 두번째 부터 완전 외국인 발음이 됨. 사용하지 말것. msg.voiceURI = 'native'; msg.volume = 1; // 0 to 1 msg.rate = 1.3; // 0.1 to 10 //msg.pitch = 2; //0 to 2 msg.text = txt; msg.lang = 'ko-KR';
전체 코드인데 제대로 된건지는 아직 모르겠다. 일단 작동은 하니깐. 여러가지 메소드들이 있는데 정확한 사용법은 앞으로 예제를 더 만들어 보면서 바로 잡도로 하자. 예제는 단순히 앞 음성인식이 끝이 나면 자도으로 다시 음성인식을 시작하도록 하였다. 다른 방법도 있을것 같은데 … 자세한 내용은 아래 사이트를 참조 하자.