javascript - 如何使用canvas在javascript上制作一个游戏,使 Sprite 看起来在跳跃

标签 javascript canvas isometric

我是 javascript 新手,正在尝试制作一款希望最终实现等距的游戏(我不太关心这一点,只要我知道如何做即可)。我的代码是:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
canvas {
    border:1px solid #d3d3d3;
    background-color: #f1f1f1;
}
</style>
</head>
<body onload="startGame()">

<script>
var myGamePiece;


function startGame() {
    myGamePiece = new component(30, 30, "blue", 225, 225);
    myGameArea.start();
}

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.width = 480;
        this.canvas.height = 270;
        this.context = this.canvas.getContext("2d");
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.frameNo = 0;
        this.interval = setInterval(updateGameArea, 20);
        window.addEventListener('keydown', function (e) {
            e.preventDefault();
            myGameArea.keys = (myGameArea.keys || []);
            myGameArea.keys[e.keyCode] = (e.type == "keydown");
        })
        window.addEventListener('keyup', function (e) {
            myGameArea.keys[e.keyCode] = (e.type == "keydown");
        })
    },
    stop : function() {
        clearInterval(this.interval);
    },
    clear : function() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }
}

function component(width, height, color, x, y, type) {

    this.type = type;
    this.width = width;
    this.height = height;
    this.speed = 0;
    this.angle = 0;
    this.moveAngle = 0;
    this.x = x;
    this.y = y;
    this.update = function() {
        ctx = myGameArea.context;
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.rotate(this.angle);
        ctx.fillStyle = color;
        ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
        ctx.restore();
    }
    this.newPos = function() {
        this.angle += this.moveAngle * Math.PI / 180;
        this.x += this.speed * Math.sin(this.angle);
        this.y -= this.speed * Math.cos(this.angle);
    }
}

function updateGameArea() {
    myGameArea.clear();
    myGamePiece.moveAngle = 0;
    myGamePiece.speed = 0;
    if (myGameArea.keys && myGameArea.keys[37]) {myGamePiece.x -=2; }
    if (myGameArea.keys && myGameArea.keys[39]) {myGamePiece.x += 2; }
    if (myGameArea.keys && myGameArea.keys[38]) {myGamePiece.y -= 1; }
    if (myGameArea.keys && myGameArea.keys[40]) {myGamePiece.y += 1; }
    if (myGameArea.keys && myGameArea.keys[32]) {myGamePiece.y -= 3;}
    myGamePiece.newPos();
    myGamePiece.update();
}
</script>

<p></p>

</body>
</html>

