首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >点击循环游戏Javascript

点击循环游戏Javascript
EN

Stack Overflow用户
提问于 2022-05-01 03:05:51
回答 2查看 226关注 0票数 3

我试图制作一个简单的互动游戏,在画布上有不同颜色的圆圈,当用户点击蓝色圆圈时,它会记录屏幕上的点击次数。当点击任何其他颜色的圆圈时,动画就停止了。

我对javascript非常陌生,但这是我现在所拥有的。我做了一个带有随机颜色圆圈的函数,还有一个蓝色圆圈移动的函数,但是当我点击带有随机颜色圆的函数并记录对蓝色圆圈的点击量时,我完全被困在了如何停止动画上。如果有人能以任何方式帮助我继续前进(不一定是全部的事情),那就太棒了,谢谢。

JS

代码语言:javascript
复制
var canvas;
var ctx;
var w = 1000;
var h = 600;
var colours = ["red", "blue"];
var allCircles = []; 


for(var i=0; i<1; i++){
    setTimeout(function(){console.log(i)},1000);
    }
    
document.querySelector("#myCanvas").onclick = click;
createData(2);
createDataTwo(20);
setUpCanvas();
animationLoop();

function animationLoop(){
    clear();
    for(var i = 0; i<allCircles.length; i++){
    circle(allCircles[i]);
    forward(allCircles[i], 5)  
    turn(allCircles[i], randn(30));
    collisionTestArray(allCircles[i],allCircles)
    bounce(allCircles[i]);
}

    requestAnimationFrame(animationLoop);
}


function collisionTestArray(o, a){
    for(var i=0; i<a.length; i++){
        if(o !=a[i]){
            collision(o,a[i]);
        }
        
    }
}




function collision(o1,o2){
    if(o1 && o2){
    var differencex = Math.abs(o1.x-o2.x);
    var differencey = Math.abs(o1.y-o2.y);
    var hdif = Math.sqrt(differencex*differencex+differencey*differencey);
    if(hdif<o1.r+o2.r){
        if(differencex < differencey){
            turn(o1, 180-2*o1.angle);
            turn(o2, 180-2*o2.angle);
        }else{
            turn(o1, 360-2*o1.angle);
            turn(o2, 360-2*o2.angle);
        }
        turn(o1, 180);
        turn(o2, 180);
        console.log("collision");
    };
    }
}


function click(event){
  clear()
}




function bounce (o){
    if(o.x > w || o.x < 0){
        turn(o, 180-2*o.angle);
    };
    if(o.y > h || o.y < 0){
        turn(o, 360-2*o.angle);
    }
}
function clear(){
    ctx.clearRect(0,0,w,h);
}
function stop (){
    o1.changex = 0;
    o1.changey = 0;
    o2.changex = 0;
    o2.changey = 0;
}

function circle (o){
    var x = o.x; 
    var y = o.y;
    var a = o.angle;
    var d = o.d;
    ctx.beginPath();
    ctx.arc(o.x,o.y,o.r,0,2*Math.PI);
    ctx.fillStyle = "hsla("+o.c+",100%,50%, "+o.a+")";
    ctx.fill();


    o.x = x;
    o.y = y;
    o.angle = a;
    o.d = d;
}


function  createData(num){
    for(var i=0; i<num; i++){
        allCircles.push({

                    "x": rand(w),
                    "changex": rand(10),
                    "y":rand(h),
                     "changex": rand(10),
                     "w": randn(w),
                    "h": randn(h),
                    "d": 1, 
                     "a": 1,
                     "angle": 0,
                     "changle":15,
                     "c":216,
                     "r": 50
         }
        )
    }
}

function  createDataTwo(num){
    for(var i=0; i<num; i++){
        allCircles.push({

                    "x": rand(w),
                    "changex": rand(10),
                    "y":rand(h),
                     "changex": rand(10),
                     "w": randn(w),
                    "h": randn(h),
                    "d": 1, 
                     "a": 1,
                     "angle": 0,
                     "changle":15,
                     "c":rand(90),
                     "r": 50
         }
        )
    }
}

function turn(o,angle){
    if(angle != undefined){ 
        o.changle=angle; 
    };
        o.angle+=o.changle;
    }


function forward(o,d){ 
    var changeX;
    var changeY;
    var oneDegree = Math.PI/180; 
    if(d != undefined){
        o.d = d;
    };
        changeX= o.d*Math.cos(o.angle*oneDegree);
        changeY = o.d*Math.sin(o.angle*oneDegree);
        o.x+=changeX; 
        o.y+=changeY;
}


function randn(r){
    var result = Math.random()*r - r/2
    return result
}

function randi(r) {
    var result = Math.floor(Math.random()*r); 
    return result
}


function rand(r){
    return Math.random()*r
}




