콘텐츠로 이동

콜백

이 섹션에서는 데이터 수집, 효과 함수 구성, Meter 클래스를 사용하여 해당 함수를 트리거하는 방법을 다룹니다. 애니메이션이나 효과 핸들러의 세부 사항 설명에는 중점을 두지 않으므로, 복습이 필요하다면 튜토리얼 또는 API 참조 섹션을 확인하십시오.

처음부터 끝까지 효과적으로 애니메이션을 트리거하는 과정은 다음과 같습니다:

  1. 업데이트 함수 내부에서 Meter.setValue(value) 메서드를 사용하여 원시 미터 데이터를 Meter 클래스의 인스턴스에 삽입합니다.
  2. Meter가 안정적이라고 판단하면 두 번째 매개변수로 전달된 콜백 함수를 활성화합니다.
  3. 이 콜백 함수에는 Meter의 상태를 평가하는 조건부 로직이 포함되어 있습니다. 상태가 참이면 효과를 효과 배열(effects.push(new yourEffect()))이나 상태 핸들러(stateMgr.Push(new yourEffect()))에 추가해야 합니다.
  4. 업데이트 함수가 실행될 때마다 전체 효과 배열과 상태 핸들러의 최신 요소가 평가됩니다. 이 단계에서 효과는 상태 변수를 기반으로 그려집니다.
  5. 그려진 후 각 효과는 수명을 확인합니다. 효과 배열의 효과는 단순히 클래스 인스턴스에 설정된 수명 변수를 반복합니다. 수명이 0 이하가 되면 효과 배열 평가 중에 splice로 쉽게 제거됩니다. 상태 핸들러의 효과는 필요할 때 스스로 제거할 수 있는데, 상태 핸들러는 스택으로 작동하고 이러한 효과의 조건부 로직이 더 복잡한 경향이 있기 때문입니다.

이 미터는 일반적인 체력 바를 찾아 일치하는 색상의 비율을 0~1 사이의 숫자로 반환합니다. 바의 색상 그라디언트를 고려하여 이 경우 HSL 범위가 상당히 넓게 설정됩니다. 이로 인해 체력 바가 줄어들면 투명한 배경이 드러나는데, 이 배경에는 색상 체크를 통과하여 미터를 방해하는 게임 환경의 녹색 요소가 포함될 수 있습니다.

<head>
<meta meter="health" tags="example" x= ".05" y=".9" width=".189" h="70-140" s="40-100" l="40-100" type="linear"/>
</head>

여기서 “데미지 입음” 효과를 활성화하기 위해 healthM이라는 Meter 클래스 인스턴스를 만들었습니다.

<script>
// Meter instance
var healthM = new Meter(25, healthHelper);
function update () => {
healthM.setValue(health);
window.requestAnimationFrame(update);
}
function healthHelper () => {
// "Took Damage" effect up next
}
// . . .
</script>

위에서 언급한 불안정성 문제를 고려하여 안정성 요구 사항(25)을 꽤 높게 설정했습니다. 연결된 콜백 함수는 미터 값이 25번의 업데이트 동안 안정적인 경우에만 활성화되므로, 플레이어가 정지해 있을 때도 실제 체력 바가 아닌 대부분의 데이터를 제외합니다. 단점은 효과의 지연이 증가한다는 것으로, 이것은 항상 이 시나리오의 제한 요소가 될 것입니다. 이 특정 체력 바의 경우 최소한 몇 가지 방법으로 이를 해결할 수 있습니다:

  • 피격 시, 초록색 바의 일부가 새로운 초록색 체력 레벨로 줄어들기 전에 즉시 빨간색으로 변환됩니다. 체력 미터와 같은 위치에서 빨간색을 찾는 healthRed 미터를 추가하면 두 값을 결합하여 더 빠른 트리거가 가능합니다. 조건부 **if ( healthM.decreased && healthRed.increased )**는 이 경우 좋은 정확도를 제공해야 합니다.
  • 동일한 색상 설정을 가진 여러 선형 미터의 값을 결합할 수도 있습니다. 현재 체력 바 중앙에 하나의 선형 미터가 설정되어 있습니다. 원래 것의 약간 위아래에 두 개를 더 설정하면, 세 미터 값의 근접성을 추가 안정성 체크로 사용할 수 있습니다. 세 미터 모두 Meter.decreased를 읽고 서로의 값이 작은 범위 내에 있어야 효과가 트리거됩니다.

