bugfix> javascript > 投稿

マップとプレイヤーを描いたこの基本的なゲームを作成しました。プレイヤーはどこにでも移動できますが、マップのタイル[1]にあるときに動かないようにするにはどうすればいいですか? また、player.xが50より大きいかどうかを確認しようとすると、左に移動する可能性がありますが、一度に2つのキーをクリックすると通過します   const context = document.querySelector( "canvas")。getContext( "2d");

var rgb = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random() + ')';
document.onload = Loop();
var width = 1500;
var height = 800;
function Loop(){
  var width = 1500;
  var height = 800;
  context.canvas.height = height;
  context.canvas.width = width;
  this.interval = setInterval(Update, 1000/100);
}

const Player = function(x, y, w, h, color) {
  this.x = x; this.y = y; this.w = w; this.h = h;
  this.speedY = 0; this.speedX = 0;
  this.Draw = function(){
    context.fillStyle = this.color;
    context.fillRect(this.x, this.y, this.w, this.h);
  };
  this.Move = function(){
    this.x += this.speedX;
    this.y += this.speedY;
  };
};<code>
var player = new Player(100,100,50, 50, rgb);

var Key = {};
function Update(){
  context.clearRect(0, 0, width, height);
  Map();
  player.Draw();
  player.Move();
onkeydown = onkeyup = function(e){
  player.speedX = 0;
  player.speedY = 0;
  e = e || event;
  Key[e.keyCode] = e.type == 'keydown';
    if(Key[37] || Key[65]) {player.speedX -= 2}
    if(Key[38] || Key[87]) {player.speedY -= 2}
    if(Key[39] || Key[68]) {player.speedX += 2}
    if(Key[40] || Key[83]) {player.speedY += 2}
    if(Key[32]) {player.color = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random()*1 + ')';}
  };
}
var map = [
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1
    ];
var row = 5;
var column = 5;

function Map(){
  for(let y = -1; y < column; y++){
    for(let x = -1; x < row; x++){
      switch(map[((y*row) + x)]) {
        case 0: context.fillStyle = player.color;
          break;
        case 1: context.fillStyle = "#ffffff";
          break;
        default: context.fillStyle = "#000000";
      }
    context.fillRect(x*50, y*50, 50, 50);
    }
  }
}

