英文:
Why does my Teleport Move not function the way I want it to?
问题
我明白你的需求,你希望你的玩家角色在触地面之前只能传送一次。在你的代码中,你可以通过以下方式来实现这个功能:
- 在Teleport脚本中添加一个新的布尔变量,用于跟踪是否已经传送过:
public bool hasTeleported = false;
- 修改你的t_PORT方法,只有在玩家没有传送过(hasTeleported为false)并且同时按下鼠标左键时才执行传送操作:
public void t_PORT()
{
bool ground_check = characterController2D.m_Grounded;
if (!hasTeleported && Input.GetMouseButtonDown(0))
{
screenPosition = Input.mousePosition;
worldPosition = Camera.main.ScreenToWorldPoint(screenPosition);
transform.position = worldPosition;
// 设置已传送标志为true
hasTeleported = true;
}
if (ground_check)
{
// 如果玩家着陆,重置已传送标志为false,以便他们可以再次传送
hasTeleported = false;
}
}
这样,玩家只能在触地面之前传送一次,然后需要再次接触地面才能进行下一次传送。
英文:
I am doing my Computer Science A-Level NEA and I want to program a teleport for my player character to use in these circumstances:
- The direction of the teleport is controlled by the left mouse button
- The player can only teleport once until they touch the ground again
- If the player teleports through enemies then those enemies will be instantly killed.
The third one isn't too important at the moment as the 2nd condition isn't working properly.
> using System.Collections; using System.Collections.Generic; using
> UnityEngine;
>
> public class Teleport : MonoBehaviour {
> public Vector2 screenPosition;
> public Vector2 worldPosition;
>
> private CharacterController2D characterController2D;
>
> public bool canTeleport = true;
>
> void Awake()
> {
> characterController2D = GetComponent<CharacterController2D>();
> }
>
> public void t_PORT()
> {
> bool ground_check = characterController2D.m_Grounded;
> if (canTeleport = true && Input.GetMouseButtonDown(0))
> {
> screenPosition = Input.mousePosition;
>
> worldPosition = Camera.main.ScreenToWorldPoint(screenPosition);
>
> transform.position = worldPosition;
>
> while (ground_check = false)
> {
> if (ground_check = false)
> {
> canTeleport = false;
> }
>
> else
> {
> canTeleport = true;
> }
> }
> }
> } }
Here is the code for the teleport. It works by taking the on-screen position of the mouse when clicked, translating it into an in-game position and changing the player's position to that of the mouse's.
I took a boolean value from my Character Controller called m_grounded which checks to see if the player is currently touching the ground. I thought that if the player has already teleported I could use a while loop (it would loop on the condition that m_grounded is false and break when the player touches the ground allowing them to teleport again). The first time I tried this it didn't work as I had the code in an Update Class and when I would teleport the game would freeze. I then put it into it's own class called t_Port (which you can see above) but then the player wouldn't teleport at all. I decided to put it in a FixedUpdate class which allowed the player to teleport once more but the player could teleport an infinite amount of times (which I do not want).
The script for my character controller is here:
> using UnityEngine; using UnityEngine.Events;
>
> public class CharacterController2D : MonoBehaviour { [SerializeField]
> private float m_JumpForce = 400f; // Amount
> of force added when the player jumps. [Range(0, 1)] [SerializeField]
> private float m_CrouchSpeed = .36f; // Amount of maxSpeed
> applied to crouching movement. 1 = 100% [Range(0, .3f)]
> [SerializeField] private float m_MovementSmoothing = .05f; // How
> much to smooth out the movement [SerializeField] private bool
> m_AirControl = false; // Whether or not a
> player can steer while jumping; [SerializeField] private LayerMask
> m_WhatIsGround; // A mask determining what is
> ground to the character [SerializeField] public Transform
> m_GroundCheck; // A position marking where
> to check if the player is grounded. [SerializeField] private
> Transform m_CeilingCheck; // A position
> marking where to check for ceilings [SerializeField] private
> Collider2D m_CrouchDisableCollider; // A collider that
> will be disabled when crouching
>
> const float k_GroundedRadius = .2f; // Radius of the overlap circle
> to determine if grounded public bool m_Grounded; //
> Whether or not the player is grounded. const float k_CeilingRadius =
> .2f; // Radius of the overlap circle to determine if the player can
> stand up private Rigidbody2D m_Rigidbody2D; private bool
> m_FacingRight = true; // For determining which way the player is
> currently facing. private Vector3 m_Velocity = Vector3.zero;
>
> [Header("Events")] [Space]
>
> public UnityEvent OnLandEvent;
>
> [System.Serializable] public class BoolEvent : UnityEvent<bool> { }
>
> public BoolEvent OnCrouchEvent; private bool m_wasCrouching = false;
>
> private void Awake() { m_Rigidbody2D =
> GetComponent<Rigidbody2D>();
>
> if (OnLandEvent == null) OnLandEvent = new UnityEvent();
>
> if (OnCrouchEvent == null) OnCrouchEvent = new BoolEvent(); }
>
> public void FixedUpdate() { bool wasGrounded = m_Grounded;
> m_Grounded = false;
>
> // The player is grounded if a circlecast to the groundcheck
> position hits anything designated as ground // This can be done
> using layers instead but Sample Assets will not overwrite your project
> settings. Collider2D[] colliders =
> Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius,
> m_WhatIsGround); for (int i = 0; i < colliders.Length; i++) {
> if (colliders[i].gameObject != gameObject) {
> m_Grounded = true;
> if (!wasGrounded)
> OnLandEvent.Invoke(); } } }
>
>
> public void Move(float move, bool crouch, bool jump) { // If
> crouching, check to see if the character can stand up if (!crouch)
> { // If the character has a ceiling preventing them from standing
> up, keep them crouching if
> (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius,
> m_WhatIsGround)) {
> crouch = true; } }
>
> //only control the player if grounded or airControl is turned on
> if (m_Grounded || m_AirControl) {
>
> // If crouching if (crouch) {
> if (!m_wasCrouching)
> {
> m_wasCrouching = true;
> OnCrouchEvent.Invoke(true);
> }
>
> // Reduce the speed by the crouchSpeed multiplier
> move *= m_CrouchSpeed;
>
> // Disable one of the colliders when crouching
> if (m_CrouchDisableCollider != null)
> m_CrouchDisableCollider.enabled = false; } else {
> // Enable the collider when not crouching
> if (m_CrouchDisableCollider != null)
> m_CrouchDisableCollider.enabled = true;
>
> if (m_wasCrouching)
> {
> m_wasCrouching = false;
> OnCrouchEvent.Invoke(false);
> } }
>
> // Move the character by finding the target velocity Vector3
> targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
> // And then smoothing it out and applying it to the character
> m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity,
> targetVelocity, ref m_Velocity, m_MovementSmoothing);
>
> // If the input is moving the player right and the player is facing
> left... if (move > 0 && !m_FacingRight) {
> // ... flip the player.
> Flip(); } // Otherwise if the input is moving the player left and the player is facing right... else if (move < 0 &&
> m_FacingRight) {
> // ... flip the player.
> Flip(); } } // If the player should jump... if (m_Grounded && jump) { // Add a vertical force to the player.
> m_Grounded = false; m_Rigidbody2D.AddForce(new Vector2(0f,
> m_JumpForce)); } }
>
>
> private void Flip() { // Switch the way the player is labelled as
> facing. m_FacingRight = !m_FacingRight;
>
> // Multiply the player's x local scale by -1. Vector3 theScale =
> transform.localScale; theScale.x *= -1; transform.localScale =
> theScale; } }
And here is my Player Movement script:
> using System.Collections; using System.Collections.Generic; using
> UnityEngine;
>
> public class PlayerMovement : MonoBehaviour {
>
> public CharacterController2D controller;
> public Animator animator;
>
> float X_Speed = 0.0f;
> float Y_Speed = 0.0f;
> float Ground_speed = 0.0f;
> float Ground_angle;
>
> float acceleration_speed = 0.46875f;
> float deceleration_speed = 5.0f;
> float friction_speed = 0.66875f;
> float top_speed = 100.0f;
>
> public bool jump = false;
> bool crouch = false;
>
>
> // Update is called once per frame
> void Update()
> {
>
> if (Input.GetAxisRaw("Horizontal") < 0) //if player is pressing left
> {
> if (X_Speed > 0.0f)
> {
> X_Speed -= deceleration_speed; //decelerate
>
> if (X_Speed <= 0.0f)
> {
> X_Speed = -0.5f;
> }
> }
>
> else if (X_Speed > -top_speed)
> {
> X_Speed -= acceleration_speed; //accelerate
> if (X_Speed <= -top_speed)
> {
> X_Speed = -top_speed; //impose top speed limit
> }
> }
>
> }
>
> if (Input.GetAxisRaw("Horizontal") > 0) //if player is pressing right
> {
> if (X_Speed < 0.0f) //if moving to the left
> {
> X_Speed += deceleration_speed; //decelerate
> if (X_Speed >= 0.0f)
> {
> X_Speed = 0.5f;
> }
> }
>
> else if (X_Speed < top_speed)
> {
> X_Speed += acceleration_speed; //accelerate
> if (X_Speed >= top_speed)
> {
> X_Speed = top_speed; //impose top speed limit
> }
> }
>
> }
>
> if (Input.GetAxis("Horizontal") == 0)
> {
> X_Speed -= friction_speed; //decelerate
> if (X_Speed <= 0)
> {
> X_Speed = 0.0f;
> }
> }
>
> animator.SetFloat("Speed", Mathf.Abs(X_Speed));
>
> if (Input.GetButtonDown("Jump"))
> {
> jump = true;
> animator.SetBool("isJumping", true);
> }
>
> if (Input.GetButtonDown("Crouch"))
> {
> crouch = true;
> }
> else if (Input.GetButtonUp("Crouch"))
> {
> crouch = false;
> }
> }
>
> private void onCollisionEnter2D(Collision2D other)
> {
>
> }
>
> public void OnLanding()
> {
> animator.SetBool("isJumping", false);
> }
>
> public void OnCrouching(bool isCrouching)
> {
> animator.SetBool("isCrouching", isCrouching);
> }
>
> void FixedUpdate()
> {
> // Move the character, jump and croutch
> controller.Move(X_Speed * Time.fixedDeltaTime, crouch, jump);
> jump = false;
> } }
I would like for my player character to teleport once before having to touch the ground to be able to teleport again.
答案1
得分: 0
我欣赏您发布所有相关代码的细致,但错误出现在第一个代码片段中:
while (ground_check = false)
{
if (ground_check = false)
{
...
一个等号是赋值,两个等号是相等性检查:
while (ground_check == false)
{
if (ground_check == false)
{
...
英文:
I appreciate the thouroughness of posting all relevant code, but the error is in the very first snippet:
while (ground_check = false)
{
if (ground_check = false)
{
...
One equals sign is an assignment, two is an equality check:
while (ground_check == false)
{
if (ground_check == false)
{
...
答案2
得分: 0
这解决了我的问题:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Teleport : MonoBehaviour {
public Vector2 screenPosition;
public Vector2 worldPosition;
private CharacterController2D characterController2D;
public bool canTeleport = true;
void Awake()
{
characterController2D = GetComponent<CharacterController2D>();
}
void FixedUpdate()
{
if (canTeleport == true && Input.GetMouseButtonDown(0))
{
T_Port();
}
else
{
bool ground_check = characterController2D.m_Grounded;
if (!ground_check && canTeleport == false)
{
canTeleport = false;
}
else
{
canTeleport = true;
}
}
}
public void T_Port()
{
screenPosition = Input.mousePosition;
worldPosition = Camera.main.ScreenToWorldPoint(screenPosition);
transform.position = worldPosition;
canTeleport = false;
}
}
英文:
This fixed my problems:
> using System.Collections; using System.Collections.Generic; using
> UnityEngine;
>
> public class Teleport : MonoBehaviour {
> public Vector2 screenPosition;
> public Vector2 worldPosition;
>
> private CharacterController2D characterController2D;
>
> public bool canTeleport = true;
>
> void Awake()
> {
> characterController2D = GetComponent<CharacterController2D>();
> }
>
> void FixedUpdate()
> {
> if (canTeleport == true && Input.GetMouseButtonDown(0))
> {
>
> T_Port();
> }
>
> else
> {
> bool ground_check = characterController2D.m_Grounded;
>
> if (!ground_check && canTeleport == false)
> {
> canTeleport = false;
> }
> else
> {
> canTeleport = true;
> }
> }
> }
>
> public void T_Port()
> {
> screenPosition = Input.mousePosition;
>
> worldPosition = Camera.main.ScreenToWorldPoint(screenPosition);
>
> transform.position = worldPosition;
>
> canTeleport = false;
> }
>
> }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论