안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.
오늘은 새롭게 소개된 GPT-4o(“o”는 “omni”의 약자)에 대해 알아볼께요.
[오늘의 목표] GPT-4o 에 대해 간단히 살펴보기
1. GPT-4o 가 뭐예요?
2. 같은 질문으로 GPT-4 vs GPT-4o 비교하기
※ ChatGPT 답변 내용 중 제가 별도로 표시한 파란색 내용을 기준으로 읽으시면 좀 더 이해가 쉽게 될거예요.
GPT-4o가 뭐예요?
Open AI 에 소개된 내용은 다음과 같아요.
Hello GPT-4o
우리는 오디오, 비전(시각), 텍스트를 실시간으로 이해할 수 있는 새로운 대표 모델인 GPT-4o를 발표합니다.
GPT-4o(“o”는 “omni”의 약자)는 훨씬 더 자연스러운 인간-컴퓨터 상호작용을 위한 한 걸음입니다. 이 모델은 텍스트, 오디오, 이미지의 조합을 입력으로 받아들이고, 텍스트, 오디오, 이미지의 조합을 출력으로 생성할 수 있습니다. 오디오 입력에 대해 232밀리초, 평균 320밀리초로 응답할 수 있어 대화 중인 인간의 반응 시간과 비슷합니다. GPT-4o는 영어 텍스트와 코드에서 GPT-4 Turbo와 성능이 동일하며, 비영어 텍스트에서는 큰 향상이 있습니다. 또한, 속도가 더 빠르고 API 사용 시 비용이 50% 저렴합니다. GPT-4o는 특히 기존 모델에 비해 시각 및 오디오 이해 능력이 뛰어납니다.
모델 기능
GPT-4o 이전에는, 음성 모드를 사용하여 ChatGPT와 대화할 때 지연 시간이 평균 2.8초(GPT-3.5)와 5.4초(GPT-4)였습니다. 이를 위해 음성 모드는 세 개의 별도 모델로 이루어진 파이프라인을 사용했습니다: 하나의 간단한 모델이 오디오를 텍스트로 전사하고, GPT-3.5나 GPT-4가 텍스트를 입력받아 텍스트로 출력하며, 세 번째 간단한 모델이 그 텍스트를 다시 오디오로 변환합니다. 이 과정에서 주요 지능 소스인 GPT-4는 많은 정보를 잃게 되는데, 이는 음성 톤, 여러 화자, 배경 소음을 직접 관찰할 수 없으며 웃음, 노래, 감정 표현 등을 출력할 수 없다는 것을 의미합니다.
GPT-4o에서는 텍스트, 비전(시각), 오디오를 아우르는 단일 새로운 모델을 처음부터 끝까지 훈련하여, 모든 입력과 출력을 동일한 신경망이 처리하도록 했습니다. GPT-4o는 이러한 모든 모달리티를 결합한 최초의 모델이기 때문에, 우리는 아직 이 모델이 할 수 있는 것과 그 한계를 탐구하는 초기 단계에 있습니다.
모델 평가
전통적인 벤치마크로 측정한 결과, GPT-4o는 텍스트, 추론, 코딩 지능에서 GPT-4 Turbo 수준의 성능을 달성했으며, 다국어, 오디오, 시각 능력에서는 새로운 최고 기록을 세웠습니다.
모델 안전성 및 한계
GPT-4o는 모달리티 전반에 걸쳐 안전성을 내장하고 있으며, 훈련 데이터 필터링과 훈련 후 모델 행동 개선과 같은 기술을 통해 이를 구현했습니다. 또한 음성 출력에 대한 안전 장치를 제공하기 위해 새로운 안전 시스템을 구축했습니다.
우리는 준비된 상태 프레임워크와 자발적 약속에 따라 GPT-4o를 평가했습니다. 사이버 보안, 화학·생물학·방사능·핵(CBRN), 설득, 모델 자율성에 대한 평가 결과, GPT-4o는 어떤 범주에서도 중간 위험을 초과하지 않았습니다. 이 평가는 모델 훈련 과정 전반에 걸쳐 자동화된 평가와 인간 평가를 통해 이루어졌습니다. 모델의 안전성 완화 전후 버전을 맞춤형 미세 조정 및 프롬프트를 사용해 테스트하여 모델의 기능을 더 잘 이끌어냈습니다.
GPT-4o는 또한 사회 심리학, 편향 및 공정성, 허위 정보와 같은 분야의 70명 이상의 외부 전문가들과 함께 광범위한 외부 레드 팀 테스트를 거쳐 새로운 모달리티로 인해 도입되거나 강화된 위험을 식별했습니다. 우리는 이러한 학습을 통해 GPT-4o와 상호작용하는 안전성을 개선하기 위한 안전 개입을 구축했습니다. 새로운 위험이 발견될 때마다 이를 완화하기 위해 지속적으로 노력할 것입니다.
우리는 GPT-4o의 오디오 모달리티가 다양한 새로운 위험을 초래할 수 있음을 인식하고 있습니다. 오늘 우리는 텍스트와 이미지 입력 및 텍스트 출력을 공개합니다. 앞으로 몇 주와 몇 달 동안 나머지 모달리티를 출시하기 위해 기술 인프라, 훈련 후 사용성, 안전성을 작업할 예정입니다. 예를 들어, 출시 시점에 오디오 출력은 사전 설정된 목소리로 제한되며 기존 안전 정책을 준수할 것입니다. GPT-4o의 전체 모달리티 범위를 다루는 추가 세부 사항은 곧 시스템 카드에서 공유할 예정입니다.
모델을 테스트하고 반복하는 과정에서 모든 모달리티에 걸쳐 몇 가지 한계가 존재함을 관찰했으며, 아래에 몇 가지 예를 제시합니다.
모델 이용 가능성
GPT-4o는 실용성을 향한 방향으로 딥러닝의 경계를 확장하기 위한 우리의 최신 단계입니다. 지난 2년 동안 우리는 스택의 모든 계층에서 효율성을 개선하기 위해 많은 노력을 기울였습니다. 이 연구의 첫 번째 성과로, 우리는 GPT-4 수준의 모델을 훨씬 더 널리 사용할 수 있게 되었습니다. GPT-4o의 기능은 단계적으로 출시될 예정이며, 오늘부터 확장된 레드 팀 접근이 시작됩니다.
GPT-4o의 텍스트와 이미지 기능은 오늘부터 ChatGPT에서 단계적으로 출시됩니다. 우리는 GPT-4o를 무료 티어에서 사용할 수 있게 하고, Plus 사용자에게는 최대 5배 높은 메시지 제한을 제공합니다. 몇 주 내에 GPT-4o를 사용한 새로운 버전의 음성 모드를 ChatGPT Plus에서 알파 버전으로 출시할 예정입니다.
개발자들은 이제 API에서 텍스트 및 비전(시각) 모델로서 GPT-4o에 접근할 수 있습니다. GPT-4o는 GPT-4 Turbo에 비해 2배 빠르고, 가격은 절반이며, 5배 높은 처리 한도를 가집니다. 우리는 몇 주 내에 신뢰할 수 있는 소규모 파트너 그룹에게 GPT-4o의 새로운 오디오 및 비디오 기능에 대한 지원을 API를 통해 제공할 계획입니다.
GPT-4o에게 GPT-4o를 간단히 소개해달라고 해봤어요.
[질문] GPT-4o를 간단히 소개해줄래? 가장 중요한 부분들과 가장 쉽게 이해할 수 있도록 설명해줘
[답변]
GPT-4o 간단 소개
GPT-4o는 OpenAI가 개발한 최신 인공지능 모델로, 텍스트, 오디오, 이미지 등 다양한 데이터를 처리할 수 있는 능력을 가지고 있습니다. 아래는 가장 중요한 특징들입니다:
- 멀티모달 처리: GPT-4o는 텍스트, 오디오, 이미지 입력을 모두 처리하고 생성할 수 있습니다. 이는 더 자연스럽고 유연한 상호작용을 가능하게 합니다.
- 속도와 비용 효율성: GPT-4o는 GPT-4 Turbo에 비해 두 배 빠르고, 비용은 절반이며, 처리 한도는 다섯 배 높습니다. 이는 더 빠르고 경제적인 사용을 의미합니다.
- 강화된 성능: 텍스트와 코드 처리에서 GPT-4 Turbo 수준의 성능을 유지하면서도, 다국어 지원, 오디오 및 이미지 이해 능력에서 큰 향상을 보였습니다.
- 안전성: 모델 훈련과정에서 데이터를 필터링하고 훈련 후 행동을 조정하여 안전성을 높였습니다. 특히 음성 출력에 대한 새로운 안전 시스템도 도입했습니다.
- 무료 및 유료 이용 가능: GPT-4o는 ChatGPT의 무료 사용자도 사용할 수 있으며, Plus 사용자에게는 더 높은 메시지 제한을 제공합니다.
- 개발자 지원: 개발자들은 API를 통해 GPT-4o를 사용할 수 있으며, 앞으로 오디오와 비디오 기능도 추가될 예정입니다.
요약
GPT-4o는 다양한 입력 데이터를 처리할 수 있는 다재다능한 인공지능 모델로, 더 빠르고 저렴하게 사용할 수 있으며, 텍스트, 오디오, 이미지 처리 능력이 강화되었습니다. 또한, 안전성을 높여 사용자에게 더 신뢰할 수 있는 환경을 제공합니다.
무료로도 사용할 수 있다는 좋은 소식도 있네요.
무료 및 유료 이용 가능: GPT-4o는 ChatGPT의 무료 사용자도 사용할 수 있으며, Plus 사용자에게는 더 높은 메시지 제한을 제공합니다.
그리고 기존 GPT-4와 어떤 점이 달라졌는 지도 알려달라고 했어요.
[질문] GPT-4와 비교했을 때 어떤 점이 가장 큰 변화일까?
[답변]
GPT-4와 비교한 GPT-4o의 주요 변화
GPT-4와 비교했을 때, GPT-4o는 여러 면에서 큰 변화를 가져왔습니다. 가장 큰 변화는 다음과 같습니다:
- 멀티모달 처리 능력:
- GPT-4: 주로 텍스트 기반 처리와 생성에 중점을 두었습니다.
- GPT-4o: 텍스트뿐만 아니라 오디오와 이미지를 동시에 처리하고 생성할 수 있습니다. 이는 다양한 형태의 데이터를 이해하고 상호작용할 수 있는 능력을 제공합니다.
- 속도와 비용 효율성:
- GPT-4: 기존 모델 대비 높은 성능을 제공하지만 속도와 비용 면에서 제약이 있었습니다.
- GPT-4o: GPT-4 Turbo에 비해 두 배 빠르고, 비용은 절반이며, 처리 한도는 다섯 배 높아졌습니다. 이는 더 빠르고 경제적으로 AI 서비스를 이용할 수 있게 합니다.
- 강화된 다국어 지원:
- GPT-4: 영어 및 일부 주요 언어에서 우수한 성능을 보였지만, 비영어 언어에서는 제한적일 수 있었습니다.
- GPT-4o: 다국어 텍스트 처리 능력이 크게 향상되어 더 다양한 언어에서 뛰어난 성능을 제공합니다.
- 안전성 및 신뢰성:
- GPT-4: 안전성 강화 작업이 있었으나, 주로 텍스트 데이터에 집중되었습니다.
- GPT-4o: 데이터 필터링, 훈련 후 행동 조정, 새로운 안전 시스템 도입 등을 통해 모든 모달리티(텍스트, 오디오, 이미지)에서 높은 안전성을 제공합니다. 특히 음성 출력에 대한 안전 장치가 강화되었습니다.
- 실시간 처리 능력:
- GPT-4: 텍스트 기반의 반응 시간이 주요 초점이었습니다.
- GPT-4o: 오디오 입력에 대해 실시간으로 반응할 수 있으며, 평균 응답 시간이 320밀리초로 인간의 반응 시간과 유사합니다.
요약
GPT-4o의 가장 큰 변화는 멀티모달 처리 능력, 속도와 비용 효율성, 강화된 다국어 지원, 안전성 및 신뢰성, 그리고 실시간 처리 능력입니다. 이러한 변화는 GPT-4o가 더 다양한 상호작용을 가능하게 하고, 더 빠르고 경제적인 AI 서비스를 제공할 수 있도록 합니다.
속도는 바로 느껴질 정도로 빨라졌네요.
나머지는 천천히 확인을 해봐야겠어요.
같은 질문으로 GPT-4 vs GPT-4o 시험해보기
아래 공통 질문을 GPT-4와 GPT-4o에 해봤어요.
[공통질문] 아래 코드에서 측면에서 밀기가 되지 않고 있어. 이 부분을 수정해줘
using System.Collections; using System.Collections.Generic; using UnityEngine; using Platformer.Gameplay; using static Platformer.Core.Simulation; using Platformer.Model; using Platformer.Core; namespace Platformer.Mechanics { public class PlayerController : KinematicObject { public AudioClip jumpAudio; public AudioClip respawnAudio; public AudioClip ouchAudio; public float maxSpeed = 7; public float jumpTakeOffSpeed = 7; public float attackRange = 0.5f; public LayerMask enemyLayer; public LayerMask wallLayer; public float wallSlideSpeed = 1.5f; public float wallJumpXSpeed = 5f; public float wallJumpYSpeed = 7f; private bool isTouchingWall; private bool wallSliding; private bool wallJumping; public LayerMask pushableLayer; private Pushable currentPushable; private bool isPushing; public JumpState jumpState = JumpState.Grounded; public AttackState attackState = AttackState.Idle; private bool stopJump; public Collider2D collider2d; public AudioSource audioSource; public Health health; public bool controlEnabled = true; bool jump; Vector2 move; float lastMoveDirection; SpriteRenderer spriteRenderer; internal Animator animator; readonly PlatformerModel model = Simulation.GetModel<PlatformerModel>(); public Bounds Bounds => collider2d.bounds; void Awake() { health = GetComponent<Health>(); audioSource = GetComponent<AudioSource>(); collider2d = GetComponent<Collider2D>(); spriteRenderer = GetComponent<SpriteRenderer>(); animator = GetComponent<Animator>(); } protected override void Update() { if (controlEnabled) { move.x = Input.GetAxis("Horizontal"); if ((jumpState == JumpState.Grounded || wallSliding) && Input.GetButtonDown("Jump")) { jumpState = JumpState.PrepareToJump; } else if (Input.GetButtonUp("Jump")) { stopJump = true; Schedule<PlayerStopJump>().player = this; } if (Input.GetButtonDown("Fire1") && attackState == AttackState.Idle) { attackState = AttackState.PreparingAttack; } CheckForPushable(); lastMoveDirection = move.x; } else { move.x = 0; } UpdateWallSlide(); UpdateJumpState(); UpdateAttackState(); base.Update(); } void UpdateAttackState() { switch (attackState) { case AttackState.PreparingAttack: animator.SetTrigger("attack"); attackState = AttackState.Attacking; break; case AttackState.Attacking: CheckHit(); attackState = AttackState.Idle; break; case AttackState.Idle: break; } } void CheckForPushable() { Collider2D pushableCollider = Physics2D.OverlapBox(collider2d.bounds.center, collider2d.bounds.size, 0f, pushableLayer); if (pushableCollider != null) { var pushable = pushableCollider.GetComponent<Pushable>(); if (pushable != null) { if (Mathf.Abs(move.x) > 0.01f && IsOnSideOfPushable(pushableCollider)) { if (currentPushable == null) { currentPushable = pushable; StartPushing(); } else if (currentPushable == pushable) { if (Mathf.Sign(move.x) != Mathf.Sign(lastMoveDirection)) { EndPushing(); } } } } else if (currentPushable != null) { EndPushing(); } } else if (currentPushable != null) { EndPushing(); } } void StartPushing() { isPushing = true; currentPushable.StartPushing(); } void EndPushing() { isPushing = false; if (currentPushable != null) { currentPushable.EndPushing(); currentPushable.StopMovement(); currentPushable = null; } } bool IsOnSideOfPushable(Collider2D pushableCollider) { Vector2 playerBottom = collider2d.bounds.min; Vector2 playerTop = collider2d.bounds.max; Vector2 pushableBottom = pushableCollider.bounds.min; Vector2 pushableTop = pushableCollider.bounds.max; bool isSide = playerBottom.y < pushableTop.y && playerTop.y > pushableBottom.y; bool isTouchingSide = collider2d.bounds.max.x > pushableCollider.bounds.min.x && collider2d.bounds.min.x < pushableCollider.bounds.max.x; return isSide && isTouchingSide; } public void UpdateColliderForAnimation() { } public void ResetColliderPosition() { } void CheckHit() { Vector2 center = new Vector2(transform.position.x + (spriteRenderer.flipX ? -attackRange : attackRange), transform.position.y); Collider2D[] hits = Physics2D.OverlapCircleAll(center, attackRange, enemyLayer); foreach (var hit in hits) { if (hit.gameObject.CompareTag("Enemy")) { Debug.Log("적 타격 감지됨!"); var enemy = hit.GetComponent<EnemyController>(); if (enemy != null) { var enemyHealth = enemy.GetComponent<Health>(); if (enemyHealth != null) { enemyHealth.Decrement(); if (!enemyHealth.IsAlive) { Debug.Log("적이 처치되었습니다."); Schedule<EnemyDeath>().enemy = enemy; } else { Debug.Log("적은 타격을 받았으나 아직 살아있습니다."); } } else { Schedule<EnemyDeath>().enemy = enemy; } } else { Debug.Log("타격된 객체에 적 컴포넌트가 없습니다."); } } } } void UpdateWallSlide() { isTouchingWall = Physics2D.OverlapBox(collider2d.bounds.center, collider2d.bounds.size, 0f, wallLayer); if (isTouchingWall && !IsGrounded && move.x != 0) { wallSliding = true; velocity.y = Mathf.Clamp(velocity.y, -wallSlideSpeed, float.MaxValue); Debug.Log("Wall Sliding"); } else { wallSliding = false; } } void UpdateJumpState() { jump = false; switch (jumpState) { case JumpState.PrepareToJump: if (wallSliding) { jumpState = JumpState.WallJumping; wallJumping = true; jump = true; stopJump = false; Debug.Log("Jump State: WallJumping"); } else { jumpState = JumpState.Jumping; jump = true; stopJump = false; Debug.Log("Jump State: Jumping"); } break; case JumpState.Jumping: if (!IsGrounded) { Schedule<PlayerJumped>().player = this; jumpState = JumpState.InFlight; Debug.Log("Jump State: InFlight"); } break; case JumpState.InFlight: if (IsGrounded) { Schedule<PlayerLanded>().player = this; jumpState = JumpState.Landed; Debug.Log("Jump State: Landed"); } break; case JumpState.WallJumping: if (!wallJumping) { jumpState = JumpState.InFlight; Debug.Log("Jump State: InFlight (from WallJumping)"); } break; case JumpState.Landed: jumpState = JumpState.Grounded; Debug.Log("Jump State: Grounded"); break; } } protected override void ComputeVelocity() { if (jump) { if (wallJumping) { velocity.x = wallJumpXSpeed * (spriteRenderer.flipX ? 1 : -1); velocity.y = wallJumpYSpeed; wallJumping = false; Debug.Log("Wall Jump Performed"); } else if (IsGrounded) { velocity.y = jumpTakeOffSpeed * model.jumpModifier; Debug.Log("Regular Jump Performed"); } jump = false; } else if (stopJump) { stopJump = false; if (velocity.y > 0) { velocity.y = velocity.y * model.jumpDeceleration; Debug.Log("Jump Stopped"); } } if (isPushing && currentPushable) { currentPushable.Move(new Vector2(move.x * Time.deltaTime, 0)); } if (attackState == AttackState.Attacking) { move.x = 0; } if (move.x > 0.01f) spriteRenderer.flipX = false; else if (move.x < -0.01f) spriteRenderer.flipX = true; animator.SetBool("grounded", IsGrounded); animator.SetFloat("velocityX", Mathf.Abs(velocity.x) / maxSpeed); targetVelocity = move * maxSpeed; } public enum JumpState { Grounded, PrepareToJump, Jumping, InFlight, WallJumping, Landed } public enum AttackState { Idle, PreparingAttack, Attacking } } }
GPT-4 답변 내용 및 속도
GPT-4는 역시 생각을 천천히 하면서 답변을 제공해줘요.
GPT-3.5는 아무 생각 없이 막 답변을 하잖아요.
[답변]
코드에서 플레이어가 물체를 밀 때 문제가 발생하는 것 같습니다. 현재 CheckForPushable 메서드에서 isPushing 상태를 관리하고 있지만, 실제로 플레이어가 물체를 밀 때의 물리적 상호작용을 처리하는 부분이 충분히 구현되지 않은 것 같습니다.
플레이어가 물체를 밀 수 있게 하려면 다음과 같은 접근 방법을 사용할 수 있습니다:
- Pushable 오브젝트의 물리 설정: Pushable 스크립트에서 물리적 상호작용을 처리할 수 있도록 Rigidbody2D 컴포넌트를 활용해야 합니다. Rigidbody2D를 사용하여 실제 물리 엔진을 통한 밀기 동작을 구현할 수 있습니다.
- 플레이어와 Pushable 오브젝트 간의 상호작용 강화: 플레이어가 Pushable 오브젝트를 밀고 있을 때 Pushable 오브젝트의 위치를 조정하거나, Rigidbody2D의 힘을 적용하는 방식으로 수정할 수 있습니다.
아래는 CheckForPushable 메서드와 관련된 부분을 개선하는 예시입니다. Pushable에 Rigidbody2D가 있다고 가정하고, 플레이어가 오브젝트를 밀 때 실제로 Rigidbody2D에 힘을 적용하는 방식으로 변경했습니다:
void CheckForPushable() { Collider2D pushableCollider = Physics2D.OverlapBox(collider2d.bounds.center, collider2d.bounds.size, 0f, pushableLayer); if (pushableCollider != null) { var pushable = pushableCollider.GetComponent<Pushable>(); if (pushable != null) { if (Mathf.Abs(move.x) > 0.01f && IsOnSideOfPushable(pushableCollider)) { if (currentPushable == null) { currentPushable = pushable; StartPushing(); } else if (currentPushable == pushable) { if (Mathf.Sign(move.x) != Mathf.Sign(lastMoveDirection)) { EndPushing(); } else { currentPushable.GetComponent<Rigidbody2D>().AddForce(new Vector2(move.x * 100, 0)); // 힘의 크기를 조절하세요. } } } } else if (currentPushable != null) { EndPushing(); } } else if (currentPushable != null) { EndPushing(); } }
이 예시에서는 Pushable 오브젝트에 Rigidbody2D 컴포넌트가 있어야 하며, 플레이어가 오브젝트를 밀고 있을 때 해당 컴포넌트에 직접 힘을 적용하고 있습니다. 힘의 크기(100 등)는 상황에 따라 조절해야 합니다.
[소요 시간: 대략 50초]
GPT-4o 답변 내용 및 속도
GPT-4o는 마치 GPT-3.5와 같이 빠른 속도로 답을 하네요.
다음 번 글에서 이야기하겠지만 GPT-4가 해결하지 못한 문제를 GPT-4o가 해결한 경우도 있었어요.
빠르기도 하지만 머리도 똑똑해졌나봐요.
[답변]
측면에서 밀기 기능이 제대로 작동하지 않는 문제를 해결하려면, CheckForPushable 및 관련 함수들을 수정해야 합니다. 기존 코드를 검토한 결과, 밀기 동작이 시작되거나 끝나는 시점에서의 조건 확인 및 상태 전환 로직에 문제가 있는 것 같습니다.
다음은 이를 수정한 코드입니다:
- CheckForPushable 함수에서 밀 수 있는 오브젝트를 감지할 때 currentPushable이 설정되지 않는 문제를 수정했습니다.
- IsOnSideOfPushable 함수가 move.x의 방향에 따라 적절하게 동작하도록 수정했습니다.
- ComputeVelocity 함수에서 밀기 동작이 정상적으로 처리되도록 수정했습니다.
수정된 코드는 다음과 같습니다:
void CheckForPushable() { Collider2D pushableCollider = Physics2D.OverlapBox(collider2d.bounds.center, collider2d.bounds.size, 0f, pushableLayer); if (pushableCollider != null) { var pushable = pushableCollider.GetComponent<Pushable>(); if (pushable != null) { if (Mathf.Abs(move.x) > 0.01f && IsOnSideOfPushable(pushableCollider)) { if (currentPushable == null) { currentPushable = pushable; StartPushing(); } else if (currentPushable == pushable) { if (Mathf.Sign(move.x) != Mathf.Sign(lastMoveDirection)) { EndPushing(); } } } else { EndPushing(); } } else if (currentPushable != null) { EndPushing(); } } else if (currentPushable != null) { EndPushing(); } } bool IsOnSideOfPushable(Collider2D pushableCollider) { Vector2 playerBottom = collider2d.bounds.min; Vector2 playerTop = collider2d.bounds.max; Vector2 pushableBottom = pushableCollider.bounds.min; Vector2 pushableTop = pushableCollider.bounds.max; bool isSide = playerBottom.y < pushableTop.y && playerTop.y > pushableBottom.y; bool isTouchingSide = false; if (move.x > 0) { isTouchingSide = collider2d.bounds.max.x >= pushableCollider.bounds.min.x && collider2d.bounds.min.x < pushableCollider.bounds.min.x; } else if (move.x < 0) { isTouchingSide = collider2d.bounds.min.x <= pushableCollider.bounds.max.x && collider2d.bounds.max.x > pushableCollider.bounds.max.x; } return isSide && isTouchingSide; } void StartPushing() { isPushing = true; currentPushable.StartPushing(); } void EndPushing() { isPushing = false; if (currentPushable != null) { currentPushable.EndPushing(); currentPushable.StopMovement(); currentPushable = null; } } protected override void ComputeVelocity() { if (jump) { if (wallJumping) { velocity.x = wallJumpXSpeed * (spriteRenderer.flipX ? 1 : -1); velocity.y = wallJumpYSpeed; wallJumping = false; Debug.Log("Wall Jump Performed"); } else if (IsGrounded) { velocity.y = jumpTakeOffSpeed * model.jumpModifier; Debug.Log("Regular Jump Performed"); } jump = false; } else if (stopJump) { stopJump = false; if (velocity.y > 0) { velocity.y = velocity.y * model.jumpDeceleration; Debug.Log("Jump Stopped"); } } if (isPushing && currentPushable) { currentPushable.Move(new Vector2(move.x * Time.deltaTime, 0)); } if (attackState == AttackState.Attacking) { move.x = 0; } if (move.x > 0.01f) spriteRenderer.flipX = false; else if (move.x < -0.01f) spriteRenderer.flipX = true; animator.SetBool("grounded", IsGrounded); animator.SetFloat("velocityX", Mathf.Abs(velocity.x) / maxSpeed); targetVelocity = move * maxSpeed; }
이 코드에서 CheckForPushable 함수는 밀기 가능한 오브젝트를 감지하고, IsOnSideOfPushable 함수는 플레이어가 오브젝트의 측면에 있는지를 확인합니다. ComputeVelocity 함수에서는 밀기 동작이 정상적으로 처리되도록 보장합니다.
[소요 시간: 대략 27초]
GPT-4o 의 처리 속도가 많이 좋아졌어요.
GPT-4에 비해 GPT-4o의 속도 변화는 눈에 띄네요.
그리고 이번 공통 질문에 GPT-4와 GPT-4o가 답한 내용을 적용했을 때 수정 사항은 고쳐지지 않았어요.
하지만 나중에 GPT-4o가 수정 사항을 제대로 고쳐줬어요.
오늘은 새롭게 소개된 GPT-4o(“o”는 “omni”의 약자)에 대해 알아봤어요.
다음 시간에는 GPT-4o로 플랫폼 밀기 기능을 만들어볼께요.
지금까지,
언제나 성장하는 인텔리원스튜디오(IntelliOneStudio)입니다.
감사합니다.
'디지털노마드' 카테고리의 다른 글
[챗GPT 활용성 비교] GPT-4 vs. GPT-4o: 두 AI의 차이점과 최적 활용법 (71) | 2024.05.15 |
---|---|
[문제해결] 구조화된 데이터 문제 'query-input' 입력란 누락 문제 해결 (69) | 2024.05.14 |
[챗GPT게임개발24] ChatGPT를 활용하여 적 캐릭터에 생명력(헬스) 추가 (74) | 2024.05.13 |
[챗GPT게임개발23] ChatGPT를 활용하여 적 공격 처리 추가하기(3) (55) | 2024.05.12 |
[챗GPT게임개발22] ChatGPT를 활용하여 적 공격 처리 추가하기(2) (63) | 2024.05.12 |