导航

萌即是正义!时不时分享一些ACG活动记录与有趣代码的小站!

侧边栏
热门文章
1推文
今天在结束了《吹响吧!上低音号》的第八回定期演奏会后,去逛了《如龙》系列中出现的横滨中华街。 周末的中华街真的很热闹,人挤人。就如其名,中华的氛围感很强。 随后挑了一家中华料理放题(就是菜单上的东西随便吃)的店,结果发现比上次上野吃的北京烤鸭放题水更深。 先是一套我们原价2780日元/人(约131人民币),现价2480日元/人(约117人民币),成功诱导了我们。记住这里,有伏笔。 随后点了一些菜,可以说部分菜品和菜单上的图片毫不相干😅,尤其是北京烤鸭和白切鸡,白切鸡我是真没认出来,北京烤鸭这个卖相...不过对比隔壁2980日元(约140人民币)四片烤鸭皮的正宗北京烤鸭店,这2480日元要什么自行车? 最后结账的时候是2728日元/人,不是说好的2480日元吗?一问,原来店门口报的价格是税前价格...还是我太年轻了,默认了餐饮店报价都是税后价格。这真要较真,那肯定会在哪个犄角旮旯说我们标注了税后价吧。 不过这个价格也确实只能供应这样的菜品,这能理解,但是这个手段确实不太光彩。 总之中华街逛逛还是可以的,进店消费还是要谨慎。
热度
661
2页面
程序员老黄历&求签
热度
325
3推文
今天的《大AQUAPLUS祭 -30th Anniversary-》公布了上个世纪鼻祖级的Galgame《ToHeart》,在2025年春季发售重制版的消息!而且是全3D的版本!!?
热度
246
4页面
活动
热度
143
5博文
Live2d模型合集分享 | FaceRig | 海王星系列 | 初音未来 | 雷姆 | 凉风青叶 | 尼禄 | 薇尔莉特 | 小埋 | 樱花庄 | 玉藻前
热度
130
6页面
友链
热度
117
7推文
今天的《大AQUAPLUS祭 -30th Anniversary-》公布了《黑白莫比乌斯》的续作,标题为《うたわれるもの 白への道標》。 标题改回了《传颂之物》听说是和剧情有关。 感谢AQUAPLUS没有放弃这部作品,把坑填上了。应该是填坑吧?
热度
103
8推文
唐可可真的撑起了整部《Love Live! Superstar!!》 https://www.bilibili.com/video/BV1RLSyY5ET8
热度
90
9博文
让智能AI(waifulabs)来为你生成老婆吧!
热度
78
10推文
不知道为什么,本月的大型游戏动漫活动都挑在了这周末,导致这周末的行程需要做取舍。 其中《大AQUAPLUS祭 -30th Anniversary-》甚至还直接办2天,为了雨露均沾,我选择了一天去参加《大AQUAPLUS祭 》一天去参加《上低音号》的交响音乐会,结果前几天的直播中提到《大AQUAPLUS祭 》的2天曲单是完全不一样的! 这太不按套路了,我想听的《WHITE ALBUM》的相关歌曲以及《传颂之物》的相关歌曲在第几天啊???而且这难道不是卖点吗?为什么要在最后的时候才说,早说我就不雨露均沾了,对活动的门票销量也有好处啊?
热度
77
最新评论
广树
2024-11-11 14:21
@hikari:是的,水比较深
hikari
2024-11-11 14:19
这卖相真是绷不住了,专门来宰游客的吧
广树
2024-11-11 12:54
@大致:鼻祖级,不是鼻祖。心跳回忆是1994年的作品,《ToHeart》是1997年的作品,个人觉得蹭热度不至于。 这部作品在国内没什么热度,在当年的日本热度还是很高的。
大致
2024-11-11 12:43
没听说过。这方面的鼻祖不是《心跳回忆》么?这个名字都像在蹭心跳回忆的热度啊。
广树
2024-11-11 09:56
@老张博客:物以稀为贵
正在攻略

logo_kai.jpg


PSN奖杯卡

PSN奖杯卡

赞助商广告

【H5小游戏】利用pixi.js重写了赛车小游戏

作者:广树时间:2018-09-16 18:16:46分类:JavaScript/jQuery/Vue

早在去年十月,我写过一篇题为【H5小游戏】制作一个简单的赛车游戏》的文章。基于最基本的canvas功能,而且是以格子的形式去刷新游戏界面,游戏原理类似上世纪的game&watch。

然后最近学了些pixi.js的东西(相关文章可以从2D WebGL renderer Pixi.js v4 入门【第一回】开始看),于是就把游戏换成了基于pixi.js的游戏。

游戏质量也从game&watch模式提升到了逐帧模式了。不过总体还是很垃圾,毕竟是四个小时瞎搞出来的。

那么废话不多说,先上预览效果。(感觉游戏难度更难了……)


<点击游玩游戏>


然后是代码部分,原理基本上都注释了。这次代码基于pixi.js v4.8.2。相关内容也都是之前pixi入门中提到过的内容。

