我的朋友和我正在制作游戏。但是,我在明星精灵管理方面遇到了困难。有时,存在间隙(应该绘制精灵的区域,而不是)。我已将整个程序作为代码片段包含在内,但下面也是可能直接导致问题的代码块。
每个精灵都有坐标对。坐标图如下所示:
[{x:xCoordinate,y:yCoordinate},{x:xCoordinate,y:yCoordinate},...];
此代码生成并删除sprite ...
for(var i = 0; i < stars.positions.length; i++){
//store coordinate positions...
var x = stars.positions[i].x;
var y = stars.positions[i].y;
//delete sprites no longer visible within the viewport...
if(x > window.innerWidth || x < -spriteWidth || y < -spriteHeight || y > window.innerHeight){
//sprite is no longer visible within viewport; remove it...
stars.positions.splice(i,1);
}
//find necessary comparative coordinates...
var lowestXCoordinatePair = stars.meta.lowestXCoordinatePair;
var highestXCoordinatePair = stars.meta.highestXCoordinatePair;
var lowestYCoordinatePair = stars.meta.lowestYCoordinatePair;
var highestYCoordinatePair = stars.meta.highestYCoordinatePair;
//gather star sprite meta data...
var spriteWidth = stars.meta.spriteWidth;
var spriteHeight = stars.meta.spriteHeight;
if(lowestXCoordinatePair.x > 0){
//Gap on the left side. New sprites necessary to fill the gap on left row...
//console.log('adding sprites left row...')
for(var i = 0; i < stars.meta.imagesYRequired; i++){
stars.positions.push({
x:lowestXCoordinatePair.x-spriteWidth,
y:lowestXCoordinatePair.y+i*spriteHeight
});
}
}
if(highestXCoordinatePair.x < window.innerWidth-spriteWidth){
//Gap on the right side. New sprites necessary to fill the gap on the right row...
//console.log('adding sprites right row...')
for(var i = 0; i < stars.meta.imagesYRequired; i++){
stars.positions.push({
x:highestXCoordinatePair.x+spriteWidth,
y:highestXCoordinatePair.y+i*spriteHeight
});
}
}
if(lowestYCoordinatePair.y > 0){
//Gap on the top side. New sprites necessary to fill the gap on the top row...
//console.log('adding sprites top row...')
for(var i = 0; i < stars.meta.imagesXRequired; i++){
stars.positions.push({
x:lowestYCoordinatePair.x+i*spriteWidth,
y:lowestYCoordinatePair.y-spriteHeight
});
}
}
if(highestYCoordinatePair.y < window.innerHeight-spriteHeight){
//Gap on the bottom side. New sprites necessary to fill the gap on the bottom row...
console.log('adding sprites bottom row...')
for(var i = 0; i < stars.meta.imagesXRequired; i++){
stars.positions.push({
x:highestYCoordinatePair.x+i*spriteWidth,
y:highestYCoordinatePair.y+spriteHeight
});
}
}
'use strict';
//global variables
var canvas, c;
//viewport variables
var viewportPosition = {
x:false,
y:false
};
//game matrix settings
var gameMatrixConfig = {
width:20000,
height:20000
};
//cursor position
var cursorPosition = {
x:false,
y:false
};
//spaceship position
var spaceship = {
x:false,
y:false,
rotation:0,
gameMatrixPositionX:false,
gameMatrixPositionY:false
};
//fps monitor (for monitoring frame rate for development purposes)...
var fps = {
lastFrameTime:undefined,
timeSinceLastFrame:undefined,
startDisplayTimeInterval:function(){
setInterval(function(){
document.getElementById('fpsLabel').innerHTML = Math.floor(1000/getTimeSinceLastFrame());
},500);
}
};
function getTimeSinceLastFrame(){
return fps.timeSinceLastFrame;
}
//resize throttle timer global variable holder
var resizeTimer = false;
//the drawing frame:
var renderFrame = false;
//global events
window.addEventListener('load',function(){
initialize('load');
});
window.addEventListener('resize',function(){
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function(){
initialize('resize');
},100);
});
window.addEventListener('mousemove',function(e){
cursorPosition.x = e.clientX;
cursorPosition.y = e.clientY;
});
//global functions
function initialize(type){
if(type == 'load'){
preLoadSprites();
}
initializeCanvas();
}
function initializeCanvas(){
canvas = document.getElementById('canvas');
c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
c.width = canvas.width;
c.height = canvas.height;
}
/*a class with a filePath argument.
This class is used to create new sprite images
from an instance of the class.*/
function sprite(filePath){
//create a new image preload
this.sprite = new Image();
this.sprite.src = filePath;
//load status
this.loaded = false;
/*
holds all current positions of the sprite.
default start coordinates are 0,0
*/
this.positions = [];
//original associative array data structure...
//this.positions = {};
//the image has been preloaded
this.sprite.addEventListener('load',function(){
this.loaded = true;
/*
bind the "this" reference of the constructor to avoid referencing
the load event function
*/
}.bind(this));
}
function preLoadSprites(){
//create new objects for all the sprites to be used in the game
var sprites = {
stars:new sprite('https://drive.google.com/uc?export=download&id=0B821h2dKD0r_bERZb0RHeVRTQnM')
};
/*
check the load status of the sprites
loop through all properties of sprites object twice per second
check for load status. Load flag default is true. Set flag to false
when an unloaded image is discovered.
*/
var interval = setInterval(function(){
var x, loaded = true;
for(x in sprites){
if(!sprites[x].loaded){
loaded = false;
}
}
if(loaded){
clearInterval(interval);
//complete other tasks such as hiding a load spinner...
//ready sprites and context for graphing and provide access to sprites....
initializeGraphing(sprites);
}
},50);
}
function initializeGraphing(sprites){
//set initial viewport position in game matrix....
viewportPosition.x = gameMatrixConfig.width/2;
viewportPosition.y = gameMatrixConfig.height/2;
//start graph animation loop; provide access to sprites....
graph(sprites);
}
/*research how to inherit values from another object with
local variables.*/
function graph(sprites){
updateSpritePositions(sprites);
//testing frame rate...
setInterval(function(){draw()},16.67);
//60fps interval code. Uncomment when testing is complete...
//setInterval(function(){draw()},16.67);
//calculate sprite requirements for viewport and configure a sprite matrix...
initializeStars(sprites.stars);
fps.startDisplayTimeInterval();
//render the graphic frame
function draw(){
//console.log(fps.timeSinceLastFrame)
fps.timeSinceLastFrame = Date.now()-fps.lastFrameTime;
//fps.displayTimeInterval();
//fps.lastFrameTime = Date.now();
//clear the canvas
c.clearRect(0,0,window.innerWidth,window.innerHeight);
//graph the stars...
graphStars(sprites.stars);
updateSpritePositions(sprites);
fps.lastFrameTime = Date.now();
}
}
function initializeStars(stars){
/*
calculate sprite requirements for viewport and configure a sprite matrix
this only needs to happen once unless the viewport is resized
*/
/*
meta data used for various calculations throughout the script...
*/
stars.meta = {
//required sprites to fill the viewport width (based on sprite width)...
imagesXRequired:Math.ceil(window.innerWidth/(stars.sprite.width))+2,
//required sprites to fill the viewport height (based on sprite height)...
imagesYRequired:Math.ceil(window.innerHeight/(stars.sprite.height))+2,
//required sprites to fill the entire viewport...
get requiredSprites(){
return this.imagesXRequired*this.imagesYRequired;
},
//the sprite width...
spriteWidth:stars.sprite.width,
//the sprite height...
spriteHeight:stars.sprite.height,
//the lowest x value in stars.positions...
get lowestXCoordinatePair(){
var xCoordinates = [];
var yCoordinates = [];
for(var i = 0; i < stars.positions.length; i++){
xCoordinates.push(stars.positions[i].x);
yCoordinates.push(stars.positions[i].y);
}
var x = Math.min.apply(Math, xCoordinates);
var index = xCoordinates.indexOf(x);
var y = yCoordinates[index];
return {
x:x,
y:y
};
},
//the highest x value in stars.positions...
get highestXCoordinatePair(){
var xCoordinates = [];
var yCoordinates = [];
for(var i = 0; i < stars.positions.length; i++){
xCoordinates.push(stars.positions[i].x);
yCoordinates.push(stars.positions[i].y);
}
var x = Math.max.apply(Math, xCoordinates);
var index = xCoordinates.indexOf(x);
var y = yCoordinates[index];
return {
x:x,
y:y
};
},
//the lowest y value in stars.positions...
get lowestYCoordinatePair(){
var xCoordinates = [];
var yCoordinates = [];
for(var i = 0; i < stars.positions.length; i++){
xCoordinates.push(stars.positions[i].x);
yCoordinates.push(stars.positions[i].y);
}
var y = Math.min.apply(Math, yCoordinates);
var index = yCoordinates.indexOf(y);
var x = xCoordinates[index];
return {
x:x,
y:y
};
},
//the highest y value in stars.positions...
get highestYCoordinatePair(){
var xCoordinates = [];
var yCoordinates = [];
for(var i = 0; i < stars.positions.length; i++){
xCoordinates.push(stars.positions[i].x);
yCoordinates.push(stars.positions[i].y);
}
var y = Math.max.apply(Math, yCoordinates);
var index = yCoordinates.indexOf(y);
var x = xCoordinates[index];
return {
x:x,
y:y
};
}
};
//the y coordinate in a scaled matrix system for sprites...
var y = 0;
//the x coordinate in a scaled matrix system for sprites...
var x = 0;
//loop through the number of required sprites and graph...
for(var i = 0; i < stars.meta.requiredSprites; i++){
//calculate when a new row is necessary
if((i)%stars.meta.imagesXRequired == 0){
x = 0;
y++;
}
//set actual starting viewport matrix coordinate positions....
stars.positions[i] = {
x:x*stars.meta.spriteWidth,
y:y*stars.meta.spriteWidth
};
x++;
}
}
function graphStars(stars){
/*
prior to graphing, determine if a sprite is no longer within
the viewport matrix and remove it...
if new sprites are necessary, add new coordinates accordingly...
*/
/*
==============IMPORTANT NOTE==================
*/
for(var i = 0; i < stars.positions.length; i++){
//store coordinate positions...
var x = stars.positions[i].x;
var y = stars.positions[i].y;
//delete sprites no longer visible within the viewport...
if(x > window.innerWidth || x < -spriteWidth || y < -spriteHeight || y > window.innerHeight){
//sprite is no longer visible within viewport; remove it...
stars.positions.splice(i,1);
}
//find necessary comparative coordinates...
var lowestXCoordinatePair = stars.meta.lowestXCoordinatePair;
var highestXCoordinatePair = stars.meta.highestXCoordinatePair;
var lowestYCoordinatePair = stars.meta.lowestYCoordinatePair;
var highestYCoordinatePair = stars.meta.highestYCoordinatePair;
//gather star sprite meta data...
var spriteWidth = stars.meta.spriteWidth;
var spriteHeight = stars.meta.spriteHeight;
if(lowestXCoordinatePair.x > 0){
//Gap on the left side. New sprites necessary to fill the gap on left row...
//console.log('adding sprites left row...')
for(var i = 0; i < stars.meta.imagesYRequired; i++){
stars.positions.push({
x:lowestXCoordinatePair.x-spriteWidth,
y:lowestXCoordinatePair.y+i*spriteHeight
});
}
}
if(highestXCoordinatePair.x < window.innerWidth-spriteWidth){
//Gap on the right side. New sprites necessary to fill the gap on the right row...
//console.log('adding sprites right row...')
for(var i = 0; i < stars.meta.imagesYRequired; i++){
stars.positions.push({
x:highestXCoordinatePair.x+spriteWidth,
y:highestXCoordinatePair.y+i*spriteHeight
});
}
}
if(lowestYCoordinatePair.y > 0){
//Gap on the top side. New sprites necessary to fill the gap on the top row...
//console.log('adding sprites top row...')
for(var i = 0; i < stars.meta.imagesXRequired; i++){
stars.positions.push({
x:lowestYCoordinatePair.x+i*spriteWidth,
y:lowestYCoordinatePair.y-spriteHeight
});
}
}
if(highestYCoordinatePair.y < window.innerHeight-spriteHeight){
//Gap on the bottom side. New sprites necessary to fill the gap on the bottom row...
console.log('adding sprites bottom row...')
for(var i = 0; i < stars.meta.imagesXRequired; i++){
stars.positions.push({
x:highestYCoordinatePair.x+i*spriteWidth,
y:highestYCoordinatePair.y+spriteHeight
});
}
}
c.drawImage(stars.sprite,x,y);
}
}
function updateViewportPosition(){
}
function updateSpritePositions(sprites){
/*gather information from the cursor to influence the next frame data
cursor is a local object variable template for use within this function only
cursor stores information about the cursor's position
*/
var cursor = {
distance:{
//the cursor's distances on the planes from the origin for X and Y
cursorXDistance:Math.abs(window.innerWidth/2-cursorPosition.x),
cursorYDistance:Math.abs(window.innerHeight/2-cursorPosition.y)
},
quadrant:function(){
//method returns the appropriate quadrant number for the unit circle
if(cursorPosition.x > window.innerWidth/2 && cursorPosition.y < window.innerHeight/2){
//first quadrant
return 1;
}
if(cursorPosition.x > window.innerWidth/2 && cursorPosition.y > window.innerHeight/2){
//fourth quadrant
return 4;
}
if(cursorPosition.x < window.innerWidth/2 && cursorPosition.y < window.innerHeight/2){
//second quadrant
return 2;
}
if(cursorPosition.x < window.innerWidth/2 && cursorPosition.y > window.innerHeight/2){
//third quadrant
return 3;
}
}
};
//calculate the velocity (the number of pixels to move for the next frame)...
function velocity(){
/*
To calculate velocity ratio, divide the hypotenuse of the cursor's position
by the viewport hypotenuse.
*/
return Math.sqrt(Math.pow(cursor.distance.cursorXDistance,2) + Math.pow(cursor.distance.cursorYDistance,2))/100;
}
//calculate the movement ratio: the number of x pixels per y pixels
function movementRatio(){
var xRatio = cursor.distance.cursorXDistance/(cursor.distance.cursorYDistance+cursor.distance.cursorXDistance);
var yRatio = cursor.distance.cursorYDistance/(cursor.distance.cursorYDistance+cursor.distance.cursorXDistance);
return {xRatio,yRatio};
}
//update positions of sprites...
//retrieve the current movement ratio object...
var coordinateChange = movementRatio();
//retrieve the current quadrant of the unit circle for the cursor's position...
var quadrant = cursor.quadrant();
//retrieve velocity coefficient...
var velocity = velocity();
//update viewport position based on quadrant position...
var i;
for(i in sprites.stars.positions){
if(quadrant == 1){
//update star sprite position
sprites.stars.positions[i].x -= coordinateChange.xRatio*velocity;
sprites.stars.positions[i].y += coordinateChange.yRatio*velocity;
}
if(quadrant == 2){
//update star sprite position
sprites.stars.positions[i].x += coordinateChange.xRatio*velocity;
sprites.stars.positions[i].y += coordinateChange.yRatio*velocity;
}
if(quadrant == 3){
//update the star sprite position
sprites.stars.positions[i].x += coordinateChange.xRatio*velocity;
sprites.stars.positions[i].y -= coordinateChange.yRatio*velocity;
}
if(quadrant == 4){
//update star sprite position
sprites.stars.positions[i].x -= coordinateChange.xRatio*velocity;
sprites.stars.positions[i].y -= coordinateChange.yRatio*velocity;
}
}
}
html,body{
width:100%;
height:100%;
margin:0;
padding:0;
}
canvas{
width:100%;
height:100%;
margin-bottom:-8px;
background:#434343;
}
#gameInterface{
width:100%;
height:100%;
}
.hidden{
width:1px;
height:1px;
position:fixed;
top:0;
left:0;
z-index:-100;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Canvas Game v0.35</title>
<!--<link rel="stylesheet" href="css/index.css" type="text/css">-->
<!--<script type="text/javascript" src="js/index.js"></script>-->
</head>
<body>
<div id="fpsLabel" style="position:fixed; top:0; left:0; display:table; background:#fff;">
</div>
<div id="intro">
</div>
<div id="gameInterface">
<canvas id="canvas"></canvas>
</div>
</body>
</html>
我已经集思广益,列出了问题的可能原因:
有人可以帮助我理解为什么偶尔存在差距并帮助我了解如何解决这个问题?谢谢。