웹 프론트엔드 JS 튜토리얼 자바스크립트 쓰기 푸시박스 game_javascript 스킬

자바스크립트 쓰기 푸시박스 game_javascript 스킬

May 16, 2016 pm 03:51 PM
javascript

푸시박스 게임은 오래된 게임입니다. 푸시박스 게임의 간단한 구현과 제가 찾은 몇 가지 참고 영상에 대해 말씀드리겠습니다.

렌더링은 다음과 같습니다.

이 상자 끌기 게임은 zepto의 터치 모듈을 사용하여 손가락으로 화면을 밀어서 거북이가 다른 방향으로 이동하도록 제어했습니다.

소코반 게임은 비교적 간단하기 때문에 코드는 절차적인 방식으로 직접 작성됩니다. 모듈은 두 개의 뷰와 모델이고 나머지는 사용자의 이벤트 컨트롤러입니다. 사용자가 키보드의 방향 키를 누를 때마다. 데이터가 변경되고 게임의 정적 HTML을 다시 생성한 다음 innerHTML을 사용하여 인터페이스에 삽입하여 자동으로 DOM 노드를 생성합니다.

게임의 레벨 모델은 데이터입니다. 각 레벨의 데이터를 세 부분으로 나누었습니다.

지도 데이터, 2차원 배열(지도 데이터에는 타일, 상자의 대상 위치, 빈 위치가 포함됨)

박스 데이터, 1차원 배열(박스의 초기 위치)
작은 거북이 데이터, json 객체
각 레벨에는 해당 게임 레벨 데이터가 있습니다. 시뮬레이션 데이터는 다음과 같습니다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

level: [

  {

    //0是空的地图

    //1是板砖

    //3是目标点

    state:[

      [0,0,1,1,1,0,0,0,0],

      [0,1,1,3,3,1,0,0,0],

      [0,1,0,0,0,0,1,0,0],

      [0,1,0,0,0,0,1,0,0],

      [0,1,1,1,1,1,1,0,0]

    ],

    person: {x : 2, y : 2},

    box: [{x:3, y : 2},{x:4,y:2}]

  },

  //第二关

  {

    //0是空的地图

    //1是板砖

    //3是目标点

    state:[

      [0,1,1,1,1,1,0,0],

      [0,1,0,0,1,1,1,0],

      [0,1,0,0,0,0,1,0],

      [1,1,1,0,1,0,1,1],

      [1,3,1,0,1,0,0,1],

      [1,3,0,0,0,1,0,1],

      [1,3,0,0,0,0,0,1],

      [1,1,1,1,1,1,1,1]

    ],

    person: {x : 2, y : 2},

    box: [{x:3, y : 2}, {x:2,y:5} ,{x:5, y:6}]

    /*

    box : [

      {x:3, y : 1},

      {x:4, y : 1},

      {x:4, y : 2},

      {x:5, y : 5}

    ]

    */

  },

  //第三关

  {

    //0是空的地图

    //1是板砖

    //3是目标点

    state:[

      [0,0,0,1,1,1,1,1,1,0],

      [0,1,1,1,0,0,0,0,1,0],

      [1,1,3,0,0,1,1,0,1,1],

      [1,3,3,0,0,0,0,0,0,1],

      [1,3,3,0,0,0,0,0,1,1],

      [1,1,1,1,1,1,0,0,1,0],

      [0,0,0,0,0,1,1,1,1,0]

    ],

    person: {x : 8, y : 3},

    box: [{x:4, y : 2}, {x:3,y:3} ,{x:4, y:4},{x:5, y:3},{x:6, y:4}]

  },

  //第四关

  {

    //0是空的地图

    //1是板砖

    //3是目标点

    state:[

      [0,1,1,1,1,1,1,1,0,0],

      [0,1,0,0,0,0,0,1,1,1],

      [1,1,0,1,1,1,0,0,0,1],

      [1,0,0,0,0,0,0,0,0,1],

      [1,0,3,3,1,0,0,0,1,1],

      [1,1,3,3,1,0,0,0,1,0],

      [0,1,1,1,1,1,1,1,1,0]

    ],

    person: {x : 2, y : 3},

    box: [{x:2, y : 2}, {x:4,y:3} ,{x:6, y:4},{x:7, y:3},{x:6, y:4}]

  },

  //第五关

  {

    //0是空的地图

    //1是板砖

    //3是目标点

    state:[

      [0,0,1,1,1,1,0,0],

      [0,0,1,3,3,1,0,0],

      [0,1,1,0,3,1,1,0],

      [0,1,0,0,0,3,1,0],

      [1,1,0,0,0,0,1,1],

      [1,0,0,1,0,0,0,1],

      [1,0,0,0,0,0,0,1],

      [1,1,1,1,1,1,1,1]

    ],

    person: {x : 4, y : 6},

    box: [{x:4, y : 3}, {x:3,y:4} ,{x:4, y:5}, {x:5,y:5}]

    /*

     box : [

     {x:3, y : 1},

     {x:4, y : 1},

     {x:4, y : 2},

     {x:5, y : 5}

     ]

     */

  },

    //第六关

  {

    //0是空的地图

    //1是板砖

    //3是目标点

    state:[

      [0,0,0,0,1,1,1,1,1,1,1,0],

      [0,0,0,0,1,0,0,1,0,0,1,0],

      [0,0,0,0,1,0,0,0,0,0,1,0],

      [1,1,1,1,1,0,0,1,0,0,1,0],

      [3,3,3,1,1,0,0,0,0,0,1,1],

      [3,0,0,1,0,0,0,0,1,0,0,1],

      [3,0,0,0,0,0,0,0,0,0,0,1],

      [3,0,0,1,0,0,0,0,1,0,0,1],

      [3,3,3,1,1,1,0,1,0,0,1,1],

      [1,1,1,1,1,0,0,0,0,0,1,0],

      [0,0,0,0,1,0,0,1,0,0,1,0],

      [0,0,0,0,1,1,1,1,1,1,1,0]

    ],

    person: {x : 5, y : 10},

    box: [

      {x:5, y:6},

      {x:6, y:3},

      {x:6, y:5},

      {x:6, y:7},

      {x:6, y:9},

      {x:7, y:2},

      {x:8, y:2},

      {x:9, y:6}

    ]

  }

]

