前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Cocos Creator] 链表的应用之贪吃蛇(附项目)

[Cocos Creator] 链表的应用之贪吃蛇(附项目)

作者头像
陈皮皮
发布2020-07-10 16:56:14
7410
发布2020-07-10 16:56:14
举报
文章被收录于专栏:菜鸟小栈菜鸟小栈

前言

今天我们介绍的项目,是各位大多数人都有玩过,就算没玩过也不可能没听过的一款经典游戏,那就是 贪 吃 蛇 。

制作一个贪吃蛇游戏也有许多不同的方法,这篇文章将向大家展示的是如何使用 链表 的原理来制作一个贪吃蛇。

效果展示

吃吃吃

正文

整体思路

1. 首先还是需要简单说下链表(LinkedList)的定义:链表实际上是一种链式数据结构链表中的每一个数据节点都保存了其下一个节点的指针(也就是引用)

2. 蛇就是由一节一节的身体构成的(当然头也是身体的一部分),我们控制头部的移动头部会带着第一节身体移动,然后每一节身体移动的时候都会带着下一节身体一起移动(禁止套娃)。

代码实现

提示:这里只展示最主要部分的代码,完整项目点击文章底部 阅读原文 获取

1. 首先我们先实现一个链表节点的组件 Body 。该组件需要保存下一个节点的引用上一个位置,以及设置下一节点移动的函数:

代码语言:javascript
复制
const { ccclass, property } = cc._decorator;

@ccclass
export default class Body extends cc.Component {

    @property({ type: Body, tooltip: '下一节身体' })
    protected nextBody: Body = null;

    protected lastPos: cc.Vec2 = null; // 上一个位置

    /**
     * 设置下一节身体
     * @param body 节点
     */
    public setNextBody(body: Body) {
        this.nextBody = body;
        body.node.setPosition(this.lastPos);
    }

    /**
     * 移动该节点
     * 同时让下一个节点(如果有的话)移动到该节点之前的位置
     * @param nextPos 目标位置
     */
    public move(nextPos: cc.Vec2) {
        // 保存当前位置
        this.lastPos = this.node.getPosition();
        // 自身移动到新的位置
        this.node.setPosition(nextPos);
        // 让下一个节点移动到之前的位置
        if (this.nextBody) this.nextBody.move(this.lastPos);
    }

}

2. 实现蛇头部的组件 Head ,该组件继承于 Body ,所以 Head 拥有 Body 的所有属性以及函数。同时我们需要给 Head 新增一些头部特有的功能,比如移动和吃:

代码语言:javascript
复制
import Body from "./Body";
import PoolManager from "../manager/PoolManager";
import { GameEvent } from "../../eazax-ccc/core/GameEvent";

const { ccclass, property } = cc._decorator;

export enum Direction {
    Up = 1, // 上
    Down, // 下
    Left, // 左
    Right // 右
}

@ccclass
export default class Head extends Body {

    private timer: number = 0; // 计时器

    private moveInterval: number = 0.2; // 移动间隔

    private moveDistance: number = 20; // 移动距离

    private bodyList: Body[] = []; // 身体节点集合

    private curDirection: Direction = Direction.Up; // 当前移动的方向

    private nextDirection: Direction = Direction.Up; // 下次移动的方向

    private isAlive: boolean = false; // 是否活着

    private static instance: Head = null; // 实例

    /**
     * 获取头部位置
     */
    public static get pos() { return this.instance.node.getPosition(); }

    protected onLoad() {
        Head.instance = this;

        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);

        GameEvent.on('gameinit', this.onGameInit, this);
        GameEvent.on('gamestart', this.onGameStart, this);
    }

    protected onDestroy() {
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);

        GameEvent.off('gameinit', this.onGameInit, this);
        GameEvent.off('gamestart', this.onGameStart, this);
    }

    protected update(dt: number) {
        if (!this.isAlive) return;
        // 计时
        this.timer += dt;
        if (this.timer >= this.moveInterval) {
            this.timer -= this.moveInterval;
            // 移动到下一个位置
            switch (this.nextDirection) {
                case Direction.Up:
                    this.curDirection = Direction.Up;
                    this.move(cc.v2(this.node.x, this.node.y + this.moveDistance));
                    break;
                case Direction.Down:
                    this.curDirection = Direction.Down;
                    this.move(cc.v2(this.node.x, this.node.y - this.moveDistance));
                    break;
                case Direction.Left:
                    this.curDirection = Direction.Left;
                    this.move(cc.v2(this.node.x - this.moveDistance, this.node.y));
                    break;
                case Direction.Right:
                    this.curDirection = Direction.Right;
                    this.move(cc.v2(this.node.x + this.moveDistance, this.node.y));
                    break;
            }
        }
    }

    /**
     * 初始化
     */
    private onGameInit() {
        this.isAlive = false;
        this.node.setPosition(0, 0);
        this.nextDirection = Direction.Up;
        for (let i = 0; i < this.bodyList.length; i++) {
            PoolManager.put(this.bodyList[i].node);
        }
        this.bodyList = [];
        this.nextBody = null;
    }

    /**
     * 动起来
     */
    private onGameStart() {
        this.onGameInit();
        this.isAlive = true;
    }

    /**
     * 吃吃吃,长长长
     */
    private eat(food: cc.Node) {
        cc.log('eat');
        // 食物吃掉
        PoolManager.put(food);
        // 获取一节身体
        let node = PoolManager.get('body');
        node.setParent(this.node.parent);
        // 设置身体位置并保存身体的引用
        let body = node.getComponent(Body);
        if (this.bodyList.length > 0) this.bodyList[this.bodyList.length - 1].setNextBody(body);
        else this.setNextBody(body);
        this.bodyList.push(body);
        // 发射事件
        GameEvent.emit('snakeeat');
    }

    /**
     * GG
     */
    private die() {
        cc.log('GG');
        this.isAlive = false;
        GameEvent.emit('snakedie');
    }

    /**
     * 键盘回调
     * @param event 按键事件
     */
    private onKeyDown(event: any) {
        switch (event.keyCode) {
            case cc.macro.KEY.up:
                if (this.curDirection !== Direction.Down) this.nextDirection = Direction.Up;
                break;
            case cc.macro.KEY.down:
                if (this.curDirection !== Direction.Up) this.nextDirection = Direction.Down;
                break;
            case cc.macro.KEY.left:
                if (this.curDirection !== Direction.Right) this.nextDirection = Direction.Left;
                break;
            case cc.macro.KEY.right:
                if (this.curDirection !== Direction.Left) this.nextDirection = Direction.Right;
                break;
        }
    }

    /**
     * 碰撞回调
     * @param other
     * @param self
     */
    protected onCollisionEnter(other: cc.BoxCollider, self: cc.BoxCollider) {
        switch (other.node.name) {
            case 'food':
                this.eat(other.node);
                break;
            case 'body':
            case 'border':
                this.die();
                break;
        }
    }

}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 菜鸟小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档