TypeScript-左右躲避障碍-神手

学习typescript,第一步应该是学习官方文档,理解最基础的语法。第二步开始用typescript实现一些js+css 或者canvas类型的游行。现在开始我们用ts写跳一跳

前言:

  最近微信小程序里面,出现了一个左右手躲避障碍物的游戏:神手。玩了一下觉得很有意思,决定用typescript写一版。

核心点:

  1.识别手势动作:双指同时点击,单指随机放开

  2.障碍物的成对生成。

  3.动画帧的优化

游戏截图

  

Typescript脚本:

  

 //1.创建障碍
//2.移动障碍
//3.小球控制
//4.碰撞检测
module game { interface FootBall {
node: JQuery<HTMLElement>;
track: Track;
}
enum Direction {
left, right
}
enum Track {
one, two, three, four
}
let mask: JQuery<HTMLElement> = $(".game");
let speed: number = 10;
let score: number = 0;
let rblist: Array<RandBox> = [];
let roadList: Array<Road> = [];
let ft1: FootBall = { node: $("#ft1"), track: Track.two };
let ft2: FootBall = { node: $("#ft2"), track: Track.three };
//h5的专门适应绘制动画的属性
window.requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
(function () {
return function (callback: Function, element: { __lastTime: number }) {
var lastTime = element.__lastTime;
if (lastTime === undefined) {
lastTime = 0;
}
var currTime = Date.now();
var timeToCall = Math.max(1, 33 - (currTime - lastTime));
window.setTimeout(callback, timeToCall);
element.__lastTime = currTime + timeToCall;
};
})();
window.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame;
let requestAnimationFrameFlag = 0;
class MathHelp {
/**
* 返回范围内随机数[min,max]
* @param min 最小值
* @param max 最大值
*/
static RandRange(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1) + min);
}
}
export class Road {
top: number = 0;
id: number = 0;
heigth: number = document.documentElement.clientHeight;
node: JQuery<HTMLElement> = $('');
static num: number = 0;
constructor() {
this.id = Road.num;
this.top = -(Road.num) * this.heigth;
this.node = $(`<div id="${this.id}" class="road" style="top:${this.top}px;"></div>`);
mask.append(this.node);
Road.num++;
}
move() {
this.top += speed;
this.node.css({
top: this.top + "px"
});
//循环路面
if (this.top >= this.heigth) {
this.top -= Road.num * this.heigth;
}
}
}
export class RandBox { left: number = 0;
top: number = -100;
heigth: number = 80;
width: number = 80;
node: JQuery<HTMLElement> = $('');
type: Direction = Direction.left;
id: string = "p" + new Date().getTime();
track: Track = Track.one;
constructor(p: number = 0) {
this.top = p;
}
createrb(type: Direction) {
this.type = type;
let r = 0;
if (type == Direction.left) {
r = MathHelp.RandRange(0, 1);
} else {
r = MathHelp.RandRange(2, 3);
}
this.track = r;
//计算所属赛道
this.left = 70 + 126 * r + (126 - this.width) / 2;
this.node = $(`<div id="${this.id}" class='rb'style='left:${this.left}px;top:${this.top}px; background-image:url(img/c${MathHelp.RandRange(1, 4)}.png);'></div>`);
mask.append(this.node);
}
move() {
this.top += speed;
this.node.css({
top: this.top + "px"
});
//碰撞检测
if (this.top >= 870 && this.top < 950) {
if (this.track == ft1.track || this.track == ft2.track) {
scence.gameover();
return false;
}
}
return true;
}
} export class scence {
static timer: number;
static Init() {
//重新开始
$(".againBtn").on("click", () => {
scence.restart();
});
//创建路面
for (let i = 0; i < 3; i++) {
let road = new Road();
roadList.push(road);
}
//最开始给一对障碍,此后是每秒一对
scence.makeDoubleRb(450);
//开始游戏(可以绑定到开始按钮)
scence.start();
}
static start() {
scence.loadlisten();
//场景平移
let move = () => {
let status = true;
$.each(rblist, (i, item) => {
if (!item.move()) {
status = false;
return false;
} });
if (status) {
$.each(roadList, (i, item) => {
item.move();
});
requestAnimationFrameFlag = requestAnimationFrame(move);
} else {
cancelAnimationFrame(requestAnimationFrameFlag);
}
}
move();
//积分及创建障碍
scence.timer = setInterval(() => {
score++;
speed++;
$(".jfb").html(score.toString());
scence.makeDoubleRb();
//移除超出屏幕路障
rblist.forEach((item, i) => { if (item.top > 1200) {
$("#" + item.id).remove();
rblist.splice(i, 1);
}
})
}, 1000); }
static gameover() {
clearInterval(scence.timer);
$(".gameEnd").show();
$(".score").html(score.toString());
scence.removelisten();
//小车回到原始位置
ft1.node.animate({
left: "235px"
}, 50);
ft1.track = Track.two;
ft2.node.animate({
left: "360px"
}, 50);
ft2.track = Track.three;
}
static restart() {
speed = 10;
score = 0;
$(".rb").remove();
rblist = [];
$(".jfb").html(score.toString());
$(".gameEnd").hide();
scence.start();
}
//创建成对出现的障碍
static makeDoubleRb(top?: number) {
let RB1 = new game.RandBox(top);
RB1.createrb(Direction.left);
rblist.push(RB1);
let RB2 = new game.RandBox(top);
RB2.createrb(Direction.right);
rblist.push(RB2);
}
private static loadlisten() {
document.addEventListener('touchstart', scence.touch, false);
document.addEventListener('touchmove', scence.touch, false);
document.addEventListener('touchend', scence.touch, false);
}
private static removelisten() {
document.removeEventListener('touchstart', scence.touch, false);
document.removeEventListener('touchmove', scence.touch, false);
document.removeEventListener('touchend', scence.touch, false);
}
private static touch(e: TouchEvent) {
e.preventDefault();
if (e.type == "touchstart") {
if (e.touches.length == 1) {
//一指的情况
let x1 = e.touches[0].clientX;
if (x1 < 320) {
//左边
ft1.node.animate({
left: "112px"
}, 50);
ft1.track = Track.one; } else {
//右边
ft2.node.animate({
left: "490px"
}, 50);
ft2.track = Track.four;
}
} else if (e.touches.length == 2) {
//两指手指的情况
let x1 = e.touches[0].clientX;
let x2 = e.touches[1].clientX;
let a = x1 < 320 ? 0 : 1;
let b = x2 < 320 ? 0 : 1;
if (a + b == 0) { //两指都在左边
ft1.node.animate({
left: "112px"
}, 50);
ft1.track = Track.one; } else if (a + b == 1) {
//两指一左一右
ft1.node.animate({
left: "112px"
}, 50);
ft1.track = Track.one;
ft2.node.animate({
left: "490px"
}, 50);
ft2.track = Track.four;
} else if (a + b == 2) {
//两指都在右边
ft2.node.animate({
left: "490px"
}, 50);
ft2.track = Track.four;
}
} } else if (e.type == "touchend") { if (e.touches.length == 0) {
//放开两指
ft1.node.animate({
left: "235px"
}, 50);
ft1.track = Track.two;
ft2.node.animate({
left: "360px"
}, 50);
ft2.track = Track.three
} else if (e.touches.length == 1) {
//放开一指
let x1 = e.touches[0].clientX;
if (x1 > 320) {
//放开的左边
ft1.node.animate({
left: "235px"
}, 50);
ft1.track = Track.two;
} else {
//放开的右边
ft2.node.animate({
left: "360px"
}, 50);
ft2.track = Track.three
}
}
}
}
} } game.scence.Init();

