用 html 做了一款推箱子的小游戲(只做了一個關卡),螢屏觸控和鍵盤方向鍵控制小人推箱子、重新開始、上一步及通關等功能,直接上圖:

預覽地址
效果鏈接(只看看不如親自體驗一下,因為寫了鍵盤監聽的緣故,鍵盤事件都被停用了):
http://h5demo.yyfuncdn.com/res/gameDemo/sokoban/
手機掃碼運行:

下面是所有的專案檔案:

game.html 檔案是專案的運行檔案,里面包含了創建舞臺、創建游戲場景、人物等內容的操作,最后還設定了鍵盤操控
.
游戲原始碼被放到下面公眾號里面啦,有需要的小伙伴可以掃碼關注,發送 “推箱子” 獲取哦

感謝大家支持……^ ^
.
專案代碼
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<head>
<script src='js/pixi.js'></script>
<script src='js/background.js'></script>
<script src="js/wall.js"></script>
<script src="js/box.js"></script>
<script src="js/ball.js"></script>
<script src="js/role.js"></script>
<script src="js/text.js"></script>
<script src="js/reset.js"></script>
<meta name="viewport" content="width=device-width,height=device-height"/>
<style>
body{
background-color:black;
}
canvas{
width:100%;
max-width:500px;
position: absolute;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
</style>
</head>
<body>
<script>
//創建舞臺
var app = new PIXI.Application(560,800);
document.body.appendChild(app.view);
//生成背景
var bg = new Background(560,800);
//創建地圖陣列
var mapArr = [];
//地圖二維陣列初始化
function init(){
var width = 40;
var height = 40;
var left = 20;
var up = 200;
for(var i = 0;i < 14;i++) {
mapArr.push([]);
for(var j = 0;j < 9;j++) {
mapArr[i].push([]);
mapArr[i][j] = {type:null};
}
}
//墻方塊在陣列中的位置
var wallx = [0,0,0,0,0,0,0,1,1,2,2,2,2,2,3,3,3,4,4,4,5,5,5,5,5,5,5,6,6,7,7,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,12,12,12,13,13,13,13,13,13,13,13,13];
var wally = [0,1,2,3,4,5,6,0,6,0,6,7,8,9,0,6,9,0,6,9,0,1,2,3,5,6,9,0,9,0,3,5,6,8,9,0,3,6,9,0,3,4,9,0,3,4,9,0,1,9,1,5,9,1,2,3,4,5,6,7,8,9];
//生成墻方塊
for(var i = 0;i < wallx.length;i++) {
var x = wallx[i];
var y = wally[i];
var wall = new Wall();
wall.pos(left+x*width,up+y*height);
wall.posArr = {x:x,y:y};
mapArr[x][y] = {type:"wall"};
}
//箱子在陣列中的位置
var boxx = [4,6,7,7,9,9,10,10,11,11];
var boxy = [7,3,2,7,6,7,2,5,6,7];
//生成箱子
for(var i = 0;i < boxx.length;i++) {
var x = boxx[i];
var y = boxy[i];
var box = new Box();
box.pos(left+x*width,up+y*height);
box.posArr = {x:x,y:y};
mapArr[x][y] = {type:"box",obj:box};
boxArr.push(box);
}
//球體在陣列中的位置
var ballx = [1,1,1,1,1,2,2,2,2,2];
var bally = [1,2,3,4,5,1,2,3,4,5];
//生成球體
for(var i = 0;i < ballx.length;i++) {
var x = ballx[i];
var y = bally[i];
var ball = new Ball();
ball.pos(left+x*width,up+y*height);
ball.posArr = {x:x,y:y};
mapArr[x][y] = {type:"ball",obj:ball};
ballArr.push({obj:ball,type:false});
}
}
//用于保存球體物件的陣列
var ballArr = [];
//用于保存箱子物件的陣列
var boxArr = [];
var moveArr = [];
init();
//生成小人
var role = new Role();
role.pos(20+7*40,200+4*40);
role.posArr = {x:7,y:4};
bg.setobj(role);
//生成文字
var text = new Text();
text.setPos(280,100,280,700);
//生成重置按鈕
var reset = new Reset();
reset.setPos(100,100);
reset.setPos1(450,100);
//用于控制移動
var control = true;
document.onkeydown = keyDown;
function keyDown(event) {//鍵盤監聽
var event = event || window.event;
switch (event.keyCode) {
case 37:
bg.wasd("a");
break;
case 39:
bg.wasd("d");
break;
case 38:
bg.wasd("w");
break;
case 40:
bg.wasd("s");
break;
}
return false;
}
</script>
<div style="display:none;">
<script type="text/javascript" src="https://s4.cnzz.com/z_stat.php?id=1279820148&web_id=1279820148"></script>
</div>
</body>
</html>
背景被封裝進了 Background 物件,用于觸控控制小人的移動,監測是否觸墻、箱子是否入庫、一起推動箱子的操作
//背景物件
function Background(width,height) {
var self = this;
this.view = new PIXI.Sprite.fromImage("res/background.png");
app.stage.addChild(this.view);
this.view.height = height;
this.view.width = width;
//獲取到控制物件
var obj = null;
this.setobj = function(dx) {
obj = dx;
}
//定義變數 pos 用于記錄滑鼠按下的位置
var pos;
//開啟互動
this.view.interactive = true;
//系結滑鼠按下事件
this.view.on("pointerdown",function(event) {
pos = event.data.getLocalPosition(app.stage);
})
//撤銷事件
this.revocation = function() {
if(moveArr.length == 0)return;
switch (moveArr[moveArr.length-1].direction) {
case "a":
self.move(role,"d");
if(moveArr[moveArr.length-1].obj != null){
self.shiftOut(moveArr[moveArr.length-1].obj);
self.moveChangeMapArr(moveArr[moveArr.length-1].obj,"d");
self.immigrate(moveArr[moveArr.length-1].obj);
}
break;
case "d":
self.move(role,"a");
if(moveArr[moveArr.length-1].obj != null) {
self.shiftOut(moveArr[moveArr.length-1].obj);
self.moveChangeMapArr(moveArr[moveArr.length-1].obj,"a");
self.immigrate(moveArr[moveArr.length-1].obj);
}
break;
case "w":
self.move(role,"s");
if(moveArr[moveArr.length-1].obj != null) {
self.shiftOut(moveArr[moveArr.length-1].obj);
self.moveChangeMapArr(moveArr[moveArr.length-1].obj,"s");
self.immigrate(moveArr[moveArr.length-1].obj);
}
break;
case "s":
self.move(role,"w");
if(moveArr[moveArr.length-1].obj != null) {
self.shiftOut(moveArr[moveArr.length-1].obj);
self.moveChangeMapArr(moveArr[moveArr.length-1].obj,"w");
self.immigrate(moveArr[moveArr.length-1].obj);
}
break;
default:
break;
}
moveArr.splice(moveArr.length-1,1);
}
//用于判斷角色的移動
this.wasd = function(type) {
if(!control) {
return;
}
var dx = self.roleCrash(obj,type);
if(dx.type == false) {
return;
}
moveArr.push({direction:type,obj:null});
if(dx.obj != null){
var state = self.boxCrash(dx.obj,type);
if(state == false) {
moveArr.splice(moveArr.length-1,1);
return;
}
moveArr[moveArr.length-1].obj = dx.obj;
self.shiftOut(dx.obj);
self.moveChangeMapArr(dx.obj,type);
self.immigrate(dx.obj);
}
self.move(obj,type);
}
//檢查箱子是否移出球體位置
this.shiftOut = function(obj) {
for(var i = 0;i < ballArr.length;i++){
if(obj.posArr.x == ballArr[i].obj.posArr.x && obj.posArr.y == ballArr[i].obj.posArr.y) {
ballArr[i].type = false;
mapArr[obj.posArr.x][obj.posArr.y] = {type:"ball",obj:ballArr[i].obj};
return;
}
}
}
//檢查箱子是否移動至球體位置
this.immigrate = function(obj) {
for(var i = 0;i < ballArr.length;i++) {
if(obj.posArr.x == ballArr[i].obj.posArr.x && obj.posArr.y == ballArr[i].obj.posArr.y) {
ballArr[i].type = true;
}
}
for(var i = 0;i < ballArr.length;i++) {
if(ballArr[i].type == false) {
return;
}
}
reset.win();
}
//檢查角色觸碰到的物體并回傳物體型別及物體物件
this.boxCrash = function(obj,type) {
var state = true;
switch (type) {
case "a":
if(mapArr[obj.posArr.x-1][obj.posArr.y].type == "wall") {
state = false;
}
if(mapArr[obj.posArr.x-1][obj.posArr.y].type == "box") {
state = false;
}
break;
case "d":
if(mapArr[obj.posArr.x+1][obj.posArr.y].type == "wall") {
state = false;
}
if(mapArr[obj.posArr.x+1][obj.posArr.y].type == "box") {
state = false;
}
break;
case "w":
if(mapArr[obj.posArr.x][obj.posArr.y-1].type == "wall") {
state = false;
}
if(mapArr[obj.posArr.x][obj.posArr.y-1].type == "box") {
state = false;
}
break;
case "s":
if(mapArr[obj.posArr.x][obj.posArr.y+1].type == "wall") {
state = false;
}
if(mapArr[obj.posArr.x][obj.posArr.y+1].type == "box") {
state = false;
}
break;
default:
break;
}
return state;
}
//檢查角色觸碰到的物體并回傳物體型別及物體物件
this.roleCrash = function(obj,type) {
var state = {type:true,obj:null};
switch (type) {
case "a":
obj.wl(0);
if(mapArr[obj.posArr.x-1][obj.posArr.y].type == "wall") {
state = {type:false,obj:mapArr[obj.posArr.x-1][obj.posArr.y]};
}
if(mapArr[obj.posArr.x-1][obj.posArr.y].type == "box") {
state = {type:true,obj:mapArr[obj.posArr.x-1][obj.posArr.y].obj};
}
break;
case "d":
obj.wl(1);
if(mapArr[obj.posArr.x+1][obj.posArr.y].type == "wall") {
state = {type:false,obj:mapArr[obj.posArr.x+1][obj.posArr.y]};
}
if(mapArr[obj.posArr.x+1][obj.posArr.y].type == "box") {
state = {type:true,obj:mapArr[obj.posArr.x+1][obj.posArr.y].obj};
}
break;
case "w":
obj.wl(2);
if(mapArr[obj.posArr.x][obj.posArr.y-1].type == "wall") {
state = {type:false,obj:mapArr[obj.posArr.x][obj.posArr.y-1]};
}
if(mapArr[obj.posArr.x][obj.posArr.y-1].type == "box") {
state = {type:true,obj:mapArr[obj.posArr.x][obj.posArr.y-1].obj};
}
break;
case "s":
obj.wl(3);
if(mapArr[obj.posArr.x][obj.posArr.y+1].type == "wall") {
state = {type:false,obj:mapArr[obj.posArr.x][obj.posArr.y+1]};
}
if(mapArr[obj.posArr.x][obj.posArr.y+1].type == "box") {
state = {type:true,obj:mapArr[obj.posArr.x][obj.posArr.y+1].obj};
}
break;
default:
break;
}
return state;
}
//控制箱子移動并改變箱子在地圖陣列中的位置
this.moveChangeMapArr = function(obj,type) {
switch (type) {
case "a":
if(mapArr[obj.posArr.x][obj.posArr.y].type != "ball") {
mapArr[obj.posArr.x][obj.posArr.y] = {type:null};
}
obj.view.x += -40;
obj.posArr.x += -1;
mapArr[obj.posArr.x][obj.posArr.y] = {type:"box",obj};
break;
case "d":
if(mapArr[obj.posArr.x][obj.posArr.y].type != "ball") {
mapArr[obj.posArr.x][obj.posArr.y] = {type:null};
}
obj.view.x += 40;
obj.posArr.x += 1;
mapArr[obj.posArr.x][obj.posArr.y] = {type:"box",obj};
break;
case "w":
if(mapArr[obj.posArr.x][obj.posArr.y].type != "ball") {
mapArr[obj.posArr.x][obj.posArr.y] = {type:null};
}
obj.view.y += -40;
obj.posArr.y += -1;
mapArr[obj.posArr.x][obj.posArr.y] = {type:"box",obj};
break;
case "s":
if(mapArr[obj.posArr.x][obj.posArr.y].type != "ball") {
mapArr[obj.posArr.x][obj.posArr.y] = {type:null};
}
obj.view.y += 40;
obj.posArr.y += 1;
mapArr[obj.posArr.x][obj.posArr.y] = {type:"box",obj};
break;
default:
break;
}
}
//角色移動方法
this.move = function(obj,type) {
switch (type) {
case "a":
obj.view.x += -40;
obj.posArr.x += -1;
break;
case "d":
obj.view.x += 40;
obj.posArr.x += 1;
break;
case "w":
obj.view.y += -40;
obj.posArr.y += -1;
break;
case "s":
obj.view.y += 40;
obj.posArr.y += 1;
break;
default:
break;
}
}
//系結滑鼠抬起事件&&用抬起的位置與按下的位置做比對來辨別行動的方向
this.view.on("pointerup",function(event) {
if(pos == undefined || obj == null){
return;
}
var posup = event.data.getLocalPosition(app.stage);
if(Math.abs(posup.x - pos.x) > Math.abs(posup.y - pos.y)) {
if(posup.x - pos.x > 0) {
self.wasd("d");
}else if(posup.x - pos.x < 0) {
self.wasd("a");
}
}else if(Math.abs(posup.x - pos.x) < Math.abs(posup.y - pos.y)) {
if(posup.y - pos.y > 0) {
self.wasd("s");
}else if(posup.y - pos.y < 0) {
self.wasd("w");
}
}
})
}
從新開始按鈕單獨封裝在了 Reset 物件中
function Reset(){
var self = this;
var style1 = {
fontFamily: 'Arial',
fontStyle: 'normal',
fontSize:30,
fontWeight: 'bold',
fill: '#bf8735',
}
this.view = new PIXI.Text("重新開始",style1);
app.stage.addChild(this.view);
this.view.anchor.set(0.5,0.5);
var style2 = {
fontFamily: 'Arial',
fontStyle: 'normal',
fontSize:30,
fontWeight: 'bold',
fill: '#bf8735',
}
this.revocation = new PIXI.Text("上一步",style2);
app.stage.addChild(this.revocation);
this.revocation.anchor.set(0.5,0.5);
var style = {
fontFamily: 'Arial',
fontStyle: 'normal',
fontSize:40,
fontWeight: 'bold',
fill: '#f5286e',
}
var text = new PIXI.Text("恭 喜 過 關",style);
app.stage.addChild(text);
text.anchor.set(0.5,0.5);
text.x = 280;
text.y = 300;
text.visible = false;
this.win = function() {
text.visible = true;
self.setPos(280,400);
self.revocation.visible = false;
control = false;
}
//設定位置方法
this.setPos = function(x,y) {
self.view.x = x;
self.view.y = y;
}
this.setPos1 = function(x,y) {
self.revocation.x = x;
self.revocation.y = y;
}
//開啟重置按鈕的互動
this.view.interactive = true;
this.revocation.interactive = true;
//系結點擊事件
this.revocation.on("pointertap",function() {
bg.revocation();
})
this.view.on("pointertap",function() {
self.revocation.visible = true;
text.visible = false;
moveArr = [];
self.setPos(100,100);
var boxx = [4,6,7,7,9,9,10,10,11,11];
var boxy = [7,3,2,7,6,7,2,5,6,7];
for(var i = 0;i < boxArr.length;i++) {
var box = boxArr[i];
mapArr[box.posArr.x][box.posArr.y] = {type:null};
mapArr[boxx[i]][boxy[i]] = {type:"box",obj:box};
box.posArr = {x:boxx[i],y:boxy[i]};
box.pos(20+boxx[i]*40,200+boxy[i]*40);
}
role.pos(20+7*40,200+4*40);
role.posArr = {x:7,y:4};
for(var i = 0;i < ballArr.length;i++) {
var ball = ballArr[i];
ball.type = false;
mapArr[ball.obj.posArr.x][ball.obj.posArr.y] = {type:"ball",obj:ball.obj};
}
})
}
以下其他物件沒有什么特別的,只是單獨的物件,每次使用呼叫
球物件(藍色的目標點)
//球物件
function Ball(){
var self = this;
this.view = new PIXI.Sprite.fromImage("res/blueball.png");
app.stage.addChild(this.view);
this.view.anchor.set(0.5,0.5);
this.view.alpha = 0.7;
this.posArr;
//設定位置方法
this.pos = function(x,y) {
self.view.x = x;
self.view.y = y;
}
}
箱子物件
//箱子物件
function Box(){
var self = this;
this.view = new PIXI.Sprite.fromImage("res/bluebox.png");
app.stage.addChild(this.view);
this.view.anchor.set(0.5,0.5);
this.posArr;
//設定位置方法
this.pos = function(x,y){
self.view.x = x;
self.view.y = y;
}
}
角色物件
//角色物件
function Role() {
var self = this;
var urlArr = ["res/left.png","res/right.png","res/up.png","res/down.png"];
this.view = new PIXI.Sprite.fromImage(urlArr[3]);
app.stage.addChild(this.view);
this.view.anchor.set(0.5,0.5);
this.posArr;
//設定角色紋理
this.wl = function(num) {
var url = new PIXI.Texture.fromImage(urlArr[num]);
self.view.texture = url;
}
//設定位置方法
this.pos = function(x,y) {
self.view.x = x;
self.view.y = y;
}
}
文本物件
function Text(){
var self = this;
//設定標題樣式
var style = {
fontFamily: 'Arial',
fontSize: 40,
fontStyle: 'normal',
fontWeight: 'bold',
fill:'#bf8735',
stroke: '#000fff',
strokeThickness: 5
}
//設定說明樣式
var style2 = {
fontFamily: 'Arial',
fontStyle: 'normal',
fontWeight: 'bold',
fill: '#000fff'
}
this.view = new PIXI.Text("推 箱 子",style);
this.view.anchor.set(0.5,0.5);
app.stage.addChild(this.view);
this.explain = new PIXI.Text("滑動螢屏或鍵盤方向鍵控制小人移動",style2);
this.explain.anchor.set(0.5,0.5);
app.stage.addChild(this.explain);
//設定位置方法
this.setPos = function(viewx,viewy,explainx,explainy) {
self.view.x = viewx;
self.view.y = viewy;
self.explain.x = explainx;
self.explain.y = explainy;
}
}
墻物件
function Text(){
var self = this;
//設定標題樣式
var style = {
fontFamily: 'Arial',
fontSize: 40,
fontStyle: 'normal',
fontWeight: 'bold',
fill:'#bf8735',
stroke: '#000fff',
strokeThickness: 5
}
//設定說明樣式
var style2 = {
fontFamily: 'Arial',
fontStyle: 'normal',
fontWeight: 'bold',
fill: '#000fff'
}
this.view = new PIXI.Text("推 箱 子",style);
this.view.anchor.set(0.5,0.5);
app.stage.addChild(this.view);
this.explain = new PIXI.Text("滑動螢屏或鍵盤方向鍵控制小人移動",style2);
this.explain.anchor.set(0.5,0.5);
app.stage.addChild(this.explain);
//設定位置方法
this.setPos = function(viewx,viewy,explainx,explainy) {
self.view.x = viewx;
self.view.y = viewy;
self.explain.x = explainx;
self.explain.y = explainy;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/276693.html
標籤:其他
