Гравитация на нативном JavaScript

197
21 января 2019, 00:40

Как организовать гравитацию на js , то есть объект прыгает и приземляется на землю.

Answer 1

var c = document.getElementById("canvas"); 
var c = canvas.getContext('2d'); 
 
function Ball(x, y, r, dx, dy) { 
  this.x = x; 
  this.y = y; 
  this.r = r; 
  this.dx = dx; 
  this.dy = dy; 
 
  this.update = function() { 
    // Bounce off the edges 
    if (this.x - this.r + this.dx < 0 || 
        this.x + this.r + this.dx > w) { 
      this.dx = -this.dx; 
    } 
    if (this.y - this.r + this.dy < 0 || 
        this.y + this.r + this.dy > h) { 
      this.dy = -this.dy; 
    } else { 
      // Our only acceleration is gravity 
      this.dy += gravity; 
    } 
     
    this.x = this.x + this.dx; 
    this.y = this.y + this.dy; 
     
    this.stroke(); 
  }; 
   
  this.stroke = function() { 
    c.beginPath(); 
    c.arc(this.x, this.y, this.r, 
                 0, Math.PI * 2); 
    c.stroke(); 
  }; 
} 
 
var gravity = 0.05; 
var timeStep = 25; // In milliseconds 
var w = c.canvas.width; 
var h = c.canvas.height; 
var cmTID; 
 
function updateAll() { 
  c.clearRect(0, 0, w, h); 
  for (var i = 0; i < balls.length; i = i + 1) { 
    balls[i].update(); 
  } 
  clearTimeout(cmTID); 
  cmTID = setTimeout(updateAll, timeStep); 
} 
 
// Create the balls 
var balls = []; 
var r = 40; 
for (var i = 0; i < 1; i = i + 1) { 
  var x = Math.random() * (w - r * 2) + r; 
  var y = Math.random() * (h - r * 2) + r; 
  var dx = Math.random() * 2 - 1; 
  var dy = Math.random() * 2 - 1; 
   
  balls.push(new Ball(x, y, r, dx, dy)); 
} 
// Do the first update 
updateAll();
<canvas id="canvas" width="300" height="180"></canvas>

Код взят отсюда (ближе к концу примеры Acceleration, Velocity and Physics).

Используется random, поэтому иногда мячик скачет слабо. Тогда запустите код ещё раз.

Answer 2

Вот пример на чистом js:

let requestAnimationFrame = window.requestAnimationFrame 
let canvas = document.getElementById('canvas') 
let ctx = canvas.getContext('2d') 
let width = 100 
let height = 120 
let player = { 
  x: width / 2, 
  y: height - 5, 
  width: 10, 
  height: 10, 
  speed: 3, 
  velX: 0, 
  velY: 0, 
  jumping: false 
} 
let keys = [] 
let friction = 0.8 
let gravity = 0.2 
 
canvas.width = width 
canvas.height = height 
 
function update () { 
  // проверка клавиш 
  if (keys['ArrowUp'] || keys[' ']) { // ' ' значит пробел 
    if (!player.jumping) { 
      player.jumping = true 
      player.velY = -player.speed * 2 
    } 
  } 
  if (keys['ArrowRight']) { 
    if (player.velX < player.speed) { 
      player.velX++ 
    } 
  } 
  if (keys['ArrowLeft']) { 
    if (player.velX > -player.speed) { 
      player.velX-- 
    } 
  } 
 
  player.velX *= friction 
 
  player.velY += gravity 
 
  player.x += player.velX 
  player.y += player.velY 
 
  if (player.x >= width - player.width) { 
    player.x = width - player.width 
  } else if (player.x <= 0) { 
    player.x = 0 
  } 
 
  if (player.y >= height - player.height) { 
    player.y = height - player.height 
    player.jumping = false 
  } 
 
  ctx.clearRect(0, 0, width, height) 
  ctx.fillStyle = 'red' 
  ctx.fillRect(player.x, player.y, player.width, player.height) 
 
  requestAnimationFrame(update) 
} 
 
document.body.addEventListener('keydown', function (e) { 
  keys[event.key] = true 
}) 
 
document.body.addEventListener('keyup', function (e) { 
  keys[event.key] = false 
}) 
 
window.addEventListener('load', function () { 
  update() 
})
#canvas { 
  border:1px solid #000; 
}
<canvas id="canvas"></canvas>

Если хотите делать 2d игру то очень советую использовать какой-то движок иначе будет очень тяжело.

Когда-то делал платформер на очень крутой либе для 2d физики: Matter.js

// алиасы модулей 
const { Engine, Render, World, Bodies, Body, Runner, Events, Query } = Matter; 
const { applyForce } = Body; 
const keyboard = {}; 
 
// создает движок 
const log = console.log.bind(console); 
const engine = Engine.create(); 
const runner = Matter.Runner.create(); 
let ticks = 0; 
let firstTick = true; 
 
Runner.start(runner, engine); 
 
// создает визуализатор 
const render = Render.create({ 
  element: document.body, 
  engine: engine 
}); 
 