이 콜백 함수는 미터가 값 배열의 모든 요소가 동일함을 확인한 후에만 실행됩니다. 이는 미터 값이 안정적인 데이터를 기반으로 함을 보장합니다. 콜백 내부에서 조건문을 사용하여 효과를 재생해야 하는지 여부를 결정합니다.

let healthPrev = 0;
function healthHelper () => {
if (healthM.decreased && healthM.value != healthPrev){
effects.push(new healthEffect());
healthPrev = healthM.value;
}
}

조건문에는 두 가지 참 조건이 필요합니다: 미터의 안정적인 감소와 현재 미터 값과 이전에 기록된 값 사이의 불일치. 버그를 방지하기 위해 두 번째 조건을 추가했습니다. 감소만 확인하면 효과가 반복적으로 재생될 것입니다. Meter.decreased미터가 안정화되면 설정되므로, 미터가 변경되지 않는 한 값이 동일하게 유지됩니다. 이렇게 하면 마지막 안정값과 다른 감소가 있는 경우에만 효과가 재생됩니다.

두 가지 효과를 만들겠습니다: 하나는 효과 배열용이고 다른 하나는 상태 핸들러용입니다.

이 첫 번째 코드 블록은 효과 배열을 위한 효과 함수를 정의합니다. 여러 사소한 효과가 동시에 실행될 수 있도록 빠르고 가볍게 설계되었습니다. 시스템 부하를 줄이기 위해 재사용을 위한 매개변수를 통해 효과를 쉽게 커스터마이징할 수 있도록 만들었습니다.

function healthEffect(color, direction, speed){
// The lifetime of the effect should be iterated in the draw function.
this.lifetime = 200;
this.speed = speed;
this.direction = direction;
this.color = color;
this.draw = () => {
// Set fill from parameter
ctx.fillStyle = `hsl(${this.color}, 100%, 50%)`;
// Check direction
if (this.direction == "up"){
ctx.fillRect(0, this.lifetime, width, 30);
} else {
ctx.fillRect(0, height - this.lifetime, width, 30);
}
// As the lifetime decreases by 5 each update, the rectangle moves accordingly.
this.lifetime -= speed;
}
}
function update() {
// Background color
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 320, 200);
// Draw all effects in array and remove them if they are done.
effects.forEach((ele, i) => {
ele.draw();
if (ele.lifetime == 0){
effects.splice(i, 1);
}
})
window.requestAnimationFrame(update);
}
function healthHelper () => {
if (healthM.decreased && healthM.value != healthPrev){
// Make sure to correctly set the color and direction paremeters.
effects.push(new healthEffect(1, "down", 5));
healthPrev = healthM.value;
}
}

실제로 어떻게 표시되는지 확인하십시오:

함수의 편집 가능한 설계 덕분에 회복 효과도 쉽게 만들 수 있습니다! 콜백 함수에 추가 조건만 추가하면 됩니다.

function healthHelper () => {
if (healthM.decreased && healthM.value != healthPrev){
// Damage effect
effects.push(new healthEffect(1, "down", 5));
healthPrev = healthM.value;
}
if (healthM.increased && healthM.value != healthPrev){
// Healing effect
effects.push(new healthEffect(120, "up", 5));
healthPrev = healthM.value;
}
}

