开维游戏引擎实例:赛车小游戏

0 阅读3分钟

开维游戏引擎(Kaiwei Engine)是基于js设计的跨平台游戏引擎。内核c++编写,v8引擎封装游戏函数,Assembly实现htm跨平台高效运行。下面以“赛车小游戏”为实例,演示实现过程。

下载源码,打开gmp工程后,运行即可出现界面:

image.png

代码如下:

// 赛车小游戏

//  初始化游戏主屏幕
game.initSize(400,800) // 设置分辨率
game.setFPS(30); // 设置帧率

// 设置窗口log和标题
var texture = game.getResource().getTexture("logo.png"); // 另一种获取纹理数据对象
var window = game.getWindow(); //获取游戏窗口
window.setIcon(texture); // 设置窗口图标
window.setTitle("赛车小游戏");

// 创建游戏类
new Car();

// 设置键盘回调函数
game.setKeyCallBack((key,action)=>{
    if (key == Car.KEY_W || key == Car.KEY_UP){
        Car.type = "up";
    }
    else if (key == Car.KEY_S || key == Car.KEY_BOTTOM){
        Car.type =  "down";
    }
    else if (key == Car.KEY_A || key == Car.KEY_LEFT){
        Car.type =  "left";
    }
    else if (key == Car.KEY_D || key == Car.KEY_RIGHT){
        Car.type =  "right";
    }
    //log("key "+key+" action "+action+" type "+Car.type);
});

// 运行游戏
game.run();
class Car {
    // 移动距离
    static carSpeed = 30;
    static updateTime = new Date().getTime();
    static KEY_W = 87;
    static KEY_S = 83;
    static KEY_A = 65;
    static KEY_D = 68;
    static KEY_BOTTOM = 40;
    static KEY_UP = 38;
    static KEY_LEFT = 37;
    static KEY_RIGHT = 39;
    // 默认移动方向
    static type = "up";
    static gameOver = false;
    static score = 0;
    static score_text;
    static jp_button;
    static car;
    static car2;
    static scene;
    // 道路移动速度
    static roadSpeed = 10;
    static roadHeight = 1100;
    constructor() {
        Car.init();
    }

    static init(){
        let w = game.getWindow().getWidth();
        let h = game.getWindow().getHeight();
        let bgLocationY = h - this.roadHeight;
        let {scene,backgroundNode} = Util.bj({
            x:0,
            y: bgLocationY,
            width: w,
            height: this.roadHeight,
            picture: "cityRoad.jpg"
        });
        this.scene = scene;
        this.createJp(200,200)
        this.score_text = Util.newText(w-50,20,""+this.score,30,20);
        // 重新开始按钮
        Util.newSprite({
            x: 10,
            y: 5,
            width: 80,
            height: 40,
            texture: 'zaicitiaozhan.png',
            clickCb: ()=>{
                Car.restart();
            }
        })

        this.createCar((w / 2)-50,500);
        this.scene.upDate((time)=>{
            if(!this.gameOver){
                const etime = new Date().getTime();
                const st = etime - this.updateTime;

                this.updateTime = etime;
                if(backgroundNode){
                    let {x,y} = Util.getPosition(backgroundNode);
                    if(y >= 0){
                        backgroundNode.setPosition(0,bgLocationY);
                    }else{
                        backgroundNode.setPosition(0,y + this.roadSpeed);
                    }
                }
                let {x,y} = Util.getPosition(this.jp_button);

                this.jp_button.setPosition(x,y + this.roadSpeed);
                this.changePosition(this.car,this.type);
                if(this.car2){
                    let {x,y} = Util.getPosition(this.car2);
                    this.car2.setPosition(x,y + this.roadSpeed);
                }
                if(this.score_text){
                    this.score_text.setText(""+this.score);
                }

                if(this.gameOver){
                    Util.newText(w/2-50,20,"游戏结束",85,30);
                    return;
                }
            }
        });

    }


    static restart(){
        this.gameOver = false;
        this.score = 0;
        this.car2 = null;
        this.car = null;
        this.init();
    }


    static createCar(x,y){
        let car = Util.newSprite({
            x,y,
            texture:"car.png",
            width:130,
            height: 130,
        });

        this.car = car;
    }

    static createCar2(x,y){
        let car = Util.newSprite({
            x,y,
            texture:"police.png",
            width:130,
            height: 130,
        });

        this.car2 = car;
    }

   // 函数功能:创建奖品
    static createJp(x,y){
        let jp_button = Util.newSprite({
            x,y,
            texture:"phbjp.png",
            width:34,
            height: 34,
        });

        this.jp_button = jp_button;
    }

