介紹
最近用 Html 制作了一款洛克人游戲,直接上效果圖:

預覽地址
效果鏈接(只看看不如親自體驗一下):
http://h5demo.yyfuncdn.com/res/gameDemo/man/
手機掃描運行:

最近用 pixi 和 js 制作了一款洛克人游戲,致敬一下經典,簡單實作了人物的跑動、跳躍、以及鏡頭跟隨的效果,在手機及網頁做了相關適配,下面是手機橫屏的一些操作效果圖:
接下來我們來看一看原始碼,是如何實作這些功能的
先給大家分享到這里~更多的可以下載原始碼看一看,以下是原始碼下載鏈接:
點擊下載
(http://h5demo.yyfuncdn.com/res/gameDemo/man.zip)
這是所有的專案檔案

index 頁面為這個專案的運行檔案,主要用于創建舞臺以及適配,利用 Game 物件來創建整個游戲場景
完整代碼
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<script src="js/pixi.min.js"></script>
<script src="js/game.js"></script>
<script src="js/people.js"></script>
<script src="js/ground.js"></script>
<script src="js/button.js"></script>
<script src="js/Animation.js"></script>
<script src="js/AnimationData.js"></script>
<style>
body{
margin: 0;
}
</style>
</head>
<body>
<script>
//判斷橫豎屏及重繪
function orientationChange() {
switch(window.orientation) {
case 0: //豎屏
alert("建議在橫屏狀態下瀏覽");
window.localStorage.setItem('name','a');
break;
case -90: //橫屏
var shu=window.localStorage.getItem('name');
console.log(shu)
if(shu=='a'){
window.location.reload();
window.localStorage.setItem('name','b');
}
//alert('豎屏')
orientation = 'portrait';
break;
case 90: //橫屏
var shu=window.localStorage.getItem('name')
if(shu=='a'){
window.location.reload();
window.localStorage.setItem('name','b');
}
//alert('豎屏')
orientation = 'portrait';
break;
case 180: //豎屏
alert("建議在橫屏狀態下瀏覽");
window.localStorage.setItem('name','a');
break;
};
};
window.addEventListener("load", orientationChange, false);
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", orientationChange, false);
//獲取當前螢屏寬高
var html = document.getElementsByTagName('html')[0];
var phoneHeight = html.clientHeight;
var phoneWidth = html.clientWidth;
//創建當前螢屏大小舞臺
var app = new PIXI.Application(phoneWidth,phoneHeight);
document.body.appendChild(app.view);
//創建游戲界面
var game = new Game();
app.stage.addChild(game.gameCeng);
//操作提示
var text = new PIXI.Text("鍵盤操作:A 左移動 D 右移動 K 跳躍");
text.x = 50;
text.y = 50;
text.style.fill = 0xffffff;
app.stage.addChild(text);
//創建幀頻影片
app.ticker.add(animate);
var frame = 1;
function animate() {
if(frame >= Math.round(app.ticker.FPS / 60)) {
game.update();
frame = 0;
}
frame ++;
}
</script>
</body>
</html>
接下來再創建整個游戲場景,即 Game 物件,里面創建圖層用于碼放所有的背景、角色、按鈕,并且在最后還添加了鍵盤事件用于操控角色
function Game(){
//當前螢屏寬高比
var screenScale = phoneHeight / phoneWidth;
//自適應縮放比例
var scale = (phoneHeight / 561);
//游戲元素圖層
this.gameCeng = new PIXI.Container();
//游戲元素圖層場景圖層
this.gameCjCeng = new PIXI.Container();
this.gameCeng.addChild(this.gameCjCeng);
//游戲元素人物場景圖層
this.gameManCeng = new PIXI.Container();
this.gameCeng.addChild(this.gameManCeng);
//背景
var background = new PIXI.Sprite.fromImage("img/bg.png");
this.gameCjCeng.addChild(background);
background.width = phoneWidth;
background.height = phoneHeight;
//背景圖寬高比
var bgScale = 640 / 960;
if(bgScale > screenScale) {
background.width = phoneWidth;
background.height = 640 * (phoneWidth / 960);
} else {
background.width = 960 * (phoneHeight / 640);
background.height = phoneHeight;
}
//路面
var ground = new Ground();
this.gameCjCeng.addChild(ground.groundView);
//人物
var people = new People();
ground.groundView.addChild(people.peopleView);
people.player.init(action_data);
people.player.play("stand")
//向左按鈕
var leftBtn = new Button("img/left.png",0,phoneHeight*0.2,phoneHeight - 150*scale,people);
this.gameManCeng.addChild(leftBtn.buttonView);
//向右按鈕
var rightBtn = new Button("img/right.png",1,phoneHeight*0.2+150*scale,phoneHeight - 150*scale,people);
this.gameManCeng.addChild(rightBtn.buttonView);
//跳躍按鈕
var jumpBtn = new Button("img/jump.png",2,phoneWidth - 200*scale,phoneHeight - 150*scale,people);
this.gameManCeng.addChild(jumpBtn.buttonView);
this.update = function() {
//人物移動
people.update();
//地面跟隨
ground.groundFollow(people.peopleView);
}
//鍵盤控制
document.onkeydown = function (e) {
var e = e || window.event; //標準化事件物件
var keyCode = e.keyCode;
if(keyCode == 75) { //k 跳躍
people.textureType = 2;
people.isJump = true;
} else if (keyCode == 65) { //a 左
if(people.textureType != 2) {
people.textureType = 1;
}
people.peopleView.scale.x = -1;
people.isMove = true;
people.speedX = -(phoneWidth / 180);
} else if (keyCode == 68) { //d 右
if(people.textureType != 2) {
people.textureType = 1;
}
people.peopleView.scale.x = 1;
people.isMove = true;
people.speedX = phoneWidth / 180;
}
}
document.onkeyup = function (e) {
var e = e || window.event; //標準化事件物件
var keyCode = e.keyCode;
if(keyCode == 65 || keyCode == 68) { //a 左 d 右
people.isMove = false;
people.speedX = 0;
if(people.textuerType != 2 && people.peopleView.y == -phoneHeight*0.3/scale) {//判斷人物是否在地面
people.player.play("stand");
people.textureType = 3;
}
}
}
}
整個人物物件我封裝到了 People 物件中,并寫了他的移動、跳躍的方法,人物影片的紋理切換我封裝成了影片工具 Animation 物件,即存盤好所有的紋理圖及播放間隔時間即可
function People(){
var self = this;
var scale = phoneHeight / 561;//自適應縮放比例
this.textureType = 3;//人物運動型別:1 為跑動 2 為跳躍 3 為靜止
this.player = new Animation();//人物影片
this.peopleView = this.player.sprite;//人物圖片
this.peopleView.x = phoneWidth*0.3/scale;//人物 x 坐標 & 在所有螢屏位置自適應
this.peopleView.y = -phoneHeight*0.3/scale;//人物 y 坐標 & 在所有螢屏位置自適應
this.peopleView.scale.x = 1;//人物圖片翻轉
this.peopleView.anchor.set(0.6,1);//人物圖片錨點設定
this.jumpSpeed = -7;//跳躍距離&跳躍初始速度
this.speedX = 0;//水平速度
this.speedY = this.jumpSpeed;//垂直速度
this.isMove = false;//人物移動開關量
this.isJump = false;//人物跳躍開關量
this.distance = 0;//移動距離
this.peopleMove = function() {//人物移動
if(this.isMove) {
//人物跑動影片
if(this.textureType == 1) {
self.player.play("run");
}
//控制人物移動
if(this.peopleView.x <= 0 && this.speedX < 0) { // 判斷左極限
this.peopleView.x = 0;
} else if (this.peopleView.x >= 2300 && this.speedX > 0) { // 判斷右極限
this.peopleView.x = 2300;
} else {
this.peopleView.x += this.speedX;
}
}
}
this.peopleJump = function() {//人物跳躍
if(this.isJump) {
//人物跳躍影片
this.speedY += 0.2;
this.peopleView.y += this.speedY;
if(this.speedY < 0){
this.player.play("jump");
}else{
this.player.play("fall");
}
if(this.peopleView.y >= -phoneHeight*0.3/scale) {//結束跳躍
this.peopleView.y = -phoneHeight*0.3/scale;
this.isJump = false;
this.speedY = this.jumpSpeed;
if(self.isMove) {
this.textureType = 1;
this.player.play("run");
} else {
this.textureType = 3;
this.player.play("fallover");
this.player.play("stand");
}
}
}
}
this.update = function(){
this.peopleMove();
this.peopleJump();
this.player.action();
}
}
所有的按鈕都是共用一個 Button 物件創建,每次傳入對應資料即可,其方法根據資料的不同系結不同的方法
function Button(url,type,x,y,object) {//路徑 型別 x坐標 y坐標 控制物件
var self = this;
var scale = phoneHeight / 561;
this.url = url;
this.type = type;// 0 :為向左按鈕 1 :為向右按鈕 2:為跳躍按鈕
this.buttonView = new PIXI.Sprite.fromImage(this.url);
this.buttonView.x = x;
this.buttonView.y = y;
this.buttonView.width = 100*scale;
this.buttonView.height = 100*scale;
this.buttonView.interactive = true;
this.speedX = phoneWidth / 180;
this.buttonView.on("pointerdown",function() {//按下
if(self.type == 0) {//左按鈕
if(object.textureType != 2) {
object.textureType = 1;
}
object.peopleView.scale.x = -1;
object.isMove = true;
object.speedX = -self.speedX;
} else if (self.type == 1) {//右按鈕
if(object.textureType != 2) {
object.textureType = 1;
}
object.peopleView.scale.x = 1;
object.isMove = true;
object.speedX = self.speedX;
} else if (self.type == 2) {//跳躍按鈕
object.textureType = 2;
object.isJump = true;
}
})
this.buttonView.on("pointerup",function() {//抬起
if(self.type == 0 || self.type == 1) {//左按鈕 & 右按鈕
object.isMove = false;
object.speedX = 0;
if(object.textuerType != 2 && object.peopleView.y == -phoneHeight*0.3/scale) {//判斷人物是否在地面
object.player.play("stand");
object.textureType = 3;
}
}
})
}
角色跟隨這里是我最滿意的地方,為了體驗的舒適并沒有做成同步移動,而是跟隨的效果,這里是利用的角色系結在地面圖片上,保證角色始終保持在中間位置,當脫離中間位置,地面跟隨移動,保證其位置始終在中間
function Ground() {
var self = this;
var scale = phoneHeight / 561;//自適應縮放比例
this.groundView = new PIXI.Sprite.fromImage("img/ground.png");
this.groundView.anchor.set(0,1);
this.groundView.y = phoneHeight+phoneHeight*0.2;
this.groundView.height = phoneHeight;
this.groundView.width = 2300 * scale;
this.speedX = -5;
this.distance = 0;
this.groundFollow = function(obj) {
var obj = obj.getGlobalPosition();//獲取角色當前視窗位置
if(obj.x != phoneWidth/2) {//判斷角色位置偏移視窗中心點
var deviation_x = obj.x-phoneWidth/2;//計算角色X值與視窗中心點偏移距離
var correct_speed = deviation_x/10;//計算角色矯正速度
self.groundView.x -= correct_speed;
if(self.groundView.x >= 0) {//判斷場景為最左側時矯正場景位置
self.groundView.x = 0;
correct_speed = 0;
} else if (self.groundView.x <= phoneWidth-self.groundView.width) {//判斷場景為最右側時矯正場景位置
self.groundView.x = phoneWidth-self.groundView.width;
correct_speed = 0;
}
}
if(obj.y != phoneHeight*0.9) {//判斷角色位置偏移視窗中心點
var deviation_y = obj.y-phoneHeight*0.9;//計算角色Y值與視窗中心點偏移距離
var correct_speed = deviation_y/10;//計算角色矯正速度
self.groundView.y -= correct_speed;
if(self.groundView.y >= phoneHeight+phoneHeight*0.4) {//判斷場景為最上側時矯正場景位置
self.groundView.y = phoneHeight+phoneHeight*0.4;
correct_speed = 0;
} else if (self.groundView.y <= phoneHeight+phoneHeight*0.2) {//判斷場景為最下側時矯正場景位置
self.groundView.y = phoneHeight+phoneHeight*0.2;
correct_speed = 0;
}
}
}
}
下面的即是我影片方法的封裝,類似相關的影片都可以用其實作,非常的通用
function Animation() {
var self = this;
this.sprite = new PIXI.Sprite();
this.frameData = {};
this.frameIndex = 0;
this.actionName = "";
this.waitTime = 0;
this.isPlay = true; //是否播放狀態
this.targetFrame = -1; //目標幀
this.init = function(frameData) {
this.frameData = frameData;
}
this.play = function(actionName) {
if(self.actionName != actionName) {
self.actionName = actionName;
self.frameIndex = 0;
self.waitTime = 0;
self.action(true);
}
}
this.update = function() {
this.action();
}
this.action = function(isUpdate = false) {
var frameArr = self.frameData[self.actionName];
if(self.frameIndex == frameArr.length) {
self.frameIndex = 0;
}
//切換紋理
var frameInfo = frameArr[self.frameIndex];
if(frameInfo.wait == self.waitTime || isUpdate == true) {
this.sprite.texture = new PIXI.Texture.fromImage(frameInfo.url);
this.frameIndex ++;
self.waitTime = 0;
} else {
self.waitTime ++;
}
}
}
人物影片資料
var action_data = {
"stand": [
{"url":"img/Z0001.png", "wait": 20, "frame": 1},
{"url":"img/Z0002.png", "wait": 15, "frame": 2},
{"url":"img/Z0003.png", "wait": 15, "frame": 3},
{"url":"img/Z0004.png", "wait": 15, "frame": 4},
{"url":"img/Z0005.png", "wait": 15, "frame": 5},
{"url":"img/Z0006.png", "wait": 15, "frame": 6},
],
"run": [
{"url":"img/P0001.png", "wait": 5, "frame": 1},
{"url":"img/P0002.png", "wait": 5, "frame": 2},
{"url":"img/P0003.png", "wait": 5, "frame": 3},
{"url":"img/P0004.png", "wait": 5, "frame": 4},
{"url":"img/P0005.png", "wait": 5, "frame": 5},
{"url":"img/P0006.png", "wait": 5, "frame": 6},
{"url":"img/P0007.png", "wait": 5, "frame": 7},
{"url":"img/P0008.png", "wait": 5, "frame": 8},
{"url":"img/P0009.png", "wait": 5, "frame": 9},
{"url":"img/P0010.png", "wait": 5, "frame": 10},
],
"jump": [
{"url":"img/T0001.png", "wait": 5, "frame": 1},
{"url":"img/T0002.png", "wait": 5, "frame": 2},
{"url":"img/T0003.png", "wait": 5, "frame": 3},
{"url":"img/T0004.png", "wait": 5, "frame": 4},
{"url":"img/T0005.png", "wait": 5, "frame": 5},
{"url":"img/T0006.png", "wait": 5, "frame": 6},
{"url":"img/T0007.png", "wait": 5, "frame": 7},
{"url":"img/T0008.png", "wait": 5, "frame": 8},
{"url":"img/T0009.png", "wait": 5, "frame": 9},
{"url":"img/T0010.png", "wait": 120, "frame": 10},
],
"fall": [
{"url":"img/T0007.png", "wait": 5, "frame": 7},
{"url":"img/T0008.png", "wait": 5, "frame": 8},
{"url":"img/T0009.png", "wait": 5, "frame": 9},
{"url":"img/T0010.png", "wait": 5, "frame": 10},
],
"fallover": [
{"url":"img/T0011.png", "wait": 5, "frame": 9},
{"url":"img/T0012.png", "wait": 5, "frame": 10},
]
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/273596.html
標籤:其他
上一篇:FatMouse‘s Speed
下一篇:C1第一個任務