我主要是从另一个网站( http://www.w3schools.com/games/tryit.asp?filename=trygame_movement_keyboard )复制和粘贴的。我想知道的是如何做到当玩家按下空格键时,myGamePiece上下移动,看起来像是在跳跃;使其向上移动一定数量的空格,然后返回到之前的坐标。

最佳答案

游戏物理。跳跃基础知识

真实世界V游戏世界。

游戏跳跃通常是不确定的,这意味着你不确定游戏可能在何时何地落地。非常不像现实生活。现实生活中一旦跳跃,落地的地点和时间取决于重力和空气摩擦力,除非你能飞,否则跳跃的结果取决于宇宙。

在游戏世界中,情况远非如此。跳投者通常可以改变方向、二段跳、做一些悬空时间或组合加速强力拳击。所有这些事情都可能随时发生,具体取决于用户的输入。另外,游戏世界中的重力并不像真正的重力一样,有时有些东西因为重而下落得更快,有些东西需要一秒钟或才能感受到重力的效果。这样的例子不胜枚举。

坠落

但尽管如此,游戏仍然必须做一些重要的事情,使坠落与乘坐电梯不同。当自由落体时,你会加速,每次你的速度都会改变,当你跳起来时,你会减速,当你坠落时,你会加速。我们有位置y和速度dy(delta y)来添加重力(g),当在屏幕上移动时,我们为速度添加一个常数(dy是< 0) 或向下,重力以相同的速率沿相同方向改变速度。

所以每一帧,添加重力dy += g,然后将我们的速度添加到我们的位置y += dy。这就是一个非常简单的重力模拟,如果您在游戏帧中测量时间,它也是对真实重力的完美模拟(靠近像地球这样的大物体)

因此,执行诸如跳跃之类的操作以及发挥作用的重力的最佳方法是逐帧执行。

让我们定义跳跃所需的内容。

简单的 Angular 色

var c = {
    x : ?, // this character's position
    y : ?,
    dx : ?, // the amount to move per frame The players velocity in x and y
    dy : ?,
    w : ?,  // the character's width and height
    h : ?,
    onGround : false, // a flag to indicate on the ground or not
}

以及一些环境信息

const GROUND_Y = canvas.height - 10; // where the ground is
const GRAVITY = 1; // in pixels per frame

然后每一帧我们都会更新 Angular 色,检查是否在地面上,如果没有施加重力并检查地面。

c.update = function(){
    if(this.onGround){ // nothing to do but wait

    }else{ // must be in the air
       // Every frame the player accelerates down by the pull of gravity
       // so increase the player y speed
       this.dy += GRAVITY; // apply the gravity to the speed. 

       // now add the y speed to the y position
       this.y += this.dy;

       // Now we must check for the ground which if the player position x,y is for 
       // its center the ground will be half it's height away
       if(this.y + (this.h / 2) > GROUND_Y){ // have we hit the ground
            // yes stop downward motion
            this.dy = 0;
            // the speed may have put the character slightly below the ground
            // so fix the postion so that it is correct
            this.y =  GROUND_Y - this.h /2; // set position to the ground - half its height

            // And set the flag to indicate that the character is on the ground
            this.onGround = true;
      }
       
    }
}

 
   

这就是重力问题。

跳跃

为了跳跃,我们施加了一个使我们加速离开地面的力。这个力只是瞬间的,一旦离开地面,我们就没有什么可以推挤的了,所以我们就不能再施加力了,就靠重力把我们拉下来。由于重力已经在上面的函数中排序,我们需要做的就是应用跳跃力。

const JUMP_ACCELERATION = GRAVITY * 20; // the bigger this number the higher the jump

现在添加进行跳转的函数

c.jump = function(){
     // check if we can jump. That is are we on the ground
     if(this.onGround){
         // flag that we are no longer on the ground and left to the will of gravity
         this.onGround = false;
         // then apply the change in speed. 
         this.dy -= JUMP_ACCELERATION; // subtract jump accel from the speed
                                       // to give a negative speed (up)
      }
}

就是这样,重力函数将为您处理所有事情,因此您必须每帧调用一次 c.update 函数,每次跳跃只需调用一次跳跃函数。

跳跃它演示

点击鼠标跳跃,一个没有挑战性的flappy It。

这个演示取自一个旧项目,展示了一个非常简单的跳跃 Angular 色。对象名称为 it,您要查看的函数为 it.update()it.jump() >it.preJump() 你想要的代码在注释之间//Answer code

Angular 色所能做的就是跳跃,可以多次跳跃,并且按住鼠标然后松开跳跃可以跳得更高。

/** ImageTools.js begin **/
var imageTools = (function () {
var tools = {
    canvas : function (width, height) {  // create a blank image (canvas)
        var c = document.createElement("canvas");
        c.width = width;
        c.height = height;
        return c;
    },
    createImage : function (width, height) {
        var i = this.canvas(width, height);
        i.ctx = i.getContext("2d");
        return i;
    },
    loadImage : function (url, cb) {
        var i = new Image();
        i.src = url;
        i.addEventListener('load', cb);
        i.addEventListener('error', cb);
        return i;
    },
    image2Canvas : function (img) {
        var i = this.canvas(img.width, img.height);
        i.ctx = i.getContext("2d");
        i.drawImage(i, 0, 0);
        return i;
    },
    drawSpriteLinked : function(image,spriteIndex, x, y, scale, ang, alpha) {
        
        var w,h,spr;
        spr = image.sprites[spriteIndex];
        w = spr.w; h = spr.h;
        ctx.globalAlpha = alpha;
        var xdx = Math.cos(ang) * scale;
        var xdy = Math.sin(ang) * scale;
        ctx.save();
        ctx.transform(xdx, xdy, -xdy, xdx, x, y);
        ctx.drawImage(image, spr.x, spr.y, w, h, -w/2, -h/2, w, h);
        ctx.restore();
    }, 
    drawSprite : function(image,spriteIndex, x, y, scale, ang, alpha) {
        var w,h,spr;
        spr = image.sprites[spriteIndex];
        w = spr.w; h = spr.h;
        ctx.globalAlpha = alpha;
        ctx.setTransform(scale, 0, 0, scale, x, y);
        ctx.rotate(ang);
        ctx.drawImage(image, spr.x, spr.y, w, h, -w/2, -h/2, w, h);
    },        
    drawSpriteSLinked : function(image,spriteIndex, x, y, scale, scaleX, ang, alpha) {
       
        var w,h,spr;
        spr = image.sprites[spriteIndex];
        w = spr.w; h = spr.h;
        ctx.globalAlpha = alpha;
        var xdx = Math.cos(ang) * scale;
        var xdy = Math.sin(ang) * scale;
        ctx.save()
        ctx.transform(xdx * scaleX, xdy * scaleX, -xdy, xdx, x, y);
        ctx.drawImage(image, spr.x, spr.y, w, h, -w/2, -h/2, w, h);
        ctx.restore();
    },
    drawSpriteS : function(image,spriteIndex, x, y, scale, scaleX, ang, alpha) {
        var w,h,spr;
        spr = image.sprites[spriteIndex];
        w = spr.w; h = spr.h;
        ctx.globalAlpha = alpha;
        ctx.setTransform(scale * scaleX, 0, 0, scale, x, y);
        ctx.rotate(ang);
        ctx.drawImage(image, spr.x, spr.y, w, h, -w/2, -h/2, w, h);
    },
    hex2RGBA : function(hex){
        if(typeof hex === "string"){
            var str = "rgba(";
            if(hex.length === 4 || hex.length === 5){
                str += (parseInt(hex.substr(1,1),16) * 16) + ",";
                str += (parseInt(hex.substr(2,1),16) * 16) + ",";
                str += (parseInt(hex.substr(3,1),16) * 16) + ",";
                if(hex.length === 5){
                    str += (parseInt(hex.substr(3,1),16) / 16);
                }else{
                    str += "1";
                }
                return str + ")";
            }
            if(hex.length === 7 || hex.length === 8){
                str += parseInt(hex.substr(1,2),16) + ",";
                str += parseInt(hex.substr(3,2),16) + ",";
                str += parseInt(hex.substr(5,2),16) + ",";
                if(hex.length === 5){
                    str += (parseInt(hex.substr(7,2),16) / 255).toFixed(3);
                }else{
                    str += "1";
                }
                return str + ")";                
            }
            return "rgba(0,0,0,0)";
        }
        
            
    },            
    createGradient : function(ctx, type, x, y, xx, yy, colours){
        var i,g,c;
        var len = colours.length;
        if(type.toLowerCase() === "linear"){
            g = ctx.createLinearGradient(x,y,xx,yy);
        }else{
            g = ctx.createRadialGradient(x,y,xx,x,y,yy);
        }
        for(i = 0; i < len; i++){
            c = colours[i];
            if(typeof c === "string"){
                if(c[0] === " #"){
                    c = this.hex2RGBA(c);
                }
                g.addColorStop(Math.min(1,i / (len -1)),c); // need to clamp top to 1 due to floating point errors causes addColorStop to throw rangeError when number over 1
            }
        }
        return g;
        
    },
};
return tools;
})();

/** ImageTools.js end **/
/** SimpleFullCanvasMouse.js begin **/
const CANVAS_ELEMENT_ID = "canv";
const U = undefined;
var w, h, cw, ch; // short cut vars 
var canvas, ctx, mouse;
var globalTime = 0; 
var globalTimeInt = 0;
var createCanvas, resizeCanvas, setGlobals;
var L = typeof log === "function" ? log : function(d){ console.log(d); }
createCanvas = function () {
var c,cs;
cs = (c = document.createElement("canvas")).style; 
c.id = CANVAS_ELEMENT_ID;    
cs.position = "absolute";
cs.top = cs.left = "0px";
cs.zIndex = 1000;
document.body.appendChild(c); 
return c;
}
var resized = false;
resizeCanvas = function () {
if (canvas === U) { canvas = createCanvas(); }
canvas.width = window.innerWidth;
canvas.height = window.innerHeight; 
resized = true;
ctx = canvas.getContext("2d"); 
if (typeof setGlobals === "function") { setGlobals(); }
}
setGlobals = function(){ 
cw = (w = canvas.width) / 2; ch = (h = canvas.height) / 2; 
if(it !== undefined){
    it = createIt(cw,ch,sprites);
}
}
mouse = (function(){
function preventDefault(e) { e.preventDefault(); }
var mouse = {
    x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false, buttonRaw : 0,
    over : false,  // mouse is over the element
    bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
    mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
var m = mouse;
function mouseMove(e) {
    var t = e.type;
    m.x = e.offsetX; m.y = e.offsetY;
    if (m.x === U) { m.x = e.clientX; m.y = e.clientY; }
    m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey;
    if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1]; }  
    else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2]; }
    else if (t === "mouseout") { m.buttonRaw = 0; m.over = false; }
    else if (t === "mouseover") { m.over = true; }
    else if (t === "mousewheel") { m.w = e.wheelDelta; }
    else if (t === "DOMMouseScroll") { m.w = -e.detail; }
    if (m.callbacks) { m.callbacks.forEach(c => c(e)); }
    e.preventDefault();
}
m.addCallback = function (callback) {
    if (typeof callback === "function") {
        if (m.callbacks === U) { m.callbacks = [callback]; }
        else { m.callbacks.push(callback); }
    } else { throw new TypeError("mouse.addCallback argument must be a function"); }
}
m.start = function (element, blockContextMenu) {
    if (m.element !== U) { m.removeMouse(); }        
    m.element = element === U ? document : element;
    m.blockContextMenu = blockContextMenu === U ? false : blockContextMenu;
    m.mouseEvents.forEach( n => { m.element.addEventListener(n, mouseMove); } );
    if (m.blockContextMenu === true) { m.element.addEventListener("contextmenu", preventDefault, false); }
}
m.remove = function () {
    if (m.element !== U) {
        m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); } );
        if (m.contextMenuBlocked === true) { m.element.removeEventListener("contextmenu", preventDefault);}
        m.element = m.callbacks = m.contextMenuBlocked = U;
    }
}
return mouse;
})();
var done = function(){
window.removeEventListener("resize",resizeCanvas)
mouse.remove();
document.body.removeChild(canvas);    
canvas = ctx = mouse = U;
L("All done!")
}

