view melee/melee.d @ 19:08ddf9e71b88

steer to avoid
author zzzzrrr <mason.green@gmail.com>
date Wed, 25 Mar 2009 14:44:47 -0400
parents 7f74e064dad5
children cad384ad349e
line wrap: on
line source

/*
 * Copyright (c) 2009, Mason Green (zzzzrrr)
 * http://www.dsource.org/projects/openmelee
 * 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of the polygonal nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
module openmelee.melee.melee;

import tango.io.Stdout;

version(distrib) import tango.io.vfs.ZipFolder;
import tango.time.StopWatch;
import fc = tango.text.convert.Float : toString;
import tango.util.log.Trace;

import xf.core.JobHub;
import xf.hybrid.Hybrid;
import xf.hybrid.backend.GL;

import blaze.common.bzMath : bzVec2;
import blaze.bzWorld : bzWorld;
import blaze.collision.bzCollision : bzAABB;

import openmelee.melee.boundaryListener;
import openmelee.melee.contactListener;
import openmelee.render.render;
import openmelee.ai.ai;
import openmelee.ai.human;
import openmelee.ships.urQuan;
import openmelee.ships.orz;
import openmelee.ships.planet;

const ITERS_PER_SECOND = 100;
const k_maxContactPoints = 100;

// Melee settings
struct Settings {
    float hz = 60;
    int velocityIterations = 3;
    int positionIterations = 1;
    bool drawShapes = true;
    bool drawJoints = true;
    bool drawControllers;
    bool drawCoreShapes;
    bool drawAABBs;
    bool drawOBBs;
    bool drawPairs;
    bool drawContactPoints;
    bool drawContactNormals;
    bool drawContactForces;
    bool drawFrictionForces;
    bool drawCOMs;
    bool drawStats;
    bool enableWarmStarting;
    bool enableTOI;
}

class Melee {
    
    Settings settings;
    float timeStep;
    const bzVec2 gravity = bzVec2(0.0f, 0.0f);
    bool allowSleep;
    Render draw;
    
    AI ai;
    Human human;
    Ship ship1;
	Ship ship2;
    
    bool running;
    
    StopWatch timer;
    bzAABB worldAABB;
    bzWorld world;
    bzBoundaryListener m_boundaryListener;
	bzContactListener m_contactListener;
	ContactPoint[k_maxContactPoints] points;
    int pointCount;
    
    this() {
    }
    
    void init() {

        timeStep = settings.hz > 0.0f ? 1.0f / settings.hz : 0.0f;
        version(distrib) gui.vfs.mount(new ZipFolder("./gui.zip"));
        scope cfg = loadHybridConfig("./gui.cfg");
        scope renderer = new Renderer;
    
		m_boundaryListener = new BoundaryListener(this);
		m_contactListener = new ContactListener(this);
        initWorld();
        running = true;
        
        draw = new Render(world, ship1, ship2, settings);
        human = new Human(ship1);
        ai = new AI(ship2, world);
    
        gui.begin(cfg).retained;
        gui.push(`main`);
        GLViewport(`glview`).renderingHandler(&draw.draw)
        .addHandler(&human.onClick)
        .addHandler(&human.onMove)
        .addHandler(&human.onKey)
        .addHandler(&human.onDT)
        .addHandler(&human.onMouseEnter)
        .addHandler(&human.onMouseLeave)
        .grabKeyboardFocus;
        gui.pop();
        gui.immediate.end;
    
        jobHub.addRepeatableJob( {
            // Update physics
            world.step(timeStep, settings.velocityIterations, settings.positionIterations);
        }, ITERS_PER_SECOND);

        jobHub.addPreFrameJob( {
            // Update AI
            ai.move(ship1);
        });

        jobHub.addPostFrameJob( {
            
            // Limit velocity
            ship1.limitVelocity();
            ship2.limitVelocity();
            ship1.updateState();
            ship2.updateState();
            
            gui.begin(cfg);
            gui.push(`main`);
            if (gui().getProperty!(bool)("frame.closeClicked")) {
                running = false;
            }

            if(human.thrust) {
                ship1.thrust();
            }

            gui().setProperty!(bool)("showCursor", true);
            gui.pop();
            gui.end;
            gui.render(renderer);
            
        });
        
        while (running && !human.quit) {
            float delta = timer.stop;
            timer.start;
            jobHub.update(delta);
        }
    }

    void initWorld() {
	    // Define world boundaries
		worldAABB.lowerBound.set(-400.0f, -250.0f);
		worldAABB.upperBound.set(400.0f, 250.0f);
		world = new bzWorld(worldAABB, gravity, allowSleep);
		world.boundaryListener = m_boundaryListener;
		world.contactListener = m_contactListener;
		ship1 = new UrQuan(world);
		ship2 = new Orz(world);
        ship2.rBody.angle = 3.14159265/4;
        auto planet = new Planet(world);
	}
    
    void boundaryViolated(bzBody rBody)
	{
        float x,y;
        
        if(rBody.position.x > worldAABB.upperBound.x) {
            x = worldAABB.lowerBound.x + 5;
            rBody.position = bzVec2(x, rBody.position.y);
        } else if (rBody.position.x < worldAABB.lowerBound.x) {
            x = worldAABB.upperBound.x - 5;
            rBody.position = bzVec2(x, rBody.position.y);
        } else if (rBody.position.y > worldAABB.upperBound.y) {
            y = worldAABB.lowerBound.y + 5;
            rBody.position = bzVec2(rBody.position.x, y);
        } else if(rBody.position.y < worldAABB.lowerBound.y) {
            y = worldAABB.upperBound.y - 5;
            rBody.position = bzVec2(rBody.position.x, y);
        }        
	}
}