这是参加Nway的面试,测试题,有猎头推荐,Nway,时空之刃,公司的主要人员,参与暗黑游戏,火炬之光等高质量的游戏成员主导研发。国内由网易雷火发行,现在正成立中国区团队。
Client Engineer Programming Test:
Please write a simple breakout clone in Unity.
When completed please return the completed Unity project and playable scene.
This project should take roughly 3 – 4 hours to complete, however you can spend more time on it if you feel it will give a better impression of your skills, please report back with how much time you spent on it.
Bonus points for tile effects, ball effects, and visually amazing submissions.
Very basic breakout:
https://www.youtube.com/watch?v=hW7Sg5pXAok
More advanced breakout (Arkanoid):
https://www.youtube.com/watch?v=YzplBmJ8Q-4
观看需要翻墙。
高等难度的有实现:
1.有随机的buff掉落
2.球可以变为实心的,可以一下穿过所有的障碍物
3.滑板,可以变为double,
4.小球每撞击下,可以分类成3个。
5.实现滑板可以直接射击砖块
项目在github 上https://github.com/zhutaorun/Breakout/
master 分支是最快实现的方法
branch 是重新整合,从统一管理和游戏状态是实现,可扩展性比较高了
考察点:
1.是对unity本身的熟悉
2.对编码风格的了解
3.对一些常见的物理场景的实现
4.一些知识点的考察,如碰撞和物理实现
master上最主要的代码 Player,挂在滑板上的,难点是左右边距,在不同的显示屏幕下,边框距离是不同,可以使用boxcollider,来约束。
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
public float playerVelocity;
private Vector3 playerPosition;
public float boundary;
private int playerLives;
private int playerPoints;
public AudioClip pointSound;
public AudioClip lifeSound;
// Use this for initialization
void Start() {
playerPosition = gameObject.transform.localPosition;
playerLives = 3;
playerPoints = 0;
}
// Update is called once per frame
private void Update()
{
//horizontal movement
playerPosition.x += Input.GetAxis("Horizontal")*playerVelocity;
//leave the game
if (Input.GetKeyDown(KeyCode.Escape))
{
Application.Quit();
}
transform.localPosition =playerPosition;
// boundaries
if (playerPosition.x < -boundary)
{
transform.localPosition = new Vector3(-boundary, playerPosition.y, playerPosition.z);
}
if (playerPosition.x > boundary)
{
transform.localPosition = new Vector3(boundary, playerPosition.y, playerPosition.z);
}
//check game state
WinLose();
}
private void WinLose()
{
//restart the game
if (playerLives == 0)
{
Application.LoadLevel("first");
}
//blocks destroyed
if(GameObject.FindGameObjectsWithTag("Block").Length==0)
{
//Check the current level
if (Application.loadedLevelName == "first")
{
Application.LoadLevel("second");
}
else
{
Application.Quit();
}
}
}
public void AddPoints(int points)
{
playerPoints += points;
GetComponent<AudioSource>().PlayOneShot(pointSound);
}
private void OnGUI()
{
GUI.Label(new Rect(5.0f,3.0f,200.0f,200.0f),"lives:"+playerLives +"Score:" +playerPoints);
}
public void TakeLife()
{
playerLives--;
GetComponent<AudioSource>().PlayOneShot(lifeSound);
}
}
BallScript,挂着球体上,难点是掉落的算法,一种是y坐标低于滑板,或者colldier下来判断,在develop分支使用这种方法
using UnityEngine;
using System.Collections;
public class BallScript : MonoBehaviour {
private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;
private Rigidbody2D ballRigidbody2D;
// GameObject
public GameObject playerObject;
public AudioClip hitSound;
// Use this for initialization
void Start() {
// create the force
ballInitialForce = new Vector2(2000.0f, 4000.0f);
// set to inactive
ballIsActive = false;
// ball position
ballPosition = transform.position;
ballRigidbody2D = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update() {
// check for user input
if (Input.GetButtonDown("Jump") == true)
{
// check if is the first play
if (!ballIsActive){
// add a force
ballRigidbody2D.isKinematic = false;
ballRigidbody2D.AddForce(ballInitialForce);
// set ball active
ballIsActive = !ballIsActive;
}
}
if (!ballIsActive && playerObject != null)
{
// get and use the player position
ballPosition.x = playerObject.transform.position.x;
// apply player X position to the ball
transform.position = ballPosition;
}
//Check if ball falls
if (ballIsActive && transform.position.y < -6)
{
ballIsActive = !ballIsActive;
ballPosition.x = playerObject.transform.position.x;
ballPosition.y = 65f;
transform.position = ballPosition;
ballRigidbody2D.isKinematic = true;
playerObject.SendMessage("TakeLife");
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (ballIsActive)
{
GetComponent<AudioSource>().PlayOneShot(hitSound);
}
}
}
BlockScript,OnCollisionEnter2D,是现实的重点,这边实现了多种颜色装块的不同碰撞次数和得分值。sendMessage 方法,从实现角度,算是最快的
using UnityEngine;
using System.Collections;
public class BlockScript : MonoBehaviour
{
public int hitsTokill;
public int points;
private int numberOfHits;
// Use this for initialization
void Start()
{
numberOfHits = 0;
}
// Update is called once per frame
void Update() {
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Ball")
{
numberOfHits++;
if (numberOfHits == hitsTokill)
{
//get reference of player object
GameObject player = GameObject.FindGameObjectWithTag("Player");
//send message
player.SendMessage("AddPoints", points);
//destroy the object
Destroy(this.gameObject);
}
}
}
}
develop 分支最重要的脚本GameManager
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public static int lives = 3;
public static int score = 0;
public static GameState currentGameState = GameState.Start;
public static int blockCount = 28;
private GameObject[] blocks;
public static BallScript ball;
Text statusText;
// Use this for initialization
void Start () {
blocks = GameObject.FindGameObjectsWithTag("Block");
ball = GameObject.Find ("Ball").GetComponent<BallScript>();
statusText = GameObject.Find ("Status").GetComponent<Text>();
}
private bool InputTake()
{
return Input.touchCount > 0 || Input.GetMouseButtonUp(0);
}
// Update is called once per frame
void Update ()
{
switch (currentGameState)
{
case GameState.Start:
if(InputTake())
{
statusText.text = string.Format("Lives:{0}Score:{1}",lives,score);
currentGameState = GameState.Playing;
ball.StartBall();
}
break;
case GameState.Playing:
statusText.text = string.Format("Lives:{0}Score:{1}",lives,score);
break;
case GameState.Won:
if(InputTake())
{
Restart();
ball.StartBall();
statusText.text = string.Format("Lives:{0}Score:{1}",lives,score);
currentGameState = GameState.Playing;
}
break;
case GameState.LostALife:
if(InputTake())
{
ball.StartBall();
statusText.text = string.Format("Lives:{0}Score:{1}",lives,score);
currentGameState = GameState.Playing;
}
break;
case GameState.LostAllLives:
if(InputTake())
{
Restart();
ball.StartBall();
statusText.text = string.Format("Lives:{0}Score:{1}",lives,score);
currentGameState = GameState.Playing;
}
break;
default:
break;
}
}
private void Restart()
{
foreach (var item in blocks)
{
item.SetActive(true);
}
lives = 3;
score = 0;
}
public void DecreaseLives()
{
if (lives > 0)
{
lives--;
}
if (lives == 0)
{
statusText.text = "Lost all lives.Tap to play again";
currentGameState = GameState.LostAllLives;
}
else
{
statusText.text = "Lost a life.Tap to continue";
currentGameState = GameState.LostALife;
}
ball.StopBall();
}
public enum GameState
{
Start,
Playing,
Won,
LostALife,
LostAllLives
}
}
面试反馈。我是在大概3个月没碰unity的情况下,电话面试,因为手机的问题,不是很好,还在等消息.
消息出来了,继续看机会了
使用unity5.1版本,4.6的版本打不开的。
unitypackage下载 http://pan.baidu.com/s/1mgq1QNe