resizeCanvas(); // create and size canvas
resized = false;
mouse.start(canvas,true); // start mouse on canvas and block context menu
window.addEventListener("resize",resizeCanvas); // add resize event
function drawText(text,x,y,size,col){
var f = size + "px Arial";
if(f !== ctx.font){
    ctx.font = f;
} 
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = col;
ctx.fillText(text,x,y);
}
function drawLoad(){
if(!resourcesReady || !canPlay){
    drawText(message,cw,ch * 0.5, FONT_SIZE, MESSAGE_COL);
    if (!canPlay && resourcesReady){
        drawText("Try reloading the page.",cw,ch * 0.5 + FONT_SIZE + 8,Math.floor(FONT_SIZE /2) ,MESSAGE_COL);
    }else{
        
        drawText("Loading resources." ,cw,ch * 0.5 + FONT_SIZE + 8,Math.floor(FONT_SIZE /2) ,MESSAGE_COL);
    }
    
}else{
    if(message !== ""){
        drawText(message,cw,ch * 0.5, FONT_SIZE, MESSAGE_COL);
        
    }
}
}
const FONT = "px Arial"
const FONT_SIZE = Math.max(Math.floor(window.innerHeight/20),24)
ctx.textAlign = "center";
ctx.textBaseline = "middle";
function loaded(e){
if(e.type !== "error"){
    this.sprites = [
        { x : 0, y : 0, w : 74, h : 116, },
        { x : 0, y : 126, w : 100, h : 113, },
        { x : 75, y : 0, w : 29, h : 42, },
        { x : 75, y : 43, w : 17, h : 22, },
        { x : 0, y : 249, w : 42, h : 18, },
        { x : 75, y : 66, w : 17, h : 15, },
        { x : 75, y : 82, w : 17, h : 12, },
        { x : 75, y : 95, w : 16, h : 9, },
        { x : 75, y : 105, w : 7, h : 7, },
        { x : 0, y : 268, w : 11, h : 5, },
    ]
    resourcesReady = true;
    canPlay = true;
    it = createIt(cw,ch,this );
    message = "";
    return;
}
resourcesReady = true;
message = "LOAD FAILED!"

}
var it = null; // it is the character
var resourcesReady = false;
var canPlay = false;
var message = "Please Wait..."
const MESSAGE_COL = "white";
//var sprites = imageTools.loadImage("GreenIt.png",loaded )
var sprites = imageTools.loadImage("/image/ED6oC.png",loaded )
var background = imageTools.createImage(8,8);
background.ctx.fillStyle = imageTools.createGradient(ctx,"linear",0,0,8,8,["#0AF","#05A"]);
background.ctx.fillRect(0,0,8,8);
var ground = imageTools.createImage(8,32);
ground.ctx.fillStyle = imageTools.createGradient(ctx,"linear",0,0,8,32,["#0A0","#450","#754"]);
ground.ctx.fillRect(0,0,8,32);
ground.ctx.fillStyle = "black";
ground.ctx.fillRect(0,0,8,4);
const GROUND_OFFSET = 32;
const GRAV = 1;
var landed = false;
const MESSAGES = [
"Click mouse button to Jump",
"Click hold ... release to to add power to jump",
"Double click to double jump",
""
];
var messageCount = 0;
var fly = { // something to see
x : 0,
y : 0,
dx : 0,
dy : 0,
wait : 0,
onTheWall : false,
update : function(){
    if(this.wait <= 0){
        this.wait = Math.random() * 200+ 60;
        this.onTheWall = Math.random() < 0.1 ? true : false;
        if(this.onTheWall){
            this.dx = 0;
            this.dy = 0;
        }else{
            this.wait = Math.random() < 0.2 ? 10 : this.wait;
            var x = (Math.random()-0.5) * 200;
            var y = (Math.random()-0.5) * 200;
            this.dx = (x - this.x) / this.wait;
            this.dx = (y - this.y) / this.wait;
            
        }
    }else{
        this.wait -= 1;
        this.x += this.dx;
        this.y += this.dy;
    }
}
};