html代码

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8" />
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
var isios = false;
! function(userAgent) {
var screen_w = parseInt(window.screen.width),
scale = screen_w / 640;
console.log(scale);
if(/Android (\d+\.\d+)/.test(userAgent)) {
var version = parseFloat(RegExp.$1);
document.write(version > 2.3 ? '<meta name="viewport" content="width=640, initial-scale = ' + scale + ',user-scalable=1, minimum-scale = ' + scale + ', maximum-scale = ' + scale + ', target-densitydpi=device-dpi">' : '<meta name="viewport" content="width=640, target-densitydpi=device-dpi">');
} else {
isios = true;
document.write('<meta name="viewport" content="width=640, initial-scale = ' + scale + ' ,minimum-scale = ' + scale + ', maximum-scale = ' + scale + ', user-scalable=no, target-densitydpi=device-dpi">');
}
}(navigator.userAgent);
</script>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
} .game {
height: 100%;
width: 100%;
background-size: 100% auto;
position: relative;
left: 0;
top: 0;
}
.road{
height: 100%;
width: 100%;
background: url(img/road.jpg) no-repeat;
background-size: 100% 100%;
position: absolute;
left: 0;
top: 0;
z-index: 10; }
.rb {
height: 80px;
width: 80px;
position: absolute;
left: 70px;
top: 70px;
background-position: left top;
background-size: 100% 100%;
/* animation: move 5s linear;*/
z-index: 11;
} .ft {
height: 139px;
width: 63px;
/*border-radius: 25px;*/
background-image: url(img/tyn.png);
background-position: left top;
background-size: 100% 100%;
position: absolute;
bottom: 50px;
left: 235px;
z-index: 11;
} #ft1 {
/*animation: football1 1.5s linear infinite;*/
} #ft2 {
left: 360px;
/*animation: football2 1.5s linear infinite;*/
} @keyframes football2 {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
} @keyframes football1 {
from {
transform: rotate(0deg);
}
to {
transform: rotate(-360deg);
}
} @keyframes move {
from {
top: 0px;
}
to {
top: 1300px;
}
} .gameEnd {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: rgba(0, 0, 0, .8);
z-index: 999;
display: none;
} .getScore {
width: 492px;
height: 760px;
background: url(img/getScore.png) no-repeat;
background-size: 100% auto;
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
} .score {
color: #dcc226;
font-size: 130px;
text-align: center;
margin-top: 120px;
font-weight: 900;
} .againBtn {
width: 309px;
height: 87px;
background: url(img/bg.png) no-repeat;
background-size: 100% 100%;
font-size: 40px;
color: #dcc226;
text-align: center;
border: none;
font-weight: 900;
position: absolute;
left: 50%;
margin-left: -154.5px;
} .jfb {
position: absolute;
top: 30px;
right: 100px;
font-size: 45px;
font-weight: 800;
color: #FFF;
text-align: center;
line-height: 45px;
z-index: 11;
}
</style>
</head> <body>
<div class="game"> <div id="ft1" class="ft"></div>
<div id="ft2" class="ft"></div>
<div class="jfb">0</div>
</div>
<div class="gameEnd"> <div class="getScore"> <p class="score">10</p>
<button class="againBtn">再来一局</button> </div> </div>
<script src="js/game.js" type="text/javascript" charset="utf-8"></script>
</body> </html>