// создать объекты(x, y, sizeX, sizeY) 
const boxA = Bodies.rectangle(400, 200, 80, 80); 
const boxB = Bodies.rectangle(450, 50, 80, 80); 
const ground = Bodies.rectangle(400, 610, 1200, 60, { isStatic: true }); 
const platform = Bodies.rectangle(350, 450, 200, 60, { isStatic: true }) 
const platform2 = Bodies.rectangle(100, 350, 200, 60, { isStatic: true }) 
const surfaces = [ 
  ground, 
  platform, 
  platform2, 
  boxB, 
]; 
 
// добавить все тела в мир 
World.add(engine.world, [boxA, ...surfaces]); 
 
Events.on(runner, 'tick', (event) => { 
  Render.lookAt(render, boxA, {x: 500, y: 500}); 
  const { delta } = event.source; 
  if(ticks === 0 || ticks === 1) { 
    firstTick = false; 
  } 
  const onGround = isOnSurface(boxA); 
  const jumpSpeed = 20; // скорость прыжка 
  const seconds = delta / 1000; 
  const bottom = getBottom(boxA); 
  const speed = 0.8 * (onGround ? 1 : 0.25); // скорость героя 
  Body.setAngle(boxA, 0); 
   
  /* УПРАВЛЕНИЕ */ 
  applyForce(boxA, bottom, { 
    x: key('ArrowRight') * speed * seconds, 
    y: 0 
  }); 
 
  applyForce(boxA, bottom, { 
    x: key('ArrowLeft') * speed * seconds * -1, 
    y: 0 
  }); 
   
  // только если на земле 
  if(onGround) { 
    applyForce(boxA, bottom, { 
      x: 0, 
      y: jumpSpeed * key('ArrowUp') * seconds * -1 
    }); 
  } 
   
  ticks++; 
}); 
 
window.addEventListener('keydown', event => { 
  // console.log(event.key); 
  keyboard[event.key] = 1; 
  event.preventDefault(); 
}) 
 
window.addEventListener('keyup', event => { 
  keyboard[event.key] = 0; 
}); 
 
// возвращает 1 если нажал на кнопку 
function key(c) { 
  return keyboard[c] || 0; 
} 
 
function getBottom(body) { 
  const { min, max } = body.bounds; 
 
  return { 
    x: min.x + ((max.x - min.x) / 2), 
    y: max.y 
  }; 
} 
 
function getBottomRight(body) { 
  const { min, max } = body.bounds; 
 
  return { 
    x: min.x + (max.x - min.x), 
    y: max.y 
  }; 
} 
 
function getBottomLeft(body) { 
  const { min, max } = body.bounds; 
 
  return { 
    x: min.x, 
    y: max.y 
  }; 
} 
 
function isOnSurface(body, floors=surfaces) { 
  const bottomLeft = getBottomLeft(body); 
  const bottomCenter = getBottom(body); 
  const bottomRight = getBottomRight(body); 
 
  return ( 
    Query.ray(floors, bottomLeft, {x: bottomLeft.x, y: bottomLeft.y + 1}).length || 
    Query.ray(floors, bottomCenter, {x: bottomCenter.x, y: bottomCenter.y + 1}).length || 
    Query.ray(floors, bottomRight, {x: bottomRight.x, y: bottomRight.y + 1}).length 
  ); 
} 
 
// запустить движок 
Engine.run(engine); 
 
// запустить визуализатор 
Render.run(render);
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js"></script>

Answer 3

Вот пример, в нем в консоль кидает цифры у вас должно быть смещение на интервал. Не знаю кто дизлайкнул, кинул пример. При нажатии кнопки мышки будет лететь вверх.

var c = document.getElementById("myCanvas"); 
var ctx = c.getContext("2d"); 
 
var img = new Image(); 
img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw=='; 
 
var i = 0; 
 
function draw() { 
  ctx.clearRect(0, 0, 300, 500); 
  ctx.drawImage(img, 0, i); 
  i = i + 0.1; 
  requestAnimationFrame(draw); 
} 
 
draw(); 
 
// Нажимаем кнопкой мышки 
document.addEventListener("mousedown", moveUp); 
 
function moveUp() { 
  i -= 3; 
}
<canvas id="myCanvas" width="300" height="500"></canvas>

READ ALSO
Как в JPA Entity ограничить размер id типа String чтобы не выбрасывался SQLSyntaxErrorException: Specified key was too long

Как в JPA Entity ограничить размер id типа String чтобы не выбрасывался SQLSyntaxErrorException: Specified key was too long

Использую spring+jpaЕсть сущность, у которой id или поле name является String:

163
Выборка значений подзапросом

Выборка значений подзапросом

Существует многоуровневый список этажей и кабинетов на каждом этаже в зданииВ этом списке есть этаж ID=1 и кабинет ID=2

167
Помогите с запросом MySQL. 100.000 вопрос

Помогите с запросом MySQL. 100.000 вопрос

Имеется две таблицы с одинаковой структурой: Id int, Type int, Data blob Нужно во второй таблице выбрать первые 10 записей по каждому Type и изменить случайными...

167
Как починить поехавшие блоки картинок CSS

Как починить поехавшие блоки картинок CSS

Необходимо убрать расстояние между разными строками(блоками)

191