我在画布游戏中拍摄时遇到了问题。当我向目标(敌人)射击子弹并且前方没有其他敌人时,子弹向右移动,但当敌人在玩家面前并且他们正在直接射向目标时,当遇到第一个敌人时子弹消失。我希望子弹直接攻击敌人,我不知道如何实现目标。
var ctx = $("#canvas")[0].getContext('2d'),
cHeight = canvas.height = 800,
cWidth = canvas.width = 1300,
canvasOffset = $('#canvas').offset(),
offsetX = canvasOffset.left,
offsetY = canvasOffset.top,
frameCounter = 0,
enemyList = [],
bulletList = [],
spawningEnemies_FLAG = true,
isLeftMouseButtonHeld_FLAG = false,
isAnyEnemySelected_FLAG = false,
cursors = ['default', 'pointer'],
enemiesOnMap = 10;
ctx.font = '22px Arial';
var sharedBehaviour = {
x: (cWidth / 2) - (cWidth / 8) + randomNumberFromRange(1, (cWidth / 8)),
y: (cHeight / 2) - (cHeight / 8) + randomNumberFromRange(1, (cHeight / 8)),
id: undefined,
type: 'entity',
width: 15,
height: 15,
fillColor: '#E15258',
targetX: null,
targetY: null,
bulletSpeed: 1,
aimAngle: null,
circleRadius: null,
circleColor: 'black',
circleWidth: 1,
// Statistics
hp: 10,
shield: 0,
speed: 1,
update( type ) {
if( type === 'player' ) {
enemyList.forEach( enemy => {
if ( enemy.isMouseOver() ) {
if( isLeftMouseButtonHeld_FLAG ) {
player.targetX = player.targetY = null;
}
}
});
}
// if there is target
if( this.targetX !== null ) {
// Find out distance to target
var distanceX = this.targetX - this.x; // distance on X axis
var distanceY = this.targetY - this.y; // distance on Y axis
var distanceToTarget = Math.sqrt( distanceX*distanceX + distanceY*distanceY ); // distance
// If distance is smaller or equal speed, then just set position
if( distanceToTarget <= this.speed ) {
this.x = this.targetX;
this.y = this.targetY;
// Then reset
this.targetX = this.targetY = null;
} else { // If distance is bigger than speed, so we want to move with speed
distanceX = distanceX / distanceToTarget;
distanceY = distanceY / distanceToTarget;
distanceX = distanceX * this.speed;
distanceY = distanceY * this.speed;
this.x += distanceX;
this.y += distanceY;
}
}
},
draw( ) {
drawRect( this.x - this.width/2,
this.y - this.height/2,
this.width,
this.height,
this.fillColor );
},
highlight( ) {
crosshair( this.x - this.width/2, this.y - this.height/2, this.width, this.height,
20, 25, // radius1, radius2
6, // endLineWidth
1, 2, // circle1Width, circle2Width
2, 2, 2, 2, // topLineWidth, rightLineWidth, bottomLineWidth, leftLineWidth
'#E15258', '#E15258', // circle1Color, circle2Color
'#C25975' ); // linesColor
},
isColliding( entity ) {
// Collision: rect to rect
return testCollisionRectRect( this, entity );
},
drawCircle( ) {
drawCircle( this.x, this.y, this.circleRadius, this.circleWidth, this.circleColor );
}
};
var player = Object.assign({}, sharedBehaviour, {
x: cWidth/2 - 10,
y: cHeight/2 - 10,
id: 980722,
type: 'player',
width: 20,
height: 20,
fillColor: '#82d877',
bulletSpeed: 1,
circleRadius: 200,
circleColor: 'black',
circleWidth: 1,
pressingC: false,
// Player stats
name: 'player1',
pd: 0,
hp: 10,
speed: 2.5
});
function createEnemy( x, y, id, width, height, fillColor, speed, type ) {
var newEnemy = Object.assign({}, sharedBehaviour, {
x,
y,
id,
width,
height,
type,
fillColor,
mouseX: null,
mouseY: null,
isHighlighted: false,
isClicked: false,
circleRadius: 50,
circleColor: 'red',
circleWidth: 1,
// Statistics
hp: 100,
shield: 0,
speed,
setTarget( entity ) {
this.targetX = entity.x + randomNumberFromRange(-50, 50);
this.targetY = entity.y + randomNumberFromRange(-50, 50);
},
isOnPlayer( val ) {
// Check if enemy is on player
var distanceX = player.x - this.x;
var distanceY = player.y - this.y;
return Math.sqrt( distanceX*distanceX + distanceY*distanceY ) < val;
},
isMouseOver( ) {
return (this.mouseX + this.width/2 >= this.x && this.mouseX + this.width/2 <= this.x + this.width && this.mouseY + this.height/2 >= this.y && this.mouseY + this.height/2 <= this.y + this.height);
}
});
enemyList.push( newEnemy );
}
function createBullet( actor ) {
var newBullet = Object.assign({}, sharedBehaviour, {
x: actor.x,
y: actor.y,
height: 7,
width: 7,
aimAngle: actor.aimAngle,
fillColor: 'green',
spdX: Math.cos(actor.aimAngle/180*Math.PI)*8,
spdY: Math.sin(actor.aimAngle/180*Math.PI)*8,
update ( ) {
this.x += this.spdX;
this.y += this.spdY;
}
});
bulletList.push( newBullet );
}
function newGame( ) {
// Reset all to its defaults
player.hp = 10;
frameCounter = 0;
enemyList = [];
bulletList = [];
spawningEnemies_FLAG = true;
isLeftMouseButtonHeld_FLAG = false;
// Spawning enemies
for( i=0; i < randomNumberFromRange(15, 25); i++ ) {
createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'str' + (i+1), randomNumberFromRange(12, 18), randomNumberFromRange(12, 18), 'red', 1, 's' );
createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'lor' + (i+1), randomNumberFromRange(10, 16), randomNumberFromRange(10, 16), 'lightblue', 1.5, 'l' );
}
requestAnimationFrame(update);
}
function update( ) {
frameCounter++;
ctx.clearRect(0,0,cWidth,cHeight);
enemyList.forEach( enemy => {
enemy.update();
});
// Update bullet position and remove if goes out of canvas
bulletList.forEach( bullet => {
bullet.update();
if ( bullet.x < 0 || bullet.x > cWidth || bullet.y < 0 || bullet.y > cHeight) {
bulletList.remove(bullet);
}
});
player.update('player');
enemyList.forEach( enemy => {
if( enemy.isHighlighted ) {
if( enemy.isMouseOver() ) {
enemy.draw();
enemy.highlight();
} else {
enemy.draw()
}
} else {
enemy.draw();
}
if( enemy.isClicked ) {
enemy.draw();
enemy.highlight();
} else {
enemy.draw();
}
if ( Math.random() < ( 1 / 15 ) ) { // 1 in 25 chance to look for player about once every 0.25 sec
if ( enemy.isOnPlayer( player.circleRadius ) ) {
if ( ! (enemy.isOnPlayer( 50 )) ) {
enemy.setTarget( player );
}
}
}
if ( Math.random() < ( 1 / 800 )) { // 1 in 500 chance to look for player about once every 5 sec
if ( ! (enemy.isOnPlayer( player.circleRadius )) ) {
enemy.setTarget( enemy );
}
}
if ( enemy.isOnPlayer(player.circleRadius/4 ) ) {
enemy.targetX = enemy.targetY = null; // Reset enemy target
}
// If bullet has collision with enemy, rcemove both and add reward
bulletList.forEach( bullet => {
if ( testCollisionRectRect(enemy, bullet) ) {
if( enemy.isClicked ) {
enemy.hp -= 5;
bulletList.remove(bullet);
if ( enemy.hp <= 0 ) {
enemyList.remove(enemy);
}
}
}
});
});
bulletList.forEach( bullet => {
bullet.draw();
});
player.draw();
player.drawCircle();
if ( frameCounter % 500 === 0 && spawningEnemies_FLAG ) {
createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'str' + (i+1), randomNumberFromRange(12, 18), randomNumberFromRange(12, 18), 'red', 1, 's' );
createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'lor' + (i+1), randomNumberFromRange(10, 16), randomNumberFromRange(10, 16), 'lightblue', 1.5, 'l' );
}
if ( enemyList.length === enemiesOnMap ) {
spawningEnemies_FLAG = false;
} else {
spawningEnemies_FLAG = true;
}
ctx.fillText(player.hp + " hp", 10, 25);
ctx.fillText('Map 1', cWidth-70, 25);
requestAnimationFrame(update);
}
document.onmousedown = function( mouse ) {
isLeftMouseButtonHeld_FLAG = true;
setPlayerTargetAndCheckAvailableArea( mouse );
}
document.onmouseup = function( mouse ) {
isLeftMouseButtonHeld_FLAG = false;
}
document.onmousemove = function( mouse ) {
if ( isLeftMouseButtonHeld_FLAG ) {
setPlayerTargetAndCheckAvailableArea( mouse );
}
var mouseX = mouse.clientX - document.getElementById('canvas').getBoundingClientRect().left;
var mouseY = mouse.clientY - document.getElementById('canvas').getBoundingClientRect().top;
var newX, newY;
enemyList.forEach( enemy => {
if( enemy.isClicked ) {
isAnyEnemySelected_FLAG = true;
newX = enemy.x;
newY = enemy.y;
}
});
if( isAnyEnemySelected_FLAG ) {
newX -= player.x;
newY -= player.y;
player.aimAngle = Math.atan2(newY, newX) / Math.PI * 180;
} else {
isAnyEnemySelected_FLAG = false;
mouseX -= player.x;
mouseY -= player.y;
player.aimAngle = Math.atan2(mouseY, mouseX) / Math.PI * 180;
}
var mousexX = parseInt(mouse.clientX - offsetX);
var mouseyY = parseInt(mouse.clientY - offsetY);
var currentCursor = 0;
enemyList.forEach( enemy => {
enemy.mouseX = mousexX;
enemy.mouseY = mouseyY;
if(enemy.isMouseOver()) {
currentCursor = 1;
if(enemy.isClicked) {
enemy.isHighlighted = false;
} else {
enemy.isHighlighted = true;
}
} else {
enemy.isHighlighted = false;
}
});
canvas.style.cursor = cursors[currentCursor];
}
document.onclick = function( mouse ) {
var mousexX = parseInt(mouse.clientX - offsetX);
var mouseyY = parseInt(mouse.clientY - offsetY);
enemyList.forEach( enemy => {
enemy.mouseX = mousexX;
enemy.mouseY = mouseyY;
if(enemy.isMouseOver()) {
if(enemy.isHighlighted) {
enemy.isHighlighted = false;
enemy.isClicked = true;
} else {
enemy.isClicked = false;
}
} else {
enemy.isClicked = false;
}
});
}
document.onkeydown = function ( key ) {
switch(key.keyCode) {
case 67:
player.pressingC = true;
break;
}
}
document.onkeyup = function ( key ) {
switch(key.keyCode) {
case 67:
player.pressingC = false;
if( isAnyEnemySelected_FLAG ) {
createBullet( player );
}
break;
}
}
function setPlayerTargetAndCheckAvailableArea ( mouse ) {
player.targetX = mouse.clientX - document.getElementById('canvas').getBoundingClientRect().left;
player.targetY = mouse.clientY - document.getElementById('canvas').getBoundingClientRect().top;
if (player.targetX < player.width/2) {
player.targetX = player.width/2;
}
if (player.targetX > cWidth - player.width/2) {
player.targetX = cWidth - player.width/2
}
if (player.targetY < player.height/2) {
player.targetY = player.height/2;
}
if (player.targetY > cHeight - player.height/2) {
player.targetY = cHeight - player.height/2
}
}
function randomNumberFromRange( min, max ) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function testCollisionRectRect( rectangle1, rectangle2 ) {
return rectangle1.x - rectangle1.width/2 <= rectangle2.x - rectangle2.width/2 + rectangle2.width
&& rectangle2.x - rectangle2.width/2 <= rectangle1.x - rectangle1.width/2 + rectangle1.width
&& rectangle1.y - rectangle1.height/2 <= rectangle2.y - rectangle2.height/2 + rectangle2.height
&& rectangle2.y - rectangle2.height/2 <= rectangle1.y - rectangle1.height/2 + rectangle1.height;
}
Array.prototype.remove = function() {
var what, a = arguments, L = a.length, ax;
while (L && this.length) {
what = a[--L];
while ((ax = this.indexOf(what)) !== -1) {
this.splice(ax, 1);
}
}
return this;
}; // Function to pop specific element drom array by value
function crosshair( x, y, width, height, radius1, radius2, endLineWidth, circle1Width, circle2Width, topLineWidth, rightLineWidth, bottomLineWidth, leftLineWidth, circle1Color, circle2Color, linesColor) {
drawCircle(x + width/2, y + height/2, radius1, circle1Width, circle1Color);
drawCircle(x + width/2, y + height/2, radius2, circle2Width, circle2Color);
drawLine(x + radius1 + width/2, y + height/2, x + (radius2 + endLineWidth) + width/2, y + height/2, linesColor, leftLineWidth);
drawLine(x - radius1 + width/2, y + height/2, x - (radius2 + endLineWidth) + width/2, y + height/2, linesColor, rightLineWidth);
drawLine(x + width/2, y + radius1 + height/2, x + width/2, y + (radius2 + endLineWidth) + height/2, linesColor, bottomLineWidth);
drawLine(x + width/2, y - radius1 + height/2, x + width/2, y - (radius2 + endLineWidth) + height/2, linesColor, topLineWidth);
}
function drawLine( startX, startY, endX, endY, color, width ) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(endX,endY);
ctx.stroke();
ctx.restore();
}
function drawCircle( x, y, radius, lineWidth, strokeColor ) {
ctx.save();
ctx.beginPath();
ctx.arc( x, y, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
ctx.restore();
}
function drawBorder( x, y, width, height, lineWidth, strokeColor ) {
ctx.save();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor;
ctx.strokeRect( x, y, width, height);
ctx.restore();
}
function drawRect( x, y, width, height, fillColor ) {
ctx.save();
ctx.fillStyle = fillColor;
ctx.fillRect( x, y, width, height );
ctx.restore();
}
newGame();
&#13;
canvas {
border: 1px solid black;
background-color: white;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<canvas id="canvas" width="1300" height="800"></canvas>
&#13;