로그인 후 복사
아주 중요한 것 중 하나는 푸시박스 게임의 주요 논리입니다. 꼬마 거북이가 걸을 수만 있는 곳은 빈 공간이고, 거북이 앞에 벽이 있으면 걸을 수 없거나, 거북이 앞에 상자가 있으면 상자 앞쪽을 판단하세요. 벽이 없으면 거북이와 상자 모두 앞으로 나아갈 수 있습니다. 벽이 있으면 움직일 수 없습니다. 작은 거북이가 떠날 때마다 지도 데이터가 변경되고 인터페이스가 다시 생성됩니다. 이 주기에서는 작은 거북이가 걸어갈 때마다 지도 데이터의 상자 데이터가 모두 정렬되어 있는지 확인합니다. , 사용자에게 다음 레벨이 표시됩니다.

게임의 템플릿 엔진은 HandlebarsJS를 사용합니다. 공식 웹사이트에 가면 API를 볼 수 있습니다. 제가 쓴 블로그입니다. Handlebars 사용법 문서(Handlebars.js): 오픈, 템플릿 콘텐츠:

1

2

3

4

5

6

7

8

9

10

11

12

13

<script id="tpl" type="text/x-handlebars-template">

  {{#initY}}{{/initY}}

  {{#each this}}

    {{#each this}}

      <div class="{{#getClass this}}{{/getClass}}" data-x="{{@index}}" data-y="{{#getY}}{{/getY}}" style="left:{{#calc @index}}{{/calc}};top:{{#calc 1111}}{{/calc}}">

        <!--{{@index}}

        {{#getY}}{{/getY}}

        -->

      </div>

    {{/each}}

    {{#addY}}{{/addY}}

  {{/each}}

</script>

로그인 후 복사
initY, getClass, getY, calc,,,,를 포함하여 Handlebars에 대한 여러 도우미가 정의되어 있습니다. 템플릿 엔진은 주로 보조 기능으로 사용됩니다. 여기서는 코드의 가독성이 떨어집니다. 조금 더 나쁘게도 클로저는 전역 변수의 오염을 피하기 위해 변수를 저장하는 데에도 사용됩니다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

(function() {

  var y = 0;

  Handlebars.registerHelper("initY", function() {

    y = 0;

  });

  Handlebars.registerHelper("addY", function() {

    y++;

  });

  Handlebars.registerHelper("getY", function() {

    return y;

  });

  Handlebars.registerHelper("calc", function(arg) {

    //console.log(arg)

    if(arg!==1111) {

      return 50*arg + "px";

    }else{

      return 50*y + "px";

    };

  });

  Handlebars.registerHelper("getClass", function(arg) {

    switch( arg ) {

      case 0 :

        return "bg"

      case 1 :

        return "block"

      case 2 :

        return "box"

      case 3 :

        return "target"

    };

  });

  window.util = {

    isMobile : function() {

      return navigator.userAgent.toLowerCase().indexOf("mobile") !== -1 || navigator.userAgent.toLowerCase().indexOf("android") !== -1 || navigator.userAgent.toLowerCase().indexOf("pad") !== -1;

    }

  }

})();

로그인 후 복사
모바일 기기와 호환되어야 하기 때문에 휴대폰인지 태블릿인지 확인해야 합니다. 그렇다면 해당 DOM 요소(방향키 DOM 요소)를 추가한 후 해당 이벤트를 바인딩하겠습니다. zeptoJS는 터치 모듈을 제공합니다. 공식 웹사이트로 이동하여 찾은 다음 추가 참조를 추가하고 주소를 연 다음 swipeLeft, swipeUp, swipeDown, swipeRight 이벤트를 사용할 수 있습니다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

if( window.util.isMobile() ) {

  $(window).on("swipeLeft",function() {

    _this.step("left");

  }).on("swipeRight",function() {

    _this.step("right");

  }).on("swipeUp",function() {

    _this.step("top");

  }).on("swipeDown",function() {

    _this.step("bottom");

  });

  mobileDOM();

 

  $(".arrow-up").tap(function() {

    _this.step("top");

  });

  $(".arrow-down").tap(function() {

    _this.step("bottom");

  });

  $(".arrow-left").tap(function() {

    _this.step("left");

  });

  $(".arrow-right").tap(function() {

    _this.step("right");

  });

}else{

  $(window).on("keydown", function(ev) {

    var state = "";

    switch( ev.keyCode ) {

      case 37 :

        state = "left";

      break;

      case 39 :

        state = "right";

      break;

      case 38 :

        state = "top";

      break;

      case 40 :

        state = "bottom";

      break;

    };

    _this.step(state)

  });

};

로그인 후 복사
사용자의 현재 레벨을 저장해야 하기 때문에 레벨이 성공적으로 지워질 때마다 사용자가 플레이를 원하지 않거나 종료할 때 jQuery-cookies 플러그인도 사용합니다. 다른 이유로 인해 브라우저가 닫히면 며칠 후에 다시 플레이하고 싶을 때 계속 플레이할 수 있습니다.

1

2

3

4

5

6

7

8

9

10

11

if( G.now+1 > G.level.length-1 ) {

  alert("闯关成功");

  return ;

}else{

  //如果可用的等级大于当前的等级,就把level设置进去;

  if( G.now+1 > parseInt( $.cookie('level') || 0 )) {

    $.cookie('level' , G.now+1 , { expires: 7 });

  };

  start( G.now+1 );

  return ;

};

로그인 후 복사
모든 코드는 여기에 있습니다:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

<!DOCTYPE html>

<html>

<head lang="en">

  <meta charset="UTF-8">

  <title></title>

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

  <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css">

  <link rel="stylesheet" href="http://sqqihao.github.io/games/rusBlock/libs/Tiny-Alert/css/zepto.alert.css"/>

  <script src="libs/jquery-1.9.1.min.js"></script>

  <script src="libs/handlebars.js"></script>

  <script src="libs/jquery-cookie.js"></script>

  <script src="http://sqqihao.github.io/games/rusBlock/libs/Tiny-Alert/js/zepto.alert.js"></script>

  <script id="tpl" type="text/x-handlebars-template">

    {{#initY}}{{/initY}}

    {{#each this}}

      {{#each this}}

        <div class="{{#getClass this}}{{/getClass}}" data-x="{{@index}}" data-y="{{#getY}}{{/getY}}" style="left:{{#calc @index}}{{/calc}};top:{{#calc 1111}}{{/calc}}">

          <!--{{@index}}

          {{#getY}}{{/getY}}

          -->

        </div>

      {{/each}}

      {{#addY}}{{/addY}}

    {{/each}}

  </script>

  <script>

    (function() {

      var y = 0;

      Handlebars.registerHelper("initY", function() {

        y = 0;

      });

      Handlebars.registerHelper("addY", function() {

        y++;

      });

      Handlebars.registerHelper("getY", function() {

        return y;

      });

      Handlebars.registerHelper("calc", function(arg) {

        //console.log(arg)

        if(arg!==1111) {

          return 50*arg + "px";

        }else{

          return 50*y + "px";

        };

      });

      Handlebars.registerHelper("getClass", function(arg) {

        switch( arg ) {

          case 0 :

            return "bg"

          case 1 :

            return "block"

          case 2 :

            return "box"

          case 3 :

            return "target"

        };

      });

      window.util = {

        isMobile : function() {

          return navigator.userAgent.toLowerCase().indexOf("mobile") !== -1 || navigator.userAgent.toLowerCase().indexOf("android") !== -1 || navigator.userAgent.toLowerCase().indexOf("pad") !== -1;

        }

      }

    })();

  </script>

</head>

<style>

  #game{

    display: none;

  }

  #house{

    position: relative;

  }

  .bg{

    position: absolute;

    width:50px;

    height:50px;

    box-sizing: border-box;

  }

  .block{

    position: absolute;

    background-image: url(imgs/wall.png);

    width:50px;

    height:50px;

    box-sizing: border-box;

  }

  .box{

    position: absolute;

    background: #fbd500;

    width:50px;

    height:50px;

    background-image: url(imgs/box.png);

  }

  .target{

    position: absolute;

    background: url(imgs/target.jpg);

    background-size: 50px 50px;;

    width:50px;

    height:50px;

    box-sizing: border-box;

  }

  #person{

    background-image: url(imgs/person.png);

    width:50px;

    height:50px;

    position: absolute;

  }

  #person.up{

    background-position: 0 0;

  }

  #person.right{

    background-position:-50px 0 ;

  }

  #person.bottom{

    background-position:-100px 0 ;

  }

  #person.left{

    background-position:-150px 0 ;

  }

  /*移动端的DOM*/

  .operate-bar{

    font-size:30px;

  }

  .height20percent{

    height:30%;

  }

  .height30percent{

    height:30%;

  }

  .height40percent{

    height:40%;

  }

  .height100percent{

    height:100%;

  }

  .font30{

    font-size:30px;

    color:#34495e;

  }

</style>

<body>

  <div id="select">

    <div class="container">

      <div class="row">

        <p class="text-info">

          已经解锁的关卡:

        <p id="level">

        </p>

        </p>

        <button id="start" class="btn btn-default">

          开始游戏

        </button>

      </div>

    </div>

  </div>

  <div id="game" class="container">

    <div class="row">

      <button onclick="location.reload()" class="btn btn-info" >

        返回选择关卡重新

      </button>

      <div id="house">

      </div>

    </div>

  </div>

 

  <script>

    G = {

      level: [

        {

          //0是空的地图

          //1是板砖

          //3是目标点

          state:[

            [0,0,1,1,1,0,0,0,0],

            [0,1,1,3,3,1,0,0,0],

            [0,1,0,0,0,0,1,0,0],

            [0,1,0,0,0,0,1,0,0],

            [0,1,1,1,1,1,1,0,0]

          ],

          person: {x : 2, y : 2},

          box: [{x:3, y : 2},{x:4,y:2}]

        },

        //第二关

        {

          //0是空的地图

          //1是板砖

          //3是目标点

          state:[

            [0,1,1,1,1,1,0,0],

            [0,1,0,0,1,1,1,0],

            [0,1,0,0,0,0,1,0],

            [1,1,1,0,1,0,1,1],

            [1,3,1,0,1,0,0,1],

            [1,3,0,0,0,1,0,1],

            [1,3,0,0,0,0,0,1],

            [1,1,1,1,1,1,1,1]

          ],

          person: {x : 2, y : 2},

          box: [{x:3, y : 2}, {x:2,y:5} ,{x:5, y:6}]

          /*

          box : [

            {x:3, y : 1},

            {x:4, y : 1},

            {x:4, y : 2},

            {x:5, y : 5}

          ]

          */

        },

        //第三关

        {

          //0是空的地图

          //1是板砖

          //3是目标点

          state:[

            [0,0,0,1,1,1,1,1,1,0],

            [0,1,1,1,0,0,0,0,1,0],

            [1,1,3,0,0,1,1,0,1,1],

            [1,3,3,0,0,0,0,0,0,1],

            [1,3,3,0,0,0,0,0,1,1],

            [1,1,1,1,1,1,0,0,1,0],

            [0,0,0,0,0,1,1,1,1,0]

          ],

          person: {x : 8, y : 3},

          box: [{x:4, y : 2}, {x:3,y:3} ,{x:4, y:4},{x:5, y:3},{x:6, y:4}]

        },

        //第四关

        {

          //0是空的地图

          //1是板砖

          //3是目标点

          state:[

            [0,1,1,1,1,1,1,1,0,0],

            [0,1,0,0,0,0,0,1,1,1],

            [1,1,0,1,1,1,0,0,0,1],

            [1,0,0,0,0,0,0,0,0,1],

            [1,0,3,3,1,0,0,0,1,1],

            [1,1,3,3,1,0,0,0,1,0],

            [0,1,1,1,1,1,1,1,1,0]

          ],

          person: {x : 2, y : 3},

          box: [{x:2, y : 2}, {x:4,y:3} ,{x:6, y:4},{x:7, y:3},{x:6, y:4}]

        },

        //第五关

        {

          //0是空的地图

          //1是板砖

          //3是目标点

          state:[

            [0,0,1,1,1,1,0,0],

            [0,0,1,3,3,1,0,0],

            [0,1,1,0,3,1,1,0],

            [0,1,0,0,0,3,1,0],

            [1,1,0,0,0,0,1,1],

            [1,0,0,1,0,0,0,1],

            [1,0,0,0,0,0,0,1],

            [1,1,1,1,1,1,1,1]

          ],

          person: {x : 4, y : 6},

          box: [{x:4, y : 3}, {x:3,y:4} ,{x:4, y:5}, {x:5,y:5}]

          /*

           box : [

           {x:3, y : 1},

           {x:4, y : 1},

           {x:4, y : 2},

           {x:5, y : 5}

           ]

           */

        },

          //第六关

        {

          //0是空的地图

          //1是板砖

          //3是目标点

          state:[

            [0,0,0,0,1,1,1,1,1,1,1,0],

            [0,0,0,0,1,0,0,1,0,0,1,0],

            [0,0,0,0,1,0,0,0,0,0,1,0],

            [1,1,1,1,1,0,0,1,0,0,1,0],

            [3,3,3,1,1,0,0,0,0,0,1,1],

            [3,0,0,1,0,0,0,0,1,0,0,1],

            [3,0,0,0,0,0,0,0,0,0,0,1],

            [3,0,0,1,0,0,0,0,1,0,0,1],

            [3,3,3,1,1,1,0,1,0,0,1,1],

            [1,1,1,1,1,0,0,0,0,0,1,0],

            [0,0,0,0,1,0,0,1,0,0,1,0],

            [0,0,0,0,1,1,1,1,1,1,1,0]

          ],

          person: {x : 5, y : 10},

          box: [

            {x:5, y:6},

            {x:6, y:3},

            {x:6, y:5},

            {x:6, y:7},

            {x:6, y:9},

            {x:7, y:2},

            {x:8, y:2},

            {x:9, y:6}

          ]

        }

      ],

      //map data

      mapData : (function() {

        var data = {};

        return {

          get: function () {

            return data;

          },

          set: function (arg) {

            data = arg;

          },

          //穿进来的数据在界面中是否存在;

          collision: function (x, y) {

            if( data.state[y][x] === 1)return true;

            return false;

          },

          collisionBox : function(x,y) {

            for(var i= 0, len= data.box.length; i< len; i++) {

              if( data.box[i].x === x&& data.box[i].y === y)return data.box[i];

            };

            return false;

          }

        }

      })(),

      view : {

        initMap : function(map) {

          document.getElementById("house").innerHTML = Handlebars.compile( document.getElementById("tpl").innerHTML )( map );

        },

        initPerson : function(personXY) {

          var per = document.createElement("div");

          per.id = "person";

          G.per = per;

          document.getElementById("house").appendChild(per);

          per.style.left = 50* personXY.x+"px";

          per.style.top = 50* personXY.y+"px";

        },

        initBox : function(boxs) {

          for(var i=0;i<boxs.length; i++) {

            var box = document.createElement("div");

            box.className = "box";

            G.box = box;

            document.getElementById("house").appendChild(box);

            box.style.left = boxs[i].x*50 + "px";

            box.style.top = boxs[i].y*50 + "px";

          };

        },

        deleteBox : function() {

          var eBoxs = document.getElementsByClassName("box");

          var len = eBoxs.length;

          while( len-- ) {

            eBoxs[len].parentNode.removeChild( eBoxs[len] );

          };

        }

      },

      /*

      * 0;向上

      * 1:向右

      * 2:向下

      * 3:向左

      * */

      direction : 0,

      step : function(xy) {

        //这里面要做很多判断

        /*包括:

         用户当前的方向和以前是否一样,如果不一样要先转头;

         如果一样的话,判断前面是否有石头, 是否有箱子;

           如果前面有墙壁或者

           前面有箱子,而且箱子前面有墙壁就return

         把人物往前移动

         如果人物的位置上有一个箱子,把箱子也移动一下;

         */

        var mapData = this.mapData.get();

        //对参数进行处理;

        if ( typeof xy === "string" ) {

          var x = 0, y = 0, xx = 0, yy = 0;

          switch( xy ) {

            case "left" :

                if(this.direction==0){

                  x = -1;

                  xx = -2;

                }else{

                  x = 0;

                };

              this.direction = 0;

              break;

            case "top" :

                if(this.direction===1){

                  y = -1;

                  yy = -2

                }else{

                  y = 0;

                };

                this.direction = 1;

              break;

            case "right" :

                if(this.direction === 2) {

                  x = 1;

                  xx = 2;

                }else{

                  x = 0;

                };

              this.direction = 2;

              break;

            case "bottom" :

                if(this.direction ===3 ) {

                  y = 1;

                  yy = 2;

                }else{

                  y = 0;

                };

              this.direction = 3;

          };

          //如果是墙壁就不能走

          if( this.mapData.collision(mapData.person.x + x, mapData.person.y+y) ) {

            return;

          };

          //如果碰到的是箱子, 而且箱子前面是墙壁, 就return

          if( this.mapData.collisionBox(mapData.person.x+x, mapData.person.y+y) && this.mapData.collision(mapData.person.x+xx, mapData.person.y+yy)) {

            return;

          };

          if( this.mapData.collisionBox(mapData.person.x+x, mapData.person.y+y) && this.mapData.collisionBox(mapData.person.x+xx, mapData.person.y+yy)) {

            return

          }

          //mapData.x+xx, mapData.y+yy

          mapData.person.x = mapData.person.x + x;

          mapData.person.y = mapData.person.y + y;

 

          this.per.style.left = 50* mapData.person.x+"px";

          this.per.style.top = 50* mapData.person.y+"px";

          this.per.className = {

            0:"up",

            1:"right",

            2:"bottom",

            3:"left"

          }[this.direction];

          var theBox = {};

          if(theBox = this.mapData.collisionBox(mapData.person.x, mapData.person.y)) {

            theBox.x = mapData.person.x+x;

            theBox.y = mapData.person.y+y;

            this.view.deleteBox();

            this.view.initBox(mapData.box);

            this.testSuccess();

          };

          //如果碰到了箱子,而且箱子前面不能走就return, 否则就走箱子和人物;

        };

      },

      /*

      * return Boolean;

      * */

      //遍历所有的box,如果在box中的所有x,y在地图中对应的值为3,全部通过就返回true

      testSuccess : function() {

        var mapData = this.mapData.get();

        for(var i=0; i<mapData.box.length; i++) {

          if(mapData.state[mapData.box[i].y][mapData.box[i].x] != 3) {

            return false;

          };

        };

        $.dialog({

          content : '游戏成功, 进入下一关!',

          title : 'alert',

          ok : function() {

            if( G.now+1 > G.level.length-1 ) {

              alert("闯关成功");

              return ;

            }else{

              //如果可用的等级大于当前的等级,就把level设置进去;

              if( G.now+1 > parseInt( $.cookie('level') || 0 )) {

                $.cookie('level' , G.now+1 , { expires: 7 });

              };

              start( G.now+1 );

              return ;

            };

          },

          cancel : function(){

            location.reload();

          },

          lock : true

        });

      },

      //这里面需要处理 map, 人物数据, box数据

      init : function() {

        //更新地图;

        //this.level[0].state

        this.view.initMap( this.mapData.get().state );

        this.view.initPerson( this.mapData.get().person );

        this.view.initBox( this.mapData.get().box );

        //this.person = this.factory.Person(0,0);

        //this.box = this.factory.Box([{x:0,y:1},{x:1,y:1},{x:0,y:2},{x:1,y:2}]);

        if( this.hasBind ) {

          return

        };

        this.hasBind = true;

        this.controller();

      },

      controller : function() {

        function mobileDOM() {

          var mobileDOMString = '\

            <div class="navbar-fixed-bottom height20percent operate-bar" >\

              <div class="container height100percent">\

                <div class="row text-center height100percent">\

                  <div class="height40percent arrow-up">\

                    <span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>\

                  </div>\

                  <div class="height30percent">\

                    <div class="col-xs-6 arrow-left">\

                      <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>\

                    </div>\

                    <div class="col-xs-6 arrow-right">\

                      <span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span>\

                    </div>\

                  </div>\

                  <div class="height30percent arrow-down">\

                    <span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>\

                  </div>\

                </div>\

              </div>\

            </div>\

            ';

            +function addDOM() {

              $("#game").append( mobileDOMString );

            }();

        };

        var _this = this;

        if( window.util.isMobile() ) {

          $(window).on("swipeLeft",function() {

            _this.step("left");

          }).on("swipeRight",function() {

            _this.step("right");

          }).on("swipeUp",function() {

            _this.step("top");

          }).on("swipeDown",function() {

            _this.step("bottom");

          });

          mobileDOM();

 

          $(".arrow-up").tap(function() {

            _this.step("top");

          });

          $(".arrow-down").tap(function() {

            _this.step("bottom");

          });

          $(".arrow-left").tap(function() {

            _this.step("left");

          });

          $(".arrow-right").tap(function() {

            _this.step("right");

          });

        }else{

          $(window).on("keydown", function(ev) {

            var state = "";

            switch( ev.keyCode ) {

              case 37 :

                state = "left";

              break;

              case 39 :

                state = "right";

              break;

              case 38 :

                state = "top";

              break;

              case 40 :

                state = "bottom";

              break;

            };

            _this.step(state)

          });

        };

      }

    };

 

    function start( level ) {

      G.now = level;

      G.mapData.set(G.level[level] );

      G.init();

      $("#game").show();

      $("#select").hide();

    };

 

    function init() {

      var cookieLevel = $.cookie('level') || 0;

      start( cookieLevel );

    };

    $("#start").click(function() {

      init();

    });

    String.prototype.repeat = String.prototype.repeat || function(num) {

      return (new Array(num+1)).join( this.toString() );

    };

 

    window.onload = function() {

      var cookieLevel = $.cookie('level') || 0;

      $("#level").html( function() {

        var index = 0;

        return "<a href='###' class='btn btn-info' onclick='start({{i}})'>关卡</a>    ".repeat((parseInt($.cookie('level')) || 0)+1).replace(/{{i}}/gi, function() {

          return index++;

        })

      });

    }

  </script>

</body>

</html>

로그인 후 복사
게임에는 6개의 레벨이 있습니다. 각 레벨을 성공적으로 통과하면 다음 레벨이 잠금 해제됩니다. 하하.

Sokoban 게임 온라인 데모:

공개

위 내용은 이 글의 전체 내용입니다. 모두 마음에 드셨으면 좋겠습니다.

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 Dec 17, 2023 pm 02:54 PM

WebSocket 및 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 소개: 지속적인 기술 개발로 음성 인식 기술은 인공 지능 분야의 중요한 부분이 되었습니다. WebSocket과 JavaScript를 기반으로 한 온라인 음성 인식 시스템은 낮은 대기 시간, 실시간, 크로스 플랫폼이라는 특징을 갖고 있으며 널리 사용되는 솔루션이 되었습니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법을 소개합니다.

WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 Dec 17, 2023 pm 05:30 PM

WebSocket과 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 서론: 인터넷 기술의 급속한 발전과 함께 실시간 모니터링 시스템이 다양한 분야에서 널리 활용되고 있다. 실시간 모니터링을 구현하는 핵심 기술 중 하나는 WebSocket과 JavaScript의 조합입니다. 이 기사에서는 실시간 모니터링 시스템에서 WebSocket 및 JavaScript의 적용을 소개하고 코드 예제를 제공하며 구현 원칙을 자세히 설명합니다. 1. 웹소켓 기술

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 Dec 17, 2023 pm 12:09 PM

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 소개: 인터넷의 대중화와 기술의 발전으로 점점 더 많은 레스토랑에서 온라인 주문 서비스를 제공하기 시작했습니다. 실시간 온라인 주문 시스템을 구현하기 위해 JavaScript 및 WebSocket 기술을 사용할 수 있습니다. WebSocket은 TCP 프로토콜을 기반으로 하는 전이중 통신 프로토콜로 클라이언트와 서버 간의 실시간 양방향 통신을 실현할 수 있습니다. 실시간 온라인 주문 시스템에서는 사용자가 요리를 선택하고 주문을 하면

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 Dec 17, 2023 am 09:39 AM

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 오늘날의 디지털 시대에는 점점 더 많은 기업과 서비스에서 온라인 예약 기능을 제공해야 합니다. 효율적인 실시간 온라인 예약 시스템을 구현하는 것이 중요합니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. WebSocket이란 무엇입니까? WebSocket은 단일 TCP 연결의 전이중 방식입니다.

JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 Dec 17, 2023 pm 05:13 PM

JavaScript 및 WebSocket: 효율적인 실시간 일기 예보 시스템 구축 소개: 오늘날 일기 예보의 정확성은 일상 생활과 의사 결정에 매우 중요합니다. 기술이 발전함에 따라 우리는 날씨 데이터를 실시간으로 획득함으로써 보다 정확하고 신뢰할 수 있는 일기예보를 제공할 수 있습니다. 이 기사에서는 JavaScript 및 WebSocket 기술을 사용하여 효율적인 실시간 일기 예보 시스템을 구축하는 방법을 알아봅니다. 이 문서에서는 특정 코드 예제를 통해 구현 프로세스를 보여줍니다. 우리

간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 Jan 05, 2024 pm 06:08 PM

JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

자바스크립트에서 insertBefore를 사용하는 방법 자바스크립트에서 insertBefore를 사용하는 방법 Nov 24, 2023 am 11:56 AM

사용법: JavaScript에서 insertBefore() 메서드는 DOM 트리에 새 노드를 삽입하는 데 사용됩니다. 이 방법에는 삽입할 새 노드와 참조 노드(즉, 새 노드가 삽입될 노드)라는 두 가지 매개 변수가 필요합니다.

JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 Jan 05, 2024 pm 01:37 PM

JavaScript에서 HTTP 상태 코드를 얻는 방법 소개: 프런트 엔드 개발에서 우리는 종종 백엔드 인터페이스와의 상호 작용을 처리해야 하며 HTTP 상태 코드는 매우 중요한 부분입니다. HTTP 상태 코드를 이해하고 얻는 것은 인터페이스에서 반환된 데이터를 더 잘 처리하는 데 도움이 됩니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. HTTP 상태 코드란 무엇입니까? HTTP 상태 코드는 브라우저가 서버에 요청을 시작할 때 서비스가

See all articles