最新文章

  1. 【swift】BlockOperation和GCD实用代码块
  2. SDWebImage的简单使用
  3. 现代Web应用开发者必备的六大技能
  4. float 和 inline-block的心得
  5. java5 Lock用法
  6. ReactNative——生命周期
  7. The type xxx cannot be resolved. It is indirectly referenced from required .class files
  8. python写的第一个简单小游戏-猜数字
  9. python在linux制作图形界面(snack)
  10. C#初步接触
  11. BZOJ 2324: [ZJOI2011]营救皮卡丘( floyd + 费用流 )
  12. 网络层 IP 协议首部格式与其配套使用的四个协议(ARP,RARP,ICMP,IGMP)
  13. 38.Linux驱动调试-根据系统时钟定位出错位置
  14. Http请求-get和post的区别
  15. maven打包含有多个main程序的jar包及运行方式
  16. 重新生成ssh
  17. 安卓项目R,java文件不能自动更新,clean之后,R.java消失 (转自 Cynosure鱼)
  18. 实现JTextfield 的右键 复制、剪切、粘贴功能。
  19. Python3基础 str swapcase 英文字母大小写反转
  20. Java中3种代理总结(示例代码见之前文章)

热门文章

  1. HDFS的存储策略
  2. 服务命令只支持基本的LSB操作(启动、停止、重新启动、尝试重启、重新加载、强制重新加载、状态)。对于其他操作,请尝试使用systemctl。
  3. 14.2 multiprocessing--多线程
  4. flex布局入门总结——语法篇
  5. 基于设备树的led驱动程序
  6. elasticsearch搜索引擎搭建
  7. C++ 指针初始化要注意的地方
  8. 最短路径问题 3.Bellman-Ford算法
  9. Unity3d脚本生命周期
  10. ionic 向路由中的templateUrl(模板页)传值