function setUpCanvas(){
    canvas = document.querySelector("#myCanvas");
    ctx = canvas.getContext("2d");
    canvas.width = w;
    canvas.height = h;
    canvas.style.border = "5px solid orange"
    ctx.fillStyle = "blue";
    ctx.fillRect(0, 0, w, h);
}

console.log("assi4")

HTML

代码语言:javascript
复制
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="../modules.css">
    </head>
    <body>
        <div id="container">
            <h1>Click the Blue Circles Only</h1>
            <canvas id = "myCanvas"></canvas>
        </div>
        <script src="assi5.js"></script>
    </body>
</html>

CSS

代码语言:javascript
复制
#container {
    margin: auto;
    width: 75%;
    text-align: center;
}
EN

回答 2

Stack Overflow用户

发布于 2022-05-01 12:22:24

单击非蓝色圆圈时,可以使用cancelAnimationFrame停止动画。

您需要将一个引用传递给从requestAnimationFrame返回的框架ID,这样它才能正常工作。

为了判断是否单击了一个圆,您需要根据单击的坐标检查每个圆圈的坐标。

下面有一个示例,如果您的蓝色圆圈位于“蓝色”数组中,而其他圆圈位于数组" other“中,则requestAnimationFrame返回的ID为"frame”。

check函数返回被击中的蓝色圆圈的数目(得分),如果有任何其他的圆圈被击中,它将停止动画。

getCoords从单击事件返回单击画布的坐标。

代码语言:javascript
复制
canvas.addEventListener('click', event=>{
    points += check(getCoords(event), blue, other, frame);
    document.getElementById('points').textContent = points;
})

function check({x, y}, blue, other, frame) {
    other.filter(circle=>circle.isWithin(x, y))
        .length && cancelAnimationFrame(frame); // This is where animation stops
    return blue.filter(circle=>circle.isWithin(x, y)).length;
}

function getCoords(event) {
    const canvas = event.target;
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    return { x, y };
}

下面是一个示例,在这个示例中,我将圆圈更改为函数的结果,而不是内联对象,并将您对它们使用的函数移到它们自己的类中。你不必这么做,但我觉得这更容易理解。

代码语言:javascript
复制
function main() {
  const canvas = document.getElementById('canvas');
  const context = canvas.getContext("2d");
  const clear = () => context.clearRect(0, 0, canvas.width, canvas.height);
  const blue = new Array(2).fill().map(() => new Circle(context, 216));
  const other = new Array(10).fill().map(() => new Circle(context));
  let circles = [...blue, ...other];
  let frame = 0;
  let points = 0;

  // Move the circle a bit and check if it needs to bounce
  function update(circle) {
    circle.forward(1)
    circle.turn(30, true)
    circle.collisionTestArray(circles)
    circle.bounce();
  }

  // Main game loop, clear canvas, update circle positions, draw circles
  function loop() {
    clear();
    circles.filter(circle => circle.free).forEach(update);
    circles.forEach(circle => circle.draw());
    frame = requestAnimationFrame(loop);
  }
  loop();

  canvas.addEventListener('click', event => {
    points += check(getCoords(event), blue, other, frame, circles);
    document.getElementById('points').textContent = points;
  })
}

function check({ x, y }, blue, other, frame) {
  other.filter(circle => circle.isWithin(x, y))
    // .map(circle=>circle.toggle())
    .length && cancelAnimationFrame(frame); // This is where animation stops
  return blue.filter(circle => circle.isWithin(x, y)).length;
}

function getCoords(event) {
  const canvas = event.target;
  const rect = canvas.getBoundingClientRect()
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  return { x, y };
}

main();

function Circle(context, c) {
  const randn = r => rand(r) - r / 2;
  const randi = r => Math.floor(randi(r));
  const rand = r => Math.random() * r;

  // These are for easily stopping and starting a circle;
  this.free = true;
  this.stop = () => this.free = false;
  this.release = () => this.free = true;
  this.toggle = () => this.free = !this.free;

  const {
    width,
    height
  } = context.canvas;

  // These are the same properties you were using in your code
  this.x = rand(width);
  this.changex = rand(10);
  this.y = rand(height);
  this.changey = rand(10);
  this.w = randn(width);
  this.h = randn(height);
  this.d = 1;
  this.a = 1;
  this.angle = 0;
  this.changle = 15;
  this.c = c || rand(90); // This is the only difference between blue and other circles
  this.r = 50;

  // These next functions you had in your code, I just moved them into the circle definition
  this.draw = () => {
    const { x, y, r, c } = this;
    context.beginPath();
    context.arc(x, y, r, 0, 2 * Math.PI);
    context.fillStyle = "hsla(" + c + ",100%,50%, 1)";
    context.fill();
  }
  this.bounce = () => {
    const { x, y, angle } = this;
    if (x > width || x < 0) {
      this.turn(180 - 2 * angle);
    }
    if (y > height || y < 0) {
      this.turn(360 - 2 * angle);
    }
  }
  this.turn = (angle, random = false) => {
    this.changle = random ? randn(angle) : angle;
    this.angle += this.changle;
  }
  this.forward = d => {
    this.d = d;
    this.x += this.d * Math.cos(this.angle * Math.PI / 180);
    this.y += this.d * Math.sin(this.angle * Math.PI / 180);
  }
  this.collisionTestArray = a => a
    .filter(circle => circle != this)
    .forEach(circle => this.collision(circle));
  this.collision = circle => {
    var differencex = Math.abs(this.x - circle.x);
    var differencey = Math.abs(this.y - circle.y);
    var hdif = Math.sqrt(differencex ** 2 + differencey ** 2);
    if (hdif < this.r + circle.r) {
      if (differencex < differencey) {
        this.turn(180 - 2 * this.angle);
        circle.turn(180 - 2 * circle.angle);
      } else {
        this.turn(360 - 2 * this.angle);
        circle.turn(360 - 2 * circle.angle);
      }
      this.turn(180);
      circle.turn(180);
    }
  }

  // These 2 functions I added to check if the circle was clicked
  this.distanceFrom = (x, y) => Math.sqrt((this.x - x) ** 2 + (this.y - y) ** 2);
  this.isWithin = (x, y) => this.r > this.distanceFrom(x, y);
}
代码语言:javascript
复制
#canvas {
  border: 5px solid orange;
}

