First Commit
This commit is contained in:
commit
517fb6537d
1
.browserslistrc
Normal file
1
.browserslistrc
Normal file
@ -0,0 +1 @@
|
||||
last 2 versions
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
817
dist/bundle.js
vendored
Normal file
817
dist/bundle.js
vendored
Normal file
@ -0,0 +1,817 @@
|
||||
/******/ (function() { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ([
|
||||
/* 0 */,
|
||||
/* 1 */
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
||||
/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_postcss_loader_dist_cjs_js_ruleSet_1_rules_1_use_2_node_modules_less_loader_dist_cjs_js_index_less__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
||||
|
||||
|
||||
|
||||
var options = {};
|
||||
|
||||
options.insert = "head";
|
||||
options.singleton = false;
|
||||
|
||||
var update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_postcss_loader_dist_cjs_js_ruleSet_1_rules_1_use_2_node_modules_less_loader_dist_cjs_js_index_less__WEBPACK_IMPORTED_MODULE_1__.default, options);
|
||||
|
||||
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (_node_modules_css_loader_dist_cjs_js_node_modules_postcss_loader_dist_cjs_js_ruleSet_1_rules_1_use_2_node_modules_less_loader_dist_cjs_js_index_less__WEBPACK_IMPORTED_MODULE_1__.default.locals || {});
|
||||
|
||||
/***/ }),
|
||||
/* 2 */
|
||||
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
||||
|
||||
|
||||
|
||||
var isOldIE = function isOldIE() {
|
||||
var memo;
|
||||
return function memorize() {
|
||||
if (typeof memo === 'undefined') {
|
||||
// Test for IE <= 9 as proposed by Browserhacks
|
||||
// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
|
||||
// Tests for existence of standard globals is to allow style-loader
|
||||
// to operate correctly into non-standard environments
|
||||
// @see https://github.com/webpack-contrib/style-loader/issues/177
|
||||
memo = Boolean(window && document && document.all && !window.atob);
|
||||
}
|
||||
|
||||
return memo;
|
||||
};
|
||||
}();
|
||||
|
||||
var getTarget = function getTarget() {
|
||||
var memo = {};
|
||||
return function memorize(target) {
|
||||
if (typeof memo[target] === 'undefined') {
|
||||
var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself
|
||||
|
||||
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
|
||||
try {
|
||||
// This will throw an exception if access to iframe is blocked
|
||||
// due to cross-origin restrictions
|
||||
styleTarget = styleTarget.contentDocument.head;
|
||||
} catch (e) {
|
||||
// istanbul ignore next
|
||||
styleTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
memo[target] = styleTarget;
|
||||
}
|
||||
|
||||
return memo[target];
|
||||
};
|
||||
}();
|
||||
|
||||
var stylesInDom = [];
|
||||
|
||||
function getIndexByIdentifier(identifier) {
|
||||
var result = -1;
|
||||
|
||||
for (var i = 0; i < stylesInDom.length; i++) {
|
||||
if (stylesInDom[i].identifier === identifier) {
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function modulesToDom(list, options) {
|
||||
var idCountMap = {};
|
||||
var identifiers = [];
|
||||
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
var id = options.base ? item[0] + options.base : item[0];
|
||||
var count = idCountMap[id] || 0;
|
||||
var identifier = "".concat(id, " ").concat(count);
|
||||
idCountMap[id] = count + 1;
|
||||
var index = getIndexByIdentifier(identifier);
|
||||
var obj = {
|
||||
css: item[1],
|
||||
media: item[2],
|
||||
sourceMap: item[3]
|
||||
};
|
||||
|
||||
if (index !== -1) {
|
||||
stylesInDom[index].references++;
|
||||
stylesInDom[index].updater(obj);
|
||||
} else {
|
||||
stylesInDom.push({
|
||||
identifier: identifier,
|
||||
updater: addStyle(obj, options),
|
||||
references: 1
|
||||
});
|
||||
}
|
||||
|
||||
identifiers.push(identifier);
|
||||
}
|
||||
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
function insertStyleElement(options) {
|
||||
var style = document.createElement('style');
|
||||
var attributes = options.attributes || {};
|
||||
|
||||
if (typeof attributes.nonce === 'undefined') {
|
||||
var nonce = true ? __webpack_require__.nc : 0;
|
||||
|
||||
if (nonce) {
|
||||
attributes.nonce = nonce;
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(attributes).forEach(function (key) {
|
||||
style.setAttribute(key, attributes[key]);
|
||||
});
|
||||
|
||||
if (typeof options.insert === 'function') {
|
||||
options.insert(style);
|
||||
} else {
|
||||
var target = getTarget(options.insert || 'head');
|
||||
|
||||
if (!target) {
|
||||
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
|
||||
}
|
||||
|
||||
target.appendChild(style);
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
function removeStyleElement(style) {
|
||||
// istanbul ignore if
|
||||
if (style.parentNode === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
style.parentNode.removeChild(style);
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
|
||||
|
||||
var replaceText = function replaceText() {
|
||||
var textStore = [];
|
||||
return function replace(index, replacement) {
|
||||
textStore[index] = replacement;
|
||||
return textStore.filter(Boolean).join('\n');
|
||||
};
|
||||
}();
|
||||
|
||||
function applyToSingletonTag(style, index, remove, obj) {
|
||||
var css = remove ? '' : obj.media ? "@media ".concat(obj.media, " {").concat(obj.css, "}") : obj.css; // For old IE
|
||||
|
||||
/* istanbul ignore if */
|
||||
|
||||
if (style.styleSheet) {
|
||||
style.styleSheet.cssText = replaceText(index, css);
|
||||
} else {
|
||||
var cssNode = document.createTextNode(css);
|
||||
var childNodes = style.childNodes;
|
||||
|
||||
if (childNodes[index]) {
|
||||
style.removeChild(childNodes[index]);
|
||||
}
|
||||
|
||||
if (childNodes.length) {
|
||||
style.insertBefore(cssNode, childNodes[index]);
|
||||
} else {
|
||||
style.appendChild(cssNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyToTag(style, options, obj) {
|
||||
var css = obj.css;
|
||||
var media = obj.media;
|
||||
var sourceMap = obj.sourceMap;
|
||||
|
||||
if (media) {
|
||||
style.setAttribute('media', media);
|
||||
} else {
|
||||
style.removeAttribute('media');
|
||||
}
|
||||
|
||||
if (sourceMap && typeof btoa !== 'undefined') {
|
||||
css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
|
||||
} // For old IE
|
||||
|
||||
/* istanbul ignore if */
|
||||
|
||||
|
||||
if (style.styleSheet) {
|
||||
style.styleSheet.cssText = css;
|
||||
} else {
|
||||
while (style.firstChild) {
|
||||
style.removeChild(style.firstChild);
|
||||
}
|
||||
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
}
|
||||
|
||||
var singleton = null;
|
||||
var singletonCounter = 0;
|
||||
|
||||
function addStyle(obj, options) {
|
||||
var style;
|
||||
var update;
|
||||
var remove;
|
||||
|
||||
if (options.singleton) {
|
||||
var styleIndex = singletonCounter++;
|
||||
style = singleton || (singleton = insertStyleElement(options));
|
||||
update = applyToSingletonTag.bind(null, style, styleIndex, false);
|
||||
remove = applyToSingletonTag.bind(null, style, styleIndex, true);
|
||||
} else {
|
||||
style = insertStyleElement(options);
|
||||
update = applyToTag.bind(null, style, options);
|
||||
|
||||
remove = function remove() {
|
||||
removeStyleElement(style);
|
||||
};
|
||||
}
|
||||
|
||||
update(obj);
|
||||
return function updateStyle(newObj) {
|
||||
if (newObj) {
|
||||
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
update(obj = newObj);
|
||||
} else {
|
||||
remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function (list, options) {
|
||||
options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
|
||||
// tags it will allow on a page
|
||||
|
||||
if (!options.singleton && typeof options.singleton !== 'boolean') {
|
||||
options.singleton = isOldIE();
|
||||
}
|
||||
|
||||
list = list || [];
|
||||
var lastIdentifiers = modulesToDom(list, options);
|
||||
return function update(newList) {
|
||||
newList = newList || [];
|
||||
|
||||
if (Object.prototype.toString.call(newList) !== '[object Array]') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < lastIdentifiers.length; i++) {
|
||||
var identifier = lastIdentifiers[i];
|
||||
var index = getIndexByIdentifier(identifier);
|
||||
stylesInDom[index].references--;
|
||||
}
|
||||
|
||||
var newLastIdentifiers = modulesToDom(newList, options);
|
||||
|
||||
for (var _i = 0; _i < lastIdentifiers.length; _i++) {
|
||||
var _identifier = lastIdentifiers[_i];
|
||||
|
||||
var _index = getIndexByIdentifier(_identifier);
|
||||
|
||||
if (stylesInDom[_index].references === 0) {
|
||||
stylesInDom[_index].updater();
|
||||
|
||||
stylesInDom.splice(_index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
lastIdentifiers = newLastIdentifiers;
|
||||
};
|
||||
};
|
||||
|
||||
/***/ }),
|
||||
/* 3 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
|
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||
// Imports
|
||||
|
||||
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});
|
||||
// Module
|
||||
___CSS_LOADER_EXPORT___.push([module.id, "* {\n margin: 0;\n padding: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\nbody {\n width: 100vw;\n height: 100vh;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n}\n.main {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n -ms-flex-direction: column;\n flex-direction: column;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: distribute;\n justify-content: space-around;\n width: 360px;\n height: 420px;\n background-color: #ccc;\n border: 10px solid black;\n border-radius: 40px;\n}\n.stage {\n position: relative;\n width: 304px;\n height: 304px;\n border: 2px solid black;\n}\n.stage .snake > div {\n position: absolute;\n width: 10px;\n height: 10px;\n background-color: #000;\n border: 1px solid #ccc;\n}\n.stage .food {\n position: absolute;\n top: 0;\n left: 20px;\n width: 10px;\n height: 10px;\n background-color: yellow;\n border: 1px solid #ccc;\n border-radius: 50%;\n}\n.point {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-pack: distribute;\n justify-content: space-around;\n width: 100%;\n}\n", ""]);
|
||||
// Exports
|
||||
/* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___);
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 4 */
|
||||
/***/ (function(module) {
|
||||
|
||||
|
||||
|
||||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
// css base code, injected by the css-loader
|
||||
// eslint-disable-next-line func-names
|
||||
module.exports = function (cssWithMappingToString) {
|
||||
var list = []; // return the list of modules as css string
|
||||
|
||||
list.toString = function toString() {
|
||||
return this.map(function (item) {
|
||||
var content = cssWithMappingToString(item);
|
||||
|
||||
if (item[2]) {
|
||||
return "@media ".concat(item[2], " {").concat(content, "}");
|
||||
}
|
||||
|
||||
return content;
|
||||
}).join("");
|
||||
}; // import a list of modules into the list
|
||||
// eslint-disable-next-line func-names
|
||||
|
||||
|
||||
list.i = function (modules, mediaQuery, dedupe) {
|
||||
if (typeof modules === "string") {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
modules = [[null, modules, ""]];
|
||||
}
|
||||
|
||||
var alreadyImportedModules = {};
|
||||
|
||||
if (dedupe) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
var id = this[i][0];
|
||||
|
||||
if (id != null) {
|
||||
alreadyImportedModules[id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var _i = 0; _i < modules.length; _i++) {
|
||||
var item = [].concat(modules[_i]);
|
||||
|
||||
if (dedupe && alreadyImportedModules[item[0]]) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mediaQuery) {
|
||||
if (!item[2]) {
|
||||
item[2] = mediaQuery;
|
||||
} else {
|
||||
item[2] = "".concat(mediaQuery, " and ").concat(item[2]);
|
||||
}
|
||||
}
|
||||
|
||||
list.push(item);
|
||||
}
|
||||
};
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
/***/ }),
|
||||
/* 5 */
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _snake__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
|
||||
/* harmony import */ var _food__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
|
||||
/* harmony import */ var _point__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||
|
||||
//游戏控制器
|
||||
|
||||
|
||||
|
||||
|
||||
var GameControl = /*#__PURE__*/function () {
|
||||
function GameControl() {
|
||||
_classCallCheck(this, GameControl);
|
||||
|
||||
// 存储移动的方向
|
||||
this.direction = ''; // 游戏是否继续
|
||||
|
||||
this.isLive = true;
|
||||
this.snake = new _snake__WEBPACK_IMPORTED_MODULE_0__.default();
|
||||
this.food = new _food__WEBPACK_IMPORTED_MODULE_1__.default();
|
||||
this.point = new _point__WEBPACK_IMPORTED_MODULE_2__.default(10, 3);
|
||||
this.init();
|
||||
} // 游戏初始化的方法
|
||||
|
||||
|
||||
_createClass(GameControl, [{
|
||||
key: "init",
|
||||
value: function init() {
|
||||
// 绑定键盘事件
|
||||
document.addEventListener('keydown', this.keydownHandle.bind(this)); // document调用这个函数, 这里的this是document, 所以要么改成箭头函数,要么用bind
|
||||
|
||||
this.run();
|
||||
} // 按键按下事件
|
||||
|
||||
}, {
|
||||
key: "keydownHandle",
|
||||
value: function keydownHandle(e) {
|
||||
// console.log(this)
|
||||
// console.log(e.key);
|
||||
this.direction = e.key;
|
||||
} // 蛇移动的方法
|
||||
|
||||
}, {
|
||||
key: "run",
|
||||
value: function run() {
|
||||
var X = this.snake.X;
|
||||
var Y = this.snake.Y; // 检查有没有吃到食物
|
||||
|
||||
this.checkEat(X, Y); // 控制移动
|
||||
|
||||
switch (this.direction) {
|
||||
// 上
|
||||
case "ArrowUp":
|
||||
case "Up":
|
||||
Y -= 10;
|
||||
break;
|
||||
//下
|
||||
|
||||
case "ArrowDown":
|
||||
case "Down":
|
||||
Y += 10;
|
||||
break;
|
||||
// 左
|
||||
|
||||
case "ArrowLeft":
|
||||
case "Left":
|
||||
X -= 10;
|
||||
break;
|
||||
// 右
|
||||
|
||||
case "ArrowRight":
|
||||
case "Right":
|
||||
X += 10;
|
||||
break;
|
||||
} // 先检查有没有撞墙
|
||||
|
||||
|
||||
try {
|
||||
this.snake.X = X;
|
||||
this.snake.Y = Y;
|
||||
} catch (e) {
|
||||
// 捕获到异常, 结束运行
|
||||
alert(e.message);
|
||||
clearTimeout(this.timeID);
|
||||
this.isLive = false;
|
||||
}
|
||||
|
||||
this.timeID && clearTimeout(this.timeID); // 短路运算
|
||||
|
||||
if (this.isLive) {
|
||||
this.timeID = setTimeout(this.run.bind(this), 300 - (this.point.level - 1) * 30);
|
||||
}
|
||||
} // 检查是否吃到食物
|
||||
|
||||
}, {
|
||||
key: "checkEat",
|
||||
value: function checkEat(X, Y) {
|
||||
if (X === this.food.X && Y === this.food.Y) {
|
||||
console.log('吃到食物');
|
||||
this.food.change();
|
||||
this.point.addScore();
|
||||
this.snake.addBody();
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
return GameControl;
|
||||
}();
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (GameControl);
|
||||
|
||||
/***/ }),
|
||||
/* 6 */
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||
|
||||
var Snake = /*#__PURE__*/function () {
|
||||
function Snake() {
|
||||
_classCallCheck(this, Snake);
|
||||
|
||||
this.element = document.getElementById('snake');
|
||||
this.head = document.querySelector('#snake>div'); // 提示类型不匹配,断言
|
||||
|
||||
this.bodies = document.getElementById('snake').getElementsByTagName('div'); //query选择符选出来的元素及元素数组是静态的,而getElement这种方法选出的元素是动态的。静态的就是说选出的所有元素的数组,不会随着文档操作而改变.
|
||||
// 在使用的时候getElement这种方法性能比较好,query选择符则比较方便
|
||||
} // 蛇头的坐标
|
||||
|
||||
|
||||
_createClass(Snake, [{
|
||||
key: "X",
|
||||
get: function get() {
|
||||
return this.head.offsetLeft;
|
||||
},
|
||||
set: // 设置蛇头的坐标
|
||||
function set(value) {
|
||||
if (this.X == value) return; // 蛇撞墙
|
||||
|
||||
if (value < 0 || value > 290) {
|
||||
throw new Error('蛇撞墙了');
|
||||
} // 没撞墙
|
||||
// 长度大于1时,禁止掉头
|
||||
|
||||
|
||||
if (this.bodies[1] && this.bodies[1].offsetLeft === value) {
|
||||
console.log("发生了掉头");
|
||||
|
||||
if (value > this.X) {
|
||||
// 向右掉头, 则要往左修正value
|
||||
value = this.X - 10;
|
||||
} else {
|
||||
value = this.X + 10;
|
||||
}
|
||||
} // 移动身体
|
||||
|
||||
|
||||
this.moveBody(); // 这里同样要先移动身体, 再移动头
|
||||
// 移动头
|
||||
|
||||
this.head.style.left = value + 'px'; // 检查头是否撞到了身体
|
||||
|
||||
if (this.bodies.length > 4) {
|
||||
this.checkBreak();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "Y",
|
||||
get: function get() {
|
||||
return this.head.offsetTop;
|
||||
},
|
||||
set: function set(value) {
|
||||
if (this.Y == value) return; // 蛇撞墙
|
||||
|
||||
if (value < 0 || value > 290) {
|
||||
throw new Error('蛇撞墙了');
|
||||
} // 没撞墙
|
||||
// 长度大于1 , 禁止掉头
|
||||
|
||||
|
||||
if (this.bodies[1] && this.bodies[1].offsetTop === value) {
|
||||
console.log("发生了掉头");
|
||||
|
||||
if (value > this.Y) {
|
||||
// 向下掉头, 则要往上修正value
|
||||
value = this.Y - 10;
|
||||
} else {
|
||||
value = this.Y + 10;
|
||||
}
|
||||
}
|
||||
|
||||
this.moveBody();
|
||||
this.head.style.top = value + 'px'; // 检查头是否撞到了身体
|
||||
|
||||
this.checkBreak();
|
||||
} // 增加身体
|
||||
|
||||
}, {
|
||||
key: "addBody",
|
||||
value: function addBody() {
|
||||
this.element.insertAdjacentHTML("beforeend", "<div></div>");
|
||||
} // 移动身体
|
||||
// 最后一节移到倒数第二节, 把倒数第二节移到倒数第三节 ... 从后开始移动
|
||||
// 蛇头不用管
|
||||
|
||||
}, {
|
||||
key: "moveBody",
|
||||
value: function moveBody() {
|
||||
for (var i = this.bodies.length - 1; i > 0; i--) {
|
||||
// 前一截的位置
|
||||
var x = this.bodies[i - 1].offsetLeft;
|
||||
var y = this.bodies[i - 1].offsetTop; // HTMLElement 对象表示 HTML 中的一个元素。
|
||||
// HTMLElement 对象继承了Element 对象的标准属性,也实现了一些非标准属性
|
||||
// HTMLElement 简单的看成Element的子类
|
||||
// 给当前的一截赋值
|
||||
|
||||
this.bodies[i].style.left = x + 'px';
|
||||
this.bodies[i].style.top = y + 'px';
|
||||
}
|
||||
} // 检查撞身体
|
||||
|
||||
}, {
|
||||
key: "checkBreak",
|
||||
value: function checkBreak() {
|
||||
for (var i = 4; i < this.bodies.length; i++) {
|
||||
var bd = this.bodies[i];
|
||||
|
||||
if (bd.offsetLeft === this.X && bd.offsetTop === this.Y) {
|
||||
throw new Error('蛇撞到自己了');
|
||||
}
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
return Snake;
|
||||
}();
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (Snake);
|
||||
|
||||
/***/ }),
|
||||
/* 7 */
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||
|
||||
// 定义食物类
|
||||
var Food = /*#__PURE__*/function () {
|
||||
function Food() {
|
||||
_classCallCheck(this, Food);
|
||||
|
||||
this.element = document.getElementById('food'); // 这里的感叹号是非null和非undefined的类型断言
|
||||
|
||||
this.change();
|
||||
} // 获取食物的坐标
|
||||
|
||||
|
||||
_createClass(Food, [{
|
||||
key: "X",
|
||||
get: function get() {
|
||||
return this.element.offsetLeft;
|
||||
}
|
||||
}, {
|
||||
key: "Y",
|
||||
get: function get() {
|
||||
return this.element.offsetTop;
|
||||
} // 修改食物的坐标
|
||||
|
||||
}, {
|
||||
key: "change",
|
||||
value: function change() {
|
||||
this.element.style.left = Math.round(Math.random() * 29) * 10 + 'px';
|
||||
this.element.style.top = Math.round(Math.random() * 29) * 10 + 'px';
|
||||
}
|
||||
}]);
|
||||
|
||||
return Food;
|
||||
}();
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (Food);
|
||||
|
||||
/***/ }),
|
||||
/* 8 */
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||
|
||||
//定义统计类
|
||||
var Point = /*#__PURE__*/function () {
|
||||
function Point() {
|
||||
var maxLevel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
|
||||
var upScore = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
|
||||
|
||||
_classCallCheck(this, Point);
|
||||
|
||||
this.score = 0;
|
||||
this.level = 1;
|
||||
this.maxLevel = maxLevel;
|
||||
this.upScore = upScore;
|
||||
this.scoreEle = document.getElementById('score');
|
||||
this.levelEle = document.getElementById('level');
|
||||
} // 增加积分
|
||||
|
||||
|
||||
_createClass(Point, [{
|
||||
key: "addScore",
|
||||
value: function addScore() {
|
||||
this.scoreEle.innerHTML = ++this.score + ''; // 整除时升级
|
||||
|
||||
if (this.score % this.upScore === 0) {
|
||||
this.levelUp();
|
||||
}
|
||||
} // 增加等级
|
||||
|
||||
}, {
|
||||
key: "levelUp",
|
||||
value: function levelUp() {
|
||||
if (this.level < this.maxLevel) {
|
||||
this.levelEle.innerHTML = ++this.level + '';
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
return Point;
|
||||
}();
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (Point);
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ id: moduleId,
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/compat get default export */
|
||||
/******/ !function() {
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function() { return module['default']; } :
|
||||
/******/ function() { return module; };
|
||||
/******/ __webpack_require__.d(getter, { a: getter });
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/ }();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ !function() {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, definition) {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ }();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ !function() {
|
||||
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
||||
/******/ }();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ !function() {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ }();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
var __webpack_exports__ = {};
|
||||
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||
!function() {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _index_less__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var _modules_gameControl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
||||
|
||||
|
||||
new _modules_gameControl__WEBPACK_IMPORTED_MODULE_1__.default(); // 调试
|
||||
}();
|
||||
/******/ })()
|
||||
;
|
30
dist/index.html
vendored
Normal file
30
dist/index.html
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>贪食蛇</title>
|
||||
<script defer src="bundle.js"></script></head>
|
||||
<body>
|
||||
<!-- 主容器 -->
|
||||
<div class="main">
|
||||
<!-- 游戏区域 -->
|
||||
<div class="stage">
|
||||
<!-- 蛇 -->
|
||||
<div class="snake" id="snake">
|
||||
<div></div>
|
||||
</div>
|
||||
<!-- 食物 -->
|
||||
<div class="food" id="food">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计区域 -->
|
||||
<div class="point">
|
||||
<div class="score">Score: <span id="score">0</span></div>
|
||||
<div class="level">Level: <span id="level">1</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8538
package-lock.json
generated
Normal file
8538
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
package.json
Normal file
34
package.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "demo",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "webpack",
|
||||
"start": "webpack serve --open chrome.exe"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.13.10",
|
||||
"@babel/preset-env": "^7.13.10",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"core-js": "^3.9.1",
|
||||
"css-loader": "^5.1.3",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"less": "^4.1.1",
|
||||
"less-loader": "^8.0.0",
|
||||
"postcss": "^8.2.8",
|
||||
"postcss-loader": "^5.2.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"ts-loader": "^8.0.18",
|
||||
"typescript": "^4.2.3",
|
||||
"webpack": "^5.26.0",
|
||||
"webpack-cli": "^4.5.0",
|
||||
"webpack-dev-server": "^3.11.2"
|
||||
}
|
||||
}
|
30
src/index.html
Normal file
30
src/index.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>贪食蛇</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 主容器 -->
|
||||
<div class="main">
|
||||
<!-- 游戏区域 -->
|
||||
<div class="stage">
|
||||
<!-- 蛇 -->
|
||||
<div class="snake" id="snake">
|
||||
<div></div>
|
||||
</div>
|
||||
<!-- 食物 -->
|
||||
<div class="food" id="food">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计区域 -->
|
||||
<div class="point">
|
||||
<div class="score">Score: <span id="score">0</span></div>
|
||||
<div class="level">Level: <span id="level">1</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
59
src/index.less
Normal file
59
src/index.less
Normal file
@ -0,0 +1,59 @@
|
||||
@bgColor: #ccc;
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
width: 360px;
|
||||
height: 420px;
|
||||
background-color: @bgColor;
|
||||
border: 10px solid black;
|
||||
border-radius: 40px;
|
||||
}
|
||||
|
||||
.stage{
|
||||
position: relative;
|
||||
width: 304px;
|
||||
height: 304px;
|
||||
border: 2px solid black;
|
||||
|
||||
.snake{
|
||||
&>div{
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #000;
|
||||
border: 1px solid @bgColor;
|
||||
}
|
||||
}
|
||||
|
||||
.food{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: yellow;
|
||||
border: 1px solid @bgColor;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.point{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
}
|
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import './index.less'
|
||||
import gameControl from './modules/gameControl'
|
||||
|
||||
new gameControl()
|
||||
// 调试
|
28
src/modules/food.ts
Normal file
28
src/modules/food.ts
Normal file
@ -0,0 +1,28 @@
|
||||
// 定义食物类
|
||||
class Food {
|
||||
// 定义一个属性, 食物对应的元素
|
||||
element: HTMLElement // HTMLElement为ts带的类型
|
||||
|
||||
constructor(){
|
||||
this.element = document.getElementById('food')!; // 这里的感叹号是非null和非undefined的类型断言
|
||||
|
||||
this.change()
|
||||
}
|
||||
|
||||
// 获取食物的坐标
|
||||
get X(){
|
||||
return this.element.offsetLeft
|
||||
}
|
||||
|
||||
get Y(){
|
||||
return this.element.offsetTop
|
||||
}
|
||||
|
||||
// 修改食物的坐标
|
||||
change(){
|
||||
this.element.style.left = Math.round(Math.random() * 29 ) * 10 + 'px'
|
||||
this.element.style.top = Math.round(Math.random() * 29 ) * 10 + 'px'
|
||||
}
|
||||
}
|
||||
|
||||
export default Food
|
95
src/modules/gameControl.ts
Normal file
95
src/modules/gameControl.ts
Normal file
@ -0,0 +1,95 @@
|
||||
//游戏控制器
|
||||
import Snake from './snake'
|
||||
import Food from './food'
|
||||
import Point from './point'
|
||||
|
||||
class GameControl {
|
||||
snake: Snake
|
||||
food: Food
|
||||
point: Point
|
||||
timeID: any
|
||||
|
||||
// 存储移动的方向
|
||||
direction: string = ''
|
||||
|
||||
// 游戏是否继续
|
||||
isLive: boolean = true
|
||||
|
||||
constructor(){
|
||||
this.snake = new Snake()
|
||||
this.food = new Food()
|
||||
this.point = new Point(10, 3)
|
||||
this.init()
|
||||
}
|
||||
|
||||
// 游戏初始化的方法
|
||||
init (){
|
||||
// 绑定键盘事件
|
||||
document.addEventListener('keydown',this.keydownHandle.bind(this))
|
||||
// document调用这个函数, 这里的this是document, 所以要么改成箭头函数,要么用bind
|
||||
|
||||
this.run()
|
||||
}
|
||||
|
||||
// 按键按下事件
|
||||
keydownHandle(e:KeyboardEvent){
|
||||
// console.log(this)
|
||||
// console.log(e.key);
|
||||
this.direction = e.key
|
||||
}
|
||||
|
||||
// 蛇移动的方法
|
||||
run(){
|
||||
let X = this.snake.X
|
||||
let Y = this.snake.Y
|
||||
// 检查有没有吃到食物
|
||||
this.checkEat(X, Y)
|
||||
// 控制移动
|
||||
switch(this.direction) {
|
||||
// 上
|
||||
case "ArrowUp":
|
||||
case "Up": Y -= 10
|
||||
break
|
||||
//下
|
||||
case "ArrowDown":
|
||||
case "Down": Y += 10
|
||||
break
|
||||
// 左
|
||||
case "ArrowLeft":
|
||||
case "Left": X -= 10
|
||||
break
|
||||
// 右
|
||||
case "ArrowRight":
|
||||
case "Right": X += 10
|
||||
break
|
||||
}
|
||||
|
||||
// 先检查有没有撞墙
|
||||
try{
|
||||
this.snake.X = X
|
||||
this.snake.Y = Y
|
||||
}catch(e){
|
||||
// 捕获到异常, 结束运行
|
||||
alert(e.message)
|
||||
clearTimeout(this.timeID)
|
||||
this.isLive = false
|
||||
}
|
||||
|
||||
this.timeID && clearTimeout(this.timeID) // 短路运算
|
||||
if(this.isLive){
|
||||
this.timeID = setTimeout (this.run.bind(this), 300 - (this.point.level - 1) * 30)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否吃到食物
|
||||
checkEat(X:number, Y:number){
|
||||
if(X === this.food.X && Y === this.food.Y){
|
||||
console.log('吃到食物');
|
||||
this.food.change()
|
||||
this.point.addScore()
|
||||
this.snake.addBody()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GameControl
|
38
src/modules/point.ts
Normal file
38
src/modules/point.ts
Normal file
@ -0,0 +1,38 @@
|
||||
//定义统计类
|
||||
class Point {
|
||||
score = 0
|
||||
level = 1
|
||||
scoreEle:HTMLElement
|
||||
levelEle:HTMLElement
|
||||
|
||||
// 最高等级限制
|
||||
maxLevel: number
|
||||
|
||||
// 多少分升一级
|
||||
upScore: number
|
||||
|
||||
constructor(maxLevel:number=10, upScore:number = 10){
|
||||
this.maxLevel = maxLevel
|
||||
this.upScore = upScore
|
||||
this.scoreEle = document.getElementById('score')!
|
||||
this.levelEle = document.getElementById('level')!
|
||||
}
|
||||
|
||||
// 增加积分
|
||||
addScore(){
|
||||
this.scoreEle.innerHTML = ++this.score + ''
|
||||
// 整除时升级
|
||||
if(this.score % this.upScore === 0){
|
||||
this.levelUp()
|
||||
}
|
||||
}
|
||||
|
||||
// 增加等级
|
||||
levelUp(){
|
||||
if(this.level < this.maxLevel){
|
||||
this.levelEle.innerHTML = ++this.level + ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Point
|
114
src/modules/snake.ts
Normal file
114
src/modules/snake.ts
Normal file
@ -0,0 +1,114 @@
|
||||
class Snake{
|
||||
element: HTMLElement
|
||||
// 蛇头
|
||||
head:HTMLElement
|
||||
// 蛇的身体(包括蛇头)
|
||||
bodies: HTMLCollection
|
||||
|
||||
constructor(){
|
||||
this.element = document.getElementById('snake')!
|
||||
this.head = document.querySelector('#snake>div') as HTMLElement // 提示类型不匹配,断言
|
||||
this.bodies = document.getElementById('snake')!.getElementsByTagName('div')
|
||||
//query选择符选出来的元素及元素数组是静态的,而getElement这种方法选出的元素是动态的。静态的就是说选出的所有元素的数组,不会随着文档操作而改变.
|
||||
// 在使用的时候getElement这种方法性能比较好,query选择符则比较方便
|
||||
}
|
||||
|
||||
// 蛇头的坐标
|
||||
get X(){
|
||||
return this.head.offsetLeft
|
||||
}
|
||||
|
||||
get Y(){
|
||||
return this.head.offsetTop
|
||||
}
|
||||
|
||||
// 设置蛇头的坐标
|
||||
set X(value: number){
|
||||
if(this.X == value) return
|
||||
|
||||
// 蛇撞墙
|
||||
if(value < 0 || value > 290){
|
||||
throw new Error('蛇撞墙了')
|
||||
}
|
||||
|
||||
// 没撞墙
|
||||
// 长度大于1时,禁止掉头
|
||||
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){
|
||||
console.log("发生了掉头");
|
||||
if(value > this.X){
|
||||
// 向右掉头, 则要往左修正value
|
||||
value = this.X - 10
|
||||
} else {
|
||||
value = this.X + 10
|
||||
}
|
||||
}
|
||||
// 移动身体
|
||||
this.moveBody() // 这里同样要先移动身体, 再移动头
|
||||
// 移动头
|
||||
this.head.style.left = value + 'px'
|
||||
// 检查头是否撞到了身体
|
||||
if(this.bodies.length > 4){
|
||||
this.checkBreak()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set Y(value: number){
|
||||
if(this.Y == value) return
|
||||
// 蛇撞墙
|
||||
if(value < 0 || value > 290){
|
||||
throw new Error('蛇撞墙了')
|
||||
}
|
||||
// 没撞墙
|
||||
// 长度大于1 , 禁止掉头
|
||||
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value){
|
||||
console.log("发生了掉头");
|
||||
if(value > this.Y){
|
||||
// 向下掉头, 则要往上修正value
|
||||
value = this.Y - 10
|
||||
} else {
|
||||
value = this.Y + 10
|
||||
}
|
||||
}
|
||||
this.moveBody()
|
||||
this.head.style.top = value + 'px'
|
||||
// 检查头是否撞到了身体
|
||||
this.checkBreak()
|
||||
}
|
||||
|
||||
// 增加身体
|
||||
addBody (){
|
||||
this.element.insertAdjacentHTML("beforeend", "<div></div>")
|
||||
}
|
||||
|
||||
// 移动身体
|
||||
// 最后一节移到倒数第二节, 把倒数第二节移到倒数第三节 ... 从后开始移动
|
||||
// 蛇头不用管
|
||||
moveBody(){
|
||||
for(let i = this.bodies.length - 1; i > 0; i--){
|
||||
// 前一截的位置
|
||||
let x = (this.bodies[i - 1] as HTMLElement).offsetLeft
|
||||
let y = (this.bodies[i - 1] as HTMLElement).offsetTop;
|
||||
|
||||
// HTMLElement 对象表示 HTML 中的一个元素。
|
||||
// HTMLElement 对象继承了Element 对象的标准属性,也实现了一些非标准属性
|
||||
// HTMLElement 简单的看成Element的子类
|
||||
|
||||
// 给当前的一截赋值
|
||||
(this.bodies[i] as HTMLElement).style.left = x + 'px';
|
||||
(this.bodies[i] as HTMLElement).style.top = y + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
// 检查撞身体
|
||||
checkBreak(){
|
||||
for(let i = 4; i < this.bodies.length; i++){
|
||||
let bd = this.bodies[i] as HTMLElement
|
||||
if(bd.offsetLeft === this.X && bd.offsetTop === this.Y){
|
||||
throw new Error('蛇撞到自己了')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Snake
|
9
tsconfig.json
Normal file
9
tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
// 随便配置下
|
||||
"compilerOptions": {
|
||||
"module": "ES2015",
|
||||
"target": "ES2015",
|
||||
"strict": true,
|
||||
"noEmitOnError": true
|
||||
}
|
||||
}
|
103
webpack.config.js
Normal file
103
webpack.config.js
Normal file
@ -0,0 +1,103 @@
|
||||
const path = require('path')
|
||||
const htmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
|
||||
|
||||
// webpack中的所有信息都写在这里
|
||||
module.exports = {
|
||||
mode: 'none',
|
||||
// 指定入口文件
|
||||
entry: './src/index.ts',
|
||||
|
||||
//指定打包文件的左右目录
|
||||
output: {
|
||||
// 制定打包文件的目录
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
// 打包后文件的文件名
|
||||
filename: 'bundle.js',
|
||||
// 告诉webpack不使用箭头函数,const
|
||||
environment: {
|
||||
arrowFunction: false,
|
||||
const:false
|
||||
},
|
||||
},
|
||||
|
||||
// 指定webpack打包时要使用的模块
|
||||
module: {
|
||||
// 指定要加载的规则
|
||||
rules: [
|
||||
{
|
||||
// test指定的是规则生效的文件
|
||||
test: /\.ts$/,
|
||||
// 使用loader, loader的执行顺序是从下往上的
|
||||
use: [
|
||||
// 配置babel
|
||||
{
|
||||
// 指定加载器
|
||||
loader: 'babel-loader',
|
||||
// 配置项
|
||||
options: {
|
||||
// 设置预定义环境
|
||||
presets: [
|
||||
[
|
||||
// 指定环境的插件
|
||||
'@babel/preset-env',
|
||||
// 配置信息
|
||||
{
|
||||
// 要兼容的浏览器
|
||||
targets: {
|
||||
chrome: '58',
|
||||
ie: '11',
|
||||
},
|
||||
// 指定corejs的版本
|
||||
corejs: '3',
|
||||
// 使用corejs的方式, usage按需加载
|
||||
useBuiltIns: 'usage',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
'ts-loader',
|
||||
],
|
||||
// 排除的文件
|
||||
exclude: /node-modules/,
|
||||
},
|
||||
|
||||
// less文件的处理
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
'css-loader',
|
||||
// postcss配置
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: [
|
||||
"postcss-preset-env"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
'less-loader'
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// webpack插件配置
|
||||
plugins: [
|
||||
// 大包前先清空旧的文件
|
||||
new CleanWebpackPlugin(),
|
||||
new htmlWebpackPlugin({
|
||||
// title: "自定义标题"
|
||||
template: './src/index.html',
|
||||
}),
|
||||
],
|
||||
|
||||
// 设置引用模块
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user