/*==============================================================================================
// Answer code
==============================================================================================*/
// info to define the character
const IT = {
body : 0,  // sprite indexes
bodyFly : 1,
footDown : 2,
eyeOpen : 3,
foot : 4,
mouthOpen : 5,
eyeShut : 6,
mouthSmirk : 7,
eyeBall : 8,
mouth : 9,  // sprite index end
grav : GRAV, // grav accel
maxJumpPower : 40,
minJump : 10,
jumpPower : 30,  // mutiplys squat amount to give jump power
squatRate : 1,  // how quick the squat is
squatResist : 0.8,  // limits the amount of squat
landingBlinkTime : 30, // how long blink is on landing
blinkTime : 15, // how many frames to close eyes
blinkRate : 60 * 3, // 60 is one second . Time between blinks average
eyePos : {x : 0.13, y : -0.1}, // position as fraction of size
footPos : {x : 0.3, y : 0.5}, // position as fraction of size
lookAtGround : 1, // look ats
lookAtMouse : 2,
lookAtUser : 3,
lookAtFly : 4,
angle: 0,
jumpDy: 0,  // the jump up speed used to rotate It when in air

}
// Function updates the character
const updateIt = function(){
if(this.blink > 0){
    this.blink -= 1; 
}
if(this.blinkTimer > 0){
    this.blinkTimer -= 1;
    if(this.blinkTimer === 0){
        this.blink = IT.blinkTime;
    }
}else{
    // the two randoms create a random number that has a gausian distrabution centered on 0.5
    // this creates a more realistic set of numbers.
    this.blinkTimer = Math.floor(IT.blinkRate * (Math.random() + Math.random())/2 + IT.blinkRate / 2);
    this.lookAt = Math.random() < 0.33 ? IT.lookAtUser : (Math.random() < 0.5 ? IT.lookAtMouse : IT.lookAtFly);
}
if(!this.onGround){
    this.squat = 0;
    //-------------------------------------
    // do gravity
    this.dy += IT.grav;
    this.y += this.dy;
    this.x += this.dx;
    this.x = (this.x + ctx.canvas.width) %  ctx.canvas.width;
    var rotFraction = (this.jumpDy - this.dy) / this.jumpDy;

    this.angle = this.jumpAngle * -rotFraction ; 


    if(this.dy > 13){
        this.lookAt = IT.lookAtGround;
    }
    // check for the ground
    if(this.y + this.tall / 2 > h - GROUND_OFFSET){
        this.y = h - GROUND_OFFSET - this.tall / 2;
        this.blink = Math.floor(IT.landingBlinkTime * (this.dy / 20));
        this.blinkTimer = this.blink + 30;
        this.squat = this.dy;
        this.dy = 0;
        this.onGround = true;
        this.angle = -this.jumpAngle
    }
}else{
    this.squat *= IT.squatResist;
    
}

}
// draw the character
const drawIt = function(){
var bod = IT.body;
var spr = this.img.sprites;
var eye = this.blink > 0 ? IT.eyeShut : IT.eyeOpen;
var foot = IT.foot;
var footBehind = false; // draw feet behind or infront of body

if(!this.onGround){
    if(this.dy >= 0){
        if(this.dy > 2){
            bod = IT.bodyFly;
        }
    }else{
        footBehind = true;
        foot = IT.footDown;
    }
}
var xdx = Math.cos(this.angle);
var xdy = Math.sin(this.angle);
var px = this.x;  // pivot
var py = this.y + 50;
var x = this.x ;
var y = this.y + this.squat;
var t = this.tall;
var f = this.fat;
if(footBehind){
    if(!this.onGround){
        var r = 1 - Math.min(1,-this.dy / 10);
        imageTools.drawSpriteS(this.img,foot,x + f * IT.footPos.x,y - this.squat+  t * IT.footPos.y,1,-1,r,1);
        imageTools.drawSprite(this.img,foot,x - f * IT.footPos.x,y - this.squat +  t * IT.footPos.y,1,r,1);
    }
}
ctx.setTransform(xdx,xdy,-xdy,xdx,px,py);
imageTools.drawSpriteLinked(this.img,bod,x - px,y - py,1,0,1);
if(!footBehind){
    if(this.onGround){
        imageTools.drawSpriteS(this.img,foot,x + f * IT.footPos.x,y - this.squat+  t * IT.footPos.y,1,-1,0,1);
        imageTools.drawSprite(this.img,foot,x - f * IT.footPos.x,y - this.squat +  t * IT.footPos.y,1,0,1);
    }else{
        var r = this.dy / 10;
        imageTools.drawSpriteS(this.img,foot,x + f * IT.footPos.x,y - this.squat+  t * IT.footPos.y,1,-1,r,1);
        imageTools.drawSprite(this.img,foot,x - f * IT.footPos.x,y - this.squat +  t * IT.footPos.y,1,r,1);
    }
}
if(this.blink){
    ctx.setTransform(xdx,xdy,-xdy,xdx,px,py);

    imageTools.drawSpriteLinked(this.img,eye,x + f * IT.eyePos.x - px, y +  t * IT.eyePos.y - py,1,0,1);
    imageTools.drawSpriteSLinked(this.img,eye,x - f * IT.eyePos.x - px, y +  t * IT.eyePos.y - py,1,-1,0,1);
}else{
    ctx.setTransform(xdx,xdy,-xdy,xdx,px,py);
    imageTools.drawSpriteLinked(this.img,eye,x + f * IT.eyePos.x - px, y +  t * IT.eyePos.y - py,1,0,1);
    imageTools.drawSpriteSLinked(this.img,eye,x - f * IT.eyePos.x - px, y +  t * IT.eyePos.y - py,1,-1,0,1);
    var eyeDir = 0;
    var eyeDist = 0;
    if(this.blink === 0){
        if(this.lookAt === IT.lookAtGround){
            eyeDir = Math.PI/2;
            eyeDist = 0.3;
        }else if(this.lookAt === IT.lookAtUser){
            eyeDir = 0;
            eyeDist = 0;
        }else if(this.lookAt === IT.lookAtFly){
            eyeDir = Math.atan2(fly.y, fly.x);
            eyeDist = (Math.hypot(fly.y ,fly.x) /  200) * 0.3;
  
        }else{
            eyeDir = Math.atan2(mouse.y - this.y, mouse.x - this.x);
            eyeDist = (Math.hypot(this.y - mouse.y,this.x - mouse.x) / (Math.min(w,h)/2)) * 0.3;
        
        }
        eyeDist = Math.max(-0.3, Math.min(0.3, eyeDist));
        var ex,ey;
        ex = Math.cos(eyeDir) * spr[IT.eyeOpen].w * eyeDist;
        ey = Math.sin(eyeDir) * spr[IT.eyeOpen].h * eyeDist;
        imageTools.drawSpriteLinked(this.img, IT.eyeBall, x + f * IT.eyePos.x + ex - px, y +  t * IT.eyePos.y + ey-py,1,0,1);
        imageTools.drawSpriteLinked(this.img, IT.eyeBall, x - f * IT.eyePos.x + ex - px, y +  t * IT.eyePos.y + ey-py,1,0,1);
    }
}
}


