大家都知道Google断线时会有小恐龙的离线游戏,
以前第一次看到的时候超惊喜!(我到现在断线的时候还是会玩一下XD)
品牌如果发挥一点创意,将品牌元素加进小游戏里面,
奔跑吧台北!就是完全以游戏的方式,
将政见放在游戏里面~
或是将游戏放在404页面里面,也许是个不错的主意!?
今天就来用昨天Canvas做的小人物和背景,
结合昨天做的Spritesheet动画传送门
做个Google小恐龙游戏的都市老妹生存记
版本!
老样子先看成品~
按住S或Shift
键低头,按住W或空白键
往上跳
小心不要被经痛还是加班还是渣男
给扣分了XD
在这边玩
今天的内容主要是参照:这个影片教学 所做~
但加上了sprite动画的code & 做了一些code的整理&和命名,往下看一起拆解吧!
(今天的篇幅史上无敌长XD)
主要分成
1.主角&敌人&分数的Class
2.游戏功能的撰写
因为敌人和主角和分数都要重复绘制,所以做成class。
首先是游戏主角的Class (放在constructor.js 里面)
class Player {
constructor (x, y, w, h) {
//xy座标,宽高,
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.dy = 0;
this.originalHeight = h;
this.grounded = false; //看是不是踏在地上
//设定一个跳的动力!
this.jumpForce = 15;
this.jumpTimer = 0;
//draw animate 昨天spritesheet动画的部分~
this.cols = 5;
this.rows = 1;
this.spriteSheet = new Image();
this.spriteSheet.src="./test.png";
this.spriteWidth = 229.4;
this.spriteHeight = 557;
this.srcX =0;
this.srcY =0;
//控制主角的动画速度
this.totalFrames = 5;
this.currentFrame = 0;
this.frameDrawn =0;
}
Animate () {
// 跳
if (keys['Space'] || keys['KeyW']) {
this.Jump();
} else {
this.jumpTimer = 0;
}
// 蹲下
if (keys['ShiftLeft'] || keys['KeyS']) {
this.h = this.originalHeight / 3 * 2; //让画面变矮
} else {
this.h = this.originalHeight;
}
this.y += this.dy; //跳起来会变高,y会变小,所以dy是负的
// 判断他是不是在空中,
//踩在地上的时候应该是this.y + this.h <= canvas.height
if (this.y + this.h < canvas.height) {
this.dy += gravity; //全域宣告
this.grounded = false;
} else {
this.dy = 0;
this.grounded = true;
this.y = canvas.height - this.h;
}
//spritesheet画画的部分,不清楚的可以看昨天的文章![传送门](https://ithelp.ithome.com.tw/articles/10279291)
this.currentFrame = this.currentFrame % this.totalFrames;
this.srcX = this.currentFrame * this.spriteWidth;
this.frameDrawn++;
if(this.frameDrawn>=10){
this.currentFrame++;
this.frameDrawn=0;
}
this.Draw();
}
Jump () {
//在地上的时候
if (this.grounded && this.jumpTimer == 0) {
this.jumpTimer = 1;
this.dy = -this.jumpForce;
} else if (this.jumpTimer > 0 && this.jumpTimer < 15) {
//按压越久,jumptimer越大, y的位置越高
this.jumpTimer++;
this.dy = - this.jumpForce - (this.jumpTimer / 50);
//jumptimer除以的系数越小,可以跳越高
}
}
Draw () {
ctx.drawImage(this.spriteSheet, this.srcX, this.srcY,this.spriteWidth, this.spriteHeight, this.x, this.y,this.w, this.h);
}
}
再来是敌人的class
class Obstacle {
constructor (x, y, w, h, t) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.t = t; //type = 文字和颜色
}
Update () {
//敌人的位置, gamespeed会在start时候宣告
//其实老妹没动,是敌人一直往左边滑
this.x -= gameSpeed;
this.Draw();
}
Draw () {
ctx.beginPath();
ctx.fillStyle = this.t.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
ctx.fillStyle = '#ffffff';
ctx.fillText(this.t.text, this.x + 40, this.y+ 20); //写上渣男、加班、经痛的文字哈
ctx.closePath();
}
}
写分数
class Text {
constructor (t, x, y, a, c, s){
this.t = t;
this.x = x;
this.y = y;
this.a = a;
this.c = c;
this.s = s;
}
Draw () {
ctx.beginPath();
ctx.fillStyle = this.c;
ctx.font = this.s + "px sans-serif";
ctx.textAlign = this.a;
ctx.fillText(this.t, this.x, this.y);
ctx.closePath();
}
}
这边功能主要就是
A.createCanvas() 呼叫—> B.Update () 然後会不停呼叫自己,重新绘制Canvas
在createCanvas里面,就会利用主角和文字的Class去做内容。
Update() 里面重要的功能:
1.createObstacle() —>制作障碍物
2.spawnObstacles:撒障碍物—>设置障碍物的x座标,会不断更新=加快速度移动感觉
3.重置游戏:当主角撞到障碍物就会重置速度分数等
4.setScore(); —>随着主角越过越多障碍物,分数要一直更新
5.player.Animate(); —> 让player动起来
6.requestAnimationFrame(Update);—>不断呼叫自己,重复上述动作
大致上说明如上,详细code:
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
// Variables
let score;
let scoreText;
let highscore;
let highscoreText;
let player;
let gravity;
let obstacles = [];
let gameSpeed;
let keys = {};
let obstacleType = [{text: '加班', color: '#4530ff'},{text: '渣男', color: '#009c27'},{text: '经痛', color: '#ff3e30'}];
let initialSpawnTimer = 200; //数字越小越快归零就会越多敌人
let spawnTimer = initialSpawnTimer;
// Event Listeners
document.addEventListener('keydown', function (evt) {
keys[evt.code] = true;
});
document.addEventListener('keyup', function (evt) {
keys[evt.code] = false;
});
//重要Function
//A.游戏最开始的绘制
function createCanvas () {
canvas.width = 648;
canvas.height = 572;
ctx.font = "20px sans-serif";
gameSpeed = 3;
gravity = 1;
//做玩家
player = new Player(25, 0, 80, 180);
getScore();
scoreText = new Text("Score: " + score, 25, 25, "left", "#ffffff", "20");
highscoreText = new Text("Highscore: " + highscore, canvas.width - 25, 25, "right", "#ffffff", "20");
//呼叫Update
requestAnimationFrame(Update);
}
//A. 相关:取得以前的分数
function getScore(){
score = 0;
highscore = 0;
//看local storage有没有之前玩的分数~
if (localStorage.getItem('highscore')){
highscore = localStorage.getItem('highscore');
}
}
//重要Function
//B. 游戏进行时Update会一直呼叫自己
function Update () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
spawnTimer--;
if (spawnTimer <= 0) {
createObstacle(); //1.制作敌人
spawnTimer = initialSpawnTimer - gameSpeed * 8; //数字越来越小=制作敌人速度越来越快
if (spawnTimer < 60) {
spawnTimer = 60; //但最快还是有60
}
}
//2.Spawn enimies,撒敌人更新位置,并且看是不是撞到了
spawnObstacles();
//4.设置分数
setScore();
//5.让主角动起来!
player.Animate();
gameSpeed += 0.003;
requestAnimationFrame(Update); //6.重复呼叫自己
}
//1.做障碍物
function createObstacle () {
//一次只做一个
let size = RandomIntInRange(40, 70);
let typeNum = RandomIntInRange(0, 2);
let type = RandomIntInRange(0, 1);
let obstacle = new Obstacle(canvas.width + size, canvas.height - size, size, size, obstacleType[typeNum]);
//做高高的障碍物
if (type == 1) {
obstacle.y -= player.originalHeight - 10;
}
obstacles.push(obstacle);
}
//1.相关 做障碍物使用的函数
function RandomIntInRange (min, max) {
return Math.round(Math.random() * (max - min) + min);
}
//2.撒敌人
function spawnObstacles(){
for (let i = 0; i < obstacles.length; i++) {
let o = obstacles[i];
//移除滑出视窗的
if (o.x + o.w < 0) {
obstacles.splice(i, 1);
}
//3.撞到障碍物的话,重置游戏
if (
player.x < o.x + o.w &&
player.x + player.w > o.x &&
player.y < o.y + o.h &&
player.y + player.h > o.y
) {
obstacles = [];
score = 0;
spawnTimer = initialSpawnTimer;
gameSpeed = 3;
window.localStorage.setItem('highscore', highscore);
}
o.Update(); //放置敌人位置=敌人移动的速度
}
}
4. 设定分数
function setScore(){
score++;
scoreText.t = "Score:" + score;
scoreText.Draw();
if (score > highscore) {
highscore = score;
highscoreText.t = "Highscore: " + highscore;
}
highscoreText.Draw();
}
//最开始呼叫
createCanvas();
今天的成果在这边玩
原始码放这里:Class建构式 和 这里:游戏的功能
(但上面的有整理,原始码没整理QQ)
这是我第一次写游戏!!
JS底还不够扎实,也是第一次写ES6以後才有的class功能。XD
这次铁人赛参考很多人的写法,也给自己不同的程序码思维。
一样有任何批评指教,请留言!!
祝福大家都能战胜经痛/头痛/各种痛 & 加班 & 和渣男/女
今天来用kotlin实作一个BaseActivity,方便以後跳页传值使用 fun start(ne...
前言: 人工智慧这个名词相信大家都一定常常听到看到,不管什麽产品都要是智能的,手机上更是有大量的运用...
前言 该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系...
Azure face service: Face recognition- 让你的机器人认得你 人脸...
作业系统L5-行程排班 CPU-I/O分割 简介:CPU分割後接着IO分割 CPU排班程序 短程排班...