2048 Source

2048 source code is here:

https://github.com/gabrielecirulli/2048

Play here!
http://gabrielecirulli.github.io/2048/

The code contains 2 parts: logic and presentation(ui, animation, etc.).

In order to make it run in Unity editor, JSBinding rewrited presentation part. JSBinding only made slight change to logic part(less than 5 lines).

Presentation code contains:

  1. storage (store last game state)
  2. input manager (handle input)
  3. actuator (ui, animation)

JSBinding's storage code

It's quite simple, just use PlayerPrefs to store int and string.

var UnityStorageManager = function () {
var bestScoreKey = "2048BestScroe";
var gameStateKey = "2048GameState"; this.getBestScore = function () {
var bs = UnityEngine.PlayerPrefs.GetInt$$String$$Int32(bestScoreKey, 0);
return bs;
}
this.setBestScore = function (bestScore) {
UnityEngine.PlayerPrefs.SetInt(bestScoreKey, bestScore);
} this.clearGameState = function () {
UnityEngine.PlayerPrefs.SetString(gameStateKey, "");
}
this.getGameState = function () {
var gameState = UnityEngine.PlayerPrefs.GetString$$String$$String(gameStateKey, "");
if (gameState != null && gameState.length > 0) {
return JSON.parse(gameState);
}
}
this.setGameState = function (gameState) {
UnityEngine.PlayerPrefs.SetString(gameStateKey, JSON.stringify(gameState));
}
}

JSBinding's input manager code

It's quite simple as well, not much difference from original. It cooperates with ui_controller, see below.

var InputManager = function () {
var events = {}; this.on = function (e, cb) {
if (!events[e]) {
events[e] = [];
}
events[e].push(cb);
} this.emit = function (e, data) {
var cbs = events[e];
if (cbs) {
cbs.forEach(function(cb) {
cb(data);
});
}
} this.keepPlaying = function () {
//print("InputManager.keeyPlaying");
}
}

JSBindng's actuator code

var Actuator = function (ui) {

    this.continueGame = function () {
print("Actuator.continueGame");
} this.actuate = function (grid, metadata) {
var self = this; self.clearContainer(self.tileContainer); grid.cells.forEach(function (column) {
column.forEach(function (tile) {
if (tile) {
self.addTile(tile);
}
});
}); self.updateScore(metadata.score);
self.updateBestScore(metadata.bestScore); if (metadata.terminated) {
if (metadata.over) {
self.message(false); // You lose
}
else if (metadata.won) {
self.message(true); // You win!
}
}
} this.clearContainer = function () {
ui.clearUITiles();
} this.addTile = function (tile) {
var position = tile.previousPosition || { x: tile.x, y: tile.y }; var uiTile = ui.getUITile(tile.x, tile.y)
uiTile.setValue(tile.value); if (tile.previousPosition) {
var previousUITile = ui.getUITile(tile.previousPosition.x, tile.previousPosition.y);
uiTile.moveFrom(previousUITile.originPos);
} else if (tile.mergedFrom) {
tile.mergedFrom.forEach(function (merged) {
//print("merged from (" + merged.x + "," + merged.y + ") -> (" + tile.x + "," + tile.y + ")");
var tempUITile = ui.createTempUITile(tile.x, tile.y);
tempUITile.setValue(merged.value);
var previousUITile = ui.getUITile(merged.previousPosition.x, merged.previousPosition.y);
tempUITile.moveFromTo(previousUITile.originPos, uiTile.originPos, true);
}); uiTile.playMergedAnim();
} else {
uiTile.playBornAnim();
}
} this.message = function (won) {
//var type = won ? "game-won" : "game-over";
//var message = won ? "You win!" : "Game over!"; ui.showResult(won);
} this.continueGame = function () {
//print("continueGame");
} var ls = null;
this.updateScore = function (score) {
if (ls == null || ls != score) {
if (ls != null) {
var a = ui.oScore.GetComponent$1(UnityEngine.Animator.ctor);
a.set_enabled(true);
a.Play$$Int32(0);
} ls = score;
ui.oScore.set_text(score.toString());
}
} var lbs = null;
this.updateBestScore = function (score) {
if (lbs == null || lbs != score) {
if (lbs != null) {
var a = ui.oBestScore.GetComponent$1(UnityEngine.Animator.ctor);
a.set_enabled(true);
a.Play$$Int32(0);
} lbs = score;
ui.oBestScore.set_text(score.toString());
}
} }

ui_controller (handle Unity stuff)

It does everything related to Unity. Serialization, input detection, Unity UI stuff, animation, etc.

var gameManager = null;

jss.define_mb("UIController", function() {
"use strict";// gameObject
this.oTileRoot = null; // text
this.oScore = null;
this.oBestScore = null; // button
this.oNewGame = null; var size = 4;
var uiTiles = [];
var inputMgr, actuator, storageMgr; var keyCode = [273, 275, 274, 276];
var keyCodeString = ["Up", "Right", "Down", "Left"];
var keyCodeData = [0, 1, 2, 3]; var createUITile = function (trans) {
var t = {
trans: trans,
image: trans.GetComponent$1(UnityEngine.UI.Image.ctor), setValue: function(v) {
this.image.set_sprite(UnityEngine.Resources.Load$1$$String(UnityEngine.Sprite.ctor, "2048/"+v.toString()));
this.setVisible(true);
}, moveFromTo : function (fromPos, toPos, destroyAfterFinish) {
this.movement.moveFromTo(fromPos, toPos, destroyAfterFinish);
}, moveFrom: function (fromPos, destroyAfterFinish) {
this.moveFromTo(fromPos, this.originPos, destroyAfterFinish);
}, setVisible: function (visible) {
this.image.set_enabled(visible);
}
}; t.originPos = t.trans.get_position();
t.movement = t.trans.GetComponent$1(jss.TileMovement);
t.animator = t.trans.GetComponent$1(UE.Animator.ctor);
t.animator.set_enabled(false); t.playMergedAnim = function () {
this.animator.set_runtimeAnimatorController(UnityEngine.Resources.Load$1$$String(UnityEngine.RuntimeAnimatorController.ctor, "2048/MergedCtrl"));
this.animator.set_enabled(true);
this.animator.Play$$Int32(0);
} t.playBornAnim = function () {
this.animator.set_runtimeAnimatorController(UnityEngine.Resources.Load$1$$String(UnityEngine.RuntimeAnimatorController.ctor, "2048/BornCtrl"));
this.animator.set_enabled(true);
this.animator.Play$$Int32(0);
} return t;
} this.clearUITiles = function () {
for (var i = 0; i < uiTiles.length; i++) {
uiTiles[i].setVisible(false);
}
} this.getUITile = function (i, j) {
return uiTiles[i + j * size];
} this.createTempUITile = function (copy_i, copy_j) {
var transCopy = this.getUITile(copy_i, copy_j).trans;
var goCopy = transCopy.get_gameObject();
var go = UnityEngine.Object.Instantiate$$Object(goCopy);
var trans = go.get_transform();
trans.SetParent$$Transform$$Boolean(transCopy.get_parent(), false);
trans.set_position(transCopy.get_position());
trans.SetSiblingIndex(0);
return createUITile(trans);
} var btn_helper = function (parent, path, active, cb) {
var btn = parent.FindChild(path).GetComponent$1(UnityEngine.UI.Button.ctor);
btn.get_gameObject().SetActive(active);
if (active) {
btn.get_onClick().RemoveAllListeners();
btn.get_onClick().AddListener$$UnityAction(cb);
}
} this.oMsgBox = null;
this.showResult = function (win) {
this.oMsgBox.SetActive(true); var trans = this.oMsgBox.get_transform(); var msg = trans.FindChild("Message").GetComponent$1(UnityEngine.UI.Text.ctor);
msg.set_text(win ? "You won!" : "Game over!"); btn_helper(trans, "NewGameButton", win, function () {
this.oMsgBox.SetActive(false);
inputMgr.emit("restart");
}.bind(this)); btn_helper(trans, "ContinuePlayButton", win, function () {
this.oMsgBox.SetActive(false);
inputMgr.emit("keepPlaying");
}.bind(this)); btn_helper(trans, "RetryButton", !win, function () {
this.oMsgBox.SetActive(false);
inputMgr.emit("restart");
}.bind(this));
} this.Start = function () {
// init ui tiles
var parent = this.oTileRoot.get_transform();
var chCount = parent.get_childCount();
for (var i = 0; i < chCount; i++) {
var child = parent.GetChild(i);
uiTiles.push(createUITile(child));
} inputMgr = new InputManager();
actuator = new Actuator(this);
storageMgr = new UnityStorageManager(); //
this.oNewGame.get_onClick().AddListener$$UnityAction(function () {
inputMgr.emit("restart");
}); // start game
gameManager = new GameManager(size, inputMgr, actuator, storageMgr);
} this.listen = function () {
if (UnityEngine.Application.get_isMobilePlatform()) {
var md = this.md = this.md || {}; var I = UnityEngine.Input;
if (I.get_touchCount() == 1) {
if (md.state == 2) {
return;
} var p = I.get_mousePosition();
if (md.state == 0) {
md.initpos = p;
md.state = 1;
} else {
var dis = UnityEngine.Vector3.Distance(p, md.initpos);
if (dis > 20) {
var xd = Math.abs(p.x - md.initpos.x);
var yd = Math.abs(p.y - md.initpos.y);
if (xd > yd) {
inputMgr.emit("move", p.x > md.initpos.x ? 1 : 3);
} else {
inputMgr.emit("move", p.y > md.initpos.y ? 0 : 2);
}
md.state = 2;
}
}
} else {
md.state = 0;
}
} else {
for (var i = 0; i < keyCode.length; i++) {
if (UnityEngine.Input.GetKeyDown$$KeyCode(keyCode[i])) {
inputMgr.emit("move", keyCodeData[i]);
break;
}
} }
} this.Update = function () {
this.listen();
};
});