// While mouse is down squat and prep to jump
const preJump = function(){
this.squat += IT.squatRate;
this.jumpPower += 0.5;
if(this.jumpPower > 30 && this.wiggle === 0) {
   this.wiggle = 1;
}
this.jumpReady = true;
}
// when mouse released apply jump force
const jumpIt = function(){

var power = -IT.jumpPower * Math.min(IT.maxJumpPower,Math.max(IT.minJump,this.jumpPower))/IT.maxJumpPower;
this.dy = Math.sin(this.angle + Math.PI /2) * power;
this.dx = Math.cos(this.angle + Math.PI /2) * power;
if(this.onGround){
    this.jumpDy = this.dy;
    this.jumpAngle = this.angle;
}

this.wiggle = 0;
this.jumpPower = 0;
this.jumpReady = false;    
this.squat = 0;
this.onGround = false;
}

// creates a character
var createIt = function(x,y,img){
return {
    img : img,
    x : x,  // position
    y : y,
    dx : 0, // deltat speed
    dy : 0,
    sqaut : 0, // for landing and pre jump slight squat
    onGround : false,
    jumpPower : 0,
    blink : 0, // blink controls
    blinkTimer : 0,
    lookAt : "ground", /// where to look
    jumpReady : false, // flags if ready to jump
    tall : img.sprites[IT.body].h,   // how tall
    fat : img.sprites[IT.body].w, // how wide
    draw : drawIt, // functions
    update : updateIt,
    jump : jumpIt,
    squatF : preJump,
}
}



