RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 999988
Accepted
helloworld
helloworld
Asked:2022-10-10 15:11:57 +0000 UTC2022-10-10 15:11:57 +0000 UTC 2022-10-10 15:11:57 +0000 UTC

如何使物体“变硬” | 关卡地图错误

  • 772

曾几何时,我发现,他们说,“最难的游戏”(http://caniplay.ru/flash/4565),现在,几年后,我决定做一些类似的事情,但不是很硬核. 事实是我学会了如何检测碰撞,但是如何在碰撞期间使物体成为实体已经更加复杂了。完全看不懂代码哪里出了问题,一切似乎都是合乎逻辑的,但是js不这么认为。

也与地图的关卡问题:上半部分移出。你不能用逻辑来接受这个。请帮帮我。

PS只是一个清晰而准确的答案,而不是来自habr的伪代码或愚蠢的解释,即一个工作示例。

<!DOCTYPE html>
<html>
<head>
	<title>.</title>
	<meta charset="UTF-8">
</head>
<body style="margin: 0">
	<canvas id="can" style="display: block"></canvas>
	<script type="text/javascript">
		function getId(o){return document.getElementById(o)};
		class Block {
			constructor(position, size, color, type) {
				this.position = position,
				this.size = size,
				this.sys = {color: color}
			}
		};

		let can = getId("can"), ctx = can.getContext('2d'), game = {
			size: 35
		},
		player = {
			position: {
				x: innerWidth / 2 - 25,
				y: innerHeight - 25 - 300
			},
			size: {
				width: 50,
				height: 50
			},
			sys: {
				color: "#AA00FF",
				velocity: {
					x: 0,
					y: 0,
					friction: .9,
					plus: 1
				},
				keys: {
					w: false,
					a: false,
					s: false,
					d: false
				},
				scroll: {
					x: 0,
					y: 0
				}
			}
		}, blocks = [], createBlock = (x, y, w, h, color) => blocks.push( new Block({x: x, y: y}, {width: w, height: h}, color)),
		collides = (pl1, pl2) => (pl1.position.x + pl1.size.width < pl2.position.x ||
			pl2.position.x + pl2.size.width < pl1.position.x ||
			pl1.position.y + pl1.size.height < pl2.position.y ||
			pl2.position.y + pl2.size.height < pl1.position.y) ? false : true,
		map = `
		bbbbbbbbbbbbbbbbbbbbbbbbbbbb-b
		b----------------------------b
		b----------------------------b
		b----------------------------b
		b----------------------------b
		b----------------------------b
		b-------------P--------------b
		b-------------b--------------b
		b----------------------------b
		b----------------------------b
		bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
		`.trim().split('\n');

		// Тут какая-то фигня: блоки вверху "слетают" почему-то.
		for(let y = 0; y < map.length; y++) {
			for(let x = 0; x < map[y].length; x++) {
				let sym = map[y][x],
				w = game.size,
				h = game.size;
				if(sym == "P") {
					player.position.x = x * w;
					player.position.y = y * h;
					player.size.width = w;
					player.size.height = h
				} else if(sym == "b") {
					createBlock(x * w, y * h, w, h, "#902")
				}
			}
		};

		onresize = () => {
			can.width = innerWidth;
			can.height = innerHeight
		};
		onresize();

		document.onkeydown = e => {
			let kc = e.keyCode;
			if(kc == 'W'.charCodeAt()) player.sys.keys.w = true;
			if(kc == 'A'.charCodeAt()) player.sys.keys.a = true;
			if(kc == 'S'.charCodeAt()) player.sys.keys.s = true;
			if(kc == 'D'.charCodeAt()) player.sys.keys.d = true;
			if(kc == 'Z'.charCodeAt()) blocks.pop()
		};
		document.onkeyup = e => {
			let kc = e.keyCode;
			if(kc == 'W'.charCodeAt()) player.sys.keys.w = false;
			if(kc == 'A'.charCodeAt()) player.sys.keys.a = false;
			if(kc == 'S'.charCodeAt()) player.sys.keys.s = false;
			if(kc == 'D'.charCodeAt()) player.sys.keys.d = false
		};
		
		(loop = () => {
			ctx.fillStyle = "rgba(0, 0, 0, .24903)";
			ctx.fillRect(-3e38, -3e38, 3e38 * 2, 3e38 * 2);

			// Скроллинг
			player.sys.scroll.x = -player.position.x + innerWidth / 2 - player.size.width / 2;
			player.sys.scroll.y = -player.position.y + innerHeight / 2 - player.size.height / 2;
			ctx.save();
			ctx.translate(player.sys.scroll.x, player.sys.scroll.y);

			if(player.sys.keys.w) player.sys.velocity.y -= player.sys.velocity.plus;
			if(player.sys.keys.s) player.sys.velocity.y += player.sys.velocity.plus;
			if(player.sys.keys.a) player.sys.velocity.x -= player.sys.velocity.plus;
			if(player.sys.keys.d) player.sys.velocity.x += player.sys.velocity.plus;

			player.sys.velocity.y *= player.sys.velocity.friction;
			player.sys.velocity.x *= player.sys.velocity.friction;
			player.position.y += player.sys.velocity.y;
			player.position.x += player.sys.velocity.x;

			blocks.forEach(block => {
				// ВОТ ТУТ ВООБЩЕ НИЧЕГО НЕ ПОНЯТНО
				if(collides(block, player)) {
					if(player.position.y + player.size.height + player.sys.velocity.y > block.position.y) {
						player.position.y = block.position.y - block.size.height
					} else if(player.position.y - player.sys.velocity.y < block.position.y + block.size.height) {
						player.position.y = block.position.y + block.size.height
					}
				};

				ctx.fillStyle = block.sys.color;
				ctx.fillRect(block.position.x, block.position.y, block.size.width, block.size.height)
			});

			ctx.fillStyle = player.sys.color;
			ctx.fillRect(player.position.x, player.position.y, player.size.width, player.size.height);
			ctx.restore();

			requestAnimationFrame(loop)
		})();
	</script>
</body>
</html>

javascript разработка-игр
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Stranger in the Q
    2020-07-07T12:55:39Z2020-07-07T12:55:39Z

    在这里,我认为是这样的,即使在某些地方比我想要的更难=)。

    关卡地图的错误 - 打印构成关卡的行的内容,您将在那里看到\t

    我在那里添加了任何用于调试的绘图:

    class Block {
      constructor(position, size, color, type) {
        this.position = position,
          this.size = size,
          this.sys = {
            color: color
          }
      }
    };
    let debug = false;
    let ctx = can.getContext('2d'),
      game = {size: 35},
      player = {
        position: {x: innerWidth / 2 - 25,y: innerHeight - 25 - 300},
        size: {width: 50, height: 50},
        sys: {
          color: "#AA00FF",
          velocity: {x: 0, y: 0,friction: .9,plus: .99},
          keys: {w: false,a: false,s: false, d: false},
          scroll: {x: 0, y: 0}
        }
      },
      blocks = [],
      createBlock = (x, y, w, h, color) => 
        blocks.push(new Block({x: x, y: y}, {width: w, height: h}, color)),
      collides = (pl1, pl2) => !(
        pl1.position.x + pl1.size.width < pl2.position.x ||
        pl2.position.x + pl2.size.width < pl1.position.x ||
        pl1.position.y + pl1.size.height < pl2.position.y ||
        pl2.position.y + pl2.size.height < pl1.position.y),
      map = `
    		bbbbbbbbbbbbbbbbbbbbbbbbb----b
    		b----------------------------b
    		b-------------------------bbbb
    		b----------------------------b
    		b----b-----------------------b
    		b----------------------------b
    		b-------------P--------------b
    		b-------------b--------------b
    		b-----------------------b----b
    		b----------------------------b
    		bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    		`.trim().split('\t').join('').split('\n');
    
    for (let y = 0; y < map.length; y++) {
      for (let x = 0; x < map[y].length; x++) {
        let sym = map[y][x], w = game.size,  h = game.size;
        if (sym == "P") {
          player.position.x = x * w;
          player.position.y = y * h;
          player.size.width = w;
          player.size.height = h
        } else if (sym == "b") {
          createBlock(x * w, y * h, w, h, "#902")
        }
      }
    };
    
    onresize = () => {can.width = innerWidth;can.height = innerHeight};
    onresize();
    
    document.onkeydown = e => {
      let kc = e.keyCode;
      if (kc == 'W'.charCodeAt()) player.sys.keys.w = true;
      if (kc == 'A'.charCodeAt()) player.sys.keys.a = true;
      if (kc == 'S'.charCodeAt()) player.sys.keys.s = true;
      if (kc == 'D'.charCodeAt()) player.sys.keys.d = true;
      if (kc == 'Z'.charCodeAt()) blocks.pop()
    };
    
    document.onkeyup = e => {
      let kc = e.keyCode;
      if (kc == 'W'.charCodeAt()) player.sys.keys.w = false;
      if (kc == 'A'.charCodeAt()) player.sys.keys.a = false;
      if (kc == 'S'.charCodeAt()) player.sys.keys.s = false;
      if (kc == 'D'.charCodeAt()) player.sys.keys.d = false
    };
    
    (loop = () => {
    
      requestAnimationFrame(loop);
    
      ctx.fillStyle = "rgba(0, 0, 0, .24903)";
      ctx.fillRect(-3e38, -3e38, 3e38 * 2, 3e38 * 2);
    
      // Скроллинг
      player.sys.scroll.x = -player.position.x + innerWidth / 2 - player.size.width / 2;
      player.sys.scroll.y = -player.position.y + innerHeight / 2 - player.size.height / 2;
      ctx.save();
      ctx.translate(player.sys.scroll.x, player.sys.scroll.y);
    
      if (player.sys.keys.w) player.sys.velocity.y -= player.sys.velocity.plus;
      if (player.sys.keys.s) player.sys.velocity.y += player.sys.velocity.plus;
      if (player.sys.keys.a) player.sys.velocity.x -= player.sys.velocity.plus;
      if (player.sys.keys.d) player.sys.velocity.x += player.sys.velocity.plus;
    
      player.sys.velocity.y *= player.sys.velocity.friction;
      player.sys.velocity.x *= player.sys.velocity.friction;
    
      let top = null, bottom = null, left = null, right = null;
      blocks.forEach(block => {
        let a, collision = collides(block, player);
        if (collision) {
          // определяем с какой стороны стена и запоминаем ограничения
          let dy = player.position.y - block.position.y;
          let dx = player.position.x - block.position.x;
          a = Math.atan2(dy, dx)/Math.PI*180;
          if (a> 45 && a< 135) top = block.position.y+block.size.height;
          if (a<-45 && a>-135) bottom = block.position.y-player.size.height;
          if (a< 45 && a> -45) left = block.position.x+block.size.width;
          if (a>135 || a<-135) right = block.position.x-player.size.width;
        };
    
        ctx.fillStyle = debug && collision ? 'wheat' : block.sys.color;
        ctx.fillRect(block.position.x, block.position.y, block.size.width, block.size.height)
        if (debug && collision){
          let cx = block.position.x+block.size.width/2;
          let cy = block.position.y+block.size.height/2;
          ctx.beginPath(); 
          ctx.moveTo(cx,cy);
          ctx.lineTo(cx+Math.cos(a/180*Math.PI)*15,cy+Math.sin(a/180*Math.PI)*15);
          ctx.stroke();
        }
      });
      let f = 0.66; // имитация трения об препятствия
      let fritcion = (bottom?f:1)*(top?f:1)*(left?f:1)*(right?f:1);
      player.position.y += player.sys.velocity.y * fritcion;
      player.position.x += player.sys.velocity.x * fritcion;
      
      if (bottom != null)
        player.position.y = Math.min(player.position.y, bottom);
      if (top != null)
        player.position.y = Math.max(player.position.y, top);
      if (left != null)
        player.position.x = Math.max(player.position.x, left);
      if (right != null)
        player.position.x = Math.min(player.position.x, right);
        
      ctx.fillStyle = player.sys.color;
      ctx.fillRect(player.position.x, player.position.y, player.size.width, player.size.height);
      
      if (!debug)
        return ctx.restore();
      
      ctx.fillStyle = 'green';
      if (player.sys.velocity.y < 0 && top)
       ctx.fillRect(player.position.x, player.position.y, player.size.width, 4);
      if (player.sys.velocity.y > 0 && bottom)
       ctx.fillRect(player.position.x, player.position.y+player.size.height-4, player.size.width, 4);
      if (player.sys.velocity.x < 0 && left)
       ctx.fillRect(player.position.x, player.position.y, 4, player.size.height);
      if (player.sys.velocity.x > 0 && right)
       ctx.fillRect(player.position.x+player.size.width-4, player.position.y, 4, player.size.height); 
      
      ctx.restore();
      
    })();
    body, canvas {margin: 0; display: block}
    <canvas id="can"></canvas>

    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5