- Home /
Adding collision detection to movement script...
I found a great script on the forums and modified it slightly to do my bidding; I am attempting to create a grid-based movement system, similar to that of classic games such as Eye of the Beholder. The system is working out fine in terms of movement, yet it does not detect collision, and completely stops functioning when a RigidBody component is added to my character (who is just a cube with a camera). I was wondering how collision detection may be carried out in the sense that moving when stood in front of a wall is not permitted, instead of just smashing into the wall and destroying the metric offset of the project.
Here is the script I am using:
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour {
//Translation:
float movSpeed = 4.0f;
Vector3 pos;
Transform tr ;
bool moving = false;
//Rotation:
bool rotating = false;
public float rotSpeed = 360f;
float rotDegrees = 0f;
Quaternion rotToAngle ;
void Start () {
pos = transform.position;
tr = transform;
}
// Update is called once per frame
void Update () {
Debug.DrawRay(transform.position, transform.forward, Color.red);
//Input:
if (!moving && !rotating) {
if (Input.GetKey(KeyCode.D) && tr.position == pos) {
//pos += Vector3.right;
pos += transform.right;
moving=true;
// print ("MOVE LEFT");
} else if (Input.GetKey(KeyCode.A) && tr.position == pos) {
pos += -transform.right;
moving=true;
// print ("MOVE RIGHT");
} else if (Input.GetKey(KeyCode.W) && tr.position == pos) {
pos += transform.forward;
moving=true;
// print ("MOVE FORWARD");
} else if (Input.GetKey(KeyCode.S) && tr.position == pos) {
pos += -transform.forward;
moving=true;
// print ("MOVE BACK");
} else if (Input.GetKey(KeyCode.Q) && tr.position == pos) {
rotDegrees -= 90f;
//rotToAngle = Quaternion.Euler(0, rotDegrees, 0);
rotToAngle = Quaternion.Euler(0, rotDegrees, 0);
rotating = true;
// print ("TURN LEFT");
} else if (Input.GetKey(KeyCode.E) && tr.position == pos) {
rotDegrees += 90f;
//rotToAngle = Quaternion.Euler(0, rotDegrees, 0);
rotToAngle = Quaternion.Euler(0, rotDegrees, 0);
rotating = true;
// print ("TURN RIGHT");
}
}
//Translation:
if (moving) {
if (Vector3.Distance(transform.position,pos) <0.05f){
transform.position = pos;
moving=false;
// print ("FINISHED MOVE");
} else {
transform.position = Vector3.MoveTowards(transform.position, pos, Time.deltaTime * movSpeed);
}
}
//Rotation:
if (rotating) {
if (Quaternion.Angle(transform.rotation,rotToAngle) <10f) {
transform.rotation = rotToAngle;
rotating=false;
// print ("FINISHED TURN");
} else {
transform.rotation = Quaternion.RotateTowards(transform.rotation, rotToAngle, rotSpeed * Time.deltaTime);
}
}
}
}
Thanks in advance!
Hi, well, at the time of "Eye of the Beholder", there was very limited CPU and RA$$anonymous$$ so collisions were managed using 2D grids = 2 dimension tables of bytes or integers containing flags. Example: you could represent the "collision world" (= not the graphic one) by a "$$anonymous$$yEnum $$anonymous$$yTable[,]". $$anonymous$$yEnum would be an enum/bitfield that could be "floor", "wall", "trap" etc... Players and NPC would check collisions by checking if the element of the table they want to go is a wall or not. Level design could be done using a simple text file loaded in this table... Now, things gets more complicated than that but that's a start :-)
You've got me all curious and interested!
Can you please give me a simple example and how it could be done in Unity3D?
Thanks a lot! :D
Edit: I'd like, if possible, the enumeration to have two values, one for no collision and the second for collision. I'd program every other thing (traps, etc...) through triggers and simple scripts.
Here are some resources about loading a text file in a table to represent the level design: http://www.michaeljohnstephens.com/devblog/creating-storing-and-loading-levels-with-text-files-in-unity or http://answers.unity3d.com/questions/577889/create-level-based-on-xmltxt-file.html
The table will be the "logical" world, with coordinates like mytable[i,j] with i, j being integers. The "graphical world" can be instantiated based on this logical world at coordinates represented by Vector3((float)i, 0.0f, (float)j). This is the same concept as a platformer or 2D game, with 3D elements ins$$anonymous$$d of 2D sprites to represent the graphical world.
Would be awesome if you can convert your comment to an answer, I'd mark it as accepted :D
Answer by Mmmpies · Dec 29, 2014 at 09:15 PM
Really all that text file stuff is creating an array based on a text file.
So all you need is an array to store where your walls are, lets say free space to move to = 0 and a wall = 1.
using UnityEngine;
using System.Collections;
public class MapArray : MonoBehaviour {
public int[,] mapArray = new int[6,6] {
{1, 1, 0, 1, 1, 1},
{1, 0, 0, 1, 0, 1}, // start point xPos = 1 (this line) yPos = 4 (5th number)
{1, 0, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 1},
{1, 0 ,0, 0 ,1, 1},
{1, 1, 1, 1, 1, 1}
};
private int xPos;
private int yPos;
void Start()
{
xPos = 1;
yPos = 4;
Debug.Log ("Starting on a point that == " + mapArray[xPos,yPos]);
}
}
Basic I know but before you move onto the next place check that place == 0 and not 1. You'll need to establish which way you're facing but if you intend to move down then check mapArray[xPos + 1, yPos] and if = 0 move, if = 1 don't move.
You could also add other numbers that reference traps or gold. Sorry I'm not familiar with Eye of the Beholder so don't know if you want those things in your game.