이 효과의 단순함이 LightScript 개발자에게 가장 큰 장점입니다. 수백 줄의 코드가 필요한 맞춤형 디자이너 효과를 만드는 대신, 특정 트리거의 구성 요소로 사용할 수 있는 작고 재사용 가능한 효과를 만드십시오. 다음 세 가지 효과는 방금 만든 작은 효과를 기반으로 한 변형입니다. 자유롭게 실험하며 어떤 것을 만들 수 있는지 확인해 보십시오!

상태 핸들러는 매우 구체적인 상태 로직을 가진 크고 복잡한 효과, 특히 다른 모든 효과보다 우선시되어야 하는 경우를 위해 사용하는 것이 좋습니다. 상태 핸들러는 스택처럼 작동하고 상단 효과만 실행한다는 점을 명심하십시오. 각 상태 효과는 완료되면 스스로 제거할 책임이 있습니다. 이 예시는 검색 중인지 여부에 따라 적응하는 매치메이킹 로비 애니메이션을 보여줍니다. 여기에는 도우미 효과가 있는 자체 소형 효과 배열도 포함되어 있습니다. 여기서 사용된 미터는 inLobbyyellowPlayButton으로, 매치메이킹 로비에서만 활성화됩니다. yellowPlayButton은 검색 중인지 여부에 따라 색상이 변경됩니다.

function lobbyAnimation(){
// Instance variables
this.start = new Date().getTime();
this.elapsed = 0;
this.radius = 0;
this.searching = 1000;
// Instance effects array
this.effects = [];
// Process is the method that allows a state effect to remove itself
this.Process = function () {
// If the lobby menu and play button disappear, remove the effect
if (inLobby.decreased && yellowPlayButton.decreased) {
stateMgr.Pop();
// Global boolean to prevent duplicate lobby effects in the state handler
lobbyAnim = false;
}
// If the play button is present, edit this.searching based on its color
yellowPlayButton.value == 1 ? this.searching = 1000 : this.searching = 100;
// Call the Draw function attached to the effect
this.Draw();
};
this.Draw = function(){
// Iterate important variables
this.elapsed = new Date().getTime() - this.start;
this.radius = 50 + (Math.sin(this.elapsed/this.searching)*10);
// Fill the background to overwrite other effects
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, 320, 200);
// Draw the main arc
ctx.beginPath();
ctx.strokeStyle = `hsl(120, 100%, 50%)`;
ctx.lineWidth = 20;
ctx.arc(160, 100, this.radius, 0, 2 * Math.PI);
ctx.stroke();
// If the main arc is the right size, push helper effects into the helper array
if(this.radius > 59 && this.elapsed % 2 == 0){
this.effects.push(new lobbyHelper(160, 100, 69));
}
// Play and remove helper effects if necessary
this.effects.forEach((e, i) => {
ctx.lineWidth = 1;
e.draw();
if (e.radius > 360) {
this.effects.splice(i, 1);
}
});
}
}
function lobbyHelper(x, y, radius){
this.x = x;
this.y = y;
this.radius = radius;
this.draw = function(){
// Set the global transparency value. 1 is opaque, 0 is invisible.
ctx.globalAlpha = 1 - this.radius/360;
ctx.beginPath();
ctx.strokeStyle = `hsl(120, 100%, ${50 + (this.radius/7)}%)`;
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.stroke();
// Set the global transparency back to 1 so your other effects are opaque
ctx.globalAlpha = 1;
this.radius++;
}
}
// Declare state handler (found in Snippets)
var stateMgr = new StateHandler();
// Global boolean to prevent duplicate lobby animations
var lobbyAnim = false;
function update(){
// Run the Process function to draw the animation
stateMgr.Process();
}
function lobbyAnimationPlay(){
if(inLobby.value == 1 && yellowPlayButton.value == 1 && !lobbyAnim){
stateMgr.Push(new lobbyAnimation());
lobbyAnim = true;
}
};

검색 중이 아닐 때:

검색 중:

이것으로 콜백 튜토리얼과 공식 SignalRGB 개발 연습 과정을 마칩니다. 연습 과정의 마지막 추가 사항인 Lightscript 유지 관리를 기대해 주십시오!