    static changePosition(node,direction){
        let w = game.getWindow().getWidth();
        let h = game.getWindow().getHeight();
        let position = Util.getPosition(node);
        let x = position.x;
        let y = position.y;
        //log("direction "+direction);
        if(direction){
            let speed = this.carSpeed;
            if(direction == "left"){
                x = x - speed;
                if(x <= - speed){
                    x = - speed;
                }
            }
            if(direction == "right"){
                x = x + speed;
                if(x >= w-100){
                    x = w-100;
                }
            }

            let newPosition = {x,y,width:position.width,height:position.height};
            const jpPosition = Util.getPosition(this.jp_button);
            // 吃奖牌
            const jp_x = Math.floor(Math.random() * w + 50);
            if(Physics.rectRect(jpPosition,newPosition)){
                this.score = this.score + 1;
                this.jp_button.setPosition(jp_x > w-100 ? w-100 : jp_x,-150);
            }else {
                if(jpPosition.y > h){
                    this.jp_button.setPosition(jp_x > w-100 ? w-100 : jp_x,-150);
                }
            }

            node.setPosition(x,y);

            let car2_x = jp_x - 100 < 0 ?jp_x + 100 :jp_x - 200;
            if(this.car2){
                const carPosition = Util.getPosition(this.car2);
                if(Physics.rectRect(carPosition,newPosition,0.6,0.6)){
                    this.gameOver = true;
                }
                if(carPosition.y > h){
                    this.car2.setPosition(car2_x ,-100);
                }
            }else {
                if(this.score >= 1) {
                    log("创汽车");
                    this.createCar2(car2_x,-100)
                }
            }
        }

        this.type = "up";
    }
}

class Physics {
    // 碰撞检测算法: 矩形 vs 矩形
    static rectRect(rect1, rect2,rate1 = 1,rate2=1) {
        if(rate1!==1){
            rect1.x += (rate1-1)*rect1.width;
            rect1.y += (rate1-1)*rect1.height;
            rect1.width *= rate1;
            rect1.height *= rate1;
        }
        if(rate2!==1){
            rect2.x += (rate2-1)*rect2.width;
            rect2.y += (rate2-1)*rect2.height;
            rect2.width *= rate2;
            rect2.height *= rate2;
        }
        return rect1.x < rect2.x + rect2.width
            && rect1.x + rect1.width > rect2.x
            && rect1.y < rect2.y + rect2.height
            && rect1.y + rect1.height > rect2.y;
    }

    // 碰撞检测算法: 圆形 vs 圆形
    static circleCircle(circle1, circle2) {
        const dx = circle1.x - circle2.x;
        const dy = circle1.y - circle2.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        return distance < circle1.radius + circle2.radius;
    }

    // 碰撞检测算法: 矩形 vs 圆形
    static rectCircle(rect, circle) {
        let testX = circle.x;
        let testY = circle.y;
        if (circle.x < rect.x) testX = rect.x; else if (circle.x > rect.x + rect.width) testX = rect.x + rect.width;
        if (circle.y < rect.y) testY = rect.y; else if (circle.y > rect.y + rect.height) testY = rect.y + rect.height;
        const distX = circle.x - testX;
        const distY = circle.y - testY;
        const distance = Math.sqrt(distX * distX + distY * distY);
        return distance <= circle.radius;
    }
}
class Util{
    static scene;
    static bj=(options={})=>{

        let w = game.getWindow().getWidth();
        let h = game.getWindow().getHeight();
        let config = {
            x: 0,
            y: 0,
            width: w,
            height: h,
            picture: "mainbg.png",
            ...options
        };


        let scene = new Scene();
        this.scene = scene;
        game.pushScene(scene);

        const cache_ = game.getResource();

        let bg = cache_.getTexture(config.picture);
        const node = new Sprite();
        node.setTexture(bg);
        node.setSize(config.width,config.height);
        node.setPosition(config.x,config.y);
        node.setColor(1,1,1,1);
        scene.addNode(node);

        return {scene:scene,backgroundNode:node};
    }

    static newSprite(options={}){
        let config = {
            x: 0,
            y: 0,
            width: 50,
            height: 30,
            clickCb: undefined,
            texture: "",
            ...options
        };
        if(!this.scene){
            return;
        }
        const cache_ = game.getResource();
        let bg = cache_.getTexture(config.texture);
        let sprite = new Sprite();
        sprite.setTexture(bg);
        sprite.setSize(config.width, config.height);
        sprite.setPosition(config.x, config.y);
        this.scene.addNode(sprite);

        sprite.click(()=>{
            if (config.clickCb !== undefined && config.clickCb instanceof Function){
                config.clickCb();
            }
        });
        return sprite;
    }


    static newText(x,y,text,width=50,height=30){
        if(!this.scene){
            return;
        }

        const lab = new Label();
        lab.setPosition(x, y);
        lab.setSize(width, height);
        lab.setFont("st.ttf", 20);
        lab.setText(text);
        lab.setTextColor(1.0,0.5,0.2,1.0);
        lab.setColor(0,0,0,0);
        this.scene.addNode(lab);
        return lab;
    }


   // 函数功能:获取节点位置和大小
    static getPosition(node){
        if (!node){
            return;
        }
        let x = node.getPosition().x;
        let y = node.getPosition().y;
        
        let width = node.getSize().x;
        let height = node.getSize().y;

        return {x:x, y:y, width:width, height:height};
    }
}

代码功能:

  1. main.js:游戏初始化,设置背景音乐等
  2. util.js:公共类,设置文字等
  3. car.js:汽车移动类
  4. physics.js:碰撞算法

开维游戏引擎代码简单,函数精简,尽量用极少的js脚本实现游戏功能。代码跨平台通用,一次编写,多端运行,可以直接导出生成exe或者html目录直接运行:

image.png

开维游戏引擎下载: www.ikaiwei.com/download/ga…

赛车小游戏html版页面演示: www.ikaiwei.com/gamejs/exam…

源码下载: github.com/ctrljshaha/…

开发文档: www.ikaiwei.com/gamejs/api/…