Coder Social home page Coder Social logo

coquette's Introduction

Coquette

A micro framework for JavaScript games.

Handles collision detection, the game update loop, canvas rendering, and keyboard and mouse input.

http://coquette.maryrosecook.com

Get the code

Example

A game where you, the valiant player, must find a person of indeterminate gender in distress so you can take them away from all this. The code below appears in /demos/simple/. Open /demos/simple/index.html to play.

The HTML below defines a canvas element and loads in Coquette and the game code.

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="../../coquette.js"></script>
    <script type="text/javascript" src="game.js"></script>
  </head>
  <body><canvas id="canvas"></canvas></body>
</html>

The game code:

var Game = function() {
  this.c = new Coquette(this, "canvas", 500, 150, "#000");

  // paramour
  this.c.entities.create(Person, { center: { x:250, y:40 }, color:"#099" });

  // player
  this.c.entities.create(Person, { center: { x:256, y:110 }, color:"#f07",
    update: function() {
      if (this.c.inputter.isDown(this.c.inputter.UP_ARROW)) {
        this.center.y -= 0.4;
      }
    },

    collision: function(other) {
      other.center.y = this.center.y; // follow the player
    }
  });
};

var Person = function(game, settings) {
  this.c = game.c;
  for (var i in settings) {
    this[i] = settings[i];
  }

  this.size = { x:9, y:9 };
  this.draw = function(ctx) {
    ctx.fillStyle = settings.color;
    ctx.fillRect(this.center.x - this.size.x / 2,
                 this.center.y - this.size.y / 2,
                 this.size.x,
                 this.size.y);
  };
};

window.addEventListener('load', function() {
  new Game();
});

Demos

Five demos are included in this repository:

  • /demos/spinning-shapes - an example of collisions between rotated entities.
  • /demos/racecar - a 2D racing game.
  • /demos/box2d-physics - a game that uses the Box2D physics engine.
  • /demos/leftrightspace - a complete game.
  • /demos/simple - the example at the top of this readme.

Reference

Instantiate Coquette

Pass in:

  • Your main game object.
  • The ID of the canvas element, e.g. "canvas".
  • The desired width of the canvas element.
  • The desired height of the canvas element.
  • The background colour of your game, e.g. "#000".
var YourGame = function() {
  this.c = new Coquette(this, "canvas", 150, 150, "#000");
};

Modules

When you instantiate Coquette, you get an object that has some modules. You can use these modules in your game.

Entities

Keeps track of all the entities in the game: the player, enemies, obstacles.

Define an entity

Most entities will have these attributes:

  • center: The center of the entity, e.g. { x: 10, y: 20 }
  • size: The size of the entity, e.g. { x: 50, y: 30 }
  • angle: The orientation of the entity in degrees, e.g. 30

And these methods:

  • update(timeSinceLastTick): Called every tick. You should change the state of the entity in this method.
  • draw(canvasCtx): Called every tick. You should draw the entity upright in this method. The drawing will automatically get rotated to the orientation indicated by angle.

For example:

var Block = function(game, settings) {
  this.game = game;
  this.center = settings.center;
  this.size = settings.size;
  this.angle = 30;
};

Block.prototype = {
  update: function(timeSinceLastTick) {
    this.center.x += 0.02 * timeSinceLastTick;
    this.center.y += 0.02 * timeSinceLastTick;
  },

  draw: function(canvasCtx) {
    ctx.fillStyle = "black";
    ctx.fillRect(this.center.x - this.size.x / 2,
                 this.center.y - this.size.y / 2,
                 this.size.x,
                 this.size.y);
  }
};

See the Collider section for instructions on enabling collision detection.

Create an entity

Call c.entities.create() with:

  • The constructor function of the entity you want to create, e.g. Block.
  • An optional settings object that will be passed into the constructor, e.g. { center: { x: 5, y: 10 }, size: { x: 10, y: 30 } }.

Returns the created entity.

var Block = function(game, settings) {
  this.game = game;
  this.center = settings.center;
  this.size = settings.size;
  this.angle = 0;
};

var myBlock = c.entities.create(Block, {
  center: { x: 5, y: 10 },
  size: { x: 10, y: 30 }
});
Destroy an entity

Call c.entities.destroy() with:

  • The entity you want to destroy, e.g. myBlock.
c.entities.destroy(myBlock);
Get all the entities in the game
var all = c.entities.all();
Get all the entities of a certain type
var invaders = c.entities.all(Invader);

Inputter

Handles keyboard and mouse input from the player.

Find out if a certain key or mouse button is down
var leftArrowDown = c.inputter.isDown(c.inputter.LEFT_ARROW);
var rightMouseDown = c.inputter.isDown(c.inputter.RIGHT_MOUSE);
Find out if a certain key or mouse button is pressed

This returns true for the tick following the key going down. In subsequent ticks, it returns false until the key is released and pressed down again.

var leftArrowPressed = c.inputter.isPressed(c.inputter.LEFT_ARROW);
var rightMousePressed = c.inputter.isPressed(c.inputter.RIGHT_MOUSE);
Run a function every time the mouse is moved
c.inputter.bindMouseMove(function(position) {
  console.log("The mouse is at", position.x, position.y);
});

position is relative to the game canvas. If the mouse pointer is in the top left corner, position will be { x: 0, y: 0 }.

Get the current mouse position
var position = c.inputter.getMousePosition();

position is relative to the game canvas. If the mouse pointer is in the top left corner, position will be { x: 0, y: 0 }.

Renderer

Holds the canvas drawing context. Calls draw() on the main game object and all the game entities.

Draw an entity

See the Define an Entity sub-section of the Entities section.

