益智小游戏:连线最短距离的点

639 阅读2分钟

我正在参加掘金注意:随机点的数目越多,距离可能很小,图中看出的效果可能不明显。社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛

游戏地址:不会搞(所以没放)git地址:gitee.com/fwjzzz/Conn…

前言

初中阶段我们经常遇到求“最短距离”的数学问题,很多同学对此类问题毫无头绪,遇到此类问题总是一头雾水、无从下手。其实这类题难度并不大,如果我们能掌握解决这类题的本质及方法,“最短距离”问题将迎刃而解。

游戏规则

非常简单:在随机生成的点中,找到之间距离最短的点,计算两点间的直线距离并连接点,然后加分。

实现

初始化

布局

 <div id="app">
			<div id="score"></div>
			<svg id="svg"></svg>
			<div id="launch-screen" class="is-visible">
				<div id="launch-screen-content">
					<h1 id="launch-screen__title"></h1>
					<p id="launch-screen__description"></p>
					<button class="btn" id="start-btn">PLAY</button>
				</div>
			</div>
		</div>           

image.png

开始游戏

                       app.launchScreen(
				0,
				"最短距离",
				"寻找最近的点.",
				"开始"
			);

激活点用于存储游戏过程中单击点的数据执行进行,selected属性为false则未选中无法进行选择,为true 则可以单击,监听点击push进svg中

function Dot(r, cx, cy) {
  this.r = r;
  this.cx = cx;
  this.cy = cy;
  this.el = document.createElementNS("http://www.w3.org/2000/svg", "circle");
  this.class = "dot";
  this.update = function () {
    this.el.setAttribute("r", this.r);
    this.el.setAttribute("cx", this.cx);
    this.el.setAttribute("cy", this.cy);
    this.setAttr("class", this.class);
  };

  // 激活一个点用于存储游戏中每个点的所有数据的对象。
  this.activate = function () {
    for (i = 0; i < dots.num; i++) {
      dots.list[i].setAttr("data-selected", "false");
    }
    this.setAttr("data-selected", "true");
    // 将所有其他点的 selected 属性设置为 false,因此它们未被选中且无法单击。
    // 它将这个点的 selected 属性设置为 true,以便它现在可以选择并且可以单击。
  };

  this.visited = function () {
    this.setAttr("data-visited", "true");
    // 创建一个新的函数 单击点进行访问,执行函数
    // 在这种情况下,它将其自己的访问属性设置为 true,以便我们知道哪些点之前已访问过,
    // 哪些点在我们当前与游戏的会话期间尚未访问过。
  };

  // 将属性设置为元素
  this.setAttr = function (attr, value) {
    this.el.setAttribute(attr, value);
  };

  // 获取元素的属性。
  this.getAttr = function (attr) {
    return this.el.getAttribute(attr);
  };

  // 元素追加到SVG并附加事件监听器
  this.append = function () {
    svg.appendChild(this.el);
    this.el.addEventListener("click", this.onClick);
  };

  // 点击点元素
  this.onClick = function (event) {
    //gets the id and the coords of the dot
    var thisId = Number(event.target.getAttribute("data-id").substr(3, 2));
    var thisCx = dots.list[thisId].cx;
    var thisCy = dots.list[thisId].cy;

    // 计算点之间的距离
    var distances = [];
    for (i = 0; i < dots.num; i++) {
      distances[i] = [i, getDistance(dots.selected, dots.list[i])];
    }
    distances.sort(comparator);
    distances.splice(0, 1);
    var distancesLeft = [];
    for (i = 0; i < distances.length; i++) {
      if (dots.left.includes(distances[i][0])) {
        distancesLeft.push(distances[i][0]);
      }
    }

    //如果元素是最近的
    if (thisId == distancesLeft[0] && dots.left.includes(thisId)) {
      // 计算距离
      var newDistance = getDistance(dots.list[thisId], dots.selected);

      app.score.update(1); // punteggio x numero di poi
      // app.score.update(newDistance); punteggio x distanza

      //设置为选定的点
      dots.list[thisId].activate();
      dots.list[thisId].visited();

      // 创建线
      lines.list.push(
        new Line(
          dots.selected.cx,
          dots.selected.cy,
          dots.list[thisId].cx,
          dots.list[thisId].cy
        )
      );
      lines.list[lines.list.length - 1].update();
      lines.list[lines.list.length - 1].append();

      // 创建预览行
      //除去这些,你就能活下去了

      svg.addEventListener("mousemove", function prelineMove(e) {
        mouseX = e.pageX;
        mouseY = e.pageY;
        app.preline.update(thisCx, thisCy, mouseX, mouseY);
      });

      //保存选定的点坐标
      dots.selected.id = thisId;
      dots.selected.cx = thisCx;
      dots.selected.cy = thisCy;

      //将圆点从剩余的圆点列表中移除
      for (i = 0; i < dots.left.length; i++) {
        if (dots.left[i] === thisId) {
          dots.left.splice(i, 1);
        }
      }

      if (dots.left.length == 0) {
        app.end(true);
      }
    } else {
      app.end(false);
    }
  };
}

Snipaste_2022-04-16_17-01-52.png

注意:随机点的数目越多,距离可能很小,图中看出的效果可能不明显。

计算两点之间距离