//别名
let Application = PIXI.Application,
    Container = PIXI.Container,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    Graphics = PIXI.Graphics,
    TextureCache = PIXI.utils.TextureCache,
    Sprite = PIXI.Sprite,
    Text = PIXI.Text,
    TextStyle = PIXI.TextStyle;

//创建一个pixi应用
let app = new Application({ 
    width: 240, 
    height: 120,                       
    antialiasing: true, 
    transparent: false, 
    resolution: 2
  }
);

//将pixi插入文档
document.body.appendChild(app.view);
//加载素材图片
loader
  .add("img/bg.png")
  .add("img/boom.png")
  .add("img/emcar.png")
  .add("img/mycar.png")
  .load(setup);
//设置要用到的变量
let state,gameScene,gameOverScene,message,bg,mycarSprite,blobs,numberOfBlobs,score,hp;
function setup() {
  numberOfBlobs = 2;//初始化最大敌车数量
  score = 0;//初始化分数
  hp = 5;//初始化HP
  document.getElementById('hp').innerHTML = String(hp);//将HP写入元素
  //设置游戏场景容器
  gameScene = new Container();
  app.stage.addChild(gameScene);
  //设置背景
  bg = new Sprite(resources["img/bg.png"].texture);
  bg.width = 480;
  bg.height = 120;
  gameScene.addChild(bg);

  //设置自己的车
  mycarSprite=new Sprite(resources["img/mycar.png"].texture);
  mycarSprite.position.set(2,5);//自己的车的初始位置
  mycarSprite.width = 18;//自己的车宽度
  mycarSprite.height = 11;//高度
  mycarSprite.vy = 0;//y轴加速度
  mycarSprite.vx = 0;//x轴加速度
  mycarSprite.invl = 0;//初始化无敌时间
  gameScene.addChild(mycarSprite);

  //一个存地方车辆的数组
  blobs = [];

  //创建一个游戏结束的场景
  gameOverScene = new Container();
  app.stage.addChild(gameOverScene);

  //先让游戏结束场景隐藏
  gameOverScene.visible = false;

  //设置一个默认字体
  let style = new TextStyle({
    "wordWrap": true,
    "align": "center",
    "fill": "white",
    "fontSize": 14
  });
  message = new Text("", style);
  message.y = app.stage.height / 2 - 32;
  message.x = app.stage.width / 4;
  //字体中心点用于居中
  message.anchor.set(0.5,0.5)
  gameOverScene.addChild(message);

  //设置按键代码
  let left = keyboard(37),
      up = keyboard(38),
      right = keyboard(39),
      down = keyboard(40);

  //左按下去之后
  left.press = function() {

    //改变自己车子的加速度
    mycarSprite.vx = -5;
    mycarSprite.vy = 0;
  };

  //松开左键
  left.release = function() {

    //防止键位冲突
    if (!right.isDown && mycarSprite.vy === 0) {
      mycarSprite.vx = 0;
    }
  };

  //Up
  up.press = function() {
    mycarSprite.vy = -5;
    mycarSprite.vx = 0;
  };
  up.release = function() {
    if (!down.isDown && mycarSprite.vx === 0) {
      mycarSprite.vy = 0;
    }
  };

  //Right
  right.press = function() {
    mycarSprite.vx = 5;
    mycarSprite.vy = 0;
  };
  right.release = function() {
    if (!left.isDown && mycarSprite.vy === 0) {
      mycarSprite.vx = 0;
    }
  };

  //Down
  down.press = function() {
    mycarSprite.vy = 5;
    mycarSprite.vx = 0;
  };
  down.release = function() {
    if (!up.isDown && mycarSprite.vx === 0) {
      mycarSprite.vy = 0;
    }
  };
  state = play;
  app.ticker.add(delta => gameLoop(delta));
}
function creatEMCar(){
  //设置敌人
  //根据最大敌车数创建车子
  for (let i = 0; i < numberOfBlobs-blobs.length; i++) {

    //创建敌车
    let blob = new Sprite(resources["img/emcar.png"].texture);
    blob.width = 18;
    blob.height = 11;
    let EMCarIsHit = true;
    while(EMCarIsHit){
      //随机车子x坐标在画布外
      let x = randomInt(250, 500);

      //随机y坐标在画布范围内
      let y = randomInt(2, app.stage.height - 2 - blob.height);

      //设置车辆位置
      blob.x = x;
      blob.y = y;

      //检测车辆位置是否有重叠
      EMCarIsHit = checkEMCarPositionHit(blob);
    }

    //将车子加入数组
    blobs.push(blob);

    //渲染
    gameScene.addChild(blob);
  }
}
//检查生成的地方车辆是否有重叠
function checkEMCarPositionHit(blob){
  for(var i=0;i<blobs.length;i++){
    if(hitTestRectangle(blob,blobs[i])){
      return true;
      break;
    }
  }
}
function gameLoop(delta){
  //更新游戏场景:
  state(delta);
}
function play(delta) {
  //背景移动
  bg.x -= 10;
  if(bg.x<-230){
    bg.x = 0;
  }
  //移动赛车
  mycarSprite.x += mycarSprite.vx;
  mycarSprite.y += mycarSprite.vy;
  if(mycarSprite.invl>0){
    mycarSprite.invl --;
  }
  //判断车辆是否超出画布
  contain(mycarSprite, {x: 0, y: 2, width: 240, height: 118});
  //设置敌人
  creatEMCar();
  let explorerHit = false;
  //移动敌人
  blobs.forEach(function(blob) {

    //移动地方车辆
    blob.x -= 5;

    //如果和我方车辆发生碰撞
    if(hitTestRectangle(mycarSprite, blob)) {
      explorerHit = true;
    }
  });
  //去除已经行驶到画布外的敌军车辆
  removeEmCar();
  //加分
  score += 1;
  document.getElementById('score').innerHTML = String(score);
  //如果分数大于2000则每1000分场景车辆+1,最多八辆
  if(score>2000){
    numberOfBlobs = Math.floor(score/1000);
    if(numberOfBlobs>8){
      numberOfBlobs = 8;
    }
  }
  //如果发生碰撞且在无敌时间之外
  if(explorerHit&&mycarSprite.invl===0) {

    //车子图片变更为爆炸
    mycarSprite.texture = resources["img/boom.png"].texture;
    //减血
    hp --;
    document.getElementById('hp').innerHTML = String(hp);
    //判断是否血量归零
    if(hp<1){
      //抛出游戏结束
      state = end;
      message.text = "你的车炸了!刷新重来";
    }
    mycarSprite.invl = 30//设置无敌时间

  }else if(mycarSprite.invl<=0){//如果不在无敌时间内
    //车辆贴图变回去
    mycarSprite.texture = resources["img/mycar.png"].texture;
  } else {//其他情况
    mycarSprite.texture = resources["img/mycar.png"].texture;
  }
}
//移除已经行驶到画布外围的敌方车辆
function removeEmCar(){
  for(var i=0;i<blobs.length;i++){
    if(blobs[i].x<-50){
      //从数组删除
      blobs.splice(i, 1);
      //从场景删除
      gameScene.removeChildAt(i+2);
    }
  }
}
//按键方法
function keyboard(keyCode) {
  var key = {};
  key.code = keyCode;
  key.isDown = false;
  key.isUp = true;
  key.press = undefined;
  key.release = undefined;

  key.downHandler = function(event) {
    if (event.keyCode === key.code) {
      if (key.isUp && key.press) key.press();
      key.isDown = true;
      key.isUp = false;
    }
    event.preventDefault();
  };

  key.upHandler = function(event) {
    if (event.keyCode === key.code) {
      if (key.isDown && key.release) key.release();
      key.isDown = false;
      key.isUp = true;
    }
    event.preventDefault();
  };

  window.addEventListener(
    "keydown", key.downHandler.bind(key), false
  );
  window.addEventListener(
    "keyup", key.upHandler.bind(key), false
  );
  return key;
}
//判断是否超出画布
function contain(sprite, container) {

  let collision = undefined;

  //Left
  if (sprite.x < container.x) {
    sprite.x = container.x;
    collision = "left";
  }

  //Top
  if (sprite.y < container.y) {
    sprite.y = container.y;
    collision = "top";
  }

  //Right
  if (sprite.x + sprite.width > container.width) {
    sprite.x = container.width - sprite.width;
    collision = "right";
  }

  //Bottom
  if (sprite.y + sprite.height > container.height) {
    sprite.y = container.height - sprite.height;
    collision = "bottom";
  }

  return collision;
}
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
//碰撞检测
function hitTestRectangle(r1, r2) {

  //设置需要的变量
  let hit, combinedHalfWidths, combinedHalfHeights, vx, vy;

  //初始化是否碰撞
  hit = false;

  //寻找精灵中心点
  r1.centerX = r1.x + r1.width / 2; 
  r1.centerY = r1.y + r1.height / 2; 
  r2.centerX = r2.x + r2.width / 2; 
  r2.centerY = r2.y + r2.height / 2; 

  //计算精灵一半的宽度和高度
  r1.halfWidth = r1.width / 2;
  r1.halfHeight = r1.height / 2;
  r2.halfWidth = r2.width / 2;
  r2.halfHeight = r2.height / 2;

  //计算相互之间的距离
  vx = r1.centerX - r2.centerX;
  vy = r1.centerY - r2.centerY;

  //计算xy重叠的数值
  combinedHalfWidths = r1.halfWidth + r2.halfWidth;
  combinedHalfHeights = r1.halfHeight + r2.halfHeight;

  //检查x轴是否充电
  if (Math.abs(vx) < combinedHalfWidths) {

    //再检查y轴
    if (Math.abs(vy) < combinedHalfHeights) {

      //如果是则判断为碰撞
      hit = true;
    } else {

      //否则为没碰撞
      hit = false;
    }
  } else {

    //x轴没有碰撞
    hit = false;
  }

  //传是否碰撞
  return hit;
};
//游戏结束显示游戏结束场景,隐藏游戏场景
function end() {
  gameScene.visible = false;
  gameOverScene.visible = true;
}


#pixi.js#H5小游戏

donate.png

1210 x 50(蓝底).png

cloudcone