导航

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

侧边栏
热门文章
1页面
程序员老黄历&求签
热度
1001
2推文
用几乎纯 AI 写维基萌公会联盟这款游戏也有段时间了,可以分享一些 AI 写项目的心得了。 先说结果,现阶段面向个人的几大 AI 模型用来开发个人小项目,实现个人的一些想法是够用的。但是用在商业项目还有待商榷。 目前用下来的问题包括但不仅限于: · 不会总结需求功能中哪些函数或者组件应该共通化,同样的功能写的到处都是。 · 由于上面的问题,修改BUG的时候经常只会改一处就觉得自己解决问题了。 · AI 有时候倾向掩盖问题而不是解决问题。比如有几次指挥解决日志中的错误,结果 AI 选择遇到此类问题不输出日志。 · 受到上下文最大输入限制,现在的 AI 是以总结交接的形式将前面的信息传递到下一任 AI ,这就导致了一旦发生交接,这段代码质量会急剧下降。 · 不约束代码习惯的时候,AI 更倾向写可读性很差的语法糖。 · UI交互设计不加详细描述就会写的一团糟。 · 游戏玩法设计幻觉严重。 当然优点也有很多。最大的优点就是减少了我自己的心智负担。并且用自己的描述成功让 AI 完美实现时的成功感。我现在算是明白为什么那么多人喜欢玩抽卡游戏了。
热度
117
3推文
让AI生成了头像的表情包,都好可爱呀!
热度
91
4博文
大开眼界的《憧憬成为魔法少女非常热闹哟大感谢祭》S场
热度
78
5博文
3DS模拟器简体中文字库 | Citra3ds字库 | 符文工房4乱码解决字库 | shared_font.bin
热度
78
6博文
360度带你看《超时空辉夜姬》联动KTV联动房间
热度
52
7博文
《孤独摇滚》圣地巡礼——下北泽&下北泽咖喱节2023
热度
52
8博文
RPG Maker MV 插件制作入门(2)
热度
52
9页面
友链
热度
52
10推文
让AI生成了一个记账网页应用。 完全按照我自己的需求定制的记账应用。当然也有一定的通用性。 支持响应式布局,所以手机也能用。 本人只贡献了需求和修改了一丢丢UI体验。 成品还是很满意的,看来AI时代,小工具根本不需要下什么APP了。 直接自己定制应用的好时代来了呀! 项目地址:https://github.com/eeg1412/wikimoeBookkeeping ※截图是测试数据,不是我发财了。
热度
39
最新评论
广树管理员
2026-04-16 19:18
@Asuna:几乎是的
广树管理员
2026-04-16 19:18
@ZeroCounter:让AI实现过一版,但是修改内容比预想的多太多了,根本没时间审查😅
广树管理员
2026-04-16 19:17
@Zrzzz:说不定有了呢
Asuna
2026-04-16 06:31
佬用的是 Opus 嘛,Claude 神力!😭
ZeroCounter
2026-04-15 12:40
好可爱!建议实装到评论区(什么
攻略中
告别回忆 双想 ~Not always true~
暂无评分
Steam告别回忆 双想 ~Not always true~
2026年3月10日 22时 ~ 攻略中
已累计游玩1个月6天
“我觅见了生命中的唯一,而后——”
亚路塔:狐狸狐途的面包冒险
暂无评分
Steam亚路塔:狐狸狐途的面包冒险
2026年2月12日 19时 ~ 攻略中
已累计游玩2个月3天
一场席卷全世界的面包革命现在开始! 主人公查雅阴错阳差之下,开始了在荒废的岛屿上经营面包店的生活。 出外冒险搜集食材、研发崭新面包配方、遇见性格各异的伙伴们,建造更丰富的设施,用面包香气使无人问津的广场再次热闹起来!
ToHeart
暂无评分
SteamToHeart
2025年6月26日 19时 ~ 攻略中
已累计游玩9个月24天
AQUAPLUS推出的“温暖人心的校园恋爱游戏”将以高清全3D形式焕新归来!
fault - StP - LIGHTKRAVTE
暂无评分
Steamfault - StP - LIGHTKRAVTE
2025年5月29日 20时 ~ 攻略中
已累计游玩10个月22天
全球累计销量超过50万份的“fault”系列最新作!故事的舞台是一个融合了奇幻与科幻的超前世界——卢森海德王国。本作讲述了生活在此地的一个平凡又平庸的究极普通市民——名为果子的少年的故事。
PSN奖杯卡

PSN奖杯卡

归档
赞助商广告

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

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

早在去年十月,我写过一篇题为【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;
}


donate.png


telegram banner (1).png