#container {
  margin: auto;
  width: 75%;
  text-align: center;
}
代码语言:javascript
复制
<div id="container">
  <h1>Click the Blue Circles Only</h1>
  <canvas id="canvas" width="1000" height="600"></canvas>
  <p>
    Points: <span id="points">0</span>
  </p>
</div>

票数 2
EN

Stack Overflow用户

发布于 2022-05-01 12:35:42

在这种情况下使用OOP更好,并且可以节省大量的时间--我已经编写了OOP版本的游戏,我用harry写的,这样您可能会发现一些but,但它是一个很好的起点。

代码语言:javascript
复制
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")

let h = canvas.height = 600
let w = canvas.width = 800
const numberOfCircles = 20
let circles = []

// running gameover
let gameStatus = "running"
let score = 0
canvas.addEventListener("click", (e) => {
    if(gameStatus === "gameOver") {
       document.location.reload()
        return;
    }

    const mouse = {x: e.offsetX, y: e.offsetY}
    for(let circle of circles) {
        if(distance(mouse, circle) <= circle.radius) {
            if(circle.color == "blue") {
                gameStatus = "running"
                score += 1
            } else {
                gameStatus = "gameOver"
            }
        }
    }
}) 

class Circle {
    constructor(x, y, color, angle) {
        this.x = x
        this.y = y 
        this.color = color
        this.radius = 15
        this.angle = angle
        this.speed = 3
    }

    draw(ctx) {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fill();
    }

    move(circles) {
        this.check(circles)
        this.x += Math.cos(this.angle) * this.speed
        this.y += Math.sin(this.angle) * this.speed
    }

    check(circles) {
        if(this.x + this.radius > w || this.x - this.radius < 0) this.angle += Math.PI 
        if(this.y + this.radius > h || this.y - this.radius < 0) this.angle += Math.PI

    for(let circle of circles) {
            if(circle === this) continue
                
            if(distance(this, circle) <= this.radius + circle.radius) {
                // invert angles or any other effect
                // there are much better soultion for resolving colliusions
                circle.angle += Math.PI / 2
                this.angle += Math.PI / 2
            }
        }
}

    }
}

setUp()
gameLoop()


function gameLoop() {
    ctx.clearRect(0,0,w,h)
    if(gameStatus === "gameOver") {
        ctx.font = "30px Comic"
        ctx.fillText("Game Over", w/2 - 150, h/2 - 100)
        ctx.fillText("you have scored : " + score, w/2 - 150, h/2)
        return;
    }
    ctx.font = "30px Comic"
    ctx.fillText("score : " + score, 20, 30)
    for (let i = 0; i < circles.length; i++) {
        const cirlce = circles[i]
        cirlce.draw(ctx)
        cirlce.move(circles)
    }
    requestAnimationFrame(gameLoop)
}



function random(to, from = 0) {
    return Math.floor(Math.random() * (to - from) + from)
}

function setUp() {
    gameStatus = "running"
    score = 0
    circles = []
    for (var i = 0; i < numberOfCircles; i++) {
        const randomAngle = random(360) * Math.PI / 180
        circles.push(new Circle(random(w, 20), random(h, 20), randomColor(),  randomAngle))
    }
}

function randomColor() {
    const factor = random(10)
    if(factor < 3) return "blue"
    return `rgb(${random(255)}, ${random(255)}, ${random(100)})`
}
function distance(obj1, obj2) {
    const xDiff = obj1.x - obj2.x
    const yDiff = obj1.y - obj2.y

    return Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2))
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72073712

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档