Hello! I am making a 2D sandbox survival game (Think minecraft or terraria) and I am trying to implement a block placement/destruction system. I’ve been attempting to make this work, to no avail. Here is my character script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Oliver : MonoBehaviour {
public float speed;
public KeyCode jumpKey = KeyCode.Space;
public KeyCode walkRightKey = KeyCode.D;
public KeyCode walkLeftKey = KeyCode.A;
public Sprite walkSprite1;
public Sprite walkSprite2;
public Sprite walkSprite3;
public Sprite walkSprite4;
public Sprite walkSprite5;
public Sprite walkSprite6;
public Sprite walkSprite7;
public Sprite walkSprite8;
public Sprite walkSprite9;
public Sprite walkSprite10;
public Sprite walkSprite11;
public Sprite idleSprite;
public float jumpSpeed;
bool isWalking;
bool isGrounded;
RaycastHit2D hit;
bool facingRight;
void Update()
{
//flips the sprite
Rigidbody2D r = GetComponent<Rigidbody2D>();
r.velocity = new Vector2(Input.GetAxis("Horizontal") * speed, r.velocity.y);
if (Input.GetAxis ("Horizontal") > 0)
{
facingRight = true;
}
if (Input.GetAxis("Horizontal") < 0)
{
facingRight = false;
}
if (!facingRight)
{
GetComponent<SpriteRenderer>().flipX = true;
} else
{
GetComponent<SpriteRenderer>().flipX = false;
}
//End of flipping sprite
hit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.down);
Debug.Log(Vector2.Distance(new Vector2(transform.position.x, transform.position.y), hit.collider.transform.position));
//ignore this
if (r.velocity.magnitude > 0.1f && !isGrounded)
{
//GetComponent<SpriteRenderer>().sprite = walkSprite2;
}
//Does the walking and jumping animations
if (Input.GetKeyDown(walkLeftKey))
{
StartCoroutine(Walk());
} else if (Input.GetKeyDown(walkRightKey))
{
StartCoroutine(Walk());
} else if (isGrounded)
{
if (Input.GetKeyDown(jumpKey))
{
r.velocity = new Vector2(r.velocity.x, jumpSpeed);
StartCoroutine(Jump());
}
} else if (!isWalking)
{
GetComponent<SpriteRenderer>().sprite = idleSprite;
}
//End of animation runner
//Just for debugging
if (hit.distance < 1.9f)
{
isGrounded = true;
Debug.Log("On ground.");
}
else
{
isGrounded = false;
Debug.Log("Off ground.");
}
//End of debugging
//This is the attempted block breaking system
if (Input.GetMouseButtonDown(0))
{
Vector3 c = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit2D = Physics2D.Raycast(transform.position, c - transform.position);
if (hit2D.collider.gameObject != null)
{
Destroy(hit2D.collider.gameObject);
}
}
}
//Walk animation
IEnumerator Walk()
{
isWalking = true;
GetComponent<SpriteRenderer>().sprite = walkSprite1;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite2;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite3;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite4;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite5;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite6;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite7;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite8;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite9;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite10;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite11;
yield return new WaitForSeconds(0.05f);
isWalking = false;
}
//Jump animation
IEnumerator Jump()
{
GetComponent<SpriteRenderer>().sprite = walkSprite3;
yield return new WaitForSeconds(0.5f);
GetComponent<SpriteRenderer>().sprite = walkSprite7;
yield return new WaitForSeconds(0.5f);
}
}
For the mostpart it works but with the block destruction it does nothing. I am new to C# and Unity so maybe I made a beginner mistake.
I’ve edited your code and put in some comments. I think the issue is the raycast. you’re not hitting what you think you’re hitting. so it’s always null
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Oliver : MonoBehaviour
{
public float speed;
public KeyCode jumpKey = KeyCode.Space;
public KeyCode walkRightKey = KeyCode.D;
public KeyCode walkLeftKey = KeyCode.A;
//these sprite should be in a array, something for you to look into.
//public Sprite[] walkSprites;
public Sprite walkSprite1;
public Sprite walkSprite2;
public Sprite walkSprite3;
public Sprite walkSprite4;
public Sprite walkSprite5;
public Sprite walkSprite6;
public Sprite walkSprite7;
public Sprite walkSprite8;
public Sprite walkSprite9;
public Sprite walkSprite10;
public Sprite walkSprite11;
public Sprite idleSprite;
public float jumpSpeed;
bool isWalking;
bool isGrounded;
RaycastHit2D hit;
bool facingRight;
void Update()
{
//flips the sprite
Rigidbody2D r = GetComponent<Rigidbody2D>();
r.velocity = new Vector2(Input.GetAxis("Horizontal") * speed, r.velocity.y);
if (Input.GetAxis ("Horizontal") > 0)
{
GetComponent<SpriteRenderer>().flipX = false;
}else if (Input.GetAxis("Horizontal") < 0)
{
GetComponent<SpriteRenderer>().flipX = true;
}
//End of flipping sprite
//not being used
//hit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.down);
//Debug.Log(Vector2.Distance(new Vector2(transform.position.x, transform.position.y), hit.collider.transform.position));
//Does the walking and jumping animations
if (Input.GetKeyDown(walkLeftKey))
{
StartCoroutine(Walk());
} else if (Input.GetKeyDown(walkRightKey))
{
StartCoroutine(Walk());
} else if (isGrounded)
{
if (Input.GetKeyDown(jumpKey))
{
r.velocity = new Vector2(r.velocity.x, jumpSpeed);
StartCoroutine(Jump());
}
} else if (!isWalking)
{
GetComponent<SpriteRenderer>().sprite = idleSprite;
}
//End of animation runner
//This is the attempted block breaking system
if (Input.GetMouseButtonDown(0))
{
Vector3 c = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit2D = Physics2D.Raycast(transform.position, c - transform.position);// i assume this is the issue.
//try this, it should tell you if the raycast is hitting where you think it should be hitting.
Debug.DrawRay(transform.position, c - transform.position, Color.green);
if (hit2D.collider.gameObject != null)
{
//Debug.Log("I hit : " + hit2D.name);
Destroy(hit2D.collider.gameObject);
}
}
}
//Walk animation
IEnumerator Walk()
{
//use the array here in a loop to shorten code
isWalking = true;
GetComponent<SpriteRenderer>().sprite = walkSprite1;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite2;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite3;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite4;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite5;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite6;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite7;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite8;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite9;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite10;
yield return new WaitForSeconds(0.05f);
GetComponent<SpriteRenderer>().sprite = walkSprite11;
yield return new WaitForSeconds(0.05f);
isWalking = false;
}
//Jump animation
IEnumerator Jump()
{
GetComponent<SpriteRenderer>().sprite = walkSprite3;
yield return new WaitForSeconds(0.5f);
GetComponent<SpriteRenderer>().sprite = walkSprite7;
yield return new WaitForSeconds(0.5f);
}
}
i would also remove as many getcomponents<> that I could. They are bad for performance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Oliver : MonoBehaviour
{
public float speed;
public KeyCode jumpKey = KeyCode.Space;
public KeyCode walkRightKey = KeyCode.D;
public KeyCode walkLeftKey = KeyCode.A;
//these sprite should be in a array, something for you to look into.
//public Strite[] walkSprites;
public Sprite walkSprite1;
public Sprite walkSprite2;
public Sprite walkSprite3;
public Sprite walkSprite4;
public Sprite walkSprite5;
public Sprite walkSprite6;
public Sprite walkSprite7;
public Sprite walkSprite8;
public Sprite walkSprite9;
public Sprite walkSprite10;
public Sprite walkSprite11;
public Sprite idleSprite;
public float jumpSpeed;
bool isWalking;
bool isGrounded;
RaycastHit2D hit;
bool facingRight;
private SpriteRenderer spriteRenderer;
private Rigidbody2D r;
void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
r = GetComponent<Rigidbody2D>();
}
void Update()
{
//flips the sprite
r.velocity = new Vector2(Input.GetAxis("Horizontal") * speed, r.velocity.y);
if (Input.GetAxis ("Horizontal") > 0)
{
spriteRenderer.flipX = false;
}else if (Input.GetAxis("Horizontal") < 0)
{
spriteRenderer.flipX = true;
}
//End of flipping sprite
//not being used
//hit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.down);
//Debug.Log(Vector2.Distance(new Vector2(transform.position.x, transform.position.y), hit.collider.transform.position));
//Does the walking and jumping animations
if (Input.GetKeyDown(walkLeftKey))
{
StartCoroutine(Walk());
} else if (Input.GetKeyDown(walkRightKey))
{
StartCoroutine(Walk());
} else if (isGrounded)
{
if (Input.GetKeyDown(jumpKey))
{
r.velocity = new Vector2(r.velocity.x, jumpSpeed);
StartCoroutine(Jump());
}
} else if (!isWalking)
{
spriteRenderer.sprite = idleSprite;
}
//End of animation runner
//This is the attempted block breaking system
if (Input.GetMouseButtonDown(0))
{
Vector3 c = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit2D = Physics2D.Raycast(transform.position, c - transform.position);// i assume this is the issue.
//try this, it should tell you if the raycast is hitting where you think it should be hitting.
Debug.DrawRay(transform.position, c - transform.position, Color.green);
if (hit2D.collider.gameObject != null)
{
//Debug.Log("I hit : " + hit2D.name);
Destroy(hit2D.collider.gameObject);
}
}
}
//Walk animation
IEnumerator Walk()
{
//use the array here in a loop to shorten code
isWalking = true;
spriteRenderer.sprite = walkSprite1;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite2;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite3;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite4;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite5;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite6;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite7;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite8;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite9;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite10;
yield return new WaitForSeconds(0.05f);
spriteRenderer.sprite = walkSprite11;
yield return new WaitForSeconds(0.05f);
isWalking = false;
}
//Jump animation
IEnumerator Jump()
{
spriteRenderer.sprite = walkSprite3;
yield return new WaitForSeconds(0.5f);
spriteRenderer.sprite = walkSprite7;
yield return new WaitForSeconds(0.5f);
}
}
Made 2 corrections, 1 to prevent an exception & one to solve your raycast hit issue, I believe
if (Input.GetMouseButtonDown(0))
{
/* Changed */
Vector3 c = Camera.main.ScreenToWorldPoint(new Vector3(
Input.mousePosition.x, Input.mousePosition.y,
Mathf.Abs(Camera.main.transform.position.z - transform.position.z)));
RaycastHit2D hit2D = Physics2D.Raycast(transform.position, c - transform.position);// i assume this is the issue.
//try this, it should tell you if the raycast is hitting where you think it should be hitting.
Debug.DrawRay(transform.position, c - transform.position, Color.green,1);
/* Changed - removed '.gameObject', because if '.collider' is null, it would throw an exception */
if (hit2D.collider != null)
{
Destroy(hit2D.collider.gameObject);
}
}
Thank you for the help! I’m new to C# and Unity. But… I keep getting this error:
NullReferenceException: Object reference not set to an instance of an object
Oliver.Update () (at Assets/Scripts/Character Scripts/Oliver.cs:116)
I’m using a 2D Box collider, is that a problem?