Get the canvas drawing context
  var ctx = c.renderer.getCtx();
  ctx.fillStyle = "#f00";
  ctx.fillRect(0, 0, 10, 10);
Set the order that entities are drawn

When you create your entities, set an integer zindex attribute on them. An entity with a higher zindex will get drawn on top of an entity with a lower zindex. The default zindex is 0.

  var BackgroundTile = function() {
    this.zindex = -1;
  };

  var Player = function() {
    this.zindex = 0;
  };

  c.entities.create(BackgroundTile, {});
  c.entities.create(Player, {}); // drawn on top
Move the view

You can use c.renderer.setViewCenter() to move the view around the world. For example, to make the view follow a specific object, you could call setViewCenter(specificObj.center) in the update() function of your game:

  var Game = function() {
    var c = new Coquette(this, "canvas", 500, 500, "#000");
    var specialObject = c.entities.create(SpecialObject, {});

    this.update = function() {
      c.renderer.setViewCenter(specialObject.center);
    };
  };

Collider

Reports when entities collide.

Entity setup

To make an entity support collisions, put these attributes on it:

  • center: The center of the entity, e.g. { x: 10, y: 20 }.
  • size: The size of the entity, e.g. { x: 50, y: 30 }.
  • boundingBox: The shape that best approximates the shape of the entity, either c.collider.RECTANGLE or c.collider.CIRCLE.
  • angle: The orientation of the entity in degrees, e.g. 30.

And, optionally, this method:

  • collision(other): Called when the entity collides with another entity. Takes other, the other entity involved in the collision.

For example:

var Player = function() {
  this.center = { x: 10, y: 20 };
  this.size = { x: 50, y: 50 };
  this.boundingBox = c.collider.CIRCLE;
  this.angle = 0;
};

Player.prototype = {
  collision: function(other) {
    console.log("Ow,", other, "hit me.");
  }
};

Run the tests

Install Node.js and npm: https://github.com/isaacs/npm

Install the node dependencies and run the tests with:

$ cd path/to/coquette
$ npm install --dev
$ npm test

coquette's People

Contributors

cdosborn avatar douglascalhoun avatar eric-brechemier avatar gilhooley avatar graue avatar maryrosecook avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

coquette's Issues

API documentation?

This is an awesome library! Are you interested in API documentation but don't have time, or is it not part of the master plan? I'm game to write some API.md-style docs if you're interested in em.

Mixed Signals: new Coquette() vs Coquette.get()

The use of a constructor lets me think that multiple instances of Coquette can be created, while Coquette.get() hints at a single instance.

What is your stance on that? Would you expect multiple games to be created with Coquette in a single page?

entity paint order (ala z-index)

is there an existing way to ensure that entities are painted in a certain order? I noticed in your advanced demo that you have a zIndex field on your entities, but I didn't see where that field is actually used. I tried adding zIndex to my entities but it doesn't affect what order they are painted.

additional input keys

Is the limited support for only the up/down/left/right arrow keys and space bar deliberate? Do you want to keep the inputs limited so that the framework stays simple? Or would the introduction of other keys be welcomed? The implementation would obviously be trivial, but I was just wondering what others would think before implementing and sending a PR.

Adding support for more input devices

Hi Mary!

I was wondering if you'd accept pull requests that add support for the following types of input:

I have no idea what the API for such things would look like yet--just curious if you think they'd be in-scope for coquette, or if they should be spun off as extensions or somesuch.

Hope you're having a great summer!

Intro example positioning

The intro example on http://coquette.maryrosecook.com/ is great & succinct, but leads to some surprising collision scenarios. The example later has the collision behavior you would expect - maybe this can be displayed earlier?

    ctx.fillRect(this.center.x - this.size.x / 2,
                 this.center.y - this.size.y / 2,
                 this.size.x,
                 this.size.y);

Move drawing logic from updater to renderer

The respective roles of the Updater and the Renderer are slightly confusing in current implementation:

  • the update() method of the Renderer draws the background
  • the update() method of the Updater draws the game and entities

It would make more sense, from my point of view, to add a draw() method in the Renderer, drawing the background as well as the game and entities.

Clarify public API

There are various levels of publicness currently:

  1. properties and methods described in the README, used in examples and demos
  2. properties and methods used in the unit tests
  3. properties and methods used in a single module
  4. one property, _entities in entities.js used in a single module whose name starting with an underscore suggests that it is not for public use
  5. properties and methods actually private, only accessible in a single module or one part of a single module

I acknowledge that it is hard to make a property of an instance private since all properties set to this are publicly accessible.

I see two possible directions to solve this issue:

  • declare all methods within the constructor instead of setting them on the prototype, and set properties to local variables of the constructor instead of this (aka the Douglas Crockford way)
  • let properties and methods accessible but mark them as private by naming convention, e.g. using an initial underscore (aka the Perl way)

What is your take on the subject?

Mouse position gives incorrect coordinates

Issue: inputter.getMousePosition() gives wrong coordinates.

Trigger: set the parent of the canvas (ex. the body) to have "position:relative"

Description: canvas[offsetTop | offsetLeft ] normally give the correct offset of the canvas to calculate the mouse position relative to the canvas. However, if the parent of the canvas is "position:relative" then the offset is incorrect.

Fix: use canvas.getBoundingClientRect() which returns the correct offset.

Provide elapsed interval in update()

In the advanced demo, the update() method of Asteroid and Bullet use this.game.coquette.updater.tick as the time elapsed in the computation of the shift in position.

It would be more convenient to provide the actual time elapsed as an argument of update().

Edit: the tick is correctly updated in update() method of Updater.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.