March 17th, 2016

[KISSCODE] Let's make SNAKE Pt. 3

by Adhi.Lius

Hi happy another Thursday. Now continuing from our previous post, we are going to the next step, drawing the snake and the control.

For the first thing, we need to set the snake into the snake array with code 2. And then we are going to redraw the snake based on the position in the snake array.

//set the snake first position
public GameObject snakePrefab;
protected Vector2 FIRST_SNAKE_POS = new Vector2(20,15);
protected void InitSnake(){
snakeArray [(int) FIRST_SNAKE_POS.x,(int) FIRST_SNAKE_POS.y] = 2;
}
//draw anything besides the wall
protected void RedrawScene(){
for (int i = 1;i<39;i++){
for (int j = 1; j < 29; j++) {
int code = snakeArray [i, j];
if (code != 0) {
float POS_X = FIRST_POS_X + (i * BLOCK_SiZE);
float POS_Y = FIRST_POS_Y - (j * BLOCK_SiZE);
if (code == 2){
GameObject nSnakeBody = Instantiate (snakePrefab);
nSnakeBody.transform.parent = stageHolder;
nSnakeBody.transform.position = new Vector2 (POS_X, POS_Y);
}
}
}
}
}
// Use this for initialization
void Start () {
InitWalls ();
InitSnake ();
DrawScene ();
RedrawScene ();
}

The InitSnake method will set the snake position in the array. You can change the position to your liking but it is advisable to start it in the middle. The RedrawScene is going to be our method for redrawing the snake and fruit, everything aside from the wall. I separate it with the DrawScene method because the walls rarely needs to be redrawn.

Now we only need to assign the snakePrefab from the editor. Drag the snake body image to the scene and then drag it back to the project explorer to create a prefab. Then drag the prefab to the controller script and then hit the run and see the snake redrawn to the scene.

The next we are going to read user input. We are going to move the snake depending on the arrowkey. To do this, we need to record the snake moving direction and then change the snake position depending on the direction in each update.

protected const byte MOVE_UP = 0;
protected const byte MOVE_LEFT = 1;
protected const byte MOVE_RIGHT = 2;
protected const byte MOVE_DOWN = 3;
protected byte cSnakeDir = 0;
protected Vector2 cSnakePos;
// Update is called once per frame
void Update () {
ReadInput ();
}
//read input
protected void ReadInput(){
if (Input.GetKeyDown (KeyCode.LeftArrow)) {
cSnakeDir = MOVE_LEFT;
} else if (Input.GetKeyDown (KeyCode.RightArrow)) {
cSnakeDir = MOVE_RIGHT;
} else if (Input.GetKeyDown (KeyCode.UpArrow)) {
cSnakeDir = MOVE_UP;
} else if (Input.GetKeyDown (KeyCode.DownArrow)) {
cSnakeDir = MOVE_DOWN;
}
}

Okay the addition is pretty straightforward, we put the ReadInput in each Update to read the user input. Then we put the input to the cSnakeDir variable to record it for the update. Then the next step is to read that cSnakeDir and then updatethe cSnakeArr to represent the view.

void FixedUpdate () {
MoveSnake ();
RefreshSnakeArray ();
RedrawScene ();
}
//move snake depending on the direction
protected void MoveSnake(){
switch(cSnakeDir){
case MOVE_UP:
cSnakePos.y--;
if (cSnakePos.y < 1)
cSnakePos.y = 1;
break;
case MOVE_DOWN:
cSnakePos.y++;
if (cSnakePos.y > 28)
cSnakePos.y = 28;
break;
case MOVE_LEFT:
cSnakePos.x--;
if (cSnakePos.x < 1)
cSnakePos.x = 1;
break;
case MOVE_RIGHT:
cSnakePos.x++;
if (cSnakePos.x > 38)
cSnakePos.x = 38;
break;
}
}
//recount the array
protected void RefreshSnakeArray(){
for (int i = 1; i < 39; i++) {
for (int j = 1; j < 29; j++) {
snakeArray [i, j] = 0;
}
}
snakeArray [(int)cSnakePos.x, (int)cSnakePos.y] = 2;
}
protected List<GameObject> drawnObject = new List<GameObject>();
protected void CleanScene(){
for (int i=0;i<drawnObject.Count;i++){
Destroy (drawnObject[i]);
}
drawnObject.Clear ();
}
//draw anything besides the wall
protected void RedrawScene(){
CleanScene ();
for (int i = 1;i<39;i++){
for (int j = 1; j < 29; j++) {
int code = snakeArray [i, j];
if (code != 0) {
float POS_X = FIRST_POS_X + (i * BLOCK_SiZE);
float POS_Y = FIRST_POS_Y - (j * BLOCK_SiZE);
if (code == 2){
GameObject nSnakeBody = Instantiate (snakePrefab);
nSnakeBody.transform.parent = stageHolder;
nSnakeBody.transform.position = new Vector2 (POS_X, POS_Y);
drawnObject.Add (nSnakeBody);
}
}
}
}
}
Now we are adding more methods. First for the update, we update the redrawScene by adding a call to method CleanScene. The purpose is simple, CleanScene will remove all objects in the drawnObject list, so each time an object is created, we are going to put it inside the list. We use a list because later drawnObject will contain more than a single object inside it.

So next for the direction, we already store the snake direction inside the cSnakeDir so we are going to update the snake position . MoveSnake method is going to update it for us and making sure that the snake won't move beyond the wall. The RefreshSnakeArray will update the array and so we get a clean array with updated snake position.

For you who confuse why I put them into the FixedUpdate method instead of Update method, it is because we want to draw the scene in a fixed interval. Now run and we can see the result.

Okay for the last of today's blog, We know that in proper snake game, we should make sure that the snake can not move backwards (if it goes left, it can not just goes right). So we are going to update the ReadInput to include that limitation.

//read input
protected void ReadInput(){
if (Input.GetKeyDown (KeyCode.LeftArrow) && cSnakeDir != MOVE_RIGHT) {
cSnakeDir = MOVE_LEFT;
} else if (Input.GetKeyDown (KeyCode.RightArrow) && cSnakeDir != MOVE_LEFT) {
cSnakeDir = MOVE_RIGHT;
} else if (Input.GetKeyDown (KeyCode.UpArrow) && cSnakeDir != MOVE_DOWN) {
cSnakeDir = MOVE_UP;
} else if (Input.GetKeyDown (KeyCode.DownArrow) && cSnakeDir != MOVE_UP) {
cSnakeDir = MOVE_DOWN;
}
}

Now run the scene and you could feel the difference.

Okay I think this blog is long enough for today #KISSCodeThursday, so we are going to stop here and heads for next week when we are going to update the scripts to draw the snake body moving.

See you next week :)


Originally posted in blog.sinergistudio.com

Comments (0)