멀리 있을수록 폭이 짧아지는 판 표시
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.initattr()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.update) # 100밀리초마다 main_proc 실행
timer.start()
def initUI(self):
self.setFixedSize(800, 600) # 창 크기 고정
self.setWindowTitle('Draw road')
self.setStyleSheet('background:blue')
def initattr(self):
self.BORD_COL = [Qt.white, QColor(192, 208, 224), Qt.gray]
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.setBrush(Qt.darkGreen)
qp.drawRect(0, 300, 800, 600)
for i in range(1, 25):
w = i * 33 # 판의 폭을 변수 w에 대입
h = 12 # 판의 높이를 변수 h에 대입
x = 400 - w / 2 # 판을 그릴 X 좌표를 변수 x에 대입
y = 288 + i * h # 판을 그릴 Y 좌표를 변수 y에 대입
col = self.BORD_COL[i % 3] # 판의 색을 변수 col에 대입
qp.setBrush(col)
qp.drawRect(x, y, w, h) # (x, y) 위치에 폭 w, 높이 h인 판 그림
qp.end()
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
멀리 있는 물체의 폭이 짧아졌지만 3차원 공간에서는 높이도 짧아져야만 한다.
높이 변화시키기
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.initattr()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.update) # 100밀리초마다 main_proc 실행
timer.start()
def initUI(self):
self.setFixedSize(800, 600) # 창 크기 고정
self.setWindowTitle('Draw road')
self.setStyleSheet('background:blue')
def initattr(self):
self.BORD_COL = [Qt.white, QColor(192, 208, 224), Qt.gray]
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.setBrush(Qt.darkGreen)
qp.drawRect(0, 300, 800, 600)
h = 2 # 첫 번째 판의 높이를 변수 h에 대입
y = 300 # 첫 번째 판의 Y 좌표를 변수 y에 대입
for i in range(1, 24):
w = i * i * 1.5 # 판의 폭을 계산해서 w에 대입
x = 400 - w / 2
col = self.BORD_COL[i % 3]
qp.setBrush(col)
qp.drawRect(x, y, w, h)
y = y + h # 다음 판의 Y 좌표를 계산해서 y에 대입
h = h + 1 # 다음 판의 높이를 계산해서 h에 대입
qp.end()
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
이전 것과 비교해보면 이번 것은 화면에서 깊이가 느껴지는 것을 알 수 있다.
반복 시 변수 i를 제곱해서 폭 값을 계산하여 i * i는 훨씬 큰 값이 되어 가까운 판일수록 폭이 점점 커진다.
drawPolygon()을 사용하면 다각형을 그릴 수 있다.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.initattr()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.update) # 100밀리초마다 main_proc 실행
timer.start()
def initUI(self):
self.setFixedSize(800, 600) # 창 크기 고정
self.setWindowTitle('Draw road')
self.setStyleSheet('background:blue')
def initattr(self):
self.BORD_COL = [Qt.white, QColor(192, 208, 224), Qt.gray]
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.setBrush(Qt.darkGreen)
qp.drawRect(0, 300, 800, 600)
h = 2
y = 300
for i in range(1, 24):
uw = i * i * 1.5 # 판의 위쪽 폭을 계산해서 uw에 대입
ux = 400 - uw / 2 # 판의 위쪽 X좌표를 계산해서 ux에 대입
bw = (i + 1) * (i + 1) * 1.5 # 판의 아래쪽 폭을 계산해서 bw에 대입
bx = 400 - bw / 2 # 판의 아래쪽 X좌표를 계산해서 bx에 대입
col = self.BORD_COL[i % 3]
qp.setBrush(col)
points = [ # 다각형을 그릴 때 사용할 좌표
QPoint(ux, y),
QPoint(ux + uw, y),
QPoint(bx + bw, y + h),
QPoint(bx, y + h)
]
qp.drawPolygon(QPolygon(points)) # 주어진 좌표들로 다각형을 그림
y = y + h
h = h + 1
qp.end()
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
사다리꼴이 그려져서 판이 깔끔하게 이어진다.
누르는 방향에 따라 휘어지는 도로를 그려 도로 커브를 표현할 수 있다.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.initattr()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.update) # 100밀리초마다 main_proc 실행
timer.start()
def initUI(self):
self.setFixedSize(800, 600) # 창 크기 고정
self.setWindowTitle('Draw road')
self.setStyleSheet('background:blue')
def initattr(self):
self.BORD_COL = [Qt.white, QColor(192, 208, 224), Qt.gray]
self.key = None
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.setBrush(Qt.darkGreen)
qp.drawRect(0, 300, 800, 600)
self.draw_text(qp, '위쪽, 왼쪽, 오른쪽 방향키를 눌러 주십시오')
if self.key == Qt.Key_Up:
self.draw_road(qp, 0)
if self.key == Qt.Key_Left:
self.draw_road(qp, -10)
if self.key == Qt.Key_Right:
self.draw_road(qp, 10)
qp.end()
def draw_road(self, qp, di):
h = 24
y = 600 - h
for i in range(23, 0, -1):
uw = (i - 1) * (i - 1) * 1.5
ux = 400 - uw / 2 + di * (23 - (i - 1)) # 판의 위쪽 X 좌표를 계산해서 ux에 대입
bw = i * i * 1.5
bx = 400 - bw / 2 + di * (23 - i) # 판의 아래쪽 X 좌표를 계산해서 bx에 대입
col = self.BORD_COL[i % 3]
qp.setBrush(col)
points = [
QPoint(ux, y),
QPoint(ux + uw, y),
QPoint(bx + bw, y + h),
QPoint(bx, y + h)
]
qp.drawPolygon(QPolygon(points))
h = h - 1 # 다음 판의 높이를 계산해서 h에 대입
y = y - h # 다음 판의 Y 좌표를 계산해서 y에 대입
def draw_text(self, qp, text):
qp.setPen(QPen(Qt.white))
fm = QFontMetrics(QFont()) # QFontMetrics는 인수로 준 폰트로 문자열이나 문자의 크기를 알아냄
qp.drawText(400 - fm.boundingRect(text).width() / 2, 100, text) # fm.boundingRect(text).width()를 하면 이 문자열의 픽셀 수를 알아낼 수 있다.
def keyPressEvent(self, e):
self.key = e.key()
def keyReleaseEvent(self, e):
self.key = None
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
왼쪽, 오른쪽, 위쪽 방향키를 누르면 누르는 방향에 따른 도로가 표시된다.
draw_road() 함수는 휘어지는 방향을 인수로 받는다.
휘어진 도로를 그릴 때 유의해야할 점이 있다.
- 도로는 가까운 쪽부터 멀어지는 방향으로 그린다.
- 휘어진 도로를 만들 때 멀리 있는 판일수록 X 좌표를 많이 기울어지게 한다.
가까운 쪽부터 멀어지는 방향으로 도로의 판을 그리는 편이 도로의 굽은 정도를 계산하기 쉬워 이번에는 이렇게 그리지만 실제 게임을 제작할 때는 먼 쪽부터 가까워지는 방향으로 그릴 필요가 있다.
ux와 bx 변수에 휘어진 정도를 계산하여 값이 대입된다.
di가 양의 값이면 오른쪽 커브, 음의 값이면 왼쪽 커브, 0이면 직선 도로가 되도록 계산한다.
draw_road() 함수에 인수 10을 주고 실행하면 가장 가까운 판은 i 값이 23일 때 그리므로 아랫변의 X 좌표에 들어가는 값은 10 * (23 - 23) = 0이 되어 좌표가 미끄러지지 않는다.
2번째 판, 3번째 판으로 갈수록 어긋나는 값이 순차적으로 커지게 되어 가장 먼 판의 췻변은 10 * (23 - (1 - 1))로 230픽셀 옆으로 미끄러져 표시된다.
오르막을 올라갈 때는 일반적으로 도로의 앞쪽을 보기 어려워지며, 시야가 나빠지고, 내리막을 내려갈 때는 훨씬 앞까지 보이고 시야가 좋아진다.
이를 표현하려면 오르막에서는 길 끝에 있는 판이 움푹 들어가도록 그리고, 내리막에서는 길 끝에 있는 판이 위로 떠오르는 듯 그리면 된다.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.initattr()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.update)
timer.start()
def initUI(self):
self.setFixedSize(800, 600)
self.setWindowTitle('Draw road')
self.setStyleSheet('background:blue')
def initattr(self):
self.BORD_COL = [Qt.white, QColor(192, 208, 224), Qt.gray]
self.key = None
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.setBrush(Qt.darkGreen)
qp.drawRect(0, 300, 800, 600)
self.draw_text(qp, '위쪽, 아래쪽 방향키를 눌러 주십시오')
if self.key == Qt.Key_Up: # 내리막
self.draw_road(qp, 0, -5)
if self.key == Qt.Key_Down: # 오르막
self.draw_road(qp, 0, 5)
qp.end()
def draw_road(self, qp, di, updown):
h = 24
y = 600 - h
for i in range(23, 0, -1):
uw = (i - 1) * (i - 1) * 1.5
ux = 400 - uw / 2 + di * (23 - (i - 1))
bw = i * i * 1.5
bx = 400 - bw / 2 + di * (23 - i)
col = self.BORD_COL[i % 3]
qp.setBrush(col)
points = [
QPoint(ux, y),
QPoint(ux + uw, y),
QPoint(bx + bw, y + h),
QPoint(bx, y + h)
]
qp.drawPolygon(QPolygon(points))
h = h - 1
y = y - h + updown # 다음 판의 Y 좌표를 계산해서 y에 대입
def draw_text(self, qp, text):
qp.setPen(QPen(Qt.white))
fm = QFontMetrics(QFont())
qp.drawText(400 - fm.boundingRect(text).width() / 2, 100, text)
def keyPressEvent(self, e):
self.key = e.key()
def keyReleaseEvent(self, e):
self.key = None
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
위쪽 방향키를 누르면 판의 Y 좌표를 위로 미끄러뜨린 내리막 상태가 되고, 아래쪽 방향키를 누르면 판의 Y 좌표를 아래로 미끄러뜨린 오르막 상태가 표시된다.
삼각함수를 사용해 도로의 끝을 지평선에 맞출 수 있다.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import math
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.initattr()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.update)
timer.start()
def initUI(self):
self.setFixedSize(800, 600)
self.setWindowTitle('Draw road')
self.setStyleSheet('background:blue')
def initattr(self):
self.BORD_COL = [Qt.white, QColor(192, 208, 224), Qt.gray]
self.key = None
self.updown = [0] * 24 # 판의 Y 좌표를 미끄러뜨린 값을 대입할 리스트
for i in range(23, -1, -1): # 반복, i는 23 ~ -1까지 1씩 감소
self.updown[i] = math.sin(math.radians(180 * i / 23)) # 삼각함수로 미끄러뜨린 값을 updown에 대입
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.setBrush(Qt.darkGreen)
qp.drawRect(0, 300, 800, 600)
self.draw_text(qp, '위쪽, 아래쪽 방향키를 눌러 주십시오')
if self.key == Qt.Key_Up: # 오르막
self.draw_road(qp, 0, -50)
if self.key == Qt.Key_Down: # 내리막
self.draw_road(qp, 0, 50)
qp.end()
def draw_road(self, qp, di, ud):
h = 24
y = 600 - h
for i in range(23, 0, -1):
uw = (i - 1) * (i - 1) * 1.5
ux = 400 - uw / 2 + di * (23 - (i - 1))
uy = y + int(self.updown[i - 1] * ud) # 판의 윗변 Y 좌표를 계산해서 uy에 대입
bw = i * i * 1.5
bx = 400 - bw / 2 + di * (23 - i)
by = y + h + int(self.updown[i] * ud) # 판의 아랫변 Y 좌표를 계산해서 by에 대입
col = self.BORD_COL[i % 3]
qp.setBrush(col)
points = [
QPoint(ux, uy),
QPoint(ux + uw, uy),
QPoint(bx + bw, by),
QPoint(bx, by)
]
qp.drawPolygon(QPolygon(points))
h = h - 1
y = y - h
def draw_text(self, qp, text):
qp.setPen(QPen(Qt.white))
fm = QFontMetrics(QFont())
qp.drawText(400 - fm.boundingRect(text).width() / 2, 100, text)
def keyPressEvent(self, e):
self.key = e.key()
def keyReleaseEvent(self, e):
self.key = None
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
도로 앞을 지평선에 맞추기 위해서는 도로를 그릴 때 sin() 함수를 사용해 이 파형과 같이 판의 Y 좌표를 변화시킨다.
sin 값은 0도일 때 0, 90도일 때 최댓값인 1, 180도일 때 다시 0이 된다. 가장 가까운 판부터 먼 판까지 0도부터 180도의 sin() 함수 값을 Y 좌표에 더해서 그려나간다.
updown에 대입하는 부분을 보자.
self.updown = [0] * 24 # 판의 Y 좌표를 미끄러뜨린 값을 대입할 리스트
for i in range(23, -1, -1): # 반복, i는 23 ~ -1까지 1씩 감소
self.updown[i] = math.sin(math.radians(180 * i / 23)) # 삼각함수로 미끄러뜨린 값을 updown에 대입
radians() 명령에 작성한 각도는 180 * i / 23으로 이는 i 값이 23일 때 180이라는 의미이다. i가 1증가할 때마다 약 8도씩 줄고, i가 0일 때 0도가 된다.
이 계산식으로 180도부터 0도까지의 값을 계산해 이를 updown에 대입한다.
이렇게 구한 값으로 uy와 by, 사다리꼴 윗변과 아랫변의 Y 좌표에 인수로 전달한 기복의 크기 ud를 곱한 값을 더해준다.
ud의 값이 양수인 경우에는 내리막을 그리고 음수인 경우에는 파형의 상하가 역전 되므로 오르막을 그리게 된다.
이 ud 값을 바꾸면 기복을 크거나 작게 바꿀 수 있다.