Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 48 additions & 40 deletions cactus.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,55 @@ import {
const SPEED = 0.05
const CACTUS_INTERVAL_MIN = 500
const CACTUS_INTERVAL_MAX = 2000
const worldElem = document.querySelector("[data-world]")

let nextCactusTime
export function setupCactus() {
nextCactusTime = CACTUS_INTERVAL_MIN
document.querySelectorAll("[data-cactus]").forEach(cactus => {
cactus.remove()
})
}

export function updateCactus(delta, speedScale) {
document.querySelectorAll("[data-cactus]").forEach(cactus => {
incrementCustomProperty(cactus, "--left", delta * speedScale * SPEED * -1)
if (getCustomProperty(cactus, "--left") <= -100) {

export class Cactus {
selector
nextTime
worldElem
constructor(selector, worldElem) {
this.worldElem = worldElem
this.selector = selector
}

setup() {
this.nextTime = CACTUS_INTERVAL_MIN
document.querySelectorAll(this.selector).forEach(cactus => {
cactus.remove()
})
}

update(delta, speedScale) {
document.querySelectorAll(this.selector).forEach(cactus => {
incrementCustomProperty(cactus, "--left", delta * speedScale * SPEED * -1)
if (getCustomProperty(cactus, "--left") <= -100) {
cactus.remove()
}
})

if (this.nextTime <= 0) {
this.create()
this.nextTime =
this.randomNumberBetween(CACTUS_INTERVAL_MIN, CACTUS_INTERVAL_MAX) / speedScale
}
})
this.nextTime -= delta
}

getRects() {
return [...document.querySelectorAll("[data-cactus]")].map(cactus => {
return cactus.getBoundingClientRect()
})
}

create() {
const cactus = document.createElement("img")
cactus.dataset.cactus = true
cactus.src = "imgs/cactus.png"
cactus.classList.add("cactus")
setCustomProperty(cactus, "--left", 100)
this.worldElem.append(cactus)
}

if (nextCactusTime <= 0) {
createCactus()
nextCactusTime =
randomNumberBetween(CACTUS_INTERVAL_MIN, CACTUS_INTERVAL_MAX) / speedScale
randomNumberBetween(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
nextCactusTime -= delta
}

export function getCactusRects() {
return [...document.querySelectorAll("[data-cactus]")].map(cactus => {
return cactus.getBoundingClientRect()
})
}

function createCactus() {
const cactus = document.createElement("img")
cactus.dataset.cactus = true
cactus.src = "imgs/cactus.png"
cactus.classList.add("cactus")
setCustomProperty(cactus, "--left", 100)
worldElem.append(cactus)
}

function randomNumberBetween(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
}
102 changes: 54 additions & 48 deletions dino.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,75 @@ import {
getCustomProperty,
} from "./updateCustomProperty.js"

const dinoElem = document.querySelector("[data-dino]")
const JUMP_SPEED = 0.45
const GRAVITY = 0.0015
const DINO_FRAME_COUNT = 2
const FRAME_TIME = 100

let isJumping
let dinoFrame
let currentFrameTime
let yVelocity
export function setupDino() {
isJumping = false
dinoFrame = 0
currentFrameTime = 0
yVelocity = 0
setCustomProperty(dinoElem, "--bottom", 0)
document.removeEventListener("keydown", onJump)
document.addEventListener("keydown", onJump)
}

export function updateDino(delta, speedScale) {
handleRun(delta, speedScale)
handleJump(delta)
}
export class Dino {
element
isJumping
frame
currentFrameTime
yVelocity

export function getDinoRect() {
return dinoElem.getBoundingClientRect()
}

export function setDinoLose() {
dinoElem.src = "imgs/dino-lose.png"
}
constructor(selector) {
this.element = document.querySelector(selector)
}
setup() {
this.isJumping = false
this.frame = 0
this.currentFrameTime = 0
setCustomProperty(this.element, "--bottom", 0)
document.removeEventListener("keydown", this.onJump.bind(this))
document.addEventListener("keydown", this.onJump.bind(this))
}

function handleRun(delta, speedScale) {
if (isJumping) {
dinoElem.src = `imgs/dino-stationary.png`
return
update(delta, speedScale) {
this.handleRun(delta, speedScale)
this.handleJump(delta)
}

if (currentFrameTime >= FRAME_TIME) {
dinoFrame = (dinoFrame + 1) % DINO_FRAME_COUNT
dinoElem.src = `imgs/dino-run-${dinoFrame}.png`
currentFrameTime -= FRAME_TIME
getRect() {
return this.element.getBoundingClientRect()
}
currentFrameTime += delta * speedScale
}

function handleJump(delta) {
if (!isJumping) return
setLose() {
this.element.src = "imgs/dino-lose.png"
}

incrementCustomProperty(dinoElem, "--bottom", yVelocity * delta)
handleRun(delta, speedScale) {
if (this.isJumping) {
this.element.src = `imgs/dino-stationary.png`
return
}

if (getCustomProperty(dinoElem, "--bottom") <= 0) {
setCustomProperty(dinoElem, "--bottom", 0)
isJumping = false
if (this.currentFrameTime >= FRAME_TIME) {
this.frame = (this.frame + 1) % DINO_FRAME_COUNT
this.element.src = `imgs/dino-run-${this.frame}.png`
this.currentFrameTime -= FRAME_TIME
}
this.currentFrameTime += delta * speedScale
}

yVelocity -= GRAVITY * delta
}
handleJump(delta) {
if (!this.isJumping) return

incrementCustomProperty(this.element, "--bottom", this.yVelocity * delta)

function onJump(e) {
if (e.code !== "Space" || isJumping) return
if (getCustomProperty(this.element, "--bottom") <= 0) {
setCustomProperty(this.element, "--bottom", 0)
this.isJumping = false
}

yVelocity = JUMP_SPEED
isJumping = true
}
this.yVelocity -= GRAVITY * delta
}

onJump(e) {
if (e.code !== "Space" || this.isJumping) return

this.yVelocity = JUMP_SPEED
this.isJumping = true
}
}
29 changes: 17 additions & 12 deletions ground.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@ import {
} from "./updateCustomProperty.js"

const SPEED = 0.05
const groundElems = document.querySelectorAll("[data-ground]")

export function setupGround() {
setCustomProperty(groundElems[0], "--left", 0)
setCustomProperty(groundElems[1], "--left", 300)
}
export class Ground {
elements
constructor(selector) {
this.elements = document.querySelectorAll(selector)
}
setup() {
setCustomProperty(this.elements[0], "--left", 0)
setCustomProperty(this.elements[1], "--left", 300)
}

export function updateGround(delta, speedScale) {
groundElems.forEach(ground => {
incrementCustomProperty(ground, "--left", delta * speedScale * SPEED * -1)
update(delta, speedScale) {
this.elements.forEach(ground => {
incrementCustomProperty(ground, "--left", delta * speedScale * SPEED * -1)

if (getCustomProperty(ground, "--left") <= -300) {
incrementCustomProperty(ground, "--left", 600)
}
})
if (getCustomProperty(ground, "--left") <= -300) {
incrementCustomProperty(ground, "--left", 600)
}
})
}
}
28 changes: 16 additions & 12 deletions script.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { updateGround, setupGround } from "./ground.js"
import { updateDino, setupDino, getDinoRect, setDinoLose } from "./dino.js"
import { updateCactus, setupCactus, getCactusRects } from "./cactus.js"
import { Ground } from "./ground.js"
import { Dino } from "./dino.js"
import { Cactus } from "./cactus.js"

const WORLD_WIDTH = 100
const WORLD_HEIGHT = 30
Expand All @@ -10,6 +10,10 @@ const worldElem = document.querySelector("[data-world]")
const scoreElem = document.querySelector("[data-score]")
const startScreenElem = document.querySelector("[data-start-screen]")

const dino = new Dino("[data-dino]");
const cactus = new Cactus("[data-cactus]", worldElem);
const ground = new Ground("[data-ground]");

setPixelToWorldScale()
window.addEventListener("resize", setPixelToWorldScale)
document.addEventListener("keydown", handleStart, { once: true })
Expand All @@ -25,9 +29,9 @@ function update(time) {
}
const delta = time - lastTime

updateGround(delta, speedScale)
updateDino(delta, speedScale)
updateCactus(delta, speedScale)
ground.update(delta, speedScale)
dino.update(delta, speedScale)
cactus.update(delta, speedScale)
updateSpeedScale(delta)
updateScore(delta)
if (checkLose()) return handleLose()
Expand All @@ -37,8 +41,8 @@ function update(time) {
}

function checkLose() {
const dinoRect = getDinoRect()
return getCactusRects().some(rect => isCollision(rect, dinoRect))
const dinoRect = dino.getRect()
return cactus.getRects().some(rect => isCollision(rect, dinoRect))
}

function isCollision(rect1, rect2) {
Expand All @@ -63,15 +67,15 @@ function handleStart() {
lastTime = null
speedScale = 1
score = 0
setupGround()
setupDino()
setupCactus()
ground.setup()
dino.setup()
cactus.setup()
startScreenElem.classList.add("hide")
window.requestAnimationFrame(update)
}

function handleLose() {
setDinoLose()
dino.setLose()
setTimeout(() => {
document.addEventListener("keydown", handleStart, { once: true })
startScreenElem.classList.remove("hide")
Expand Down