魔的石板和被詛咒的犬公主是一款畫風超級可愛的2D的日系SLG游戲,游戲內容的制作也相當不錯。游戲內可以選擇英語、日語和繁體中文三種語言,是官方漢化的版本。游戲采用二次元動漫風格打造而成,擁有十分精美的人物立繪以及場景長途,為你帶來更加良好的視覺體驗。玩家在游戲中會根據自己不同的操作來解鎖出不同的劇情,玩法十分自由,開放式的游戲結局,為你帶來許多意想不到的游戲體驗!在游戲里,玩家需要在這款手游中,去拯救公主,從而踏上末知的道路。玩家需要攻克重重困難,去拯救公主,將她拯救出來。惡魔石板和被詛咒的犬公主手游設計了經典的宮廷風,偏向西方世界的經典場景。
下載地址:http://www.32r.com/app/78321.html
在很久很久以前,有個看上去就不咋靠譜的王國
王國最大的熊孩子——小公主
因為皮,不小心把自己封在了一面寄宿了惡魔的鏡子里面!
這下可完了不僅再也不能到處搗亂,甚至可以預見要在這個鬼鏡子里面過一輩子?
國王著急上火心急如焚,甚至一天只能睡8個小時的覺!
(我尋思這也不著急啊……)
于是,他一拍腦袋想出來一個辦法
只要能救公主出來,我就將她嫁給這位勇士!
前來嘗試的勇者們絡繹不絕,但是一個個全都失敗了
而你,是個奇怪的中年大叔,帶著猥瑣的笑容進入了王宮……
不過,寄宿在鏡子中的惡魔卻想出了一個奇怪的方法決勝負
大名鼎鼎的友情泯滅游戲精神崩潰!
1、游戲中玩家的任務就是想辦法去把公主揪出來。
2、拯救公主的路途上會遇到很多的艱難險阻,但那都不是問題。
3、只要我們玩家能有耐心刷級刷裝備過關還是很簡單的。
4、傳統的rpg玩法,以打怪升級為輔,劇情為主,給人 不一樣的體驗。
5、豐富的游戲內容以及超多的精彩小劇情,讓玩家能夠捧腹大笑。
6、清新脫俗的游戲畫面,卡通簡約的游戲場景,帶給玩家一種親切的感覺。
1、傳統的rpg玩法,以打怪升級為輔,劇情為主,給人 不一樣的體驗。
2、豐富的游戲內容以及超多的精彩小劇情,讓玩家能夠捧腹大笑。
3、惡魔石板和被詛咒的犬公主有著趣味性十足的游戲劇情,加上可愛的游戲畫風,能讓人非常喜歡這款游戲。
4、游戲中玩家可以經常和公主對話,每一次都能有一些不一樣的對話哦!
1、豐富的養成元素,可以查看角色的各種具體數值,全方位了解人物;
2、有著諸多的變化,屏幕的靚麗特性,互動的十足,期待不同人群的相遇;
3、結合了浪漫的戀愛元素,生動的對話與場景,讓玩家獲得最真實的體驗。
那么本篇攻略的最大難點和關鍵就在于知道有多少格子了!知道表格幾行幾列,就可以把字母對應記下來,由于游戲沒有時間限制,你大可以慢慢看哪些字母重復的,就可以翻牌了!另外你和惡魔的挑戰必須一次性通關,中途輸了只能從頭來過,雖然它也有好處可以增加點數?你完全可以失敗無數次把前兩行點數刷滿,不過愛動腦的妹推醬怎么可能硬肝?
第一局: 5列6行,先從第1行最中間開始,然后是最后1行最中間,運氣好可以碰上一樣的。
第一局按妹推醬的表格5列6行
注意注意!因為前幾次失敗已經積累了點數可以透視到周圍的字母,所以開局沒翻很多的時候上下左右就沒必要再點一次去看它是啥,反而會給惡魔暴露出你點到的剛想匹配的字母,前期可能還好,后面兩局如果繼續這樣,惡魔也不會手軟,連續地把你提供的重復字母給點掉了。(玩過的自然懂)
第二局:6列7行,圖片里多畫了一行,劃了條橫線表示不算數。第二局玩的時間最久,因為石碑大小是一樣的,里面的方塊會變小,所以第二局第一次玩的時候根本不知道幾行幾列所以很難找準位置記錄字母。為此妹推醬的方法是這樣的,先不畫表格,找準位置,點惡魔形象左邊第一行那個位置,記錄字母,下左右的字母也出來了,隔一格在右邊再點一次,也會有下左右的字母出來,這個時候就可以大致分辨出有幾列了。
如圖所示,可以肉眼分辨出幾行幾列,不要盲目往中間湊。
第三局:8行7列,這一把開始雖然越來越難,字母也是加了很多,但方法在手,就是一路由我掌控了,惡魔只點了三回吧,不需要全部字母都知道,只要關注石碑下面,左邊藍色是勇者“我”,成功翻牌一次就得一塊藍塊,誰先到最中間誰勝利。
第四局:9行8列,有個小機關,可能其他玩家遇到的不一樣,就是有同樣的字母K,一個是紅色,一個是灰色,兩個不能匹配,必須字母顏色一樣才行。
這個有點亂,四把一口氣都贏了以后惡魔才能認可你,把公主換回來,后續劇情不多贅述。
先來預覽,咳咳,這個比上次那個地鼠會好看點……
效果
代碼是可以設置難度的,3 就是 9,9 就是 81……
相比來說,此程序難度可是遠遠高過打地鼠的,希望小伙伴能跟上~
html
<header> <button='Game.restart()'>重新開始</button> <button id="download"='Game.openImage()'>新標簽打開圖片</button> </header> <main> <section class="game-area"> <img id='background-img' src="#" alt="backgroundImg"> <div id="cut-imgs"></div> </section> </main>
header 好理解,注意其中的“新標簽打開圖片”相當于過關福利,平常是隱藏的。
之所以內容這么少,是因為主邏輯這一塊的 html 代碼許多屬性都是動態的,所以寫死沒有價值,需要在 js 里面動態生成與刪除,所以基本都移到 js 里面了,這里只要看到幾個容器就行。其中 #cut-imgs 是下面游戲的容器。
css
.cut-img { position: absolute; top: 0; left: 0; border: 0; padding: 0; transition: transform .3s linear; box-sizing: border-box; } html, body { height: 100%; margin: 0; } body { display: flex; flex-direction: column; justify-content: center; align-items: center; } header, main, footer { width: 50%; } header { display: flex; justify-content: space-between; } main { position: relative; height: auto; } .game-area { position: relative; height: auto; } #background-img { max-width: 100%; max-height: 100%; vertical-align: top; opacity: 0; } #cut-imgs { position: absolute; top: 0; left: 0; display: flex; flex-wrap: wrap; width: 100%; height: 100%; } button:focus { outline: none; } .selected { border: 1px solid blue; } #download { display: none; }
css 里面注意動畫的設置,還有切片圖像的處理。
這里相信第一反應下面是把一整張圖切 9 份。其實不然,不過是 9 個容器(本例用的是 button)分別展示了不同圖片的一部分,然后控制相關的容器即可。
所有容器的位置都是左上角,設置偏移量使其在各個位置上,具體設置方法在 js 里面。
js
const Game={ // 重新開始游戲 restart() { // 清空已有數據,重置按鈕 this.reset() const level=this.config.level // 計算 position 的參數 const positionParam=1 / (level - 1) * 100 const imgUrl=this.config.imgUrl=`https://h5games-dom.oss-cn-hangzhou.aliyuncs.com/puzzle/${~~(Math.random() * 5)}.png` const backgroundImg=document.querySelector('#background-img') backgroundImg.src=imgUrl // 獲取樣式表 const styleSheet=this.config.imgCutStyle=document.styleSheets[0] // 如果添加過自定義則刪除 let firstRule=styleSheet.rules[0] if (firstRule.selectorText==='.custom') styleSheet.deleteRule(0) let scale=1 / this.config.level * 100 + '%' styleSheet.insertRule(`.custom { width: ${scale}; height: ${scale}; background: url(${imgUrl}) no-repeat; background-size: ${this.config.level * 100}%; }`, 0) backgroundImg.=()=> { for (let i=0, j=Math.pow(this.config.level, 2); i < j; i++) { this.config.cutImgsCountArray.push(i) } // DOM字符串 let cutImgsStr='' this.getInitialSort() this.config.cutImgsCountArray.forEach((num, index)=> { // 保存正確的變化,做判斷是否獲勝的基礎 this.config.trueTransforms.push(`translate(${index % level * 100}%, ${~~(index / level) % level * 100}%)`) // 這里設置會變動的 style const transform=`transform: translate(${num % level * 100}%, ${~~(num / level) % level * 100}%);` const backgroundPosition=`background-position: ${index % level * positionParam}% ${~~(index / level) % level * positionParam}%;` // 全部在左上初始位置,設置偏移量即可 cutImgsStr +=`<button class="cut-img custom" data-index=${index}="Game.click(event)" style="${transform + backgroundPosition}"></button>` }) document.querySelector('#cut-imgs').innerHTML=cutImgsStr this.instance.cutImgs=document.querySelectorAll('.cut-img') } }, // 點擊圖片 click(e) { const index=e.target.dataset.index // 第一次點擊直接結束 if (this.tool.currentIndex===-1) { this.getCutImg(index).classList.add('selected') this.tool.currentIndex=index return } const oldCutImg=this.getCutImg(this.tool.currentIndex) // 如果點擊不是同一個再走邏輯 if (this.tool.currentIndex===index) { this.getCutImg(index).classList.remove('selected') this.tool.currentIndex=-1 } else { const newCutImg=this.getCutImg(index) const [a, b]=[newCutImg.style.transform, oldCutImg.style.transform] oldCutImg.style.transform=a newCutImg.style.transform=b this.tool.currentIndex=-1 setTimeout(()=> { download.style.display='none' oldCutImg.classList.remove('selected') newCutImg.classList.remove('selected') if (this.checkNoWin()) console.log('NoWin') else { download.style.display='block' alert('win') } }, 500); } }, // 獲取實例 getCutImg(index) { return this.instance.cutImgs[index] }, // 獲取初始的正確排序 getInitialSort() { const cal=arr=> { let length=arr.length let reverse=0 for (let i=0; i < length - 1; i++) { let n=arr[i] for (let j=i + 1; j < length; j++) { let m=arr[j] if (n > m) reverse +=1 } } return reverse } // 數組隨機排序 const randomSort=(a, b)=> Math.random() > 0.5 ? -1 : 1 // 循環直到獲取可還原的排序 while (1) { if (cal(this.config.cutImgsCountArray.sort(randomSort)) % 2===0) return } }, // 檢查是否還沒勝利 checkNoWin() { let cutImgs=this.instance.cutImgs let trueTransforms=this.config.trueTransforms for (let i=0, j=this.instance.cutImgs.length; i < j; i++) { if (cutImgs[i].style.transform !==trueTransforms[i]) return true } }, // 清空已有數據 reset() { let resetParam=this.resetParam this.config=this.deepCopy(resetParam.config) this.instance=this.deepCopy(resetParam.instance) this.tool=this.deepCopy(resetParam.tool) download.style.display='none' }, deepCopy(obj) { return JSON.parse(JSON.stringify(obj)) }, // 打開圖片 openImage() { window.open(this.config.imgUrl) }, // 重置時候的初始化參數 resetParam: { // 配置 config: { level: 3, cutImgsCountArray: [], trueTransforms: [], imgCutStyle: {}, imgUrl: '', }, // 實例 instance: { // 所有圖片的實例 cutImgs: [], }, // 記錄工具 tool: { currentIndex: -1 }, } } Game.restart()
js 就麻煩許多許多了,邏輯和功能匹配,還要用到一些冷門的知識,比如 styleSheets 相關知識,一直用框架,都快忘光了。
說起來簡單,就是把前后選中的容器進行 transform 的替換。但是需要注意是基礎的業務邏輯:
注意里面有個生成可還原的排序,具體見我之前文章:逆序數,拼圖游戲必備知識
具體基本邏輯都在代碼里面,相關注釋也有加上,喜歡喜歡的小伙伴仔細看看,試試手,練一練。
在這里就不長篇贅述了。
祝你玩的開心。
歡迎關注,如有需要 Web,App,小程序,請留言聯系。
又在別的地方嫖到了這個效果研究了億下下,制作過程如下(超詳細):
<canvas id="canvas"></canvas>
#canvas{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
box-shadow: 0 0 10px rgb(150, 150, 150);
}
position: absolute; 絕對定位。
top: 50%;
left: 50%;
transform: translate(-50%,-50%); 居中。
box-shadow: 0 0 10px rgb(150, 150, 150); 陰影。
var canvas=document.querySelector("#canvas");
var ctx=canvas.getContext('2d');
//畫布寬
var wide=600;
//畫布高
var high=600;
// 變量,判斷一次渲染中只識別按鍵一次
var kd=0;
//當前分數
var fraction=0;
//速度,就是執行定時器的時間參數
var speed=250;
// 蛇的初始顏色 紅色
var yanse=`red`;
// 蛇數組,組成蛇的每一個方塊
var snake=[];
// 食物數組
var food={};
// 蛇的移動方向,x軸:1為向右,-1為向左;y軸:1為向下,-1為向上 。不能斜著走,所以0為某軸無方向。
var diretion={
x:-1,
y:0
}
// 給畫布寬高賦值 打算畫一個長寬都是30個20px的方塊畫布
canvas.width=wide;
canvas.height=high;
function chushi(){
//蛇初始長度為3個方塊,位置如下(這個隨意)
for(let i=0;i<3;i++){
snake.push({
x: i+10,
y: 10
})
}
// 給食物一個隨機位置和隨機顏色
food={
x: parseInt(Math.random()*30),
y: parseInt(Math.random()*30),
color:`rgb(${Math.random()*255},${Math.random()*255},${Math.random()*255})`
}
}
// 繪制圖形
function draw(){
// 繪制顯示當前分數的文字
ctx.fillStyle='rgba(255,255,255,0.5)';
ctx.font="50px 仿宋";
ctx.textAlign='center';
ctx.fillText("你的分數為:"+fraction+" 分",300,300);
// 繪制方格,長寬都是30個,都是19px*19px的方格
for(let i=0;i<30;i++){
for(let j=0;j<30;j++){
ctx.fillStyle='rgba(255, 255, 255,.3)';
ctx.fillRect(i*20,j*20,19,19);
}
}
// 繪制蛇
for(let i=0;i<snake.length;i++){
temp=snake[i];
ctx.fillStyle=yanse;
ctx.fillRect(temp.x*20,temp.y*20,19,19);
// 判斷蛇頭(第一個方塊)是否與身體某個方塊重合 ,就是頭撞到身體
if(temp.x==snake[0].x&&temp.y==snake[0].y&&i!=0){
// 游戲結束,重新給初始化
alert('游戲結束~點擊確認再來一次~');
fraction=0;
snake.length=0;
chushi();
}
}
// 繪制食物,繪制一個圓形
ctx.beginPath();
ctx.fillStyle=food.color;
ctx.arc(food.x*20+9.5,food.y*20+9.5,7,0,Math.PI*2,false);
ctx.stroke();
ctx.fill();
ctx.closePath();
// 給蛇頭繪制一個字符,☆ ,好區分頭尾 ,也可省略
ctx.fillStyle='yellow';
ctx.font="15px 仿宋";
ctx.textAlign="start";
ctx.fillText("☆",snake[0].x*20+2,snake[0].y*20+14.5);
}
//更新
function update(){
// 建一個對象head,這個為蛇的新頭,通過繪制新頭,去掉尾部實現移動效果
var head={};
//判斷蛇頭是否遇到邊界,到邊界則在另一邊重新繪制 x軸
switch (snake[0].x+diretion.x){
case -1: head.x=29;break;
case 30: head.x=0;break;
// 沒到邊界則為當前位置加方向
default: head.x=snake[0].x+diretion.x;
}
//判斷蛇頭是否遇到邊界,到邊界則在另一邊重新繪制 y軸
switch (snake[0].y+diretion.y){
case -1: head.y=29;break;
case 30: head.y=0;break;
// 沒到邊界則為當前位置加方向
default: head.y=snake[0].y+diretion.y;
}
// 判斷新蛇頭是否與食物重合,就是吃到食物
if(head.x==food.x&&head.y==food.y){
//蛇的顏色為吃到食物的顏色
yanse=food.color;
// 重新給食物初始化
food={
x: parseInt(Math.random()*30),
y: parseInt(Math.random()*30),
color:`rgb(${Math.random()*255},${Math.random()*255},${Math.random()*255})`
}
//在蛇尾添加一節
let temp=snake[length-1];
snake.push(temp);
fraction+=1;
// 吃完食物速度加快
if(speed>80){
//定時器間隔減10
speed=speed-10;
// 清除原來定時器,重新繪制
clearInterval(time);
time=setInterval(function () {
kd=0;
ctx.clearRect(0, 0, wide, high);
update();
draw();
}, speed);
}
}
//添加新頭
snake.splice(0,0,head);
//去掉尾部
snake.pop();
}
//判斷點擊事件
document.addEventListener('keydown', event=>{
switch (event.keyCode){
// 按了向上鍵
case 38:
// 判斷當前不是向下移動與還沒按過鍵,否則蛇會重疊
if(diretion.y!=1&&kd==0){
// 重新給移動方向賦值
diretion.x=0;
diretion.y=-1;
kd=1;
}
break;
// 下面以此類推一樣的原理
case 39:
if(diretion.x!=-1&&kd==0){
diretion.x=1;
diretion.y=0;
kd=1;
}
break;
case 40:
if(diretion.y!=-1&&kd==0){
diretion.x=0;
diretion.y=1;
kd=1;
}
break;
case 37:
if(diretion.x!=1&&kd==0){
diretion.x=-1;
diretion.y=0;
kd=1;
}
break;
}
})
chushi();
var time=setInterval(function(){
kd=0;
ctx.clearRect(0,0,wide,high);
update();
draw();
},speed);
*請認真填寫需求信息,我們會在24小時內與您取得聯系。