Skip to content

Instantly share code, notes, and snippets.

@nasser
Created April 25, 2015 20:59
Show Gist options
  • Select an option

  • Save nasser/7400f6afac202b3a64d3 to your computer and use it in GitHub Desktop.

Select an option

Save nasser/7400f6afac202b3a64d3 to your computer and use it in GitHub Desktop.
QuadC - Final
//
// ECS.cpp
// quadc_two
//
// Created by Ramsey Nasser on 4/25/15.
//
//
//////// framework
#include "ECS.h"
// to add the component, extract its name and assign that index in the map
// to the value of the component
void ecsEntity::addComponent(ecsComponent *c) {
components[c->name()] = c;
}
// to retrieve a component, look it up by name in the map
ecsComponent* ecsEntity::getComponent(string name) {
return components[name];
}
// to remove a component, remove it by name from the map
void ecsEntity::removeComponent(string name) {
components.erase(name);
}
// to run an entity, loop through every component in the components map
// and call run on it, passing this (the current object, an entity) to the
// run method. this allows each component to modify the entity they are
// attached to
void ecsEntity::run() {
// looping though a map, you are given key,value pairs. the begin, end, ++
// syntax here is c++ iterators, which is what you use to move through
// a datastructure like a map
for(auto pair = components.begin(); pair != components.end(); pair++) {
// pair->first refers to the key, in our case the string that contains
// the name of the component. pair->second refers to the value, in our
// case the actual component object
ecsComponent* theComponent = pair->second;
// call run, passing the entity
theComponent->run(this);
}
}
//////// components
// run method implememtation for circle draw component
void ecsCircleDrawComponent::run(ecsEntity *e) {
// grab the position component from the entity e, cast it to ecsPositionComponent
// so c++ does not complain, then extract its position value
ofVec2f p = ((ecsPositionComponent*)e->getComponent("position"))->position;
// draw a circle at the position just extracted with the radius that the
// circle draw component maintains
ofCircle(p, radius);
}
// run method implememtation for chaser component
void ecsChaserComponent::run(ecsEntity *e) {
// grab the position component from the entity e and cast it to ecsPositionComponent
ecsPositionComponent* pc = ((ecsPositionComponent*)e->getComponent("position"));
// update its position value to a value between the current position value and the target
// this is an implementation of linear interpolation
pc->position.set(pc->position.x * speed + target.x * (1 - speed),
pc->position.y * speed + target.y * (1 - speed));
}
// run method implememtation for mouse control component
void ecsMouseControlComponent::run(ecsEntity *e) {
// grab the chaser component from the entity e and cast it to ecsChaserComponent
ecsChaserComponent* chaser = ((ecsChaserComponent*)e->getComponent("chaser"));
// update the target of the chaser component to the current mouse position
chaser->target.set(ofGetMouseX(), ofGetMouseY());
}
//
// ECS.h
// quadc_two
//
// Created by Ramsey Nasser on 4/25/15.
//
//
#ifndef quadc_two_ECS_h
#define quadc_two_ECS_h
#include "ofMain.h"
//////// framework
// forward declare ecsEntity so that ecsComponent does not freak out
class ecsEntity;
// base class for all components
class ecsComponent {
public:
// every component must be able to produce its own name
// the = 0 means that there is no default, and writing a
// component without a name() method is an error
virtual string name() = 0;
// every component can optionally implement a run method
// if present, it will be used to update the entity that
// the component is attached to. the { } means that the
// default implementation is to do nothing, and that a run
// method is not required
virtual void run(ecsEntity* e) { };
};
// class for all entities
class ecsEntity {
public:
// components can be added to an entity
void addComponent(ecsComponent* c);
// components can be returned from an entity
ecsComponent* getComponent(string name);
// components can be removed from an entity
void removeComponent(string name);
// entities can be run, running all their components as a result
void run();
private:
// internally, components are maintained in a map from their name to their instance
// e.g. "position" -> the actual position component object
std::map<string, ecsComponent*> components;
};
//////// components
// position component encodes the position of an object
// no run logic, just data
class ecsPositionComponent : public ecsComponent {
public:
virtual string name() { return "position"; }
ofVec2f position;
};
// circle drawing component draws a circle at the position component's position
// maintains radius as data
class ecsCircleDrawComponent : public ecsComponent {
public:
virtual string name() { return "circleDraw"; }
float radius;
virtual void run(ecsEntity* e);
};
// chaser component updates the position component's position to move closer to a target
// maintains the target position and speed as data
class ecsChaserComponent : public ecsComponent {
public:
virtual string name() { return "chaser"; }
ofVec2f target;
float speed;
virtual void run(ecsEntity* e);
};
// mouse control component upadates the chaser component to target the mouse
class ecsMouseControlComponent : public ecsComponent {
public:
virtual string name() { return "mouse"; }
virtual void run(ecsEntity* e);
};
#endif
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
// create a new entity
ecsEntity* e = new ecsEntity();
// create and attach a position component
ecsPositionComponent* positionComponent = new ecsPositionComponent();
positionComponent->position.set(42, 13);
e->addComponent(positionComponent);
// create and attach a circle draw component
ecsCircleDrawComponent* circleDraw = new ecsCircleDrawComponent();
circleDraw->radius = 30;
e->addComponent(circleDraw);
// create and attach a chaser component
ecsChaserComponent* chaser = new ecsChaserComponent();
chaser->target.set(ofGetWidth(), ofGetHeight());
chaser->speed = 0.9;
e->addComponent(chaser);
// create and attach a circle draw component
e->addComponent(new ecsMouseControlComponent());
// add the entity to app
addEntity(e);
// create a DIFFERENT entity
ecsEntity* e2 = new ecsEntity();
// create and attach a different position component
ecsPositionComponent* positionComponent2 = new ecsPositionComponent();
positionComponent2->position.set(100, 50);
e2->addComponent(positionComponent2);
// create and attach a different circle draw component
ecsCircleDrawComponent* circleDraw2 = new ecsCircleDrawComponent();
circleDraw2->radius = 50;
e2->addComponent(circleDraw2);
// add the second entity to the app
addEntity(e2);
}
// adding an entity pushes it to the entities vector
void ofApp::addEntity(ecsEntity* e) {
entities.push_back(e);
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
// every frame, loop through the entities vector and tell each entity to run
for(int i=0; i<entities.size(); i++) {
entities[i]->run();
}
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
// when a key is pressed, create a new entity and add it to the scene
ecsEntity* e = new ecsEntity();
ecsPositionComponent* positionComponent = new ecsPositionComponent();
positionComponent->position.set(ofRandom(1000), ofRandom(1000));
e->addComponent(positionComponent);
ecsCircleDrawComponent* circleDraw = new ecsCircleDrawComponent();
circleDraw->radius = ofRandom(50);
e->addComponent(circleDraw);
addEntity(e);
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}
#pragma once
#include "ofMain.h"
#include "ECS.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
// add entity to the game
void addEntity(ecsEntity* e);
// the internal storage of entities
std::vector<ecsEntity*> entities;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment