在PC時代,曾有個名為“變速齒輪”的神奇軟件,可以加快或減慢系統時間。
當時常用來修改游戲速度,可實現外掛一般的效果,很不可思議。
本文,將用JAVAScript復刻這一功能,實現一個用于網頁的變速齒輪,可用于H5游戲、網頁小游戲變速。
效果展示
首先看實現后的效果演示。
圖一、減速效果:
圖二、加速效果:
網頁中有一個循環滾動的小球,通過頁面中“加速”、“減速”兩個按鈕,可以侵入并控制它的速度。
特別說明:變速操作,并未修改小球滾動的程序邏輯,而是變相的改變了網頁的時間流速,使小球滾動的速度發生了改變。
技術原理
如上圖所示,該功能是用API Hook技術實現接管setTimeout函數(滾動小球是調用setTimeout)。然后獲取第2個參數,即原函數timeout參數,通過給此值增加或減少一定量值,以實現加速或減速,然后再用Apply方式調用原始的setTimeout。
源碼解析
UI部分:
頁面UI 中,兩個按鈕、一個css實現的小球。
小球移動邏輯代碼:
從源碼可知,是用setTimeout控制小球在一定范圍內循環滾動,接下來是重點。
setTimeout的Hook操作:
如圖中代碼所示,核心代碼并不復雜,而是十分簡單明了:定義有一個公共變量speed,加速或減速就是控制此值。然后在setTimeout的替代函數中,對argument[1]參數增加此變量值。
完整代碼
以下即是此變速功能的完整測試代碼,保存為html文件即可使用。
減速加速
LOG:
//變速增量var speed = 0;document.getElementById("speed").innerHTML = speed;//Hook setTimeut,實現變速//備份原始setTimeout函數var pre_setTimeout = setTimeout;//新的setTimeout函數var setTimeout = function(){arguments[1] = arguments[1] + speed;console.log("arguments", arguments[1]);//最小為1,1毫秒if(arguments[1]<1) arguments[1] = 1;//執行回調函數pre_setTimeout.apply(this, arguments);}//加速function add_speed(){speed = speed - 20;console.log("速度",speed);document.getElementById("log").innerHTML += (new Date).toGMTString() + " 速度:" + (-speed) + "n";if(speed < -100) speed = -100document.getElementById("speed").innerHTML = -speed;}//減速function dec_speed(){speed += 20;console.log("速度",speed)document.getElementById("log").innerHTML += (new Date).toGMTString() + " 速度:" + (-speed) + "n";if(speed > 200) speed = 200document.getElementById("speed").innerHTML = -speed;}//小球移動動畫function move() {var box = document.getElementById("box");var current_position = 0;var left = 1;//循環調用function render() {setTimeout(render, 100);current_position += left;if (current_position == 200 || current_position == 0){left = -left;}box.style.left = current_position + "px";}render();}move();
JS變速齒輪DEMO
速度增量:
JS代碼保護
JavaScript是明文代碼,很容易被他人任意拿去使用。
通常,我們不希望自己寫的代碼泄露,比如本文所介紹的變速功能,初聞感覺十分神奇,但代碼公開后可知竟如此簡單。很多技術、功能都是如此,因此,可以對JavaScript代碼進行混淆加密處理。
以上面代碼為例,如果使用JShaman加密其中的JavaScript代碼:
加密后代碼將變成如下密文形式。
此舉可用于保護JavaScript代碼,防止功能邏輯被窺探、代碼被盜用等等。
功能擴展
到此,介紹了對setTimeout的Hook,可用于對setTimeout實現的H5游戲進行變速。而除此之外,有的游戲還可能使用setInterval、requestAnimationFrame實現游戲動畫刷新。那么,也可以用同樣的方法對這兩個函數進行Hook,道理相通。