开维游戏引擎(Kaiwei Engine)是基于js设计的跨平台游戏引擎。内核c++编写,v8引擎封装游戏函数,Assembly实现htm跨平台高效运行。下面以“赛车小游戏”为实例,演示实现过程。
下载源码,打开gmp工程后,运行即可出现界面:
代码如下:
// 赛车小游戏
// 初始化游戏主屏幕
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};
}
}
代码功能:
- main.js:游戏初始化,设置背景音乐等
- util.js:公共类,设置文字等
- car.js:汽车移动类
- physics.js:碰撞算法
开维游戏引擎代码简单,函数精简,尽量用极少的js脚本实现游戏功能。代码跨平台通用,一次编写,多端运行,可以直接导出生成exe或者html目录直接运行:
开维游戏引擎下载: www.ikaiwei.com/download/ga…
赛车小游戏html版页面演示: www.ikaiwei.com/gamejs/exam…
源码下载: github.com/ctrljshaha/…