function display(){  // put code in here
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1;           // reset alpha
ctx.drawImage(background,0,0,w,h)
ctx.drawImage(ground,0,h-GROUND_OFFSET,w,GROUND_OFFSET);
fly.update()
drawLoad();
if(canPlay){
    if(messageCount < MESSAGES.length){
        if(it.onGround && !landed){
            landed = true;
            message = MESSAGES[messageCount];
            messageCount += 1;
        }
    }       
    if(resized) {  // to prevent resize display issue
       resized = false;
       it.y = h - GROUND_OFFSET - it.tall / 2;
    }
        
    if(it.onGround) {
       it.angle = Math.atan2((it.y + 130)-10, it.x- mouse.x) / 3;
       it.angle = it.angle < -1 ? -1 : it.angle > 1 ? 1 : it.angle;
       it.angle = Math.pow(Math.abs(it.angle),0.5) * Math.sign(it.angle);
       it.angle -= Math.PI / 4;
       if(it.wiggle > 0.1) {
          it.angle += Math.sin((it.wiggle * Math.PI) ** 2) * 0.01 * it.wiggle;
          it.wiggle *= 0.95;
       }
    } 
    if(mouse.buttonRaw & 1){
        it.squatF();
    }else{
        if(it.jumpReady){
            it.jump();
            landed = false;
        }
    }


    it.update();
    it.draw();
}
//ctx.clearRect(0,0,w,h);
}
/*==============================================================================================
// Answer End
==============================================================================================*/

function update(timer){ // Main update loop
globalTimeInt = Math.floor(globalTime = timer);
display();  // call demo code

requestAnimationFrame(update);
}
requestAnimationFrame(update);

/** SimpleFullCanvasMouse.js end **/

关于javascript - 如何使用canvas在javascript上制作一个游戏,使 Sprite 看起来在跳跃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38084820/

相关文章:

javascript - 使用 Canvas 和环画一朵花

javascript - HTML5/Canvas 是否支持双缓冲?

平铺 map 编辑器 : size of isometric tile side

javascript - 嵌套 jQuery radio 输入

css - 如何在视频上叠加 Canvas

javascript - 等距图 block 图中的 Z 轴

java - 有效地将 BufferedImage 中的球形区域设置为一定的不透明度

javascript - 使用iframe嵌入有哪些陷阱

javascript - 生成随机唯一数据花费的时间太长并且占用 100% CPU

javascript - jQuery datepicker 未显示,初始化调用已执行