tilemovement

Moves tile from pos (i,j) to pos (x,y). If the tile is temporary, destroy it after move.

jss.define_mb("TileMovement", function () {
this.Awake = function() {
this.trans = this.get_transform();
} this.moving = false; var $cv = { Value: UnityEngine.Vector3.get_zero() };
this.Update = function () {
if (!this.moving) {
return;
} var newPos = UnityEngine.Vector3.SmoothDamp$$Vector3$$Vector3$$Vector3$$Single(
this.trans.get_position(),
this.toPos,
$cv,
0.07); this.trans.set_position(newPos); var dis = UnityEngine.Vector3.Distance(newPos, this.toPos);
if (dis < 0.001) {
this.moving = false; if (this.destroyAfterFinish) {
UnityEngine.Object.Destroy$$Object(this.get_gameObject());
}
}
} this.moveFromTo = function (fromPos, toPos, destroyAfterFinish) {
this.toPos = toPos;
this.destroyAfterFinish = destroyAfterFinish;
this.moving = true;
this.trans.set_position(fromPos);
}
});

back to JSBinding / Home

JSBinding / About 2048 sample的更多相关文章

  1. JSBinding / Home

    Description JSBinding is a tool enabling you to run actual javascript in Unity3D. It contains Mozill ...

  2. JSBinding / Run Samples

    This document shows you how to run JSBinding 2048 sample in Editor. First of course, create an empty ...

  3. BZOJ 2048 题解

    2048: [2009国家集训队]书堆 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1076  Solved: 499[Submit][Status ...

  4. python写2048小游戏

    #!/usr/bin/env python # coding=utf-8 #******************************************************** # > ...

  5. ZOJ3802 Easy 2048 Again (状压DP)

    ZOJ Monthly, August 2014 E题 ZOJ月赛 2014年8月 E题 http://acm.zju.edu.cn/onlinejudge/showProblem.do?proble ...

  6. 2014-2015 ACM-ICPC, NEERC, Moscow Subregional Contest A. Advanced 2048

    A. Advanced 2048 time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  7. cognos8.3 sample在DB2里的安装

    db2 create db c83 alias c83 using codeset UTF-8 territory CA 创建sample数据库 db2set db2codepage= db2 cha ...

  8. bzoj 3851: 2048 dp优化

    3851: 2048 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 22  Solved: 9[Submit][Status] Description T ...

  9. 一起来写2048(160行python代码)

    前言: Life is short ,you need python. --Bruce Eckel 我与2048的缘,不是缘于一个玩家,而是一次,一次,重新的ACM比赛.四月份校赛初赛,第一次碰到20 ...

随机推荐

  1. dll文件是什么

    dll实际上是动态链接库的缩写,从windows1.0开始,动态链接库就是整个操作系统的基础,那么这有什么作用呢?在dos时代,程序员是通过编写程序来达到预期的目的的,每实现一个目的就需要编写一个程序 ...

  2. JDK注解替代Hibernate的Entity映射

    1.在entity(实体类)模块中使用注解 1_1.注解的位置出现在 [类定义的前面] 和 [属性的get方法前面] [属性的get方法前面] Java代码: package app.entity; ...

  3. linux驱动初探之字符驱动

    关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3. ...

  4. js高级程序设计(六)面向对象

    ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”严格来讲,这就相当于说对象是一组没有特定顺序的值.对象的每个属性或方法都有一个名字,而每个名字都映射到一个值.正 ...

  5. NGINX怎样处理惊群的

    写在前面 写NGINX系列的随笔,一来总结学到的东西,二来记录下疑惑的地方,在接下来的学习过程中去解决疑惑. 也希望同样对NGINX感兴趣的朋友能够解答我的疑惑,或者共同探讨研究. 整个NGINX系列 ...

  6. android 中 webview 怎么用 localStorage?

    我在 android里面 使用html5的 localStorage 为什么存不进去也读不出来呀? 网上搜了好多都没效果 1 2 3 4 5 6 7 8 9 mainWebView = (WebVie ...

  7. NetworkComms V3 之支持TCP连接和UDP连接

    NetworkComms V3 无缝的支持TCP连接和UDP连接. 您可以很容易的创建这两种连接 //创建一个连接信息对象 ConnectionInfo connInfo = ); //创建一个TCP ...

  8. Python、PIP环境变量的配置

    Python安装的路径:D:\Python35 pip的环境变量 Python和pip的PATH: PIP下载链接:https://pypi.python.org/pypi/pip 随意解压好,然后C ...

  9. sqlserver中创建包含事务的存储过程

    什么是事务     事务时包含1条或多条语句的逻辑单元.事务中的语句是一个整体,要么一起提交,要么一起撤销.事务在提交前可以回滚,一旦提交就不能撤销修改了,是永久性的修改.   为什么使用事务     ...

  10. POJ 2226 最小点覆盖(经典建图)

    Muddy Fields Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8881   Accepted: 3300 Desc ...