回答 2 件
  • まず、コードを見ると、基本的な衝突検出を実装するために必要ないくつかの欠落しているものがあります。

    プレーヤーの現在の進行方向。これは重要です。なぜなら、プレーヤーは衝突することしかできないため、衝突検出を決定する機能が衝突をチェックしている側(上、下、左、または右)を区別できるからです。片側ずつ。

    タイルの位置とサイズ。これも非常に重要です。なぜなら、最初のポイントと同様に、プレイヤーが衝突できるのはタイルの片側だけであり、サイズと位置を知ることで、プレイヤーのサイズと位置に基づいて衝突かどうかを判断できるからです。

    また、あなたはそれが基本的なゲームであると述べたので、以下の実装は基本的な衝突検出です。より複雑で大きなゲームを作成する場合は、より効率的な衝突検出のために四分木を調べる必要があります。 https://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space--gamedev-374

    これは、読みやすさと短さのために、衝突を検出するための関数です。pはプレーヤーオブジェクトを表し、tはタイルオブジェクトを表します。この関数は、プレーヤーが移動方向に基づいてタイルと衝突しているかどうかを返します。

    function isColliding(p, t){
      if (p.direction == 'up') {
       return p.y +(p.height/2)-p.speedY< t.y + t.height && p.y > t.y
          && p.x + p.width > t.x && p.x < t.x + t.width;
      }
      if (p.direction == 'down') {
        return p.y + (p.height/2)+p.speedY > t.y && p.y < t.y
          && p.x + p.width > t.x && p.x < t.x + t.width;
      }
      if (p.direction == 'right') {
        return p.x + p.width+p.speedX > t.x && p.x < t.x
          && p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
      }
      if (p.direction == 'left') {
        return p.x -p.speedX< t.x + t.width && p.x > t.x
          && p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
      }
      return false;
    }
    
    

    プレーヤーの移動機能にこれを入れて、移動中のタイルを常に検出することをお勧めします。そのためには、キーダウン検出を変更して、キーダウンごとにプレーヤーの方向を更新するようにします。簡単な例を次に示します。

    document.onkeydown = function(event){
        if (event.keyCode == 87)
            player.up = true;
        else if (event.keyCode == 65)
            player.left = true;
        else if (event.keyCode == 83)
            player.down = true;
        else if (event.keyCode == 68)
            player.right = true;
    }
    
    

    プレーヤーが移動するたびに別の簡単な例(ユーザーがキーダウンを押す):

    const Player= function(/*Param stuff*/){
      /*Property stuff*/
      //tileArray is the array (or object, your choice) of all the current tiles in the map
      this.move=function(tileArray){
        //Go through all tiles to see if player is colliding with any of them
        for(var t in tileArray){
          if(this.up){
            if(isColliding(this, tileArray[t]){
              //functionality for when player collides
            }else{
              //functionality for when player doesn't collide
            }
          }
          //check if player is going down, left, etc
        }
      }
    }
    
    

    これらは、検出の実装方法の単なる例です。あなたが投稿した内容に基づいて書いていないので、あなたのコードがどのように機能するかを相対的に実装するためのリファレンスとして使用する必要があります。

    PS。

    ユーザーがキーを押すのをやめた後も、方向を必ずfalseに変換してください。

  • <!doctype html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<style>
    			body {
    				background-color: black;
    			}
    			
    			canvas {
    				display: block;
    				margin: auto;
    				border: solid 1px white;
    				border-radius: 10px;
    			}
    			
    			script {
    				display: none;
    			}
    		</style>
    	</head>
    	
    	<body>
    		<canvas id="canvas"></canvas>
    		<script type="application/javascript">
    		
    		void function() {
    			
    			"use strict";
    			
    			// Classes
    			function Camera(x,y) {
    				this.x = x || 0.0;
    				this.y = y || 0.0;
    			}
    			
    			Camera.prototype = {
    				set: function(x,y) {
    					this.x = x || 0.0;
    					this.y = y || 0.0;
    				},
    				
    				pan: function(x,y) {
    					this.x += x || 0.0;
    					this.y += y || 0.0;
    				}
    			};
    			
    			var nextID = 0;
    			
    			function Tile(colour) {
    				this.id = nextID++;
    				this.colour = colour || "black";
    			}
    			
    			function Map(width,height) {
    				this.width = width || 1;
    				this.height = height || 1;
    				this.map = [];
    				this.map.length = this.height;
    				
    				for (var y = 0; y < this.height; ++y) {
    					this.map[y] = [];
    					this.map[y].length = width;
    					
    					for (var x = 0; x < this.width; ++x) {
    						this.map[y][x] = Math.random() < 0.2 ?
    							this.TILE_WALL:
    							this.TILE_GRASS;
    					}
    					
    					this.map[y][0] = this.TILE_WALL;
    					this.map[y][this.width - 1] = this.TILE_WALL;
    				}
    				
    				for (var x = 0; x < this.width; ++x) {
    					this.map[0][x] = this.TILE_WALL;
    					this.map[this.height - 1][x] = this.TILE_WALL;
    				}
    			}
    			
    			Map.prototype = {
    				TILE_WIDTH: 32.0,
    				TILE_HEIGHT: 32.0,
    				INV_TILE_WIDTH: 0.0,
    				INV_TILE_HEIGHT: 0.0,
    			
    				TILE_AIR: new Tile("#00000000"),
    				TILE_GRASS: new Tile("#00AA00FF"),
    				TILE_WALL: new Tile("#555555FF"),
    			
    				set: function(x,y,tile) {
    					this.map[y][x] = tile;
    				},
    			
    				scaleX: function(x) {
    					return (x * this.INV_TILE_WIDTH) | 0;
    				},
    			
    				scaleY: function(y) {
    					return (y * this.INV_TILE_HEIGHT) | 0;
    				},
    			
    				isColliding: function(x,y) {
    					return x > -1 && x < this.width
    						&& y > -1 && y < this.height
    						&& this.map[y][x].id > 1;
    				},
    			
    				render: function(ctx,camera) {
    					for (var y = 0; y < this.height; ++y) {
    						for (var x = 0; x < this.width; ++x) {
    							var tile = this.map[y][x];
    							var _x = x * this.TILE_WIDTH - camera.x;
    							var _y = y * this.TILE_HEIGHT - camera.y;
    							
    							ctx.fillStyle = tile.colour;
    							ctx.fillRect(_x,_y,this.TILE_WIDTH - 1,this.TILE_HEIGHT - 1);
    						}
    					}
    				}
    			};
    			
    			Map.prototype.INV_TILE_WIDTH = 1.0 / Map.prototype.TILE_WIDTH;
    			Map.prototype.INV_TILE_HEIGHT = 1.0 / Map.prototype.TILE_HEIGHT;
    			
    			function Player(x,y) {
    				this.x = x || 0.0;
    				this.y = y || 0.0;
    				this.dx = 0.0;
    				this.dy = 0.0;
    				this.isUp = false;
    				this.isDown = false;
    				this.isLeft = false;
    				this.isRight = false;
    			}
    			
    			Player.prototype = {
    				WIDTH: 20.0,
    				HEIGHT: 20.0,
    				
    				ACCELERATION: 1.0,
    				DEACCELERATION: 0.5,
    				MAX_SPEED: 3.0,
    				
    				tick: function(map) {
    					// Movement
    					if (this.isUp) {
    						this.dy -= this.ACCELERATION;
    						
    						if (this.dy < -this.MAX_SPEED) {
    							this.dy = -this.MAX_SPEED;
    						}
    					} else if (this.dy < 0.0) {
    						this.dy += this.DEACCELERATION;
    						
    						if (this.dy > 0.0) {
    							this.dy = 0.0;
    						}
    					}
    					
    					if (this.isDown) {
    						this.dy += this.ACCELERATION;
    						
    						if (this.dy > this.MAX_SPEED) {
    							this.dy = this.MAX_SPEED;
    						}
    					} else if (this.dy > 0.0) {
    						this.dy -= this.DEACCELERATION;
    						
    						if (this.dy < 0.0) {
    							this.dy = 0.0;
    						}
    					}
    					
    					if (this.isLeft) {
    						this.dx -= this.ACCELERATION;
    						
    						if (this.dx < -this.MAX_SPEED) {
    							this.dx = -this.MAX_SPEED;
    						}
    					} else if (this.dx < 0.0) {
    						this.dx += this.DEACCELERATION;
    						
    						if (this.dx > 0.0) {
    							this.dx = 0.0;
    						}
    					}
    					
    					if (this.isRight) {
    						this.dx += this.ACCELERATION;
    						
    						if (this.dx > this.MAX_SPEED) {
    							this.dx = this.MAX_SPEED;
    						}
    					} else if (this.dx > 0.0) {
    						this.dx -= this.DEACCELERATION;
    						
    						if (this.dx < 0.0) {
    							this.dx = 0.0;
    						}
    					}
    					
    					// Collision
    					if (this.dx !== 0.0) {
    						var minY = map.scaleY(this.y);
    						var maxY = map.scaleY(this.y + this.HEIGHT);
    						var minX = 0;
    						var maxX = 0;
    						
    						if (this.dx < 0.0) {
    							minX = map.scaleX(this.x + this.dx);
    							maxX = map.scaleX(this.x);
    						} else {
    							minX = map.scaleX(this.x + this.WIDTH);
    							maxX = map.scaleX(this.x + this.WIDTH + this.dx);
    						}
    						
    						loop:
    						for (var y = minY; y <= maxY; ++y) {
    							for (var x = minX; x <= maxX; ++x) {
    								if (map.isColliding(x,y)) {
    									this.x = this.dx < 0.0 ?
    										(x + 1) * map.TILE_WIDTH:
    										x * map.TILE_WIDTH - this.WIDTH - 1;
    								
    									this.dx = 0.0;
    									break loop;
    								}
    							}
    						}
    					}
    					
    					if (this.dy !== 0.0) {
    						var minX = map.scaleX(this.x);
    						var maxX = map.scaleX(this.x + this.WIDTH);
    						var minY = 0;
    						var maxY = 0;
    						
    						if (this.dy < 0.0) {
    							minY = map.scaleY(this.y + this.dy);
    							maxY = map.scaleY(this.y);
    						} else {
    							minY = map.scaleY(this.y + this.HEIGHT);
    							maxY = map.scaleY(this.y + this.HEIGHT + this.dy);
    						}
    						
    						loop:
    						for (var y = minY; y <= maxY; ++y) {
    							for (var x = minX; x <= maxX; ++x) {
    								if (map.isColliding(x,y)) {
    									this.y = this.dy < 0.0 ?
    										(y + 1) * map.TILE_HEIGHT:
    										y * map.TILE_HEIGHT - this.HEIGHT - 1;
    								
    									this.dy = 0.0;
    									break loop;
    								}
    							}
    						}
    					}
    					
    					this.x += this.dx;
    					this.y += this.dy;
    				},
    				
    				render: function(ctx,camera) {
    					camera.set(this.x,this.y);
    				
    					ctx.lineWidth = 1;
    					ctx.strokeStyle = "black";
    					ctx.fillStyle = "darkred";
    					ctx.beginPath();
    					ctx.rect(this.x - camera.x,this.y - camera.y,this.WIDTH,this.HEIGHT);
    					ctx.fill();
    					ctx.stroke();
    				}
    			};
    			
    			// Variables
    			var canvasWidth = 180;
    			var canvasHeight = 160;
    			var canvas = null;
    			var ctx = null;
    			var camera = null;
    			var map = null;
    			var player = null;
    			
    			// Functions
    			function onKeyDown(e) {
    				switch(e.key.toUpperCase()) {
    					case "W": player.isUp = true; break;
    					case "S": player.isDown = true; break;
    					case "A": player.isLeft = true; break;
    					case "D": player.isRight = true; break;
    				}
    			}
    			
    			function onKeyUp(e) {
    				switch(e.key.toUpperCase()) {
    					case "W": player.isUp = false; break;
    					case "S": player.isDown = false; break;
    					case "A": player.isLeft = false; break;
    					case "D": player.isRight = false; break;
    				}
    			}
    			
    			function loop() {
    				// Tick
    				player.tick(map);
    				
    				// Render
    				ctx.fillStyle = "gray";
    				ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);
    				
    				map.render(ctx,camera);
    				player.render(ctx,camera);
    				
    				//
    				requestAnimationFrame(loop);
    			}
    			
    			// Entry point (first to execute)
    			onload = function() {
    				canvas = document.getElementById("canvas");
    				canvas.width = canvasWidth;
    				canvas.height = canvasHeight;
    				
    				ctx = canvas.getContext("2d");
    				ctx.translate(canvasWidth >> 1,canvasHeight >> 1);
    				
    				camera = new Camera(0.0,0.0);
    				map = new Map(10,10);
    				player = new Player(40.0,40.0);
    				
    				map.set(1,1,map.TILE_GRASS);
    				
    				addEventListener("keydown",onKeyDown);
    				addEventListener("keyup",onKeyUp);
    				
    				loop();
    			}
    			
    		}();
    		
    		</script>
    	</body>
    </html>
    
    

あなたの答え