cpp의 Tick은 함수이기 때문에 내부에 변수를 추가하여도 다음 Tick때는 존재하지 않는 변수이다.
그렇기 때문에 Actor의 객체에 변수를 추가하여야한다.
Item.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
UCLASS()
class TEST01_API AItem : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AItem();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// 멤버변수 RunningTime
private:
float RunningTime;
};
Item.cpp
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 1프레임당 걸리는 시간을 계속 누적한다. 즉 선형적인 값
RunningTime += DeltaTime;
// 사인함수에 선형적으로 증가하는 값을 넣었기 때문에 위아래로 흔들리는 사인함수의 그래프를 얻을 수 있다.
float DeltaZ = FMath::Sin(RunningTime);
CUSTOM_DEBUG_MESH_SingleFrame(GetActorLocation(), GetActorForwardVector() );
AddActorWorldOffset(FVector(0.f ,0.f , DeltaZ));
}
WorldContextObject: 함수가 호출되는 컨텍스트를 나타내는 UObject나 UActorComponent입니다.
Center: 스피어의 중심 위치를 나타내는 FVector입니다.
Radius: 스피어의 반지름을 나타내는 부동 소수점 값입니다.
Segments: 스피어의 그리드 분할 수를 나타내는 정수 값으로, 스피어를 얼마나 부드럽게 그릴지 결정합니다. 더 많은 세그먼트는 더 부드러운 외형을 제공하지만, 계산 비용이 증가합니다.
Color: 스피어를 그릴 때 사용할 색상을 나타내는 FLinearColor입니다.
bPersistentLines: 이 값이 true이면, 스피어는 한 프레임에서 다음 프레임으로 그려진 라인과 함께 유지됩니다. false이면, 각 호출마다 스피어가 새로 그려집니다.
LifeTime: 스피어가 지속되는 시간을 나타내는 값으로, bPersistentLines가 false인 경우에만 적용됩니다. 일정 시간이 지나면 스피어가 사라집니다.
DepthPriority: 스피어의 렌더링 깊이를 나타내며, 더 높은 값은 더 앞에 렌더링됩니다.
즉 bPersistentLines 값이 False라면 이전 프레임에 그려진 것은 지워지게 된다.
LifeTime값을 -1로 주어 이전 프레임것이 남겨지는 시간이 없도록 세팅하므로서 이동할 때 이전프레임의 디버그 구체가 남지 않는다.
Item.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "Item/Item.h"
#include "test01/CustomDebugMacro.h"
... 생략
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 프레임당 속도
float Movement = 50.f;
// 입력에 그냥 속도를 주게되면 프레임당 속도가 나온다. 즉 120프레임에서는 더 빠르며 30 프레임에서는
// 느린 이동속도를 보이게 된다.
// cm/frame * frame/s = 초당 이동거리 cm/s
float FramePerMovement = Movement * DeltaTime;
CUSTOM_DEBUG_MESH_SingleFrame(GetActorLocation(), GetActorForwardVector() );
AddActorWorldOffset(FVector(FramePerMovement,0.f , 0.f));
}
DeltaTime은 이전 프레임부터 현재 프레임까지의 걸린시간 (frame/s)
이동속도는 프레임당 이동거리 (cm/frame)
둘을 곱하면 초당 이동거리 (cm/s) 를 얻는다. 이를 대입하면 아무리 프레임이 빨라져도 동일한 이동속도를 구할 수 있다.
sql문 작성 시 검색 키워드가 존재한다면 sql문에 추가하고 정렬은 '등록일시'와 'idx'를 역순으로 정렬한다.
function getBoardList($currentPage, $itemPerPage, $searchType, $searchValue) {
$db_conn = getDbConn();
$token = $_COOKIE['REFRESH_TOKEN'];
$sql = "SELECT IDX AS idx
, TITLE as title
, CONTENT as content
, FIRST_REG_USER as regUser
, FIRST_REG_TIME as regTime
FROM tbl_board ";
//echo "searchValue is {$searchValue}";
// 키워드 검색이 들어오면 like검색 추가
// TITLE => {$searchType} 할 수도 있지만 sqlInjection의 위험이 있다.
if(!$searchValue=='' && $searchType == 'title') {
$sql = $sql. "WHERE TITLE like'%{$searchValue}%' ";
}
// idx가 AutoIncrese이기에 등록순서, 아니라면 등록시간 순으로 해야하지만
// FIRST_REG_TIME를 index를 안걸긴 했는데....
$order = "ORDER BY FIRST_REG_TIME DESC, IDX DESC limit {$currentPage},{$itemPerPage}";
$sql = $sql.$order;
//echo $sql;
return mysqli_query($db_conn, $sql);
}
페이지네이션
list.php
페이지네이션은 표기될 시작페이지번호, 현제 페이지번호, 표기될 마지막 페이지 번호로 구성 할 수 있다.
이를 구하기위해 총 페이지의 수를 가져오며 총 페이지 수를 가져올 때 목록과 동일하게 검색조건을(검색타입, 키워드) 추가한다.
또한 검색타입, 검색키워드를 가져와 사용하기 위해 onclick함수에 movePage(3) 과 같이 이동할 페이지의 값을 전달한다.
<?php
// 전체 페이지의 개수 = 올림(총 글의 개수 / 페이지 당 개수 )
$totalPage = ceil((getTotalCount($searchType, $searchValue)) / 10);
// 페이지네이션의 시작 페이지
// 현재 페이지를 기준으로 왼쪽으로 4개 표기한다
// 현재 페이지가 5보다 작다면 1이 시작페이지
$startPage = $page - 4 <= 0 ? 1 : $page - 4;
// 페이지네이션의 마지막 페이지
// 현재 페이지를 기준으로 오른쪽으로 5개 표기한다
// 현재 페이지 + 5가 totalPage보다 크다면 종료페이지는 totalPage
$endPage = $page + 5 >= $totalPage ? $totalPage : $page + 5;
ini_set('display_errors', 1);
for($i=$startPage; $i<= $endPage; $i=$i+1 )
{
// echo "<a href='/board/list.php?page={$i}'> {$i} </a>";
// 현재 페이지와 같은 페이지 일때 색상 하이라이팅
if ($page == $i) {
echo "<li class='pagenation_min_width page-item active' aria-current='page'>";
echo "<a class='page-link' href='/board/list.php?page={$i}'>{$i}</a>";
echo "</li>";
} else {
// 클릭하면 movePage(페이지번호) 함수 실행
echo "<li class='pagenation_min_width page-item'><a class='page-link' onclick='movePage({$i})' >{$i}</a></li>";
}
}
?>
function movePage()
태그의 Id로 값을 찾아와 url을 구성한다.
function movePage(page) {
// 쿼리셀렉터로 검색타입과 검색키워드를 가져와서 url 생성
// 문제 될 수 있는 Case
// 검색 후 하단의 검색키워드를 제거하고 페이지를 클릭하면... 빈 키워드가 넘어가지만 페이지는 그대로...
// 가장 좋은 방법은 페이지 클릭과 검색 클릭 시 함수를 분리하는 것... 하지만... 귀찮아...
searchType = document.querySelector("#searchType").value
searchValue = document.querySelector("#searchValue").value
location.href="/board/list.php?page=" + page + "&searchType=" + searchType + "&searchValue=" + searchValue
board_function.php
// 게시판의 총 글 수를 가져오는 코드
function getTotalCount($searchType, $searchValue) {
$db_conn = getDbConn();
$sql = "select count(IDX) as count FROM tbl_board ";
// 키워드 검색이 들어온다면 총 글의 개수가 변경 될 수 있으므로 동일한 키워드 검색추가
if(!$searchValue=='' && $searchType == 'title') {
$sql = $sql. "WHERE TITLE like'%{$searchValue}%' ";
}
$result=mysqli_query($db_conn, $sql);
$row = mysqli_fetch_array($result);
return $row['count'];
}
전체 코드
list.php
<?php
ini_set('display_errors', 1);
require_once '/app/lib/login_check.php';
require_once '../common/header.php';
require_once "/app/board/board_function.php";
?>
<div style="width: 100%; height:100%">
<div style="width: 80%; height:20%; margin: 50px">
<h1> 글 목록 </h1>
</div>
<div style="width: 80%; height:80%; margin: 50px">
<div>
<table style="display: block; width: 100" class="table">
<thead>
<tr>
<th class="header_color" scope="col">#</th>
<th class="header_color" scope="col">제목</th>
<th class="header_color" scope="col">내용</th>
<th class="header_color" scope="col">작성자</th>
<th class="header_color" scope="col">작성일시</th>
</tr>
</thead>
<tbody>
<?php
// 입력받은 페이지
$page = isset($_GET["page"])? $_GET["page"] : 1;
// 입력받은 검색타입
$searchType = isset($_GET["searchType"])? $_GET["searchType"] : '';
//입력받은 검색키워드
$searchValue = isset($_GET["searchValue"])? $_GET["searchValue"] : '';
// 한 페이지당 보여줄 개수
$itemPerPage = 10;
// limit 0, 10은 0개를 패스하고 10개까지 보여준다.
// 페이지가 2라면 10 개를 패스하고 10개를 보여줘야하기에 limit 10, 10이 되어야한다.
$boardList = getBoardList(($page-1) * $itemPerPage, $itemPerPage, $searchType, $searchValue);
while ($board = mysqli_fetch_array($boardList))
{
$idx = $board['idx'];
$title = $board['title'];
$content = $board['content'];
$regUser = $board['regUser'];
$regTime = $board['regTime'];
// var_dump($content);
echo "<tr>";
echo "<th class='idx' scope='row'>{$idx}</td>";
echo "<td class='title' >{$title}</td>";
echo "<td class='content'>{$content}</td>";
echo "<td class='reg_user'>{$regUser}</td>";
echo "<td class='reg_time'>{$regTime}</td>";
echo "</tr>";
}
?>
</tbody>
</table>
</div>
<div style="display: block; width: 100%; text-align: center;">
<nav aria-label="..." style="text-align: center;">
<ul class="pagination" style="display: inline-flex;">
<?php
// 전체 페이지의 개수 = 올림(총 글의 개수 / 페이지 당 개수 )
$totalPage = ceil((getTotalCount($searchType, $searchValue)) / 10);
// 페이지네이션의 시작 페이지
// 현재 페이지를 기준으로 왼쪽으로 4개 표기한다
// 현재 페이지가 5보다 작다면 1이 시작페이지
$startPage = $page - 4 <= 0 ? 1 : $page - 4;
// 페이지네이션의 마지막 페이지
// 현재 페이지를 기준으로 오른쪽으로 5개 표기한다
// 현재 페이지 + 5가 totalPage보다 크다면 종료페이지는 totalPage
$endPage = $page + 5 >= $totalPage ? $totalPage : $page + 5;
ini_set('display_errors', 1);
for($i=$startPage; $i<= $endPage; $i=$i+1 )
{
// echo "<a href='/board/list.php?page={$i}'> {$i} </a>";
// 현재 페이지와 같은 페이지 일때 색상 하이라이팅
if ($page == $i) {
echo "<li class='pagenation_min_width page-item active' aria-current='page'>";
echo "<a class='page-link' href='/board/list.php?page={$i}'>{$i}</a>";
echo "</li>";
} else {
// 클릭하면 movePage(페이지번호) 함수 실행
echo "<li class='pagenation_min_width page-item'><a class='page-link' onclick='movePage({$i})' >{$i}</a></li>";
}
}
?>
</ul>
<button style="margin-left: 20px" type="button" class="btn btn-primary" onclick="moveToWrite()">글쓰기</button>
</nav>
</div>
<div style="text-align: center;">
<select id="searchType">
<option value="title">제목</option>
</select>
<input id="searchValue" type="text" placholder=""
value="<?php
if ($searchValue) {
echo $searchValue;
}
?>"/>
<button style="margin-left: 20px" type="button" class="btn btn-primary" onclick="movePage(1)">검색</button>
</div>
</div>
</div>
<script>
function moveToWrite() {
location.href="/board/write.php"
}
function movePage(page) {
// 쿼리셀렉터로 검색타입과 검색키워드를 가져와서 url 생성
// 문제 될 수 있는 Case
// 검색 후 하단의 검색키워드를 제거하고 페이지를 클릭하면... 빈 키워드가 넘어가지만 페이지는 그대로...
// 가장 좋은 방법은 페이지 클릭과 검색 클릭 시 함수를 분리하는 것... 하지만... 귀찮아...
searchType = document.querySelector("#searchType").value
searchValue = document.querySelector("#searchValue").value
location.href="/board/list.php?page=" + page + "&searchType=" + searchType + "&searchValue=" + searchValue
}
</script>
<style>
.idx {
width:5%
}
.title{
width:25%;
text-overflow : ellipsis ;
}
.content{
width:30%;
text-overflow : ellipsis ;
}
.reg_user{
width:20%;
text-overflow : ellipsis;
}
.reg_time{
width:25%;
text-overflow : ellipsis ;
}
.header_color {
background: lightgray !important;
}
.pagenation_min_width {
min-width: 40px;
}
</style>
<?php
// require_once '../common/footer.php';
?>
board_function.php
<?php
require '/app/lib/db_connection.php';
function getDbConn() {
if (!isset($db_conn)) {
$db_conn = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
$db_conn -> set_charset('utf8');
}
return $db_conn;
}
function insert_tbl_board($title, $content) {
$db_conn = getDbConn();
$token = $_COOKIE['REFRESH_TOKEN'];
// 아 구문에 특수문자 제거해야하는데~~~~
$sql = "insert into tbl_board
(IDX, TITLE, CONTENT, FIRST_REG_USER, FIRST_REG_TIME, LAST_UPD_USER, LAST_UPD_TIME
) value
(null, '{$title}', '{$content}'
, (SELECT USER_ID FROM user WHERE REFRESH_TOKEN ='{$token}'), NOW()
, (SELECT USER_ID FROM user WHERE REFRESH_TOKEN ='{$token}'), NOW() )";
// echo $sql;
return mysqli_query($db_conn, $sql);
}
function getBoardList($currentPage, $itemPerPage, $searchType, $searchValue) {
$db_conn = getDbConn();
$token = $_COOKIE['REFRESH_TOKEN'];
$sql = "SELECT IDX AS idx
, TITLE as title
, CONTENT as content
, FIRST_REG_USER as regUser
, FIRST_REG_TIME as regTime
FROM tbl_board ";
//echo "searchValue is {$searchValue}";
// 키워드 검색이 들어오면 like검색 추가
// TITLE => {$searchType} 할 수도 있지만 sqlInjection의 위험이 있다.
if(!$searchValue=='' && $searchType == 'title') {
$sql = $sql. "WHERE TITLE like'%{$searchValue}%' ";
}
// idx가 AutoIncrese이기에 등록순서, 아니라면 등록시간 순으로 해야하지만
// FIRST_REG_TIME를 index를 안걸긴 했는데....
$order = "ORDER BY FIRST_REG_TIME DESC, IDX DESC limit {$currentPage},{$itemPerPage}";
$sql = $sql.$order;
//echo $sql;
return mysqli_query($db_conn, $sql);
}
// 게시판의 총 글 수를 가져오는 코드
function getTotalCount($searchType, $searchValue) {
$db_conn = getDbConn();
$sql = "select count(IDX) as count FROM tbl_board ";
// 키워드 검색이 들어온다면 총 글의 개수가 변경 될 수 있으므로 동일한 키워드 검색추가
if(!$searchValue=='' && $searchType == 'title') {
$sql = $sql. "WHERE TITLE like'%{$searchValue}%' ";
}
$result=mysqli_query($db_conn, $sql);
$row = mysqli_fetch_array($result);
return $row['count'];
}
?>