计算obj1,obj2 两个对象之间的距离。 使用 Math.sqrt 和 Math.pow 函数计算两个对象之间的平方根。


			function getRandomArbitrary(min, max) {
				return Math.floor(Math.random() * (max - min) + min);
			} //计算随机算

关卡,计算得分

// 计算
			var app = {};
			app.level = 4; //关卡
			app.score = {}; //分数
			app.score.number = 0; //分数为0
			app.score.el = document.getElementById("score");
			app.score.update = function(score) {
				//计算得分
				app.score.number += score;
				app.score.el.textContent = app.score.number;
			};
			//重置按钮分数清零
			app.score.reset = function() {
				app.score.number = 0;
				app.score.update(0);
			};

			app.results = function(points) {
				if (points == "reset") {
					sessionStorage.setItem("results", 0);
				} else {
					if (!sessionStorage.getItem("results")) {
						sessionStorage.setItem("results", points);
					} else {
						var newscore = parseInt(sessionStorage.getItem("results")) + points;
						sessionStorage.setItem("results", newscore);
					}
				}
			};

			app.launchScreen = function(lastScore, title, description, btnText) {
				//  创建一个名为 launchScreen 的函数,该函数将用于创建应用程序的一个实例并将其显示在屏幕上。
				app.launchScreen.el = document.getElementById("launch-screen");
				// 使用 document.getElementById() 来获取对启动屏幕的标题、描述和 btnText 元素的引用。
				app.launchScreen.el.setAttribute("class", "is-visible");
				var launchScreenTitle = document.getElementById("launch-screen__title");
				launchScreenTitle.textContent = title;
				var launchScreenDescription = document.getElementById(
					"launch-screen__description"
				);
				launchScreenDescription.textContent = description;
				app.launchScreen.btn = document.getElementById("start-btn");
				// 当用户单击 start-btn 或 stop-btn 以分别启动或关闭此屏幕时设置事件侦听器。
				//   会将launchScreen 的class 属性设置为“is-visible”,使其在屏幕上可见。
				app.launchScreen.btn.textContent = btnText;
				app.launchScreen.btn.addEventListener("click", function lauch() {
					app.launchScreen.el.setAttribute("class", "");
					app.start(app.level);
					app.launchScreen.btn.removeEventListener("click", lauch);
				});
			};
			app.preline = new Line(0, 0, 200, 200);
			app.preline.setAttr("id", "preline");
			// 首先设置要在屏幕上绘制的点数。
			//  然后它遍历所有点并为每个点创建一个新点。

连线起点

image.png

			app.start = function(dotsNum) {
				dots.num = dotsNum; // 将dotsNum 变量设置为一个数字
				for (i = 0; i < dots.num; i++) {
					var cx = getRandomArbitrary(10, screenW - 10);
					var cy = getRandomArbitrary(10, screenH - 10);
					dots.list[i] = new Dot(8, cx, cy);
					dots.list[i].setAttr("data-id", "id-" + i);
					dots.list[i].setAttr(
						"style",
						"animation-delay:" + i / 10 + "s; transform-origin: " + cx + 'px ' + cy + 'px;');
					dots.list[i].update();
					dots.list[i].append();
					dots.left.push(i);
					if (i == dots.start) {
						dots.selected.cx = dots.list[dots.start].cx;
						dots.selected.cy = dots.list[dots.start].cy;
						dots.list[dots.start].setAttr("class", "dot dot--starting");
						dots.left.splice(i, 1);
					}
					// 设置了一个id属性,style,animation-delay:10s;变换原点:cx+cy;对于每个点。
					// 然后它更新它们并将它们附加到左侧的点列表中(它们将显示在哪里)。
					// 添加preline
					app.preline.update(
						dots.selected.cx,
						dots.selected.cy,
						dots.selected.cx,
						dots.selected.cy
					);
					// preline 功能,当您将鼠标移到 cx 或 cy 值相对于其父位置(起点)的位置在 0 到 10 像素之间的任何点上时,该功能将更新。
					app.preline.append(); // 在屏幕上创建随机数量的点,然后将它们附加到数组中。
					svg.addEventListener("mousemove", function prelineMove(e) {
						// 一个事件侦听器,用于侦听 mousemove 事件并相应地更新点的位置。
						mouseX = e.pageX;
						mouseY = e.pageY;
						app.preline.update(dots.selected.cx, dots.selected.cy, mouseX, mouseY);
					});
				}
				// 它到达起始点时,它将 data-selected 属性设置为 true
				dots.list[dots.start].setAttr("data-selected", "true");
			};

游戏开始,下一级,游戏失败

app.end = function(win) {
				if (win) {
					app.level += 4;
					app.results(app.score.number);
				} else {
					app.level = 4;
				}

				dots.list = [];
				dots.selected = {};
				dots.left.length = 0;
				svg.innerHTML = "";

				if (win) {
					app.launchScreen(
						app.score.number,
						"非常棒!",
						"你的分数是: " + sessionStorage.getItem("results") + ' 下一级会更难哦!',
						"继续"
					);
				} else {
					app.launchScreen(
						0,
						"游戏结束!",
						"你的最终得分是: " + sessionStorage.getItem("results"),
						"再来一局"
					);
					app.results("reset");
					app.score.reset();
				}
			};

			app.launchScreen(
				0,
				"最短距离",
				"寻找最近的点.",
				"开始"
			);

鄙人最高记录

image.png

image.png

点个赞吧 球球了φ(>ω<*)